119 Commits

Author SHA1 Message Date
jdegenstein
6fe767c0a4 Delete pyinstaller.spec 2024-01-02 11:46:25 -06:00
jdegenstein
1bb94c1d76 Delete .github/workflows/pyinstaller-builds-actions.yml 2024-01-02 11:46:13 -06:00
jdegenstein
003b9eb3f5 Delete .github/workflows/pyinstaller-builds-actions-mmamba.yml 2024-01-02 11:46:06 -06:00
jdegenstein
143d7712cd Delete .github/workflows/pyinstaller-builds-actions-mmamba-TAR.yml 2024-01-02 11:45:55 -06:00
jdegenstein
aaf0d31b52 Delete .github/workflows/pyinstaller-builds-actions-build-PIP-TAR-pyinst5-6p.yml 2024-01-02 11:45:33 -06:00
jdegenstein
14d0477d1d README.md -> add bd_warehouse 2024-01-02 10:56:34 -06:00
jdegenstein
5b0504f22b pyinstaller_pip.spec -> add bd_warehouse 2024-01-02 10:55:24 -06:00
jdegenstein
3ed0deff41 pyinstaller-builds-actions-PIP-TAR.yml -> install bd_warehouse 2024-01-02 10:49:14 -06:00
jdegenstein
e00e40c7b0 Update pyinstaller-builds-actions-PIP-TAR.yml
back to python 3.10
2023-10-30 13:44:07 -05:00
jdegenstein
035b95c508 Update pyinstaller-builds-actions-PIP-TAR.yml
bump to Ubuntu-22.04 and python 3.11
2023-10-30 13:42:10 -05:00
jdegenstein
656426f645 Delete pyinstaller/extrahooks/hook-rtree.py
fixed on pyinstaller hooks contrib, this file did not produce working linux builds anyway
2023-10-26 13:40:46 -05:00
jdegenstein
ab6526c1fe Create hook-rtree.py 2023-10-20 15:19:04 -05:00
jdegenstein
d8c4e5bfac Create hook-py_lib3mf.py 2023-10-20 14:01:40 -05:00
jdegenstein
f52fc4dd42 remove getfullnameof in pyinstaller_pip.spec
changes in pyinstaller>=6.0.0 removed getfullnameof
2023-09-25 10:53:38 -05:00
jdegenstein
25d4c2c45c Swap front/back view directions to match with OCP CAD Viewer
also makes it match with many other CAD software
2023-07-05 16:41:13 -05:00
jdegenstein
e59c6ae7ba Add Release Info to README.md 2023-06-16 12:29:05 -05:00
jdegenstein
0c7237fecb GH Actions: Downgrade tartifact to @v1 for MacOS
due to shopt globstar invalid on MacOS
2023-06-15 11:13:42 -05:00
jdegenstein
a83d03c7ef GH Actions init-shell powershell for windows 2023-06-15 10:00:09 -05:00
jdegenstein
1b75bf8fc0 GH Actions to checkout@v3 and tartifact@v2
alehechka/upload-tartifact@v2
actions/checkout@v3

for Node16 compat
2023-06-15 09:49:20 -05:00
jdegenstein
21d729d758 Update actions to use setup-micromamba instead of prov mm
Update actions to use setup-micromamba instead of provision-with-micromamba
2023-06-15 09:37:19 -05:00
jdegenstein
1f546f4bc5 Update README.md 2023-05-08 14:09:54 -05:00
jdegenstein
56ca315097 testing py 3.11 2023-04-19 11:21:22 -05:00
jdegenstein
9a60cf7802 add unused parameters to show_object for compat with ocp_vscode 2023-04-12 10:49:10 -05:00
jdegenstein
151b8b8e36 fix missing import Quantity_TOC_RGB
Quantity_TOC_RGB as TOC_RGB for consistency
2023-03-19 12:19:03 -05:00
jdegenstein
0ba64024e0 change x-axis to "wine red" color
to create a difference between the axis and wires/edges
2023-03-13 13:39:27 -05:00
jdegenstein
a4b86630dc change to "wine red" x-axis 2023-03-13 13:37:25 -05:00
jdegenstein
55c23b19ff add doc for name and rand_color in show_object to README.md 2023-03-01 09:22:11 -06:00
jdegenstein
d9153abfca bump MacOS static build to pyinstaller>=5.6 2023-02-27 14:21:41 -06:00
jdegenstein
deca2f1b89 patched local hooks-contrib 2023-02-27 14:11:23 -06:00
jdegenstein
215c200aa1 install pyinstaller-hooks-contrib from GH
contains a fix for pyqtgraph builds
2023-02-27 14:04:53 -06:00
jdegenstein
c1f08af0de bump OCP static lib to python 3.10 2023-02-27 12:20:10 -06:00
jdegenstein
fba053d026 unpin casadi==3.5.5 to fix linux static builds 2023-02-27 11:54:53 -06:00
jdegenstein
be2989c424 pin all to python=3.10 2023-02-27 11:50:04 -06:00
jdegenstein
df863ae27c bump to python=3.10 to fix linux static build 2023-02-27 11:49:07 -06:00
jdegenstein
611d189051 bump python=3.10 linux static build 2023-02-27 11:45:33 -06:00
jdegenstein
653502e913 try unpin pyqtgraph==0.12.4 to fix linux static builds 2023-02-27 11:35:45 -06:00
jdegenstein
5e49adcf54 install jupyter-rfb on linux static build 2023-02-27 11:25:42 -06:00
jdegenstein
feef729143 try unpin ipython==8.4.0 to fix linux static builds 2023-02-27 11:17:43 -06:00
jdegenstein
3ef2ec4447 install pyopengl on linux static build 2023-02-21 12:10:29 -06:00
jdegenstein
0d1ee5d5af add qtbase5-dev qt5-qmake to linux static build 2023-02-21 12:05:12 -06:00
jdegenstein
c1e75a8b62 update to pyinstaller>=5.6 2023-02-21 11:40:45 -06:00
jdegenstein
b408429405 Unpin scipy from setup.py 2023-02-21 11:33:11 -06:00
jdegenstein
6a762801c1 pyinstall 5.6 remove --debug 2023-02-21 11:02:45 -06:00
jdegenstein
ba3f45ea25 Testing pyinstaller >=5.6 2023-02-21 10:53:40 -06:00
jdegenstein
9eca091fa3 test scipy<=1.9.1 in setup.py 2023-02-20 21:27:58 -06:00
jdegenstein
43c4708847 Testing unpinning jedi in setup.py 2023-02-20 09:22:13 -06:00
jdegenstein
e71a5f1c62 Update README
Update CQ pip install, and add more linux install info.
2023-02-17 13:32:41 -06:00
jdegenstein
6b762baf41 Merge pull request #6 from jdegenstein/mactrackpad
Change right click and drag to pan
2023-02-14 15:03:19 -06:00
jdegenstein
758afb5f18 Add discord link to readme 2023-02-11 13:41:56 -06:00
jdegenstein
cf43cee874 Update build123d install instruction 2023-02-11 13:31:16 -06:00
jdegenstein
29b2faeaa8 Change rand_color seed
seed(371353) - > seed(59798267586177) 
has better colors that are more distinguishable from one another
2023-02-10 19:32:34 -06:00
jdegenstein
9506307367 Add pip install instruction for build123d to README 2023-02-02 15:38:55 -06:00
jdegenstein
524a8dd6fd Change right click and drag to pan
Change right click and drag to pan (same as middle click and drag)
2023-02-02 15:25:27 -06:00
jdegenstein
bd12503e81 Additional info about build123d compat and more links 2023-01-23 11:29:18 -06:00
jdegenstein
2ba23c4659 build123d compat 2023-01-09 12:22:14 -06:00
jdegenstein
ee6a60705c remove debugging print 2023-01-09 12:18:23 -06:00
jdegenstein
a144b2e60a build123d compatibility improvements for file exporting
Removes the need to use .wrapped for the CQ-editor file exporter to work correctly. Also ran file through black formatter.
2023-01-09 12:16:49 -06:00
jdegenstein
7b49f25f94 Revert ubuntu-1804 changes to test ubuntu-2004 2022-11-03 13:57:23 -05:00
jdegenstein
2b3620b759 max verbosity 2022-11-01 21:14:08 -05:00
jdegenstein
afa20cd715 increase pip verbosity for cadquery and casadi install 2022-11-01 20:56:21 -05:00
jdegenstein
2d7fbeb08d changes for ubuntu1804
from:
casadi==3.5.5
to:
casadi
2022-11-01 20:46:50 -05:00
jdegenstein
ecaf68edac changes for ubuntu-1804
change from:
sudo apt install -y libblas-dev libblas3 libblas64-3 libblas64-dev
to:
sudo apt install -y libblas-dev libblas3
2022-11-01 20:42:57 -05:00
jdegenstein
69d6bc368e testing ubuntu-18.04 2022-11-01 20:39:09 -05:00
jdegenstein
dbc90c2724 register rand_color for use in console 2022-10-28 23:36:26 -05:00
jdegenstein
fbbb1fd7b6 Update debugger.py 2022-10-28 23:33:57 -05:00
jdegenstein
73a5825f3f add rand_color 2022-10-28 22:02:32 -05:00
jdegenstein
fefb57c2b9 remove rand_color 2022-10-28 21:59:28 -05:00
jdegenstein
5e0d68e2ad remove rand_color 2022-10-28 21:58:20 -05:00
jdegenstein
7c8fa2b100 from .widgets.object_tree import ObjectTree, rand_color 2022-10-28 21:02:07 -05:00
jdegenstein
925aded53c add rand_color() helper function
and seed(371353) global
2022-10-28 20:05:51 -05:00
jdegenstein
973448697a move to ubuntu-22.04 from ubuntu-latest (20.04)
trying to get libstdc++.so.6.30 instead of ...28
2022-10-28 15:34:40 -05:00
jdegenstein
c5e0d73422 fix list(tuple) 2022-10-28 12:05:18 -05:00
jdegenstein
a7a376f9f5 point to pyinstaller_pip.spec on Linux/MacOS 2022-10-28 11:59:52 -05:00
jdegenstein
e436bd3d7e Re-enable Linux/MacOS on -PIP-TAR.yaml
try and emulate Windows installation process, wherever possible
2022-10-28 11:52:16 -05:00
jdegenstein
26b64607a5 hookspath=['pyinstaller/extrahooks/']to _pip.spec 2022-10-28 11:28:22 -05:00
jdegenstein
000fe986e0 Delete dup hook-casadi.py 2022-10-28 11:24:30 -05:00
jdegenstein
acf5639e76 create subdir and add hook-casasi.py to it
create subdir and add hook-casasi.py to it
2022-10-28 11:24:12 -05:00
jdegenstein
ebcb831ca9 Update pyinstaller_pip.spec
add hook-casadi.py
2022-10-28 10:23:58 -05:00
jdegenstein
fd47eadcdc Create hook-casadi.py
per discussion https://github.com/pyinstaller/pyinstaller/discussions/7199
2022-10-28 10:22:11 -05:00
jdegenstein
67fa19704e Update pyinstaller-builds-actions-PIP-TAR.yml
change from:
pip install --pre cadquery casadi==3.5.5
to:
pip install --pre git+https://github.com/cadquery/cadquery casadi==3.5.5
2022-10-28 10:18:01 -05:00
jdegenstein
272bede28f Update pyinstaller-builds-actions-PIP-TAR.yml
Remove: 
        pip install pipwin
        pipwin install numpy
Will probably break everything because we may need MKL-enabled numpy.
2022-10-28 08:56:08 -05:00
jdegenstein
9f4fa50c7c Update pyinstaller-builds-actions-PIP-TAR.yml
pip list
tree $PWD /F
2022-10-27 20:31:31 -05:00
jdegenstein
03e8575210 Update README.md
add pip install directions
2022-10-27 20:17:35 -05:00
jdegenstein
0087803ee4 Update pyinstaller-builds-actions-PIP-TAR.yml
unpin ipopt==3.4.10
2022-10-27 19:45:28 -05:00
jdegenstein
72e814db3b Update pyinstaller_pip.spec 2022-10-27 19:34:34 -05:00
jdegenstein
466d1e7534 Update pyinstaller-builds-actions-PIP-TAR.yml
pin ipopt==3.4.10 casadi==3.5.5
2022-10-27 19:33:50 -05:00
jdegenstein
3f3e22c2f1 Update pyinstaller_pip.spec
remove (occt_dir, 'opencascade') from _pip.spec
2022-10-27 16:51:32 -05:00
jdegenstein
aa90e48968 Create pyinstaller_pip.spec 2022-10-27 16:40:50 -05:00
jdegenstein
0e29e3091b Update pyinstaller-builds-actions-PIP-TAR.yml
point to new spec file
2022-10-27 16:37:33 -05:00
jdegenstein
66e620a877 Update pyinstaller-builds-actions-PIP-TAR.yml
change from:
pip install git+https://github.com/cadquery/cadquery
to:
pip install --pre cadquery

hopefully will resolve cadquery-ocp
2022-10-27 16:26:56 -05:00
jdegenstein
14535ec7a4 Create pyinstaller-builds-actions-PIP-TAR.yml
trying to use as few conda/mamba steps as possible
2022-10-27 16:14:02 -05:00
jdegenstein
ee09398909 Update viewer.py to bring up to date with Mainline a2df6ff 2022-10-27 14:52:00 -05:00
jdegenstein
10a81d4e12 Update cq_utils.py to bring up to date with Mainline a2df6ff 2022-10-27 14:50:32 -05:00
jdegenstein
ca706045ba Update test_app.py to bring up to date with Mainline a2df6ff 2022-10-27 14:46:05 -05:00
jdegenstein
ce68e6e120 Update setup.py
add "pyqtgraph==0.12.4"
2022-10-27 13:30:47 -05:00
jdegenstein
839d514f66 add missing libraries to spec file
casadi_nlpsol_ipopt.dll
ipopt-3.dll
libblas.dll
liblapack.dll
dmumps.dll
flang.dll
flangrti.dll
libomp.dll
mkl*.dll (a few dozen DLLs)
2022-10-27 10:12:10 -05:00
jdegenstein
36f2896652 Fix casadi*.dll path 2022-10-26 13:10:40 -05:00
jdegenstein
36f23a4d7e change casadi...dll path in mmamba-TAR.yml 2022-10-26 12:55:46 -05:00
jdegenstein
c85c8358f5 Update mmamba-TAR.yml to include casadi_nlpsol_ipopt.dll
using Copy-Item after PyInstaller has run
2022-10-26 12:33:24 -05:00
jdegenstein
de73e88033 Remove casadi DLLs from pyinstaller.spec
remove cas_DLLs from binaries and datas
2022-10-26 12:29:24 -05:00
jdegenstein
be62509ba7 Update pyinstaller-builds-actions-mmamba-TAR.yml
install casadi and ipopt
2022-10-26 10:49:29 -05:00
jdegenstein
b0284ac80c Add ipopt and casadi to hidden imports in spec 2022-10-26 10:27:15 -05:00
jdegenstein
2d7cb64247 Update pyinstaller.spec
attempt to add cas_DLLs to datas (in addition to binaries earlier)
2022-10-25 21:41:28 -05:00
jdegenstein
5b474bb493 Update pyinstaller.spec
try to only add casadi DLLs
2022-10-25 21:17:11 -05:00
jdegenstein
0818537f34 Update pyinstaller-builds-actions-mmamba-TAR.yml
re-enable tar(tifact)
2022-10-25 21:07:35 -05:00
jdegenstein
cf7253ebe7 Update pyinstaller.spec
add casadi DLL directory
2022-10-25 20:57:27 -05:00
jdegenstein
4a6e9a1cc3 Update pyinstaller.spec
add casadi to datas
2022-10-25 19:45:18 -05:00
jdegenstein
22c3d3a37b Update pyinstaller-builds-actions-mmamba-TAR.yml 2022-10-25 16:42:33 -05:00
jdegenstein
dfb79aa306 Update pyinstaller.spec
add a comma
2022-10-25 16:41:51 -05:00
jdegenstein
3ac6e93a5e Update pyinstaller.spec to include casadi 2022-10-25 16:13:25 -05:00
jdegenstein
621e0dc86b Update pyinstaller.spec
str to list
2022-10-25 15:56:38 -05:00
jdegenstein
3764233ed7 Update pyinstaller-builds-actions-mmamba-TAR.yml
use windows only, disabled TAR
2022-10-25 15:33:08 -05:00
jdegenstein
6e26bdb7fc Testing add casadi DLLs to pyinstaller.spec 2022-10-25 15:31:03 -05:00
jdegenstein
5fd737ab50 pin jedi==0.17.2 in setup.py 2022-10-20 22:41:26 -05:00
jdegenstein
cfb952047f fix pin 2022-10-20 22:18:58 -05:00
jdegenstein
974fd51f88 Merge pull request #2 from jdegenstein/dev
Dev to Main
2022-10-21 03:13:34 +00:00
jdegenstein
6bd2148257 Pin ipython=8.4.0 version to setup.py 2022-10-20 22:11:29 -05:00
jdegenstein
39bb40289f Update setup.py for pip install per u/sethfischer
from a PR on mainline
2022-10-20 22:00:48 -05:00
jdegenstein
02453f7823 Link to projects, remove wrong install, link to build actions 2022-10-17 15:23:48 -05:00
16 changed files with 1232 additions and 1262 deletions

View File

@@ -1,4 +1,4 @@
name: build-micromamba
name: build-PIP-TAR
on:
schedule:
- cron: '0 0 * * 1'
@@ -10,112 +10,125 @@ on:
default: 'dir'
jobs:
build-linux:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: mamba-org/provision-with-micromamba@main
- uses: actions/checkout@v3
- uses: mamba-org/setup-micromamba@v1
with:
#miniconda-version: "latest"
#auto-update-conda: true
environment-name: test
environment-file: environment.yml
extra-specs:
python=3.9
- name: Mamba install CadQuery and pyinstaller
create-args: >-
python=3.10
- name: pip install cadquery CQ-editor ... etc
shell: bash --login {0}
run: |
sudo apt install -y libblas-dev libblas3 libblas64-3 libblas64-dev
sudo apt install -y libxkbcommon0
sudo apt install -y libxkbcommon-x11-0
sudo apt install -y libxcb-xinerama0
sudo apt install -y qtbase5-dev qt5-qmake
micromamba info
micromamba install -c cadquery -c conda-forge cq-editor=master cadquery=master debugpy ipython=8.4.0 jedi=0.17.2 python=3.9
micromamba install -c conda-forge pyinstaller=4.10
pip install pyopengl
pip install git+https://github.com/jdegenstein/jmwright-CQ-Editor
pip install -vvv --pre git+https://github.com/cadquery/cadquery casadi
pip install pyinstaller>=5.6 git+https://github.com/jdegenstein/pyinstaller-hooks-contrib
pip install path
pip install jupyter-rfb
pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
pip install git+https://github.com/gumyr/bd_warehouse
pip install git+https://github.com/meadiode/cq_gears.git@main
pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
pip install git+https://github.com/gumyr/build123d.git#egg=build123d
pip install git+https://github.com/gumyr/build123d
pip install git+https://github.com/JustinSDK/cqMore
pip list
- name: Run build
shell: bash --login {0}
run: |
micromamba info
pyinstaller pyinstaller.spec ${{ github.event.inputs.type }}
pyinstaller pyinstaller_pip.spec ${{ github.event.inputs.type }}
cp /home/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/pyinstaller/CQ-editor.sh /home/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/dist/
- uses: actions/upload-artifact@v2
- uses: alehechka/upload-tartifact@v2
with:
name: CQ-editor-Linux-x86_64
path: dist
build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: mamba-org/provision-with-micromamba@main
- uses: actions/checkout@v3
- uses: mamba-org/setup-micromamba@v1
with:
#miniconda-version: "latest"
#auto-update-conda: true
environment-name: test
environment-file: environment.yml
extra-specs:
python=3.9
- name: Mamba install CadQuery and pyinstaller
create-args: >-
python=3.10
- name: pip install cadquery CQ-editor ... etc
shell: bash --login {0}
run: |
micromamba info
micromamba install -c cadquery -c conda-forge cq-editor=master cadquery=master debugpy ipython=8.4.0 jedi=0.17.2 python=3.9
micromamba install -c conda-forge pyinstaller
pip install git+https://github.com/jdegenstein/jmwright-CQ-Editor
pip install --pre git+https://github.com/cadquery/cadquery casadi
pip install pyinstaller>=5.6 git+https://github.com/jdegenstein/pyinstaller-hooks-contrib
pip install path
pip uninstall -y PyQt5
pip install PyQt5==5.15.7
pip install PyQtWebEngine==5.15.6
pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
pip install git+https://github.com/gumyr/bd_warehouse
pip install git+https://github.com/meadiode/cq_gears.git@main
pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
pip install git+https://github.com/gumyr/build123d.git#egg=build123d
pip install git+https://github.com/gumyr/build123d
pip install git+https://github.com/JustinSDK/cqMore
pip list
- name: Run build
shell: bash --login {0}
run: |
micromamba info
pyinstaller pyinstaller.spec ${{ github.event.inputs.type }}
pyinstaller pyinstaller_pip.spec ${{ github.event.inputs.type }}
cp /Users/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/pyinstaller/CQ-editor.sh /Users/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/dist/
- uses: actions/upload-artifact@v2
- uses: alehechka/upload-tartifact@v1
with:
name: CQ-editor-MacOS
path: dist
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: mamba-org/provision-with-micromamba@main
- uses: actions/checkout@v3
- uses: mamba-org/setup-micromamba@v1
with:
#miniconda-version: "latest"
#auto-update-conda: true
environment-name: test
environment-file: environment.yml
extra-specs:
python=3.9
- name: Mamba install CadQuery and pyinstaller
init-shell: >-
powershell
create-args: >-
python=3.10
- name: pip install cadquery CQ-editor ... etc
shell: powershell
run: |
micromamba install -c cadquery -c conda-forge cq-editor=master cadquery=master debugpy ipython=8.4.0 jedi=0.17.2 python=3.9
micromamba install -c conda-forge pyinstaller=4.10
micromamba info
pip install git+https://github.com/jdegenstein/jmwright-CQ-Editor
pip install --pre git+https://github.com/cadquery/cadquery casadi
pip install pyinstaller>=5.6 git+https://github.com/jdegenstein/pyinstaller-hooks-contrib
pip install path
pip install pipwin
pipwin install numpy
pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
pip install git+https://github.com/gumyr/bd_warehouse
pip install git+https://github.com/meadiode/cq_gears.git@main
pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
pip install git+https://github.com/gumyr/build123d.git#egg=build123d
pip install git+https://github.com/gumyr/build123d
pip install git+https://github.com/JustinSDK/cqMore
pip list
- name: Run build
shell: powershell
run: |
micromamba info
pyinstaller --debug all pyinstaller.spec ${{ github.event.inputs.type }}
pyinstaller pyinstaller_pip.spec ${{ github.event.inputs.type }}
Copy-Item D:\a\jmwright-CQ-Editor\jmwright-CQ-Editor\pyinstaller\CQ-editor.cmd D:\a\jmwright-CQ-Editor\jmwright-CQ-Editor\dist\
- uses: actions/upload-artifact@v2
- uses: alehechka/upload-tartifact@v2
with:
name: CQ-editor-Windows
path: dist

View File

@@ -1,125 +0,0 @@
name: build-micromamba-TAR
on:
schedule:
- cron: '0 0 * * 1'
workflow_dispatch:
inputs:
type:
description: 'Whether to build a single file (onefile) or directory (dir) dist'
required: true
default: 'dir'
jobs:
# build-linux:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - uses: mamba-org/provision-with-micromamba@main
# with:
# #miniconda-version: "latest"
# #auto-update-conda: true
# environment-name: test
# environment-file: environment.yml
# extra-specs:
# python=3.9
# - name: Mamba install CadQuery and pyinstaller
# shell: bash --login {0}
# run: |
# sudo apt install -y libblas-dev libblas3 libblas64-3 libblas64-dev
# sudo apt install -y libxkbcommon0
# sudo apt install -y libxkbcommon-x11-0
# sudo apt install -y libxcb-xinerama0
# micromamba info
# micromamba install -c cadquery -c conda-forge cq-editor=master cadquery=master debugpy ipython=8.4.0 jedi=0.17.2 python=3.9
# micromamba install -c conda-forge pyinstaller=4.10
# micromamba uninstall --force -y importlib_resources
# pip install path
# pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
# pip install git+https://github.com/meadiode/cq_gears.git@main
# pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
# pip install git+https://github.com/gumyr/build123d.git#egg=build123d
# - name: Run build
# shell: bash --login {0}
# run: |
# micromamba info
# pyinstaller pyinstaller.spec ${{ github.event.inputs.type }}
# cp /home/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/pyinstaller/CQ-editor.sh /home/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/dist/
# rm /home/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/dist/CQ-editor/libstdc++.so.6
# - uses: actions/upload-tartifact@main
# with:
# name: CQ-editor-Linux-x86_64
# path: dist
# build-macos:
# runs-on: macos-latest
# steps:
# - uses: actions/checkout@v2
# - uses: mamba-org/provision-with-micromamba@main
# with:
# #miniconda-version: "latest"
# #auto-update-conda: true
# environment-name: test
# environment-file: environment.yml
# extra-specs:
# python=3.9
# - name: Mamba install CadQuery and pyinstaller
# shell: bash --login {0}
# run: |
# micromamba info
# micromamba install -c cadquery -c conda-forge cq-editor=master cadquery=master debugpy ipython=8.4.0 jedi=0.17.2 python=3.9
# micromamba install -c conda-forge pyinstaller
# micromamba uninstall --force -y importlib_resources
# pip install path
# pip uninstall -y PyQt5
# pip install PyQt5==5.15.7
# pip install PyQtWebEngine==5.15.6
# pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
# pip install git+https://github.com/meadiode/cq_gears.git@main
# pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
# pip install git+https://github.com/gumyr/build123d.git#egg=build123d
# - name: Run build
# shell: bash --login {0}
# run: |
# micromamba info
# pyinstaller pyinstaller.spec ${{ github.event.inputs.type }}
# cp /Users/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/pyinstaller/CQ-editor.sh /Users/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/dist/
# - uses: actions/upload-tartifact@main
# with:
# name: CQ-editor-MacOS
# path: dist
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: mamba-org/provision-with-micromamba@main
with:
#miniconda-version: "latest"
#auto-update-conda: true
environment-name: test
environment-file: environment.yml
extra-specs:
python=3.9
- name: Mamba install CadQuery and pyinstaller
shell: powershell
run: |
micromamba install -c cadquery -c conda-forge cq-editor=master cadquery=master debugpy ipython=8.4.0 jedi=0.17.2 python=3.9
micromamba install -c conda-forge pyinstaller=4.10
pip install path
pip install pipwin
pipwin install numpy
pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
pip install git+https://github.com/meadiode/cq_gears.git@main
pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
pip install git+https://github.com/gumyr/build123d.git#egg=build123d
- name: Run build
shell: powershell
run: |
micromamba info
pyinstaller --debug all pyinstaller.spec ${{ github.event.inputs.type }}
Copy-Item D:\a\jmwright-CQ-Editor\jmwright-CQ-Editor\pyinstaller\CQ-editor.cmd D:\a\jmwright-CQ-Editor\jmwright-CQ-Editor\dist\
- uses: alehechka/upload-tartifact@v1
with:
name: CQ-editor-Windows
path: dist
#- uses: alehechka/download-tartifact@v1
# with:
# name: CQ-editor-Windows
# path: dist

View File

@@ -1,120 +0,0 @@
name: build
on:
schedule:
- cron: '0 0 * * 1'
workflow_dispatch:
inputs:
type:
description: 'Whether to build a single file (onefile) or directory (dir) dist'
required: true
default: 'dir'
jobs:
# build-linux:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - uses: conda-incubator/setup-miniconda@v2
# with:
# mamba-version: "*"
# channels: conda-forge,defaults
# channel-priority: true
# # auto-update-conda: true
# python-version: 3.9
# activate-environment: test
# - name: Install CadQuery, CQ-editor and pyinstaller
# shell: bash --login {0}
# run: |
# sudo apt install -y libblas-dev libblas3 libblas64-3 libblas64-dev
# sudo apt install -y libxkbcommon0
# sudo apt install -y libxkbcommon-x11-0
# sudo apt install -y libxcb-xinerama0
# conda info
# conda install -c cadquery -c conda-forge cq-editor=master cadquery=master python=3.9
# conda install -c conda-forge pyinstaller=4.10
# conda uninstall --force -y importlib_resources
# pip install path
# pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
# pip install git+https://github.com/meadiode/cq_gears.git@main
# pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
# pip install git+https://github.com/gumyr/build123d.git#egg=build123d
# - name: Run build
# shell: bash --login {0}
# run: |
# conda info
# pyinstaller pyinstaller.spec ${{ github.event.inputs.type }}
# cp /home/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/pyinstaller/CQ-editor.sh /home/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/dist/
# rm /home/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/dist/CQ-editor/libstdc++.so.6
# - uses: actions/upload-artifact@v2
# with:
# name: CQ-editor-Linux-x86_64
# path: dist
# build-macos:
# runs-on: macos-latest
# steps:
# - uses: actions/checkout@v2
# - uses: conda-incubator/setup-miniconda@v2
# with:
# mamba-version: "*"
# channels: conda-forge,defaults
# # auto-update-conda: true
# python-version: 3.9
# activate-environment: test
# - name: Install CadQuery, CQ-editor and pyinstaller=4.10
# shell: bash --login {0}
# run: |
# conda info
# conda install -c cadquery -c conda-forge cq-editor=master cadquery=master python=3.9
# conda install -c conda-forge pyinstaller
# conda uninstall --force -y importlib_resources
# pip install path
# pip uninstall -y PyQt5
# pip install PyQt5==5.15.7
# pip install PyQtWebEngine==5.15.6
# pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
# pip install git+https://github.com/meadiode/cq_gears.git@main
# pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
# pip install git+https://github.com/gumyr/build123d.git#egg=build123d
# - name: Run build
# shell: bash --login {0}
# run: |
# conda info
# pyinstaller pyinstaller.spec ${{ github.event.inputs.type }}
# cp /Users/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/pyinstaller/CQ-editor.sh /Users/runner/work/jmwright-CQ-Editor/jmwright-CQ-Editor/dist/
# - uses: actions/upload-artifact@v2
# with:
# name: CQ-editor-MacOS
# path: dist
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: conda-incubator/setup-miniconda@v2
with:
miniconda-version: "latest"
auto-update-conda: true
python-version: 3.9
activate-environment: test
- name: Install CadQuery and pyinstaller
shell: powershell
run: |
conda install -c cadquery -c conda-forge cq-editor=master cadquery=master ipython=7.20 python=3.9
conda install -c conda-forge pyinstaller=4.10
pip install pipwin
pipwin install numpy
pip install path
pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse
pip install git+https://github.com/meadiode/cq_gears.git@main
pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=cq_cache&subdirectory=plugins/cq_cache"
pip install git+https://github.com/gumyr/build123d.git#egg=build123d
- name: Run build
shell: powershell
run: |
conda info
pyinstaller --debug all pyinstaller.spec ${{ github.event.inputs.type }}
Copy-Item C:\Miniconda3\Library\bin\libssl-1_1-x64.dll D:\a\jmwright-CQ-Editor\jmwright-CQ-Editor\dist\CQ-editor\
Copy-Item C:\Miniconda3\Library\bin\libcrypto-1_1-x64.dll D:\a\jmwright-CQ-Editor\jmwright-CQ-Editor\dist\CQ-editor\
Copy-Item D:\a\jmwright-CQ-Editor\jmwright-CQ-Editor\pyinstaller\CQ-editor.cmd D:\a\jmwright-CQ-Editor\jmwright-CQ-Editor\dist\
- uses: actions/upload-artifact@v2
with:
name: CQ-editor-Windows
path: dist

View File

@@ -1,10 +1,13 @@
# CadQuery editor
This is a fork of jmwright's fork of CadQuery/CQ-editor. This fork includes changes that enable dark mode for CQ-editor (see screenshot below). Under the GitHub Actions menu this fork also contains static builds of CQ-editor for Linux/MacOS/Windows that include the cq_gears, cq_cache, cq_warehouse, and build123d libraries. Note you need to change color preferences to enable dark mode for all panes (see Edit -> Preferences).
This is a fork of [jmwright's fork](https://github.com/jmwright/CQ-editor) of [CadQuery/CQ-editor](https://github.com/CadQuery/CQ-editor). This fork includes changes that enable dark mode for CQ-editor (see screenshot below). Under the GitHub Actions menu this fork also contains static builds of CQ-editor for Linux/MacOS/Windows that include the [cq_gears](https://github.com/meadiode/cq_gears), [cq_cache](https://github.com/CadQuery/cadquery-plugins/tree/main/plugins/cq_cache), [cq_more](https://github.com/JustinSDK/cqMore), [cq_warehouse](https://github.com/gumyr/cq_warehouse), [bd_warehouse](https://github.com/gumyr/bd_warehouse), and [build123d](https://github.com/gumyr/build123d) libraries. Note you need to change color preferences to enable dark mode for all panes (see Edit -> Preferences).
This fork also contains additional changes to the `show_object` function in CQ-editor that make it easier to display and export build123d objects and object lists.
Running into issues? Please click here to join the [***CadQuery, CQ-Editor, and build123d Discord***](https://discord.com/invite/Bj9AQPsCfx)
![image](https://user-images.githubusercontent.com/16868537/191054760-a2cac297-3488-48d4-b9f6-52747dffcce3.png)
[![Build status](https://ci.appveyor.com/api/projects/status/g98rs7la393mgy91/branch/master?svg=true)](https://ci.appveyor.com/project/adam-urbanczyk/cq-editor/branch/master)
[![codecov](https://codecov.io/gh/CadQuery/CQ-editor/branch/master/graph/badge.svg)](https://codecov.io/gh/CadQuery/CQ-editor)
[![Build Status](https://dev.azure.com/cadquery/CQ-editor/_apis/build/status/CadQuery.CQ-editor?branchName=master)](https://dev.azure.com/cadquery/CQ-editor/_build/latest?definitionId=3&branchName=master)
@@ -32,44 +35,35 @@ CadQuery GUI editor based on PyQT supports Linux, Windows and Mac.
### Release Packages
Stable release builds which do not require Anaconda are attached to the [latest release](https://github.com/CadQuery/CQ-editor/releases). Download the zip file for your operating system, extract it, and run the CQ-editor script for your OS (CQ-editor.cmd for Windows, CQ-editor.sh for Linux and MacOS). On Windows you should be able to simply double-click on CQ-editor.cmd. On Linux and MacOS you may need to make the script executable with `chmod +x CQ-editor.sh` and run the script from the command line. The script contains an environment variable export that may be required to get CQ-editor to launch correctly on MacOS Big Sur, so it is better to use the script than to launch CQ-editor directly.
Stable release builds which do not require Anaconda are attached to the [latest release](https://github.com/jdegenstein/jmwright-CQ-editor/releases). Download the zip file for your operating system, extract it, and run the CQ-editor script for your OS (CQ-editor.cmd for Windows, CQ-editor.sh for Linux and MacOS). On Windows you should be able to simply double-click on CQ-editor.cmd. On Linux and MacOS you may need to make the script executable with `chmod +x CQ-editor.sh` and run the script from the command line. On later MacOS versions you may also need `xattr -r -d com.apple.quarantine path/to/CQ-editor-MacOS`. The script contains an environment variable export that may be required to get CQ-editor to launch correctly on MacOS Big Sur, so it is better to use the script than to launch CQ-editor directly.
### Development Packages
Development builds are also available, but can be unstable and should be used at your own risk. Click on the newest build with a green checkmark [here](https://github.com/jmwright/CQ-editor/actions?query=workflow%3Abuild), wait for the _Artifacts_ section at the bottom of the page to load, and then click on the appropriate download for your operating system. Extract the archive file and run the shell (Linux/MacOS) or cmd (Windows) script in the root CQ-editor directory. The CQ-editor window should launch.
Development builds are also available, but can be unstable and should be used at your own risk. Click on the newest build with a green checkmark [here](https://github.com/jdegenstein/jmwright-CQ-editor/actions), wait for the _Artifacts_ section at the bottom of the page to load, and then click on the appropriate download for your operating system. Extract the archive file and run the shell (Linux/MacOS) or cmd (Windows) script in the root CQ-editor directory. The CQ-editor window should launch.
## Installation (Anaconda)
## Installation (pip)
Use conda to install:
Additional packages for Linux (known as needed on Ubuntu 22.04):
```
conda install -c cadquery -c conda-forge cq-editor=master
sudo apt install qtbase5-dev qt5-qmake
```
and then simply type `cq-editor` to run it. This installs the latest version built directly from the HEAD of this repository.
Alternatively clone this git repository and set up the following conda environment:
All platforms (Windows/Mac/Linux):
```
conda env create -f cqgui_env.yml -n cqgui
conda activate cqgui
python run.py
```
On some linux distributions (e.g. `Ubuntu 18.04`) it might be necessary to install additonal packages:
```
sudo apt install libglu1-mesa libgl1-mesa-dri mesa-common-dev libglu1-mesa-dev
```
On Fedora 29 the packages can be installed as follows:
```
dnf install -y mesa-libGLU mesa-libGL mesa-libGLU-devel
pip install git+https://github.com/jdegenstein/jmwright-CQ-Editor
pip install --pre "cadquery>=2.2"
pip install git+https://github.com/gumyr/build123d
```
## Usage
### Showing Objects
By default, CQ-editor will display a 3D representation of all `Workplane` objects in a script with a default color and alpha (transparency). To have more control over what is shown, and what the color and alpha settings are, the `show_object` method can be used. `show_object` tells CQ-editor to explicity display an object, and accepts the `options` parameter. The `options` parameter is a dictionary of rendering options named `alpha` and `color`. `alpha` is scaled between 0.0 and 1.0, with 0.0 being completely opaque and 1.0 being completely transparent. The color is set using R (red), G (green) and B (blue) values, and each one is scaled from 0 to 255. Either option or both can be omitted.
By default, CQ-editor will display a 3D representation of all `Workplane` objects in a script with a default color and alpha (transparency). To have more control over what is shown, and what the color and alpha settings are, the `show_object` method can be used. `show_object` tells CQ-editor to explicity display an object, and accepts the `options` parameter. The `options` parameter is a dictionary of rendering options named `alpha` and `color`. `alpha` is scaled between 0.0 and 1.0, with 0.0 being completely opaque and 1.0 being completely transparent. The color is set using R (red), G (green) and B (blue) values, and each one is scaled from 0 to 255. Either option or both can be omitted. The `name` parameter can assign a custom name which will appear in the objects pane of CQ-editor.
```python
show_object(result, options={"alpha":0.5, "color": (64, 164, 223)})
show_object(result, name="somename", options={"alpha":0.5, "color": (64, 164, 223)})
# or using rand_color:
show_object(result, name="somename", options=rand_color(alpha=.5))
```
Note that `show_object` works for `Shape` and `TopoDS_Shape` objects too. In order to display objects from the embedded Python console use `show`.

View File

@@ -8,54 +8,100 @@ from types import SimpleNamespace
from OCP.XCAFPrs import XCAFPrs_AISObject
from OCP.TopoDS import TopoDS_Shape
from OCP.AIS import AIS_InteractiveObject, AIS_Shape
from OCP.Quantity import \
Quantity_TOC_RGB as TOC_RGB, Quantity_Color
from OCP.Quantity import (
Quantity_TOC_RGB as TOC_RGB,
Quantity_Color,
Quantity_NOC_GOLD as GOLD,
)
from OCP.Graphic3d import Graphic3d_NOM_JADE, Graphic3d_MaterialAspect
from PyQt5.QtGui import QColor
def find_cq_objects(results : dict):
DEFAULT_FACE_COLOR = Quantity_Color(GOLD)
DEFAULT_MATERIAL = Graphic3d_MaterialAspect(Graphic3d_NOM_JADE)
return {k:SimpleNamespace(shape=v,options={}) for k,v in results.items() if isinstance(v,cq.Workplane)}
def to_compound(obj : Union[cq.Workplane, List[cq.Workplane], cq.Shape, List[cq.Shape], cq.Sketch]):
def find_cq_objects(results: dict):
return {
k: SimpleNamespace(shape=v, options={})
for k, v in results.items()
if isinstance(v, cq.Workplane)
}
def to_compound(
obj: Union[cq.Workplane, List[cq.Workplane], cq.Shape, List[cq.Shape], cq.Sketch]
):
vals = []
if isinstance(obj,cq.Workplane):
if isinstance(obj, cq.Workplane):
vals.extend(obj.vals())
elif isinstance(obj,cq.Shape):
elif isinstance(obj, cq.Shape):
vals.append(obj)
elif isinstance(obj,list) and isinstance(obj[0],cq.Workplane):
for o in obj: vals.extend(o.vals())
elif isinstance(obj,list) and isinstance(obj[0],cq.Shape):
elif isinstance(obj, list) and isinstance(obj[0], cq.Workplane):
for o in obj:
vals.extend(o.vals())
elif isinstance(obj, list) and isinstance(obj[0], cq.Shape):
vals.extend(obj)
elif isinstance(obj, TopoDS_Shape):
vals.append(cq.Shape.cast(obj))
elif isinstance(obj,list) and isinstance(obj[0],TopoDS_Shape):
elif isinstance(obj, list) and isinstance(obj[0], TopoDS_Shape):
vals.extend(cq.Shape.cast(o) for o in obj)
elif hasattr(obj, "wrapped") and isinstance(obj.wrapped, TopoDS_Shape):
vals.append(cq.Shape.cast(obj.wrapped))
elif hasattr(obj, "_obj") and hasattr(obj._obj, "wrapped") and isinstance(obj._obj.wrapped, TopoDS_Shape):
elif (
isinstance(obj, list)
and hasattr(obj[0], "wrapped")
and isinstance(obj[0].wrapped, TopoDS_Shape)
):
vals.extend(o for o in obj)
elif (
hasattr(obj, "_obj")
and hasattr(obj._obj, "wrapped")
and isinstance(obj._obj.wrapped, TopoDS_Shape)
):
vals.append(cq.Shape.cast(obj._obj.wrapped))
elif (
isinstance(obj, list)
and hasattr(obj[0], "_obj")
and hasattr(obj[0]._obj, "wrapped")
and isinstance(obj[0]._obj.wrapped, TopoDS_Shape)
):
vals.append(o for o in obj)
elif isinstance(obj, cq.Sketch):
if obj._faces:
vals.append(obj._faces)
else:
vals.extend(obj._edges)
else:
raise ValueError(f'Invalid type {type(obj)}')
raise ValueError(f"Invalid type {type(obj)}")
return cq.Compound.makeCompound(vals)
def to_workplane(obj : cq.Shape):
rv = cq.Workplane('XY')
rv.objects = [obj,]
def to_workplane(obj: cq.Shape):
rv = cq.Workplane("XY")
rv.objects = [
obj,
]
return rv
def make_AIS(obj : Union[cq.Workplane, List[cq.Workplane], cq.Shape, List[cq.Shape], cq.Assembly, AIS_InteractiveObject],
options={}):
def make_AIS(
obj: Union[
cq.Workplane,
List[cq.Workplane],
cq.Shape,
List[cq.Shape],
cq.Assembly,
AIS_InteractiveObject,
],
options={},
):
shape = None
@@ -68,29 +114,35 @@ def make_AIS(obj : Union[cq.Workplane, List[cq.Workplane], cq.Shape, List[cq.Sha
shape = to_compound(obj)
ais = AIS_Shape(shape.wrapped)
if 'alpha' in options:
ais.SetTransparency(options['alpha'])
if 'color' in options:
ais.SetColor(to_occ_color(options['color']))
if 'rgba' in options:
r,g,b,a = options['rgba']
ais.SetColor(to_occ_color((r,g,b)))
ais.SetTransparency(a)
set_material(ais, DEFAULT_MATERIAL)
set_color(ais, DEFAULT_FACE_COLOR)
return ais,shape
if "alpha" in options:
set_transparency(ais, options["alpha"])
if "color" in options:
set_color(ais, to_occ_color(options["color"]))
if "rgba" in options:
r, g, b, a = options["rgba"]
set_color(ais, to_occ_color((r, g, b)))
set_transparency(ais, a)
def export(obj : Union[cq.Workplane, List[cq.Workplane]], type : str,
file, precision=1e-1):
return ais, shape
def export(
obj: Union[cq.Workplane, List[cq.Workplane]], type: str, file, precision=1e-1
):
comp = to_compound(obj)
if type == 'stl':
if type == "stl":
comp.exportStl(file, tolerance=precision)
elif type == 'step':
elif type == "step":
comp.exportStep(file)
elif type == 'brep':
elif type == "brep":
comp.exportBrep(file)
def to_occ_color(color) -> Quantity_Color:
if not isinstance(color, QColor):
@@ -100,16 +152,14 @@ def to_occ_color(color) -> Quantity_Color:
elif isinstance(color[0], float):
color = QColor.fromRgbF(*color)
else:
raise ValueError('Unknown color format')
raise ValueError("Unknown color format")
else:
color = QColor(color)
return Quantity_Color(color.redF(),
color.greenF(),
color.blueF(),
TOC_RGB)
return Quantity_Color(color.redF(), color.greenF(), color.blueF(), TOC_RGB)
def get_occ_color(obj : Union[AIS_InteractiveObject, Quantity_Color]) -> QColor:
def get_occ_color(obj: Union[AIS_InteractiveObject, Quantity_Color]) -> QColor:
if isinstance(obj, AIS_InteractiveObject):
color = Quantity_Color()
@@ -119,13 +169,34 @@ def get_occ_color(obj : Union[AIS_InteractiveObject, Quantity_Color]) -> QColor:
return QColor.fromRgbF(color.Red(), color.Green(), color.Blue())
def set_color(ais : AIS_Shape, color : Quantity_Color) -> AIS_Shape:
def set_color(ais: AIS_Shape, color: Quantity_Color) -> AIS_Shape:
drawer = ais.Attributes()
drawer.SetupOwnShadingAspect()
drawer.ShadingAspect().SetColor(color)
return ais
def set_material(ais: AIS_Shape, material: Graphic3d_MaterialAspect) -> AIS_Shape:
drawer = ais.Attributes()
drawer.SetupOwnShadingAspect()
drawer.ShadingAspect().SetMaterial(material)
return ais
def set_transparency(ais: AIS_Shape, alpha: float) -> AIS_Shape:
drawer = ais.Attributes()
drawer.SetupOwnShadingAspect()
drawer.ShadingAspect().SetTransparency(alpha)
return ais
def reload_cq():
# NB: order of reloads is important
@@ -146,13 +217,13 @@ def reload_cq():
reload(cq.occ_impl.exporters.dxf)
reload(cq.occ_impl.exporters.amf)
reload(cq.occ_impl.exporters.json)
#reload(cq.occ_impl.exporters.assembly)
# reload(cq.occ_impl.exporters.assembly)
reload(cq.occ_impl.exporters)
reload(cq.assembly)
reload(cq)
def is_obj_empty(obj : Union[cq.Workplane,cq.Shape]) -> bool:
def is_obj_empty(obj: Union[cq.Workplane, cq.Shape]) -> bool:
rv = False

View File

@@ -299,6 +299,7 @@ class MainWindow(QMainWindow,MainMixin):
#CQ related items
console.push_vars({'show' : obj_tree.addObject,
'show_object' : obj_tree.addObject,
'rand_color' : self.components['debugger']._rand_color,
'cq' : cq,
'log' : Logger(self.name).info})

View File

@@ -6,57 +6,61 @@ from typing import List
import cadquery as cq
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QObject, pyqtSlot, pyqtSignal, QEventLoop, QAbstractTableModel
from PyQt5.QtWidgets import (QAction,
QTableView)
from PyQt5.QtCore import (
Qt,
QObject,
pyqtSlot,
pyqtSignal,
QEventLoop,
QAbstractTableModel,
)
from PyQt5.QtWidgets import QAction, QTableView
from logbook import info
from path import Path
from pyqtgraph.parametertree import Parameter
from spyder.utils.icon_manager import icon
from random import randrange as rrr, seed
from ..cq_utils import find_cq_objects, reload_cq
from ..mixins import ComponentMixin
DUMMY_FILE = '<string>'
DUMMY_FILE = "<string>"
class DbgState(Enum):
STEP = auto()
CONT = auto()
STEP_IN = auto()
RETURN = auto()
class DbgEevent(object):
LINE = 'line'
CALL = 'call'
RETURN = 'return'
class DbgEevent(object):
LINE = "line"
CALL = "call"
RETURN = "return"
class LocalsModel(QAbstractTableModel):
HEADER = ("Name", "Type", "Value")
HEADER = ('Name','Type', 'Value')
def __init__(self,parent):
super(LocalsModel,self).__init__(parent)
def __init__(self, parent):
super(LocalsModel, self).__init__(parent)
self.frame = None
def update_frame(self,frame):
self.frame = \
[(k,type(v).__name__, str(v)) for k,v in frame.items() if not k.startswith('_')]
def rowCount(self,parent=QtCore.QModelIndex()):
def update_frame(self, frame):
self.frame = [
(k, type(v).__name__, str(v))
for k, v in frame.items()
if not k.startswith("_")
]
def rowCount(self, parent=QtCore.QModelIndex()):
if self.frame:
return len(self.frame)
else:
return 0
def columnCount(self,parent=QtCore.QModelIndex()):
def columnCount(self, parent=QtCore.QModelIndex()):
return 3
def headerData(self, section, orientation, role=Qt.DisplayRole):
@@ -73,13 +77,11 @@ class LocalsModel(QAbstractTableModel):
return QtCore.QVariant()
class LocalsView(QTableView,ComponentMixin):
class LocalsView(QTableView, ComponentMixin):
name = "Variables"
name = 'Variables'
def __init__(self,parent):
super(LocalsView,self).__init__(parent)
def __init__(self, parent):
super(LocalsView, self).__init__(parent)
ComponentMixin.__init__(self)
header = self.horizontalHeader()
@@ -89,160 +91,213 @@ class LocalsView(QTableView,ComponentMixin):
vheader.setVisible(False)
@pyqtSlot(dict)
def update_frame(self,frame):
def update_frame(self, frame):
model = LocalsModel(self)
model.update_frame(frame)
self.setModel(model)
class Debugger(QObject,ComponentMixin):
name = 'Debugger'
preferences = Parameter.create(name='Preferences',children=[
{'name': 'Reload CQ', 'type': 'bool', 'value': False},
{'name': 'Add script dir to path','type': 'bool', 'value': True},
{'name': 'Change working dir to script dir','type': 'bool', 'value': True},
{'name': 'Reload imported modules', 'type': 'bool', 'value': True},
])
class Debugger(QObject, ComponentMixin):
name = "Debugger"
preferences = Parameter.create(
name="Preferences",
children=[
{"name": "Reload CQ", "type": "bool", "value": False},
{"name": "Add script dir to path", "type": "bool", "value": True},
{"name": "Change working dir to script dir", "type": "bool", "value": True},
{"name": "Reload imported modules", "type": "bool", "value": True},
],
)
sigRendered = pyqtSignal(dict)
sigLocals = pyqtSignal(dict)
sigTraceback = pyqtSignal(object,str)
sigTraceback = pyqtSignal(object, str)
sigFrameChanged = pyqtSignal(object)
sigLineChanged = pyqtSignal(int)
sigLocalsChanged = pyqtSignal(dict)
sigCQChanged = pyqtSignal(dict,bool)
sigCQChanged = pyqtSignal(dict, bool)
sigDebugging = pyqtSignal(bool)
_frames : List[FrameType]
_frames: List[FrameType]
def __init__(self,parent):
super(Debugger,self).__init__(parent)
def __init__(self, parent):
super(Debugger, self).__init__(parent)
ComponentMixin.__init__(self)
self.inner_event_loop = QEventLoop(self)
self._actions = \
{'Run' : [QAction(icon('run'),
'Render',
self,
shortcut='F5',
triggered=self.render),
QAction(icon('debug'),
'Debug',
self,
checkable=True,
shortcut='ctrl+F5',
triggered=self.debug),
QAction(icon('arrow-step-over'),
'Step',
self,
shortcut='ctrl+F10',
triggered=lambda: self.debug_cmd(DbgState.STEP)),
QAction(icon('arrow-step-in'),
'Step in',
self,
shortcut='ctrl+F11',
triggered=lambda: self.debug_cmd(DbgState.STEP_IN)),
QAction(icon('arrow-continue'),
'Continue',
self,
shortcut='ctrl+F12',
triggered=lambda: self.debug_cmd(DbgState.CONT))
]}
self._actions = {
"Run": [
QAction(
icon("run"), "Render", self, shortcut="F5", triggered=self.render
),
QAction(
icon("debug"),
"Debug",
self,
checkable=True,
shortcut="ctrl+F5",
triggered=self.debug,
),
QAction(
icon("arrow-step-over"),
"Step",
self,
shortcut="ctrl+F10",
triggered=lambda: self.debug_cmd(DbgState.STEP),
),
QAction(
icon("arrow-step-in"),
"Step in",
self,
shortcut="ctrl+F11",
triggered=lambda: self.debug_cmd(DbgState.STEP_IN),
),
QAction(
icon("arrow-continue"),
"Continue",
self,
shortcut="ctrl+F12",
triggered=lambda: self.debug_cmd(DbgState.CONT),
),
]
}
self._frames = []
def get_current_script(self):
return self.parent().components['editor'].get_text_with_eol()
return self.parent().components["editor"].get_text_with_eol()
def get_breakpoints(self):
return self.parent().components['editor'].debugger.get_breakpoints()
return self.parent().components["editor"].debugger.get_breakpoints()
def compile_code(self, cq_script):
try:
module = ModuleType('temp')
cq_code = compile(cq_script, '<string>', 'exec')
module = ModuleType("temp")
cq_code = compile(cq_script, "<string>", "exec")
return cq_code, module
except Exception:
self.sigTraceback.emit(sys.exc_info(), cq_script)
return None, None
def _exec(self, code, locals_dict, globals_dict):
with ExitStack() as stack:
fname = self.parent().components['editor'].filename
p = Path(fname if fname else '').abspath().dirname()
fname = self.parent().components["editor"].filename
p = Path(fname if fname else "").abspath().dirname()
if self.preferences['Add script dir to path'] and p.exists():
sys.path.insert(0,p)
if self.preferences["Add script dir to path"] and p.exists():
sys.path.insert(0, p)
stack.callback(sys.path.remove, p)
if self.preferences['Change working dir to script dir'] and p.exists():
if self.preferences["Change working dir to script dir"] and p.exists():
stack.enter_context(p)
if self.preferences['Reload imported modules']:
if self.preferences["Reload imported modules"]:
stack.enter_context(module_manager())
exec(code, locals_dict, globals_dict)
def _inject_locals(self,module):
def _rand_color(self, alpha=0.0, cfloat=False):
# helper function to generate a random color dict
# for CQ-editor's show_object function
lower = 10
upper = 100 # not too high to keep color brightness in check
if cfloat: # for two output types depending on need
return (
(rrr(lower, upper) / 255),
(rrr(lower, upper) / 255),
(rrr(lower, upper) / 255),
alpha,
)
return {
"alpha": alpha,
"color": (
rrr(lower, upper),
rrr(lower, upper),
rrr(lower, upper),
),
}
def _inject_locals(self, module):
cq_objects = {}
def _show_object(obj,name=None, options={}):
def _show_object(
obj,
name=None,
options={}, # all following inputs are ignored by cq-editor
parent=1,
clear=True,
port=3939,
axes=False,
axes0=False,
grid=False,
ticks=10,
ortho=True,
transparent=False,
default_color=(232, 176, 36),
reset_camera=True,
zoom=1.0,
default_edgecolor=(128, 128, 128),
render_edges=True,
render_normals=False,
render_mates=False,
mate_scale=1.0,
deviation=0.1,
angular_tolerance=0.2,
edge_accuracy=5.0,
ambient_intensity=1.0,
direct_intensity=0.12,
):
if name:
cq_objects.update({name : SimpleNamespace(shape=obj,options=options)})
cq_objects.update({name: SimpleNamespace(shape=obj, options=options)})
else:
cq_objects.update({str(id(obj)) : SimpleNamespace(shape=obj,options=options)})
cq_objects.update(
{str(id(obj)): SimpleNamespace(shape=obj, options=options)}
)
def _debug(obj,name=None):
def _debug(obj, name=None):
_show_object(obj, name, options=dict(color="red", alpha=0.2))
_show_object(obj,name,options=dict(color='red',alpha=0.2))
module.__dict__["show_object"] = _show_object
module.__dict__["debug"] = _debug
module.__dict__["rand_color"] = self._rand_color
module.__dict__["log"] = lambda x: info(str(x))
module.__dict__["cq"] = cq
module.__dict__['show_object'] = _show_object
module.__dict__['debug'] = _debug
module.__dict__['log'] = lambda x: info(str(x))
module.__dict__['cq'] = cq
return cq_objects, set(module.__dict__) - {"cq"}
return cq_objects, set(module.__dict__)-{'cq'}
def _cleanup_locals(self,module,injected_names):
for name in injected_names: module.__dict__.pop(name)
def _cleanup_locals(self, module, injected_names):
for name in injected_names:
module.__dict__.pop(name)
@pyqtSlot(bool)
def render(self):
if self.preferences['Reload CQ']:
seed(
59798267586177
) # reset the seed every time render is called (preserves colors run to run)
if self.preferences["Reload CQ"]:
reload_cq()
cq_script = self.get_current_script()
cq_code,module = self.compile_code(cq_script)
cq_code, module = self.compile_code(cq_script)
if cq_code is None: return
if cq_code is None:
return
cq_objects,injected_names = self._inject_locals(module)
cq_objects, injected_names = self._inject_locals(module)
try:
self._exec(cq_code, module.__dict__, module.__dict__)
#remove the special methods
self._cleanup_locals(module,injected_names)
# remove the special methods
self._cleanup_locals(module, injected_names)
#collect all CQ objects if no explicit show_object was called
# collect all CQ objects if no explicit show_object was called
if len(cq_objects) == 0:
cq_objects = find_cq_objects(module.__dict__)
self.sigRendered.emit(cq_objects)
self.sigTraceback.emit(None,
cq_script)
self.sigTraceback.emit(None, cq_script)
self.sigLocals.emit(module.__dict__)
except Exception:
exc_info = sys.exc_info()
@@ -251,11 +306,10 @@ class Debugger(QObject,ComponentMixin):
@property
def breakpoints(self):
return [ el[0] for el in self.get_breakpoints()]
return [el[0] for el in self.get_breakpoints()]
@pyqtSlot(bool)
def debug(self,value):
def debug(self, value):
previous_trace = sys.gettrace()
if value:
@@ -263,37 +317,35 @@ class Debugger(QObject,ComponentMixin):
self.state = DbgState.STEP
self.script = self.get_current_script()
code,module = self.compile_code(self.script)
code, module = self.compile_code(self.script)
if code is None:
self.sigDebugging.emit(False)
self._actions['Run'][1].setChecked(False)
self._actions["Run"][1].setChecked(False)
return
cq_objects,injected_names = self._inject_locals(module)
cq_objects, injected_names = self._inject_locals(module)
#clear possible traceback
self.sigTraceback.emit(None,
self.script)
# clear possible traceback
self.sigTraceback.emit(None, self.script)
try:
sys.settrace(self.trace_callback)
exec(code,module.__dict__,module.__dict__)
exec(code, module.__dict__, module.__dict__)
except Exception:
exc_info = sys.exc_info()
sys.last_traceback = exc_info[-1]
self.sigTraceback.emit(exc_info,
self.script)
self.sigTraceback.emit(exc_info, self.script)
finally:
sys.settrace(previous_trace)
self.sigDebugging.emit(False)
self._actions['Run'][1].setChecked(False)
self._actions["Run"][1].setChecked(False)
if len(cq_objects) == 0:
cq_objects = find_cq_objects(module.__dict__)
self.sigRendered.emit(cq_objects)
self._cleanup_locals(module,injected_names)
self._cleanup_locals(module, injected_names)
self.sigLocals.emit(module.__dict__)
self._frames = []
@@ -301,41 +353,37 @@ class Debugger(QObject,ComponentMixin):
sys.settrace(previous_trace)
self.inner_event_loop.exit(0)
def debug_cmd(self,state=DbgState.STEP):
def debug_cmd(self, state=DbgState.STEP):
self.state = state
self.inner_event_loop.exit(0)
def trace_callback(self,frame,event,arg):
def trace_callback(self, frame, event, arg):
filename = frame.f_code.co_filename
if filename==DUMMY_FILE:
if filename == DUMMY_FILE:
if not self._frames:
self._frames.append(frame)
self.trace_local(frame,event,arg)
self.trace_local(frame, event, arg)
return self.trace_callback
else:
return None
def trace_local(self,frame,event,arg):
def trace_local(self, frame, event, arg):
lineno = frame.f_lineno
if event in (DbgEevent.LINE,):
if (self.state in (DbgState.STEP, DbgState.STEP_IN) and frame is self._frames[-1]) \
or (lineno in self.breakpoints):
if (
self.state in (DbgState.STEP, DbgState.STEP_IN)
and frame is self._frames[-1]
) or (lineno in self.breakpoints):
if lineno in self.breakpoints:
self._frames.append(frame)
self.sigLineChanged.emit(lineno)
self.sigFrameChanged.emit(frame)
self.sigLocalsChanged.emit(frame.f_locals)
self.sigCQChanged.emit(find_cq_objects(frame.f_locals),True)
self.sigCQChanged.emit(find_cq_objects(frame.f_locals), True)
self.inner_event_loop.exec_()
@@ -354,7 +402,7 @@ class Debugger(QObject,ComponentMixin):
@contextmanager
def module_manager():
""" unloads any modules loaded while the context manager is active """
"""unloads any modules loaded while the context manager is active"""
loaded_modules = set(sys.modules.keys())
try:

View File

@@ -1,6 +1,12 @@
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAction, QMenu, QWidget, QAbstractItemView
from PyQt5.QtWidgets import (
QTreeWidget,
QTreeWidgetItem,
QAction,
QMenu,
QWidget,
QAbstractItemView,
)
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal
from pyqtgraph.parametertree import Parameter, ParameterTree
from OCP.AIS import AIS_Line
@@ -9,107 +15,118 @@ from OCP.gp import gp_Dir, gp_Pnt, gp_Ax1
from ..mixins import ComponentMixin
from ..icons import icon
from ..cq_utils import make_AIS, export, to_occ_color, is_obj_empty, get_occ_color, set_color
from ..cq_utils import (
make_AIS,
export,
to_occ_color,
is_obj_empty,
get_occ_color,
set_color,
)
from .viewer import DEFAULT_FACE_COLOR
from ..utils import splitter, layout, get_save_filename
class TopTreeItem(QTreeWidgetItem):
def __init__(self, *args, **kwargs):
super(TopTreeItem, self).__init__(*args, **kwargs)
def __init__(self,*args,**kwargs):
super(TopTreeItem,self).__init__(*args,**kwargs)
class ObjectTreeItem(QTreeWidgetItem):
props = [
{"name": "Name", "type": "str", "value": ""},
{"name": "Color", "type": "color", "value": "#f4a824"},
{"name": "Alpha", "type": "float", "value": 0, "limits": (0, 1), "step": 1e-1},
{"name": "Visible", "type": "bool", "value": True},
]
props = [{'name': 'Name', 'type': 'str', 'value': ''},
{'name': 'Color', 'type': 'color', 'value': "#f4a824"},
{'name': 'Alpha', 'type': 'float', 'value': 0, 'limits': (0,1), 'step': 1e-1},
{'name': 'Visible', 'type': 'bool','value': True}]
def __init__(self,
name,
ais=None,
shape=None,
shape_display=None,
sig=None,
alpha=0.,
color='#f4a824',
**kwargs):
super(ObjectTreeItem,self).__init__([name],**kwargs)
self.setFlags( self.flags() | Qt.ItemIsUserCheckable)
self.setCheckState(0,Qt.Checked)
def __init__(
self,
name,
ais=None,
shape=None,
shape_display=None,
sig=None,
alpha=0.0,
color="#f4a824",
**kwargs
):
super(ObjectTreeItem, self).__init__([name], **kwargs)
self.setFlags(self.flags() | Qt.ItemIsUserCheckable)
self.setCheckState(0, Qt.Checked)
self.ais = ais
self.shape = shape
self.shape_display = shape_display
self.sig = sig
self.properties = Parameter.create(name='Properties',
children=self.props)
self.properties = Parameter.create(name="Properties", children=self.props)
self.properties['Name'] = name
self.properties['Alpha'] = ais.Transparency()
self.properties['Color'] = get_occ_color(ais) if ais and ais.HasColor() else get_occ_color(DEFAULT_FACE_COLOR)
self.properties["Name"] = name
self.properties["Alpha"] = ais.Transparency()
self.properties["Color"] = (
get_occ_color(ais)
if ais and ais.HasColor()
else get_occ_color(DEFAULT_FACE_COLOR)
)
self.properties.sigTreeStateChanged.connect(self.propertiesChanged)
def propertiesChanged(self, properties, changed):
changed_prop = changed[0][0]
self.setData(0,0,self.properties['Name'])
self.ais.SetTransparency(self.properties['Alpha'])
self.setData(0, 0, self.properties["Name"])
self.ais.SetTransparency(self.properties["Alpha"])
if changed_prop.name() == 'Color':
set_color(self.ais, to_occ_color(self.properties['Color']))
if changed_prop.name() == "Color":
set_color(self.ais, to_occ_color(self.properties["Color"]))
self.ais.Redisplay()
if self.properties['Visible']:
self.setCheckState(0,Qt.Checked)
if self.properties["Visible"]:
self.setCheckState(0, Qt.Checked)
else:
self.setCheckState(0,Qt.Unchecked)
self.setCheckState(0, Qt.Unchecked)
if self.sig:
self.sig.emit()
class CQRootItem(TopTreeItem):
def __init__(self,*args,**kwargs):
super(CQRootItem,self).__init__(['CQ models'],*args,**kwargs)
def __init__(self, *args, **kwargs):
super(CQRootItem, self).__init__(["CQ models"], *args, **kwargs)
class HelpersRootItem(TopTreeItem):
def __init__(self,*args,**kwargs):
super(HelpersRootItem,self).__init__(['Helpers'],*args,**kwargs)
def __init__(self, *args, **kwargs):
super(HelpersRootItem, self).__init__(["Helpers"], *args, **kwargs)
class ObjectTree(QWidget,ComponentMixin):
name = 'Object Tree'
class ObjectTree(QWidget, ComponentMixin):
name = "Object Tree"
_stash = []
preferences = Parameter.create(name='Preferences',children=[
{'name': 'Preserve properties on reload', 'type': 'bool', 'value': False},
{'name': 'Clear all before each run', 'type': 'bool', 'value': True},
{'name': 'STL precision','type': 'float', 'value': .1}])
preferences = Parameter.create(
name="Preferences",
children=[
{"name": "Preserve properties on reload", "type": "bool", "value": False},
{"name": "Clear all before each run", "type": "bool", "value": True},
{"name": "STL precision", "type": "float", "value": 0.1},
],
)
sigObjectsAdded = pyqtSignal([list],[list,bool])
sigObjectsAdded = pyqtSignal([list], [list, bool])
sigObjectsRemoved = pyqtSignal(list)
sigCQObjectSelected = pyqtSignal(object)
sigAISObjectsSelected = pyqtSignal(list)
sigItemChanged = pyqtSignal(QTreeWidgetItem,int)
sigItemChanged = pyqtSignal(QTreeWidgetItem, int)
sigObjectPropertiesChanged = pyqtSignal()
def __init__(self,parent):
def __init__(self, parent):
super(ObjectTree, self).__init__(parent)
super(ObjectTree,self).__init__(parent)
self.tree = tree = QTreeWidget(self,
selectionMode=QAbstractItemView.ExtendedSelection)
self.tree = tree = QTreeWidget(
self, selectionMode=QAbstractItemView.ExtendedSelection
)
self.properties_editor = ParameterTree(self)
tree.setHeaderHidden(True)
@@ -117,10 +134,9 @@ class ObjectTree(QWidget,ComponentMixin):
tree.setRootIsDecorated(False)
tree.setContextMenuPolicy(Qt.ActionsContextMenu)
#forward itemChanged singal
tree.itemChanged.connect(\
lambda item,col: self.sigItemChanged.emit(item,col))
#handle visibility changes form tree
# forward itemChanged singal
tree.itemChanged.connect(lambda item, col: self.sigItemChanged.emit(item, col))
# handle visibility changes form tree
tree.itemChanged.connect(self.handleChecked)
self.CQ = CQRootItem()
@@ -132,30 +148,31 @@ class ObjectTree(QWidget,ComponentMixin):
tree.expandToDepth(1)
self._export_STL_action = \
QAction('Export as STL',
self,
enabled=False,
triggered=lambda: \
self.export('stl',
self.preferences['STL precision']))
self._export_STL_action = QAction(
"Export as STL",
self,
enabled=False,
triggered=lambda: self.export("stl", self.preferences["STL precision"]),
)
self._export_STEP_action = \
QAction('Export as STEP',
self,
enabled=False,
triggered=lambda: \
self.export('step'))
self._export_STEP_action = QAction(
"Export as STEP", self, enabled=False, triggered=lambda: self.export("step")
)
self._clear_current_action = QAction(icon('delete'),
'Clear current',
self,
enabled=False,
triggered=self.removeSelected)
self._clear_current_action = QAction(
icon("delete"),
"Clear current",
self,
enabled=False,
triggered=self.removeSelected,
)
self._toolbar_actions = \
[QAction(icon('delete-many'),'Clear all',self,triggered=self.removeObjects),
self._clear_current_action,]
self._toolbar_actions = [
QAction(
icon("delete-many"), "Clear all", self, triggered=self.removeObjects
),
self._clear_current_action,
]
self.prepareMenu()
@@ -164,135 +181,157 @@ class ObjectTree(QWidget,ComponentMixin):
self.prepareLayout()
def prepareMenu(self):
self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
self._context_menu = QMenu(self)
self._context_menu.addActions(self._toolbar_actions)
self._context_menu.addActions((self._export_STL_action,
self._export_STEP_action))
self._context_menu.addActions(
(self._export_STL_action, self._export_STEP_action)
)
def prepareLayout(self):
self._splitter = splitter((self.tree,self.properties_editor),
stretch_factors = (2,1),
orientation=Qt.Vertical)
layout(self,(self._splitter,),top_widget=self)
self._splitter = splitter(
(self.tree, self.properties_editor),
stretch_factors=(2, 1),
orientation=Qt.Vertical,
)
layout(self, (self._splitter,), top_widget=self)
self._splitter.show()
def showMenu(self,position):
def showMenu(self, position):
self._context_menu.exec_(self.tree.viewport().mapToGlobal(position))
def menuActions(self):
return {'Tools' : [self._export_STL_action,
self._export_STEP_action]}
return {"Tools": [self._export_STL_action, self._export_STEP_action]}
def toolbarActions(self):
return self._toolbar_actions
def addLines(self):
origin = (0,0,0)
origin = (0, 0, 0)
ais_list = []
for name,color,direction in zip(('X','Y','Z'),
('red','lawngreen','blue'),
((1,0,0),(0,1,0),(0,0,1))):
line_placement = Geom_Line(gp_Ax1(gp_Pnt(*origin),
gp_Dir(*direction)))
for name, color, direction in zip(
("X", "Y", "Z"),
((0.2, 0, 0), "lawngreen", "blue"),
((1, 0, 0), (0, 1, 0), (0, 0, 1)),
):
line_placement = Geom_Line(gp_Ax1(gp_Pnt(*origin), gp_Dir(*direction)))
line = AIS_Line(line_placement)
line.SetColor(to_occ_color(color))
self.Helpers.addChild(ObjectTreeItem(name,
ais=line))
self.Helpers.addChild(ObjectTreeItem(name, ais=line))
ais_list.append(line)
self.sigObjectsAdded.emit(ais_list)
def _current_properties(self):
current_params = {}
for i in range(self.CQ.childCount()):
child = self.CQ.child(i)
current_params[child.properties['Name']] = child.properties
current_params[child.properties["Name"]] = child.properties
return current_params
def _restore_properties(self,obj,properties):
for p in properties[obj.properties['Name']]:
def _restore_properties(self, obj, properties):
for p in properties[obj.properties["Name"]]:
obj.properties[p.name()] = p.value()
@pyqtSlot(dict,bool)
@pyqtSlot(dict, bool)
@pyqtSlot(dict)
def addObjects(self,objects,clean=False,root=None):
def addObjects(self, objects, clean=False, root=None):
if root is None:
root = self.CQ
request_fit_view = True if root.childCount() == 0 else False
preserve_props = self.preferences['Preserve properties on reload']
preserve_props = self.preferences["Preserve properties on reload"]
if preserve_props:
current_props = self._current_properties()
if clean or self.preferences['Clear all before each run']:
if clean or self.preferences["Clear all before each run"]:
self.removeObjects()
ais_list = []
#remove empty objects
objects_f = {k:v for k,v in objects.items() if not is_obj_empty(v.shape)}
# remove empty objects
objects_f = {k: v for k, v in objects.items() if not is_obj_empty(v.shape)}
for name,obj in objects_f.items():
ais,shape_display = make_AIS(obj.shape,obj.options)
for name, obj in objects_f.items():
ais, shape_display = make_AIS(obj.shape, obj.options)
child = ObjectTreeItem(name,
shape=obj.shape,
shape_display=shape_display,
ais=ais,
sig=self.sigObjectPropertiesChanged)
child = ObjectTreeItem(
name,
shape=obj.shape,
shape_display=shape_display,
ais=ais,
sig=self.sigObjectPropertiesChanged,
)
if preserve_props and name in current_props:
self._restore_properties(child,current_props)
self._restore_properties(child, current_props)
if child.properties['Visible']:
if child.properties["Visible"]:
ais_list.append(ais)
root.addChild(child)
if request_fit_view:
self.sigObjectsAdded[list,bool].emit(ais_list,True)
self.sigObjectsAdded[list, bool].emit(ais_list, True)
else:
self.sigObjectsAdded[list].emit(ais_list)
@pyqtSlot(object,str,object)
def addObject(self,obj,name='',options={}):
@pyqtSlot(object, str, object)
def addObject(
self,
obj,
name="",
options={}, # all following inputs are ignored by cq-editor
parent=1,
clear=True,
port=3939,
axes=False,
axes0=False,
grid=False,
ticks=10,
ortho=True,
transparent=False,
default_color=(232, 176, 36),
reset_camera=True,
zoom=1.0,
default_edgecolor=(128, 128, 128),
render_edges=True,
render_normals=False,
render_mates=False,
mate_scale=1.0,
deviation=0.1,
angular_tolerance=0.2,
edge_accuracy=5.0,
ambient_intensity=1.0,
direct_intensity=0.12,
):
root = self.CQ
ais,shape_display = make_AIS(obj, options)
ais, shape_display = make_AIS(obj, options)
root.addChild(ObjectTreeItem(name,
shape=obj,
shape_display=shape_display,
ais=ais,
sig=self.sigObjectPropertiesChanged))
root.addChild(
ObjectTreeItem(
name,
shape=obj,
shape_display=shape_display,
ais=ais,
sig=self.sigObjectPropertiesChanged,
)
)
self.sigObjectsAdded.emit([ais])
@pyqtSlot(list)
@pyqtSlot()
def removeObjects(self,objects=None):
def removeObjects(self, objects=None):
if objects:
removed_items_ais = [self.CQ.takeChild(i).ais for i in objects]
else:
@@ -301,8 +340,7 @@ class ObjectTree(QWidget,ComponentMixin):
self.sigObjectsRemoved.emit(removed_items_ais)
@pyqtSlot(bool)
def stashObjects(self,action : bool):
def stashObjects(self, action: bool):
if action:
self._stash = self.CQ.takeChildren()
removed_items_ais = [ch.ais for ch in self._stash]
@@ -315,14 +353,12 @@ class ObjectTree(QWidget,ComponentMixin):
@pyqtSlot()
def removeSelected(self):
ixs = self.tree.selectedIndexes()
rows = [ix.row() for ix in ixs]
self.removeObjects(rows)
def export(self,export_type,precision=None):
def export(self, export_type, precision=None):
items = self.tree.selectedItems()
# if CQ models is selected get all children
@@ -334,13 +370,12 @@ class ObjectTree(QWidget,ComponentMixin):
shapes = [item.shape for item in items if item.parent() is self.CQ]
fname = get_save_filename(export_type)
if fname != '':
export(shapes,export_type,fname,precision)
if fname != "":
export(shapes, export_type, fname, precision)
@pyqtSlot()
def handleSelection(self):
items =self.tree.selectedItems()
items = self.tree.selectedItems()
if len(items) == 0:
self._export_STL_action.setEnabled(False)
self._export_STEP_action.setEnabled(False)
@@ -357,10 +392,9 @@ class ObjectTree(QWidget,ComponentMixin):
self._export_STEP_action.setEnabled(True)
self._clear_current_action.setEnabled(True)
self.sigCQObjectSelected.emit(item.shape)
self.properties_editor.setParameters(item.properties,
showTop=False)
self.properties_editor.setParameters(item.properties, showTop=False)
self.properties_editor.setEnabled(True)
elif item is self.CQ and item.childCount()>0:
elif item is self.CQ and item.childCount() > 0:
self._export_STL_action.setEnabled(True)
self._export_STEP_action.setEnabled(True)
else:
@@ -371,8 +405,7 @@ class ObjectTree(QWidget,ComponentMixin):
self.properties_editor.clear()
@pyqtSlot(list)
def handleGraphicalSelection(self,shapes):
def handleGraphicalSelection(self, shapes):
self.tree.clearSelection()
CQ = self.CQ
@@ -382,14 +415,10 @@ class ObjectTree(QWidget,ComponentMixin):
if item.ais.Shape().IsEqual(shape):
item.setSelected(True)
@pyqtSlot(QTreeWidgetItem,int)
def handleChecked(self,item,col):
@pyqtSlot(QTreeWidgetItem, int)
def handleChecked(self, item, col):
if type(item) is ObjectTreeItem:
if item.checkState(0):
item.properties['Visible'] = True
item.properties["Visible"] = True
else:
item.properties['Visible'] = False
item.properties["Visible"] = False

View File

@@ -10,7 +10,7 @@ from OCP.Aspect import Aspect_DisplayConnection, Aspect_TypeOfTriedronPosition
from OCP.OpenGl import OpenGl_GraphicDriver
from OCP.V3d import V3d_Viewer
from OCP.AIS import AIS_InteractiveContext, AIS_DisplayMode
from OCP.Quantity import Quantity_Color
from OCP.Quantity import Quantity_Color, Quantity_TOC_RGB as TOC_RGB
ZOOM_STEP = 0.9
@@ -54,6 +54,8 @@ class OCCTWidget(QWidget):
Aspect_TypeOfTriedronPosition.Aspect_TOTP_RIGHT_LOWER,
Quantity_Color(), 0.1)
view.ZBufferTriedronSetup(Quantity_Color(*(0.2, 0.0, 0.0), TOC_RGB))
viewer = self.viewer
viewer.SetDefaultLights()
@@ -95,8 +97,8 @@ class OCCTWidget(QWidget):
self.old_pos.y() - y, theToStart=True)
elif event.buttons() == Qt.RightButton:
self.view.ZoomAtPoint(self.old_pos.x(), y,
x, self.old_pos.y())
self.view.Pan(x - self.old_pos.x(),
self.old_pos.y() - y, theToStart=True)
self.old_pos = pos

View File

@@ -7,21 +7,21 @@ from OCP.Graphic3d import Graphic3d_Camera, Graphic3d_StereoMode, Graphic3d_NOM_
Graphic3d_MaterialAspect
from OCP.AIS import AIS_Shaded,AIS_WireFrame, AIS_ColoredShape, AIS_Axis
from OCP.Aspect import Aspect_GDM_Lines, Aspect_GT_Rectangular
from OCP.Quantity import Quantity_NOC_BLACK as BLACK, Quantity_NOC_GOLD as GOLD,\
Quantity_TOC_RGB as TOC_RGB, Quantity_Color
from OCP.Quantity import Quantity_NOC_BLACK as BLACK, Quantity_TOC_RGB as TOC_RGB,\
Quantity_Color
from OCP.Geom import Geom_Axis1Placement
from OCP.gp import gp_Ax3, gp_Dir, gp_Pnt, gp_Ax1
from ..utils import layout, get_save_filename
from ..mixins import ComponentMixin
from ..icons import icon
from ..cq_utils import to_occ_color, make_AIS
from ..cq_utils import to_occ_color, make_AIS, DEFAULT_FACE_COLOR
from .occt_widget import OCCTWidget
from pyqtgraph.parametertree import Parameter
import qtawesome as qta
DEFAULT_FACE_COLOR = Quantity_Color(GOLD)
DEFAULT_EDGE_COLOR = Quantity_Color(BLACK)
DEFAULT_EDGE_WIDTH = 2
@@ -252,13 +252,13 @@ class OCCViewer(QWidget,ComponentMixin):
def front_view(self):
v = self._get_view()
v.SetProj(0,1,0)
v.SetProj(0,-1,0)
v.SetTwist(0)
def back_view(self):
v = self._get_view()
v.SetProj(0,-1,0)
v.SetProj(0,1,0)
v.SetTwist(0)
def left_view(self):

View File

@@ -3,4 +3,4 @@ channels:
- conda-forge
- defaults
dependencies:
- python=3.9
- python=3.10

View File

@@ -0,0 +1,9 @@
# hook-casadi.py
from PyInstaller.utils.hooks import collect_dynamic_libs
binaries = collect_dynamic_libs('casadi')
# Something about legacy import codepaths in casadi.casadi causes PyInstaller's analysis to pick up
# casadi._casadi as a top-level _casadi module, which is wrong.
hiddenimports = ['casadi._casadi']
excludedimports = ['_casadi']

View File

@@ -0,0 +1,4 @@
# hook-py_lib3mf.py
from PyInstaller.utils.hooks import collect_dynamic_libs
binaries = collect_dynamic_libs('py_lib3mf')

View File

@@ -9,27 +9,28 @@ block_cipher = None
spyder_data = Path(site.getsitepackages()[-1]) / 'spyder'
parso_grammar = (Path(site.getsitepackages()[-1]) / 'parso/python').glob('grammar*')
cqw_path = Path(site.getsitepackages()[-1]) / 'cq_warehouse'
bdw_path = Path(site.getsitepackages()[-1]) / 'bd_warehouse'
cq_path = Path(site.getsitepackages()[-1]) / 'cadquery'
if sys.platform == 'linux':
occt_dir = os.path.join(Path(sys.prefix), 'share', 'opencascade')
ocp_path = (os.path.join(HOMEPATH, 'OCP.cpython-39-x86_64-linux-gnu.so'), '.')
ocp_path = [(os.path.join(HOMEPATH, 'OCP.cpython-310-x86_64-linux-gnu.so'), '.')]
elif sys.platform == 'darwin':
occt_dir = os.path.join(Path(sys.prefix), 'share', 'opencascade')
ocp_path = (os.path.join(HOMEPATH, 'OCP.cpython-39-darwin.so'), '.')
ocp_path = [(os.path.join(HOMEPATH, 'OCP.cpython-310-darwin.so'), '.')]
elif sys.platform == 'win32':
occt_dir = os.path.join(Path(sys.prefix), 'Library', 'share', 'opencascade')
ocp_path = (os.path.join(HOMEPATH, 'OCP.cp39-win_amd64.pyd'), '.')
ocp_path = [(os.path.join(HOMEPATH, 'OCP.cp310-win_amd64.pyd'), '.')]
datas1, binaries1, hiddenimports1 = collect_all('debugpy')
hiddenimports2 = collect_submodules('xmlrpc')
a = Analysis(['run.py'],
pathex=['.'],
binaries=[ocp_path] + binaries1,
binaries=ocp_path + binaries1,
datas=[(spyder_data, 'spyder'),
(occt_dir, 'opencascade'),
(cqw_path, 'cq_warehouse'),
(bdw_path, 'bd_warehouse'),
(cq_path, 'cadquery')] +
[(p, 'parso/python') for p in parso_grammar] + datas1,
hiddenimports=['ipykernel.datapub', 'debugpy', 'vtkmodules', 'vtkmodules.all',
@@ -38,8 +39,10 @@ a = Analysis(['run.py'],
'pyqtgraph.imageview.ImageViewTemplate_pyqt5', 'xmlrpc',
'zmq.backend', 'cq_warehouse', 'cq_warehouse.bearing', 'cq_warehouse.chain',
'cq_warehouse.drafting', 'cq_warehouse.extensions', 'cq_warehouse.fastener',
'cq_warehouse.sprocket', 'cq_warehouse.thread', 'cq_gears', 'cq_cache', 'build123d', 'cqmore'] + hiddenimports1 + hiddenimports2,
hookspath=[],
'cq_warehouse.sprocket', 'cq_warehouse.thread', 'cq_gears', 'cq_cache',
'build123d', 'cqmore', 'bd_warehouse', 'bd_warehouse.pipe', 'bd_warehouse.flange',
'bd_warehouse.thread', 'bd_warehouse.gears'] + hiddenimports1 + hiddenimports2,
hookspath=['pyinstaller/extrahooks/'],
runtime_hooks=['pyinstaller/pyi_rth_occ.py',
'pyinstaller/pyi_rth_fontconfig.py'],
excludes=['_tkinter'],
@@ -50,13 +53,13 @@ a = Analysis(['run.py'],
# There is an issue that keeps the OpenSSL libraries from being copied to the output directory.
# This should work if nothing else, but does not with GitHub Actions
if sys.platform == 'win32':
from PyInstaller.depend.bindepend import getfullnameof
rel_data_path = ['PyQt5', 'Qt', 'bin']
a.datas += [
(getfullnameof('libssl-1_1-x64.dll'), os.path.join(*rel_data_path), 'DATA'),
(getfullnameof('libcrypto-1_1-x64.dll'), os.path.join(*rel_data_path), 'DATA'),
]
# if sys.platform == 'win32':
# from PyInstaller.depend.bindepend import getfullnameof
# rel_data_path = ['PyQt5', 'Qt', 'bin']
# a.datas += [
# (getfullnameof('libssl-1_1-x64.dll'), os.path.join(*rel_data_path), 'DATA'),
# (getfullnameof('libcrypto-1_1-x64.dll'), os.path.join(*rel_data_path), 'DATA'),
# ]
pyz = PYZ(a.pure, a.zipped_data,

View File

@@ -16,12 +16,24 @@ def get_version(rel_path):
else:
raise RuntimeError("Unable to find version string.")
setup(name='CQ-editor',
version=get_version('cq_editor/_version.py'),
packages=find_packages(),
entry_points={
'gui_scripts': [
'cq-editor = cq_editor.__main__:main',
'CQ-editor = cq_editor.__main__:main'
]}
)
setup(
name="CQ-editor",
version=get_version("cq_editor/_version.py"),
packages=find_packages(),
entry_points={
"gui_scripts": [
"cq-editor = cq_editor.__main__:main",
"CQ-editor = cq_editor.__main__:main",
]
},
python_requires=">=3.8,<3.12",
install_requires=[
"logbook>=1",
"ipython",
"path>=16",
"PyQt5>=5",
"requests>=2,<3",
"spyder>=5,<6",
"pyqtgraph",
],
)

View File

@@ -1093,6 +1093,36 @@ def test_render_colors_console(main_clean):
qtbot.wait(100)
assert('Unknown color format' in log.toPlainText().splitlines()[-1])
code_shading = \
'''
import cadquery as cq
res1 = cq.Workplane('XY').box(5, 7, 5)
res2 = cq.Workplane('XY').box(8, 5, 4)
show_object(res1)
show_object(res2,options={"alpha":0})
'''
def test_shading_aspect(main_clean):
qtbot, win = main_clean
obj_tree = win.components['object_tree']
editor = win.components['editor']
debugger = win.components['debugger']
editor.set_text(code_shading)
debugger._actions['Run'][0].triggered.emit()
CQ = obj_tree.CQ
# get material aspects
ma1 = CQ.child(0).ais.Attributes().ShadingAspect().Material()
ma2 = CQ.child(1).ais.Attributes().ShadingAspect().Material()
# verify that they are the same
assert ma1.Shininess() == ma2.Shininess()
def test_confirm_new(monkeypatch,editor):
qtbot, editor = editor
@@ -1433,4 +1463,3 @@ def test_modulefinder(tmp_path, main):
qtbot.wait(100)
assert("Cannot determine imported modules" in log.toPlainText().splitlines()[-1])