2 Commits

Author SHA1 Message Date
Hermes 3ab3078d39 Added name 2025-06-01 09:52:25 +02:00
Hermes 7588e2f303 Initial commit 2025-06-01 09:51:53 +02:00
891 changed files with 12 additions and 191806 deletions
Vendored
BIN
View File
Binary file not shown.
-38
View File
@@ -1,38 +0,0 @@
*.xml
*.iml
.idea
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
.venv/
venv/
ENV/
# Lock files
uv.lock
# IDE
.vscode/
*.swp
*.swo
-23
View File
@@ -1,23 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="10">
<item index="0" class="java.lang.String" itemvalue="python-rtmidi" />
<item index="1" class="java.lang.String" itemvalue="PyAudio" />
<item index="2" class="java.lang.String" itemvalue="rtmidi" />
<item index="3" class="java.lang.String" itemvalue="scikit-image" />
<item index="4" class="java.lang.String" itemvalue="python" />
<item index="5" class="java.lang.String" itemvalue="PySide6" />
<item index="6" class="java.lang.String" itemvalue="PySide6-Essentials" />
<item index="7" class="java.lang.String" itemvalue="PySide6-Addons" />
<item index="8" class="java.lang.String" itemvalue="lazy_loader" />
<item index="9" class="java.lang.String" itemvalue="typing_extensions" />
</list>
</value>
</option>
</inspection_tool>
</profile>
</component>
-6
View File
@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.11 (fluency)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (fluency)" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" />
</component>
</project>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/fluency-cad.iml" filepath="$PROJECT_DIR$/.idea/fluency-cad.iml" />
</modules>
</component>
</project>
Generated
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
-483
View File
@@ -1,483 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="8f0bafd6-58a0-4b20-aa2b-ddc3ba278873" name="Changes" comment="- added renderer&#10;- Added undo">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/rendering/mitsuba_backend.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/rendering/mitsuba_backend.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/rendering/occ_renderer.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/rendering/occ_renderer.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/rendering/render_backend.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/rendering/render_backend.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/ui/main_window.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/ui/main_window.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/ui/render_window.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/ui/render_window.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/ui/viewer_widget.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/ui/viewer_widget.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Python Script" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="single_window" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
<option name="ROOT_SYNC" value="DONT_SYNC" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProblemsViewState">
<option name="selectedTabId" value="QODANA_PROBLEMS_VIEW_TAB" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 6
}</component>
<component name="ProjectId" id="2aDywQvESFCKbJK4JUVHIhkN4S6" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;Python.2dtest.executor&quot;: &quot;Run&quot;,
&quot;Python.3d_windows.executor&quot;: &quot;Run&quot;,
&quot;Python.Unnamed.executor&quot;: &quot;Run&quot;,
&quot;Python.base.executor&quot;: &quot;Run&quot;,
&quot;Python.data_model.executor&quot;: &quot;Run&quot;,
&quot;Python.draw_widget2d.executor&quot;: &quot;Run&quot;,
&quot;Python.draw_widget_solve.executor&quot;: &quot;Run&quot;,
&quot;Python.fluency.executor&quot;: &quot;Run&quot;,
&quot;Python.fluencyb.executor&quot;: &quot;Run&quot;,
&quot;Python.gl_widget.executor&quot;: &quot;Run&quot;,
&quot;Python.gui_ui.executor&quot;: &quot;Run&quot;,
&quot;Python.kernel.executor&quot;: &quot;Run&quot;,
&quot;Python.main.executor&quot;: &quot;Run&quot;,
&quot;Python.meshtest.executor&quot;: &quot;Run&quot;,
&quot;Python.occ_renderer.executor&quot;: &quot;Run&quot;,
&quot;Python.occ_to_mesh.executor&quot;: &quot;Run&quot;,
&quot;Python.render_backend.executor&quot;: &quot;Run&quot;,
&quot;Python.side_fluency.executor&quot;: &quot;Run&quot;,
&quot;Python.simple_mesh.executor&quot;: &quot;Run&quot;,
&quot;Python.sketch.executor&quot;: &quot;Run&quot;,
&quot;Python.vtk_widget.executor&quot;: &quot;Run&quot;,
&quot;Python.vulkan.executor&quot;: &quot;Run&quot;,
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;,
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;,
&quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;feature/occ-migration&quot;,
&quot;last_opened_file_path&quot;: &quot;/Volumes/Data_drive/Programming/fluency/src/fluency/rendering&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;project.propVCSSupport.DirectoryMappings&quot;
}
}</component>
<component name="QodanaReportsService">
<option name="descriptions">
<ReportDescription localRun="true" path="/private/var/folders/kg/zm48w_r96yb68mlbzvb9gtq40000gn/T/qodana_output/qodana.sarif.json" reportGuid="5f5b823c-c594-48c5-ae1f-062e30303918" reportId="fluency/qodana/2024-02-04" />
</option>
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/src/fluency/rendering" />
<recent name="$PROJECT_DIR$/src/fluency" />
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/drawing_modules" />
<recent name="$PROJECT_DIR$/modules" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$" />
</key>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-python-sdk-c59985aa861c-c2ffad84badb-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-261.24374.152" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="8f0bafd6-58a0-4b20-aa2b-ddc3ba278873" name="Changes" comment="" />
<created>1703867682707</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1703867682707</updated>
</task>
<task id="LOCAL-00001" summary="init">
<option name="closed" value="true" />
<created>1703951701948</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1703951701948</updated>
</task>
<task id="LOCAL-00002" summary="- Basic oop sketch widget implement">
<option name="closed" value="true" />
<created>1729958532384</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1729958532384</updated>
</task>
<task id="LOCAL-00003" summary="- Sketch projection partly works again :)">
<option name="closed" value="true" />
<created>1735563255455</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1735563255455</updated>
</task>
<task id="LOCAL-00004" summary="- Sketch projection partly works again :)">
<option name="closed" value="true" />
<created>1735585968733</created>
<option name="number" value="00004" />
<option name="presentableId" value="LOCAL-00004" />
<option name="project" value="LOCAL" />
<updated>1735585968733</updated>
</task>
<task id="LOCAL-00005" summary="- Added new componnt controls">
<option name="closed" value="true" />
<created>1735601610504</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1735601610504</updated>
</task>
<task id="LOCAL-00006" summary="- Added new componnt controls">
<option name="closed" value="true" />
<created>1735601786207</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1735601786207</updated>
</task>
<task id="LOCAL-00007" summary="- changing compos for sketches works">
<option name="closed" value="true" />
<created>1735652081552</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1735652081552</updated>
</task>
<task id="LOCAL-00008" summary="- changing compos including sketches and bodies">
<option name="closed" value="true" />
<created>1735662119176</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1735662119176</updated>
</task>
<task id="LOCAL-00009" summary="- Drawing bodys depending on the selected compo&#10;- Cut working&#10;- Edit sketch working">
<option name="closed" value="true" />
<created>1735685300102</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1735685300102</updated>
</task>
<task id="LOCAL-00010" summary="- delete sketch working&#10;- added mid point snap&#10;- added hovering line with distance">
<option name="closed" value="true" />
<created>1735763743346</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1735763743346</updated>
</task>
<task id="LOCAL-00011" summary="- Added new buttons and settings">
<option name="closed" value="true" />
<created>1735825176611</created>
<option name="number" value="00011" />
<option name="presentableId" value="LOCAL-00011" />
<option name="project" value="LOCAL" />
<updated>1735825176611</updated>
</task>
<task id="LOCAL-00012" summary="- Added new buttons and settings">
<option name="closed" value="true" />
<created>1735842523870</created>
<option name="number" value="00012" />
<option name="presentableId" value="LOCAL-00012" />
<option name="project" value="LOCAL" />
<updated>1735842523870</updated>
</task>
<task id="LOCAL-00013" summary="- Added construction lines switching&#10;- Moved callbacks into sketchwidget from main.&#10;- Changed reset on right click">
<option name="closed" value="true" />
<created>1739739664763</created>
<option name="number" value="00013" />
<option name="presentableId" value="LOCAL-00013" />
<option name="project" value="LOCAL" />
<updated>1739739664763</updated>
</task>
<task id="LOCAL-00014" summary="- Added contrain displayed next to line&#10;- Slight change to point check from solver.">
<option name="closed" value="true" />
<created>1743193041868</created>
<option name="number" value="00014" />
<option name="presentableId" value="LOCAL-00014" />
<option name="project" value="LOCAL" />
<updated>1743193041868</updated>
</task>
<task id="LOCAL-00015" summary="- Added enabling of midpsnap and prepared others&#10;- Show dimesnion on hover">
<option name="closed" value="true" />
<created>1743284173326</created>
<option name="number" value="00015" />
<option name="presentableId" value="LOCAL-00015" />
<option name="project" value="LOCAL" />
<updated>1743284173326</updated>
</task>
<task id="LOCAL-00016" summary="- Fixed redraw when component changed">
<option name="closed" value="true" />
<created>1744555255868</created>
<option name="number" value="00016" />
<option name="presentableId" value="LOCAL-00016" />
<option name="project" value="LOCAL" />
<updated>1744555255868</updated>
</task>
<task id="LOCAL-00017" summary="- added MIT license">
<option name="closed" value="true" />
<created>1748764814845</created>
<option name="number" value="00017" />
<option name="presentableId" value="LOCAL-00017" />
<option name="project" value="LOCAL" />
<updated>1748764814845</updated>
</task>
<task id="LOCAL-00018" summary="- added screenshot">
<option name="closed" value="true" />
<created>1748765318267</created>
<option name="number" value="00018" />
<option name="presentableId" value="LOCAL-00018" />
<option name="project" value="LOCAL" />
<updated>1748765318267</updated>
</task>
<task id="LOCAL-00019" summary="- added sdf folder ( doesnt work via pip or git=)">
<option name="closed" value="true" />
<created>1755369224187</created>
<option name="number" value="00019" />
<option name="presentableId" value="LOCAL-00019" />
<option name="project" value="LOCAL" />
<updated>1755369224187</updated>
</task>
<task id="LOCAL-00020" summary="- Tons of addtions">
<option name="closed" value="true" />
<created>1782673954850</created>
<option name="number" value="00020" />
<option name="presentableId" value="LOCAL-00020" />
<option name="project" value="LOCAL" />
<updated>1782673954850</updated>
</task>
<task id="LOCAL-00021" summary="- Tons of addtions">
<option name="closed" value="true" />
<created>1782679912834</created>
<option name="number" value="00021" />
<option name="presentableId" value="LOCAL-00021" />
<option name="project" value="LOCAL" />
<updated>1782679912834</updated>
</task>
<task id="LOCAL-00022" summary="- Basic operations">
<option name="closed" value="true" />
<created>1782768610475</created>
<option name="number" value="00022" />
<option name="presentableId" value="LOCAL-00022" />
<option name="project" value="LOCAL" />
<updated>1782768610475</updated>
</task>
<task id="LOCAL-00023" summary="- removed cadquery deoendency">
<option name="closed" value="true" />
<created>1782928990792</created>
<option name="number" value="00023" />
<option name="presentableId" value="LOCAL-00023" />
<option name="project" value="LOCAL" />
<updated>1782928990792</updated>
</task>
<task id="LOCAL-00024" summary="- sketch enhacements">
<option name="closed" value="true" />
<created>1783108151675</created>
<option name="number" value="00024" />
<option name="presentableId" value="LOCAL-00024" />
<option name="project" value="LOCAL" />
<updated>1783108151676</updated>
</task>
<task id="LOCAL-00025" summary="- sketch enhacements">
<option name="closed" value="true" />
<created>1783159860774</created>
<option name="number" value="00025" />
<option name="presentableId" value="LOCAL-00025" />
<option name="project" value="LOCAL" />
<updated>1783159860774</updated>
</task>
<task id="LOCAL-00026" summary="- UI refinement, button position ui file as source no dirty drafting anymore">
<option name="closed" value="true" />
<created>1783174566362</created>
<option name="number" value="00026" />
<option name="presentableId" value="LOCAL-00026" />
<option name="project" value="LOCAL" />
<updated>1783174566362</updated>
</task>
<task id="LOCAL-00027" summary="- assembly draft">
<option name="closed" value="true" />
<created>1783239410744</created>
<option name="number" value="00027" />
<option name="presentableId" value="LOCAL-00027" />
<option name="project" value="LOCAL" />
<updated>1783239410744</updated>
</task>
<task id="LOCAL-00028" summary="- assembly draft">
<option name="closed" value="true" />
<created>1783272988957</created>
<option name="number" value="00028" />
<option name="presentableId" value="LOCAL-00028" />
<option name="project" value="LOCAL" />
<updated>1783272988957</updated>
</task>
<task id="LOCAL-00029" summary="- Added save file foramt&#10;- Split main.py refactor">
<option name="closed" value="true" />
<created>1783282570014</created>
<option name="number" value="00029" />
<option name="presentableId" value="LOCAL-00029" />
<option name="project" value="LOCAL" />
<updated>1783282570014</updated>
</task>
<task id="LOCAL-00030" summary="- Added save file foramt&#10;- Split main.py refactor">
<option name="closed" value="true" />
<created>1783453889199</created>
<option name="number" value="00030" />
<option name="presentableId" value="LOCAL-00030" />
<option name="project" value="LOCAL" />
<updated>1783453889199</updated>
</task>
<task id="LOCAL-00031" summary="- Added save file foramt&#10;- Split main.py refactor">
<option name="closed" value="true" />
<created>1783456842297</created>
<option name="number" value="00031" />
<option name="presentableId" value="LOCAL-00031" />
<option name="project" value="LOCAL" />
<updated>1783456842297</updated>
</task>
<task id="LOCAL-00032" summary="- Added save file foramt&#10;- Split main.py refactor">
<option name="closed" value="true" />
<created>1783755278516</created>
<option name="number" value="00032" />
<option name="presentableId" value="LOCAL-00032" />
<option name="project" value="LOCAL" />
<updated>1783755278516</updated>
</task>
<task id="LOCAL-00033" summary="- Added save file foramt&#10;- Split main.py refactor">
<option name="closed" value="true" />
<created>1783777171864</created>
<option name="number" value="00033" />
<option name="presentableId" value="LOCAL-00033" />
<option name="project" value="LOCAL" />
<updated>1783777171864</updated>
</task>
<task id="LOCAL-00034" summary="- Working assembly multi :)">
<option name="closed" value="true" />
<created>1783798201133</created>
<option name="number" value="00034" />
<option name="presentableId" value="LOCAL-00034" />
<option name="project" value="LOCAL" />
<updated>1783798201133</updated>
</task>
<task id="LOCAL-00035" summary="- Working assembly multi :)">
<option name="closed" value="true" />
<created>1783798929531</created>
<option name="number" value="00035" />
<option name="presentableId" value="LOCAL-00035" />
<option name="project" value="LOCAL" />
<updated>1783798929531</updated>
</task>
<task id="LOCAL-00036" summary="- added renderer">
<option name="closed" value="true" />
<created>1783887682052</created>
<option name="number" value="00036" />
<option name="presentableId" value="LOCAL-00036" />
<option name="project" value="LOCAL" />
<updated>1783887682052</updated>
</task>
<task id="LOCAL-00037" summary="- added renderer&#10;- Added undo">
<option name="closed" value="true" />
<created>1783887704766</created>
<option name="number" value="00037" />
<option name="presentableId" value="LOCAL-00037" />
<option name="project" value="LOCAL" />
<updated>1783887704766</updated>
</task>
<task id="LOCAL-00038" summary="- added renderer&#10;- Added undo">
<option name="closed" value="true" />
<created>1783891561116</created>
<option name="number" value="00038" />
<option name="presentableId" value="LOCAL-00038" />
<option name="project" value="LOCAL" />
<updated>1783891561116</updated>
</task>
<task id="LOCAL-00039" summary="- added renderer&#10;- Added undo">
<option name="closed" value="true" />
<created>1783918463034</created>
<option name="number" value="00039" />
<option name="presentableId" value="LOCAL-00039" />
<option name="project" value="LOCAL" />
<updated>1783918463034</updated>
</task>
<option name="localTasksCounter" value="40" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration">
<ignored-roots>
<path value="$PROJECT_DIR$/pythonProject" />
</ignored-roots>
<MESSAGE value="- Renabled extrusion with new object system" />
<MESSAGE value="- Sketch projection partly works again :)" />
<MESSAGE value="- Added new componnt controls" />
<MESSAGE value="- changing compos for sketches works" />
<MESSAGE value="- changing compos including sketches and bodies" />
<MESSAGE value="- Drawing bodys depending on the selected compo&#10;- Cut working&#10;- Edit sketch working" />
<MESSAGE value="- delete sketch working&#10;- added mid point snap&#10;- added hovering line with distance" />
<MESSAGE value="- Added new buttons and settings" />
<MESSAGE value="- Added construction lines switching&#10;- Moved callbacks into sketchwidget from main.&#10;- Changed reset on right click" />
<MESSAGE value="- Added contrain displayed next to line&#10;- Slight change to point check from solver." />
<MESSAGE value="- Added enabling of midpsnap and prepared others&#10;- Show dimesnion on hover" />
<MESSAGE value="- Fixed redraw when component changed" />
<MESSAGE value="- added MIT license" />
<MESSAGE value="- added screenshot" />
<MESSAGE value="- added sdf folder ( doesnt work via pip or git=)" />
<MESSAGE value="- Tons of addtions" />
<MESSAGE value="- Basic operations" />
<MESSAGE value="- removed cadquery deoendency" />
<MESSAGE value="- sketch enhacements" />
<MESSAGE value="- UI refinement, button position ui file as source no dirty drafting anymore" />
<MESSAGE value="- assembly draft" />
<MESSAGE value="- Added save file foramt&#10;- Split main.py refactor" />
<MESSAGE value="- Working assembly multi :)" />
<MESSAGE value="- added renderer" />
<MESSAGE value="- added renderer&#10;- Added undo" />
<option name="LAST_COMMIT_MESSAGE" value="- added renderer&#10;- Added undo" />
</component>
</project>
-4804
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) 2025 Thomas Herrmann
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+2 -109
View File
@@ -1,111 +1,4 @@
# Fluency CAD 2.0 # fluencyCAD
A parametric CAD application built on OpenCASCADE Technology (OCCT) with a modern pygfx-based 3D renderer. A CAD program based on QT - sdfCAD - Solvespace and VTK meant to deliver a fluent distraction free CAD experience with alot of freedom thanks to sdf based meshes.
## Features
- **OpenCASCADE Geometry Kernel**: Industry-standard BRep geometry with exact precision
- **STEP/IGES Import/Export**: Full support for industry-standard CAD file formats
- **Parametric Sketching**: 2D sketching with constraint solving using SolveSpace
- **Boolean Operations**: Union, difference, and intersection
- **Fillet & Chamfer**: Apply edge treatments to solid bodies
- **Modern Renderer**: WebGPU-based rendering with pygfx (smaller footprint than VTK)
## Architecture
```
fluency/
├── src/fluency/
│ ├── geometry/ # Geometry abstraction layer
│ │ └── base.py # Abstract interfaces
│ ├── geometry_occ/ # OpenCASCADE implementation
│ │ ├── kernel.py # OCGeometryKernel
│ │ └── sketch.py # OCCSketch with constraints
│ ├── rendering/ # Rendering abstraction
│ │ ├── base.py # Abstract renderer
│ │ └── pygfx_renderer.py
│ ├── models/ # Data models
│ │ └── data_model.py # Project, Component, Sketch, Body
│ └── main.py # Application entry point
├── tests/
│ └── test_geometry.py
└── pyproject.toml
```
## Installation
```bash
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install dependencies
pip install -e ".[dev]"
```
## Dependencies
| Package | Purpose |
|---------|---------|
| cadquery-ocp | OpenCASCADE Python bindings (OCP) |
| pygfx | WebGPU-based 3D renderer |
| wgpu | WebGPU Python bindings |
| PySide6 | Qt GUI framework |
| numpy | Numerical computing |
| scipy | Scientific computing |
## Usage
```bash
# Run the application
fluency-cad
# Or directly
python -m fluency.main
```
## API Example
```python
from fluency.geometry_occ.kernel import OCGeometryKernel
from fluency.geometry.base import Point2D
# Create kernel
kernel = OCGeometryKernel()
# Create a sketch
points = [
Point2D(0, 0),
Point2D(10, 0),
Point2D(10, 10),
Point2D(0, 10),
]
polygon = kernel.create_polygon(points)
# Extrude to 3D
body = kernel.extrude(polygon, height=20.0)
# Apply fillet
body = kernel.fillet(body, radius=2.0)
# Export to STEP
kernel.export_step(body, "part.step")
# Export to STL
kernel.export_stl(body, "part.stl")
```
## Comparison: Before vs After
| Aspect | Before (SDF + VTK) | After (OCC + pygfx) |
|--------|-------------------|---------------------|
| Geometry Precision | Approximate (mesh) | Exact (BRep) |
| Export Formats | STL only | STEP, IGES, STL, BREP |
| File Size | Large (mesh) | Small (BRep) |
| Fillet/Chamfer | Approximate | Exact |
| Dependency Size | ~200MB (VTK) | ~30MB (pygfx) |
| Constraint Solver | SolveSpace (separate) | SolveSpace (integrated) |
## License
MIT License
-147
View File
@@ -1,147 +0,0 @@
# WARP.md
This file provides guidance to WARP (warp.dev) when working with code in this repository.
## Project Overview
Fluency is a CAD (Computer Aided Design) application built with Python/PySide6 that provides parametric 3D modeling through a timeline-based project system. The application combines 2D sketching with constraint solving, 3D visualization using VTK, and SDF (Signed Distance Function) based mesh generation.
## Common Commands
### Development Environment Setup
```bash
# Activate virtual environment (if exists)
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
```
### Running the Application
```bash
# Run the main application
python main.py
# Run with debugging
python -u main.py
```
### UI Development
```bash
# Convert Qt Designer UI file to Python code
pyside6-uic gui.ui > Gui.py -g python
```
### Building Executable
The project uses Nuitka for compilation (configured in `main.py` header):
```bash
# Build standalone executable
nuitka --standalone --plugin-enable=pyside6 --plugin-enable=numpy --macos-create-app-bundle main.py
```
### Testing
```bash
# Run mesh generation test
python meshtest.py
```
## Architecture Overview
### Core Components
#### Main Application (`main.py`)
- **MainWindow**: Central UI controller that manages all widgets and user interactions
- **Project System**: Hierarchical structure: `Project → Timeline → Component → Sketch/Body`
- **Signal-based Communication**: Qt signals coordinate between 2D sketching and 3D rendering
#### Project Hierarchy
```
Project
├── Timeline (list of Components)
└── Component
├── Sketches (dict)
├── Bodies (dict)
└── Connectors (for assembly)
```
#### Drawing Modules (`drawing_modules/`)
- **SketchWidget** (`draw_widget_solve.py`): 2D parametric sketching with SolverSpace constraint solving
- **VTKWidget** (`vtk_widget.py`): 3D visualization and mesh interaction using VTK
- **PyVistaWidget** (`vysta_widget.py`): Alternative 3D rendering backend
#### Mesh Generation (`mesh_modules/`)
- **VESTA** (`vesta_mesh.py`): Multi-threaded SDF-to-mesh conversion using marching cubes
- **Interactor Mesh** (`interactor_mesh.py`): Simplified edge-based meshes for 3D selection
- **Simple Mesh** (`simple_mesh.py`): Basic mesh utilities
### Data Flow Architecture
#### 2D to 3D Pipeline
1. **2D Sketching**: User draws in SketchWidget using Qt coordinate system
2. **Constraint Solving**: SolverSpace resolves geometric constraints
3. **SDF Generation**: Sketch converted to Signed Distance Functions for 3D operations
4. **Mesh Generation**: VESTA generates triangle meshes from SDF using marching cubes
5. **3D Rendering**: VTK displays both solid meshes and interactive edges
#### Signal Flow (from `doc/flow.md`)
- 2D QPoint → cartesian space → SolverSpace dict → constraint solving → display
- 3D mesh selection → projection to 2D → sketch widget integration
### Key Classes
#### Core Data Structures
- **Sketch**: 2D geometric data with origin, normal, points, and constraints
- **Body**: 3D mesh representation containing SDF objects and interactor meshes
- **Component**: Container grouping related sketches and bodies
- **Interactor**: Simplified edge-based mesh for 3D manipulation
#### Constraint Solving
The application uses `python_solvespace` for parametric constraint solving:
- Point-to-point constraints
- Distance constraints
- Horizontal/vertical line constraints
- Point-to-line constraints
### Technology Stack
- **GUI**: PySide6 (Qt for Python)
- **3D Graphics**: VTK for rendering, PyVista as alternative
- **Constraint Solving**: SolverSpace for parametric geometry
- **Mesh Generation**: SDF library with custom VESTA marching cubes implementation
- **Scientific Computing**: NumPy for mathematical operations
## Development Workflow
### Adding New Sketch Tools
1. Add UI button in `gui.ui`
2. Convert UI: `pyside6-uic gui.ui > Gui.py -g python`
3. Connect signal in `MainWindow.__init__()`
4. Implement tool logic in `SketchWidget`
### Adding New 3D Operations
1. Extend operation buttons in the Modify group
2. Implement operation logic using SDF functions
3. Update Body creation and timeline management
4. Handle interactor mesh generation for selection
### Debugging Tips
- Monitor solver results through `SolverSystem` status
- Use VTK's built-in debugging for rendering issues
- Check coordinate transformations between 2D sketch and 3D space
- Verify SDF function outputs before mesh generation
### File Structure
- `main.py`: Application entry point and main window
- `Gui.py`: Auto-generated UI code (do not edit directly)
- `gui.ui`: Qt Designer UI definition file
- `drawing_modules/`: 2D and 3D rendering widgets
- `mesh_modules/`: Mesh generation and processing
- `doc/`: Architecture and command documentation
## Dependencies
Primary external libraries:
- `PySide6`: Qt GUI framework
- `vtk`: 3D visualization toolkit
- `python-solvespace`: Constraint solving
- `sdf`: Signed Distance Function operations
- `numpy`: Numerical computations
- `scikit-image`: Marching cubes algorithm
- `names`: Random name generation for sketches
-219
View File
@@ -1,219 +0,0 @@
# Fluency CAD — Agent Guide
## Project Overview
**Fluency CAD 2.0** is a parametric CAD application built on **OpenCASCADE Technology (OCCT)** with a modern **pygfx-based 3D renderer**. It provides 2D sketching with SolveSpace constraint solving, boolean operations, STEP/IGES/STL import/export, and exact BRep geometry.
- Language: **Python 3.10+**
- GUI: **PySide6** (Qt6)
- Geometry Kernel: **OCP** (cadquery-ocp — OpenCASCADE Python bindings)
- Constraint Solver: **python_solvespace**
- Renderer: **pygfx** (WebGPU) + **OCCRenderer** (native OCC AIS display)
---
## Architecture
```
src/fluency/
├── __init__.py # Package entry (version, imports)
├── main.py # Application entry point, MainWindow, Sketch2DWidget (~5000 lines)
├── sketch_solver.py # SolveSpace constraint solver wrapper (legacy)
├── geometry/
│ └── base.py # Abstract interfaces: GeometryKernel, SketchInterface, data classes
├── geometry_occ/
│ ├── kernel.py # OCGeometryKernel (extrude, boolean, fillet, import/export, mesh)
│ └── sketch.py # OCCSketch with SolveSpace integration (face detection, constraints)
├── models/
│ └── data_model.py # Project, Component, Sketch, Body dataclasses
├── rendering/
│ ├── base.py # Abstract Renderer interface
│ ├── occ_renderer.py # OCC AIS renderer (preferred — smooth BRep display)
│ └── pygfx_renderer.py # Legacy pygfx renderer
├── utils/ # Utility modules
└── widgets/ # Custom widgets
tests/
└── test_geometry.py # Comprehensive test suite (52+ tests)
```
### Key Classes & Responsibilities
| Class | File | Purpose |
|-------|------|---------|
| `OCGeometryKernel` | `kernel.py` | OCC shape ops: extrude, boolean, fillet, mesh, import/export |
| `OCCSketch` | `sketch.py` | 2D sketch with SolveSpace solver, face detection, workplane |
| `OCCSketchEntity` | `sketch.py` | Entity (point/line/circle/arc) with solver handle, is_construction, is_external |
| `Sketch2DWidget` | `main.py` | Qt widget for interactive 2D sketching (draw, snap, constrain) |
| `MainWindow` | `main.py` | Main application window, toolbars, 3D viewer, operations |
| `OCCRenderer` | `occ_renderer.py` | Native OCC AIS display (shaded + edges, face pick) |
| `Sketch` | `data_model.py` | Data model: workplane, occ_sketch ref, source_body_id |
| `Body` | `data_model.py` | 3D solid with geometry, visibility, render object |
| `Component` | `data_model.py` | Container for sketches and bodies |
| `Project` | `data_model.py` | Top-level container with kernel |
### Data Flow
```
User draws in Sketch2DWidget
→ OCCSketch entities created in solver
→ Constraint solving (python_solvespace)
→ OCCSketch.get_geometry() → detect_faces() → build_face_geometry()
→ OCGeometryKernel.extrude() → BRepPrimAPI_MakePrism
→ Boolean operations → Body added to Component
→ OCCRenderer.add_shape() → AIS display
```
---
## Development Commands
```bash
# Install editable
pip install -e ".[dev]"
# Run app
python -m fluency.main
# Run tests (52 tests)
python -m pytest tests/test_geometry.py -v
# Run single test
python -m pytest tests/test_geometry.py::TestOCCSketch::test_workplane_extrude_with_hole -xvs
# Quck geometry test (raw OCC, no Qt)
python -c "from fluency.geometry_occ.sketch import OCCSketch; ..."
```
---
## Code Conventions
### General
- Line length: **100 chars** (black/ruff config)
- Target Python: **3.10+** (uses `from __future__ import annotations`, walrus, pattern matching)
- Docstrings: Google/NumPy style preferred
- Logging: `logger = logging.getLogger(__name__)` with `logging.DEBUG` level
### OCC / OCP
- Always use `is not None` for OCP objects — `TopoDS_Shape.__bool__` can be falsy even for valid shapes
- `BRepBuilderAPI_MakeFace.Add(wire)` expects a `TopoDS_Wire`. `wire.Reversed()` returns `TopoDS_Shape` → cast via `_TopoDS.Wire_s(wire.Reversed())`
- Face normal direction: check `face.Orientation()` vs `TopAbs_REVERSED` — a REVERSED face's outward normal is the NEGATION of the surface axis
- `TopoDS_Wire_s(shape)`, `TopoDS_Face_s(shape)` — use `_s` suffix from OCP for downcasts
- Mesh: `BRepMesh_IncrementalMesh(shape, tol, False, 0.15, True)` — default deflection 0.15 rad for smooth curves
### Extrude / Cut Workflow
- Snapshot `list(self._current_component.bodies.items())` **BEFORE** `add_body()` — the new body must not be in the target set
- Cut targets the **source body** (`sketch._source_body_id` from face pick), not `bodies[0]`
- The fix: apply boolean to **target** geometry, then remove tool body
- Plain extrude with holes: inner wires must have **OPPOSITE** geometric winding to the outer wire (see `build_face_geometry` and `_loop_signed_area`)
### Sketch / Solvers
- `python_solvespace` has NO remove API for entities/constraints. Deleting requires: drop from `_points`/`_lines`, prune `_constraint_log`, `_rebuild_solver()` (recreates entire system), `_rebuild_labels()`, re-solve
- `_constraint_log`: each entry is `{"type": str, "ids": tuple[int,...], "params": tuple, "labels": set[str]}`
- Constraint labels: stored on **point** entities for paintEvent rendering; rebuilt via `_rebuild_labels()`
- Line constraints (`horizontal`/`vertical`/`parallel`/`perpendicular`) need the **line's** solver handle, not a point's. Use `_find_line_sketch_entity()` to get the correct handle
- External entities (underlay): `is_external=True`, `is_construction=True`, fixed in solver (always `dragged`). Stored in `_external_entity_ids`, excluded from `_line_segments()`, `get_polygon_points()`, `get_closed_loops()`, `detect_faces()`, `get_geometry()`
### Face Detection
- `get_closed_loops()`: uses snapped-coordinate graph (`_SNAP_TOL = 1e-4`) from line endpoint adjacency. Only accepts simple cycles (all nodes degree 2)
- `detect_faces()`: even-odd nesting rule via `_loop_contains`. Even depth = outer boundary, odd = hole
- `_loop_rep_point`: midpoint between centroid and first vertex. **Fragile** — can land inside a nested shape for certain geometries (e.g., a small hole near the centroid's direction from the first vertex)
- `_loop_signed_area`: shoelace formula for polygons, `πr²` (positive = CCW) for circles
### Rendering
- **OCCRenderer** is the main renderer (not pygfx). Uses `AIS_Shape`, `V3d_Viewer`, `AIS_InteractiveContext`
- Face pick: `pick_planar_face(x, y)``MoveTo``DetectedShape``TopoDS_Face_s``BRepAdaptor_Surface` plane check
- Highlight: `highlight_face(face)` creates a transparent AIS overlay; `clear_face_highlight()` removes it
- Preview: `preview_shape(shape)` for live transparent extrude preview
- Navigation: Left=orbit, Middle=pan, Wheel=zoom. **Right is RESERVED** — check user before reassigning
### Paint-Event Safety
- Every constraint-tag rendering loop wraps each entry in `try/except` so a bad entry (dangling id, corrupted geometry) doesn't crash the entire paint event
- `_point_world()` and `_entity_anchor()` return `None` (not raise) for malformed input
---
## Known Bugs & Fix Patterns
### 1. Hole Orientation in Extrusion (FIXED 2026-07-03)
**Symptom**: Inner shapes (circle/triangle/slot) inside a rectangle become solid islands instead of holes when extruding, depending on drag direction.
**Root Cause**: `wire_loop` in `build_face_geometry` unconditionally reversed hole wires (`w.Reversed()`). When the outer polygon was CW-winding (e.g., dragging from top-left to bottom-right), the reversed inner had the SAME effective direction as the outer, making OCC treat it as solid.
**Fix**: Added `_loop_signed_area()` to compute geometric winding. Hole wires are only reversed when their natural winding matches the outer's (ensuring opposite winding for holes).
**Relevant code**: `sketch.py`, `build_face_geometry()` and `_loop_signed_area()`
### 2. _loop_rep_point Fragility (KNOWN)
**Symptom**: Face detection fails when a nested shape contains the outer loop's representative point (midpoint between centroid and first vertex).
**Would-be fix**: Use a guaranteed-interior point (maximum inscribed circle center or perturbed centroid) instead of the centroid-first-vertex midpoint.
### 3. Extrude Cut / Target Selection (FIXED 2026-06-29)
**Symptom**: Cut created a separate "cavity-shaped" body next to the original instead of modifying the target.
**Fix**: Boolean result stored on TARGET body geometry; tool body removed from component. Auto-target via `sketch._source_body_id`.
### 4. Workplane Preservation (FIXED 2026-06-29)
**Symptom**: Sketch placed on a face lost its workplane after being added to component.
**Fix**: Copy `occ_sketch` workplane fields into `Sketch` dataclass BEFORE `apply_workplane()`.
---
## API Quirks
- **`QPoint(0,0)`**: falsy via `isNull()` in PySide6 → always use `is not None` for `Optional[QPoint]`
- **`QMouseEvent`/`QPainterPath`**: live in `PySide6.QtGui` (NOT `QtCore`)
- **`BRepBuilderAPI_MakeFace.Add()`**: needs `TopoDS_Wire`. `wire.Reversed()` returns `TopoDS_Shape` — cast via `TopoDS_Wire_s()`
- **python_solvespace**: NO entity/constraint remove API — workaround via `_rebuild_solver()`. Parameters read via `solver.params(handle.params)` → returns `(x, y)` tuple
- **OCGeometryKernel.extrude**: unwraps `OCCGeometryObject`, raw `TopoDS_Shape`, or cadquery `Workplane`. Always use `is not None` for the shape (not truthiness)
- **Sketch._source_body_id**: dynamic attribute set on `Sketch` dataclass, set during face-pick flow
- **`_get_shape(obj)`**: returns `obj.shape.wrapped` for `OCCGeometryObject`, `obj.shape` for raw shapes, `None` for empty. Use `is not None` guards everywhere
---
## Memory / Agent Context
This project has extensive Pi memory (hermes-memory) for:
- `project="fluency"` with `target="failure"`: bugs, fixes, corrections, insights
- `project="fluency"` with `target="memory"`: conventions, decisions, workflow patterns
- Available skills: `fix-cad-app-pipeline`, `refactor-from-cadquery-to-ocp`
Key memory queries for debugging:
- "hole orientation" → `_loop_signed_area` / `build_face_geometry` fix
- "extrude cut auto-target" → cut/target body fix
- "workplane preservation" → _add_sketch_to_component fix
- "_loop_rep_point" → face detection fragility
- "paint-event safety" → try/except per entry pattern
- "solver rebuild" → delete workflow via _rebuild_solver
- "face pick origin" → pick_planar_face face bbox centre
---
## Testing Patterns
```python
# Direct OCC test (no Qt)
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakePolygon, BRepBuilderAPI_MakeFace
from OCP.gp import gp_Pnt
from OCP.BRepPrimAPI import BRepPrimAPI_MakePrism
from OCP.GProp import GProp_GProps; from OCP.BRepGProp import BRepGProp
# Build test shape, extrude, verify volume
mp = BRepBuilderAPI_MakePolygon(); ...
g = GProp_GProps(); BRepGProp.VolumeProperties_s(shape, g)
assert abs(g.Mass() - expected) < 0.1
```
```python
# Sketch-based test
from fluency.geometry_occ.sketch import OCCSketch
from fluency.geometry_occ.kernel import OCGeometryKernel
sk = OCCSketch()
# ... add points, lines, circles ...
sk.solve()
geom = sk.get_geometry()
solid = OCGeometryKernel().extrude(geom, 10.0)
```
-108
View File
@@ -1,108 +0,0 @@
#!/usr/bin/env python3
"""
Debug script to test point dragging functionality in ImprovedSketchWidget
"""
import sys
import os
sys.path.append('/Volumes/Data_drive/Programming/fluency')
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton, QHBoxLayout
from PySide6.QtCore import Qt
from drawing_modules.improved_sketcher import ImprovedSketchWidget, SketchMode, Point2D
import logging
# Set up logging to see debug messages
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
class DebugMainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Debug Point Dragging")
self.resize(1000, 700)
# Create central widget
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
# Create button layout
button_layout = QHBoxLayout()
# Add test points button
add_points_btn = QPushButton("Add Test Points")
add_points_btn.clicked.connect(self.add_test_points)
button_layout.addWidget(add_points_btn)
# Check mode button
check_mode_btn = QPushButton("Check Mode")
check_mode_btn.clicked.connect(self.check_mode)
button_layout.addWidget(check_mode_btn)
# Reset mode button
reset_mode_btn = QPushButton("Reset to NONE Mode")
reset_mode_btn.clicked.connect(self.reset_mode)
button_layout.addWidget(reset_mode_btn)
layout.addLayout(button_layout)
# Create the sketcher widget
self.sketcher = ImprovedSketchWidget()
layout.addWidget(self.sketcher)
print("Debug window created. Current mode:", self.sketcher.current_mode)
def add_test_points(self):
"""Add some test points to the sketch"""
print("Adding test points...")
# Add a few points at different locations
points = [
Point2D(100, 100),
Point2D(200, 150),
Point2D(150, 200),
Point2D(50, 250)
]
for point in points:
self.sketcher.sketch.add_point(point)
print(f"Added point at ({point.x}, {point.y})")
self.sketcher.update()
print(f"Total points in sketch: {len(self.sketcher.sketch.points)}")
def check_mode(self):
"""Check current mode and dragging state"""
print(f"Current mode: {self.sketcher.current_mode}")
print(f"Dragging point: {self.sketcher.dragging_point}")
print(f"Drag start pos: {self.sketcher.drag_start_pos}")
print(f"Hovered point: {self.sketcher.hovered_point}")
print(f"Number of points: {len(self.sketcher.sketch.points)}")
# Check if points have solver handles
for i, point in enumerate(self.sketcher.sketch.points):
print(f"Point {i}: ({point.x}, {point.y}), handle: {point.handle}")
def reset_mode(self):
"""Reset to NONE mode to enable dragging"""
print("Resetting mode to NONE")
self.sketcher.set_mode(SketchMode.NONE)
print(f"Mode after reset: {self.sketcher.current_mode}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = DebugMainWindow()
window.show()
print("\n" + "="*50)
print("DEBUG INSTRUCTIONS:")
print("1. Click 'Add Test Points' to create some points")
print("2. Click 'Check Mode' to verify the current state")
print("3. Click 'Reset to NONE Mode' to ensure dragging is enabled")
print("4. Try to drag points by clicking and dragging them")
print("5. Watch the console for debug messages")
print("="*50 + "\n")
sys.exit(app.exec())
-253
View File
@@ -1,253 +0,0 @@
# Realistic Render View — Implementation Plan
## Context
Add a **"Render"** feature to Fluency CAD that opens a separate window for photorealistic rendering of the selected component or assembly (like KeyShot/Cacles).
**Constraints:**
- Open in a **new window** — don't clutter the workspace
- **Keep existing OCCRenderer** for the interactive 3D viewport — untouched
- Render backend must be a **separate, swappable module** so we can change the renderer later
- Use **Mitsuba 3** as the initial backend (`pip install mitsuba`, ~50MB)
---
## Architecture
```
┌─────────────────────────────────────────────────────────┐
│ Main Fluency Window (existing OCCRenderer — untouched) │
│ │
│ [Select body/assembly] → [Click "Render"] │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ RenderWindow (separate QMainWindow)│ │
│ │ │ │
│ │ ┌───────────────────────────────┐ │ │
│ │ │ RenderBackend (ABC) │ │ │
│ │ │ ├─ MitsubaBackend ← current │ │ │
│ │ │ ├─ (future: BlenderBackend) │ │ │
│ │ │ └─ (future: CyclesBackend) │ │ │
│ │ └───────────────────────────────┘ │ │
│ │ │ │\n│ │ [Image preview] [Progress bar] │ │
│ │ [Material ▾] [Quality ▾] [Render] │ │
│ │ [Export PNG] │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### Swappable Backend Interface
```python
from abc import ABC, abstractmethod
from dataclasses import dataclass
import numpy as np
@dataclass
class RenderMaterial:
name: str
color: tuple[float, float, float] = (0.7, 0.7, 0.7)
metallic: float = 0.0 # 0.01.0
roughness: float = 0.5 # 0.01.0
bsdf_type: str = "diffuse" # diffuse | roughconductor | roughdielectric | plastic
@dataclass
class RenderCamera:
origin: tuple[float, float, float] = (100, 100, 100)
target: tuple[float, float, float] = (0, 0, 0)
up: tuple[float, float, float] = (0, 0, 1)
fov: float = 45.0
@dataclass
class RenderSettings:
width: int = 1920
height: int = 1080
spp: int = 256 # samples per pixel
max_depth: int = 8 # path tracer bounces
class RenderBackend(ABC):
"""Swap this to change the rendering engine."""
@abstractmethod
def render(self, obj_path: str, material: RenderMaterial,
camera: RenderCamera, settings: RenderSettings) -> np.ndarray: ...
@abstractmethod
def render_preview(self, obj_path: str, material: RenderMaterial,
camera: RenderCamera, settings: RenderSettings) -> np.ndarray: ...
@abstractmethod
def name(self) -> str: ...
```
Switching backends later = write a new class implementing `RenderBackend`. One import change.
---
## Mitsuba 3 Backend
### Why Mitsuba
| Feature | Status |
|---------|--------|
| `pip install mitsuba` | Single install, no system deps |
| True path tracing | GI, caustics, spectral rendering |
| PBR materials | `roughconductor`, `roughdielectric`, `diffuse`, `plastic` |
| Python dict API | Build scenes programmatically, no XML |
| CPU + GPU backends | `scalar_rgb` (CPU), `cuda_rgb` (NVIDIA) |
| Output formats | PNG, EXR (HDR) with tonemapping |
### OCC → OBJ Conversion Path
```python
from OCP.BRepMesh import BRepMesh_IncrementalMesh
from OCP.StlAPI import StlAPI_Writer
from OCP.BRep import BRep_Builder
import tempfile, os
def occ_shape_to_obj(shape, obj_path: str, linear_deflection: float = 0.1):
"""Tessellate OCC shape and write as OBJ for Mitsuba."""
tess = BRepMesh_IncrementalMesh(shape, linear_deflection, False, 0.5, True)
tess.Perform()
# Write STL (reliable), then convert to OBJ via trimesh or direct
writer = StlAPI_Writer()
writer.SetASCIIMode(False)
stl_path = obj_path.replace(".obj", ".stl")
writer.Write(shape, stl_path)
# Mitsuba can read STL directly, or we convert to OBJ
return stl_path
```
### Mitsuba Scene Construction
```python
import mitsuba as mi
mi.set_variant("scalar_rgb")
def build_scene(mesh_path: str, material: RenderMaterial,
camera: RenderCamera, settings: RenderSettings) -> mi.Scene:
# Map our material to Mitsuba BSDF
bsdf_map = {
"diffuse": {"type": "diffuse", "reflectance": {"type": "rgb", "value": material.color}},
"roughconductor": {
"type": "roughconductor",
"material": "copper", # or铝, 钢, etc.
"alpha": material.roughness,
},
"roughdielectric": {
"type": "roughdielectric",
"int_ior": 1.5,
"alpha": material.roughness,
},
"plastic": {
"type": "plastic",
"diffuse_reflectance": {"type": "rgb", "value": material.color},
"int_ior": 1.5,
},
}
return mi.load_dict({
"type": "scene",
"integrator": {"type": "path", "max_depth": settings.max_depth},
"sensor": {
"type": "perspective",
"fov": camera.fov,
"to_world": mi.ScalarTransform4f.look_at(
origin=camera.origin, target=camera.target, up=camera.up
),
"film": {"type": "hdrfilm", "width": settings.width, "height": settings.height},
"sampler": {"type": "independent", "sample_count": settings.spp},
},
"emitter": {"type": "constant"},
"shape": {
"type": "stl", # or "obj"
"filename": mesh_path,
"bsdf": bsdf_map.get(material.bsdf_type, bsdf_map["diffuse"]),
},
})
```
---
## Files to Create/Modify
| File | Action | Description |
|------|--------|-------------|
| `src/fluency/rendering/render_backend.py` | **NEW** | Abstract `RenderBackend`, `RenderMaterial`, `RenderCamera`, `RenderSettings` |
| `src/fluency/rendering/mitsuba_backend.py` | **NEW** | `MitsubaBackend(RenderBackend)` implementation |
| `src/fluency/rendering/occ_to_mesh.py` | **NEW** | OCC `TopoDS_Shape` → STL/OBJ tessellation |
| `src/fluency/rendering/material_presets.py` | **NEW** | Preset library: Steel, Aluminum, Brass, Chrome, Plastic, Rubber, Wood |
| `src/fluency/ui/render_window.py` | **NEW** | `RenderWindow(QMainWindow)` — image preview, material/quality controls, render/export |
| `src/fluency/ui/main_window.py` | MODIFY | Add "Render" button → get selected shapes → open `RenderWindow` |
---
## UI: RenderWindow
```
┌──────────────────────────────────────────┐
│ Render — [Part Name] [─][□][×] │
├──────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────┐ │
│ │ │ │
│ │ Rendered Image Preview │ │
│ │ (QLabel with QPixmap) │ │
│ │ │ │
│ └──────────────────────────────────┘ │
│ │
│ Material: [Steel ▾] │
│ Quality: [256 SPP ▾] │
│ Resolution: [1920×1080 ▾] │
│ │
│ [▶ Render] [⏹ Cancel] [💾 Export PNG] │
│ │
│ ████████████████░░░░░░ 65% (23s left) │
└──────────────────────────────────────────┘
```
- **Preview**: progressive refinement (low SPP first, then ramp)
- **Cancel**: kill Mitsuba render thread
- **Export**: save to PNG/EXR
---
## Material Presets
| Preset | Color | Metallic | Roughness | BSDF |
|--------|-------|----------|-----------|------|
| Brushed Steel | (0.65, 0.67, 0.72) | 0.9 | 0.35 | roughconductor |
| Polished Chrome | (0.8, 0.8, 0.8) | 1.0 | 0.05 | roughconductor |
| Brushed Aluminum | (0.75, 0.75, 0.75) | 0.85 | 0.25 | roughconductor |
| Copper | (0.95, 0.64, 0.54) | 0.95 | 0.15 | roughconductor |
| Gold | (1.0, 0.76, 0.33) | 1.0 | 0.1 | roughconductor |
| Blackened Steel | (0.15, 0.15, 0.17) | 0.8 | 0.4 | roughconductor |
| Matte Plastic | (0.2, 0.5, 0.8) | 0.0 | 0.6 | plastic |
| Glossy Plastic | (0.2, 0.5, 0.8) | 0.0 | 0.1 | plastic |
| White Nylon | (0.85, 0.85, 0.83) | 0.0 | 0.45 | plastic |
| Black ABS | (0.05, 0.05, 0.05) | 0.0 | 0.35 | plastic |
| Red PA12 | (0.75, 0.08, 0.08) | 0.0 | 0.4 | plastic |
| Rubber | (0.1, 0.1, 0.1) | 0.0 | 0.9 | diffuse |
| Ceramic White | (0.92, 0.91, 0.88) | 0.0 | 0.15 | dielectric |
| Glass | (0.95, 0.95, 0.95) | 0.0 | 0.0 | dielectric |
| Wood | (0.6, 0.4, 0.2) | 0.0 | 0.7 | diffuse |
**Note:** Mitsuba pip installs don't include spectral metal data files (iron.spd, copper.spd, etc.), so metal presets use `material="none"` with `specular_reflectance` set to the metal color instead.
---
## Risks & Mitigations
| Risk | Mitigation |
|------|-----------|
| Mitsuba not installed | Graceful error: "pip install mitsuba" shown in UI |
| Slow CPU rendering | Default to low SPP (64) for preview; offer GPU variant if CUDA available |
| Large meshes slow to tessellate | Progress indicator; optional mesh decimation |
| Mitsuba STL/OCC compatibility | Test tessellation quality; tune `linear_deflection` |
---
## Estimated Effort
- **Phase 1** (abstract backend + OCC→mesh + Mitsuba impl): ~4-6 hours
- **Phase 2** (render window UI + material presets): ~3-4 hours
- **Phase 3** (polish, export, swap test): ~2-3 hours
- **Total**: ~9-13 hours
Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

-1378
View File
File diff suppressed because it is too large Load Diff
-906
View File
@@ -1,906 +0,0 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'gui.ui'
##
## Created by: Qt User Interface Compiler version 6.10.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QCursor, QFont, QFontDatabase, QGradient,
QIcon, QImage, QKeySequence, QLinearGradient,
QPainter, QPalette, QPixmap, QRadialGradient,
QTransform)
from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QGroupBox,
QHBoxLayout, QLabel, QListWidget, QListWidgetItem,
QMainWindow, QMenu, QMenuBar, QPushButton,
QSizePolicy, QSpinBox, QStatusBar, QTabWidget,
QTextEdit, QVBoxLayout, QWidget)
class Ui_fluencyCAD(object):
def setupUi(self, fluencyCAD):
if not fluencyCAD.objectName():
fluencyCAD.setObjectName(u"fluencyCAD")
fluencyCAD.resize(2359, 1285)
self.actionNew_Project = QAction(fluencyCAD)
self.actionNew_Project.setObjectName(u"actionNew_Project")
self.actionOpen_Project = QAction(fluencyCAD)
self.actionOpen_Project.setObjectName(u"actionOpen_Project")
self.actionSave_Project = QAction(fluencyCAD)
self.actionSave_Project.setObjectName(u"actionSave_Project")
self.actionSave_Project_As = QAction(fluencyCAD)
self.actionSave_Project_As.setObjectName(u"actionSave_Project_As")
self.actionImport_File = QAction(fluencyCAD)
self.actionImport_File.setObjectName(u"actionImport_File")
self.actionExport_Step = QAction(fluencyCAD)
self.actionExport_Step.setObjectName(u"actionExport_Step")
self.actionExport_Iges = QAction(fluencyCAD)
self.actionExport_Iges.setObjectName(u"actionExport_Iges")
self.actionExport_Stl = QAction(fluencyCAD)
self.actionExport_Stl.setObjectName(u"actionExport_Stl")
self.actionExit = QAction(fluencyCAD)
self.actionExit.setObjectName(u"actionExit")
self.centralwidget = QWidget(fluencyCAD)
self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout = QGridLayout(self.centralwidget)
self.gridLayout.setObjectName(u"gridLayout")
self.InputTab = QTabWidget(self.centralwidget)
self.InputTab.setObjectName(u"InputTab")
sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.InputTab.sizePolicy().hasHeightForWidth())
self.InputTab.setSizePolicy(sizePolicy)
self.sketch_tab = QWidget()
self.sketch_tab.setObjectName(u"sketch_tab")
self.verticalLayout_4 = QVBoxLayout(self.sketch_tab)
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
self.InputTab.addTab(self.sketch_tab, "")
self.code_tab = QWidget()
self.code_tab.setObjectName(u"code_tab")
self.verticalLayout = QVBoxLayout(self.code_tab)
self.verticalLayout.setObjectName(u"verticalLayout")
self.textEdit = QTextEdit(self.code_tab)
self.textEdit.setObjectName(u"textEdit")
self.verticalLayout.addWidget(self.textEdit)
self.groupBox_7 = QGroupBox(self.code_tab)
self.groupBox_7.setObjectName(u"groupBox_7")
self.gridLayout_5 = QGridLayout(self.groupBox_7)
self.gridLayout_5.setObjectName(u"gridLayout_5")
self.pushButton_5 = QPushButton(self.groupBox_7)
self.pushButton_5.setObjectName(u"pushButton_5")
self.gridLayout_5.addWidget(self.pushButton_5, 2, 0, 1, 1)
self.pushButton_4 = QPushButton(self.groupBox_7)
self.pushButton_4.setObjectName(u"pushButton_4")
self.gridLayout_5.addWidget(self.pushButton_4, 2, 1, 1, 1)
self.pb_apply_code = QPushButton(self.groupBox_7)
self.pb_apply_code.setObjectName(u"pb_apply_code")
self.gridLayout_5.addWidget(self.pb_apply_code, 1, 0, 1, 1)
self.pushButton = QPushButton(self.groupBox_7)
self.pushButton.setObjectName(u"pushButton")
self.gridLayout_5.addWidget(self.pushButton, 1, 1, 1, 1)
self.verticalLayout.addWidget(self.groupBox_7)
self.InputTab.addTab(self.code_tab, "")
self.gridLayout.addWidget(self.InputTab, 0, 1, 12, 1)
self.groupBox_9 = QGroupBox(self.centralwidget)
self.groupBox_9.setObjectName(u"groupBox_9")
self.groupBox_9.setMaximumSize(QSize(200, 16777215))
self.gridLayout_7 = QGridLayout(self.groupBox_9)
self.gridLayout_7.setObjectName(u"gridLayout_7")
self.pb_origin_wp = QPushButton(self.groupBox_9)
self.pb_origin_wp.setObjectName(u"pb_origin_wp")
self.gridLayout_7.addWidget(self.pb_origin_wp, 0, 0, 1, 1)
self.pb_origin_face = QPushButton(self.groupBox_9)
self.pb_origin_face.setObjectName(u"pb_origin_face")
self.pb_origin_face.setCheckable(True)
self.gridLayout_7.addWidget(self.pb_origin_face, 0, 1, 1, 1)
self.pb_flip_face = QPushButton(self.groupBox_9)
self.pb_flip_face.setObjectName(u"pb_flip_face")
self.gridLayout_7.addWidget(self.pb_flip_face, 1, 0, 1, 1)
self.pb_underlay = QPushButton(self.groupBox_9)
self.pb_underlay.setObjectName(u"pb_underlay")
self.pb_underlay.setEnabled(False)
self.pb_underlay.setCheckable(True)
self.pb_underlay.setChecked(True)
self.gridLayout_7.addWidget(self.pb_underlay, 3, 0, 1, 1)
self.pb_clr_face = QPushButton(self.groupBox_9)
self.pb_clr_face.setObjectName(u"pb_clr_face")
self.pb_clr_face.setEnabled(False)
self.gridLayout_7.addWidget(self.pb_clr_face, 3, 1, 1, 1)
self.pb_to_sketch = QPushButton(self.groupBox_9)
self.pb_to_sketch.setObjectName(u"pb_to_sketch")
self.pb_to_sketch.setEnabled(False)
self.gridLayout_7.addWidget(self.pb_to_sketch, 4, 0, 1, 2)
self.pb_wp_new = QPushButton(self.groupBox_9)
self.pb_wp_new.setObjectName(u"pb_wp_new")
self.gridLayout_7.addWidget(self.pb_wp_new, 1, 1, 1, 1)
self.gridLayout.addWidget(self.groupBox_9, 0, 0, 1, 1)
self.assembly_box = QGroupBox(self.centralwidget)
self.assembly_box.setObjectName(u"assembly_box")
self.assembly_box.setMinimumSize(QSize(0, 50))
self.gridLayout.addWidget(self.assembly_box, 13, 1, 1, 2)
self.joint_tools = QGroupBox(self.centralwidget)
self.joint_tools.setObjectName(u"joint_tools")
self.joint_tools.setMinimumSize(QSize(0, 50))
self.gridLayout_10 = QGridLayout(self.joint_tools)
self.gridLayout_10.setObjectName(u"gridLayout_10")
self.pb_remove_connector = QPushButton(self.joint_tools)
self.pb_remove_connector.setObjectName(u"pb_remove_connector")
self.pb_remove_connector.setMinimumSize(QSize(50, 50))
self.pb_remove_connector.setMaximumSize(QSize(50, 50))
self.gridLayout_10.addWidget(self.pb_remove_connector, 0, 2, 1, 1)
self.pb_add_connector = QPushButton(self.joint_tools)
self.pb_add_connector.setObjectName(u"pb_add_connector")
self.pb_add_connector.setMinimumSize(QSize(50, 50))
self.pb_add_connector.setMaximumSize(QSize(50, 50))
self.gridLayout_10.addWidget(self.pb_add_connector, 0, 1, 1, 1)
self.pb_add_connector_2 = QPushButton(self.joint_tools)
self.pb_add_connector_2.setObjectName(u"pb_add_connector_2")
self.pb_add_connector_2.setMinimumSize(QSize(50, 50))
self.pb_add_connector_2.setMaximumSize(QSize(50, 50))
self.gridLayout_10.addWidget(self.pb_add_connector_2, 1, 1, 1, 1)
self.pb_add_connector_3 = QPushButton(self.joint_tools)
self.pb_add_connector_3.setObjectName(u"pb_add_connector_3")
self.pb_add_connector_3.setMinimumSize(QSize(50, 50))
self.pb_add_connector_3.setMaximumSize(QSize(50, 50))
self.gridLayout_10.addWidget(self.pb_add_connector_3, 1, 2, 1, 1)
self.gridLayout.addWidget(self.joint_tools, 12, 3, 2, 1)
self.gl_box = QGroupBox(self.centralwidget)
self.gl_box.setObjectName(u"gl_box")
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(4)
sizePolicy1.setHeightForWidth(self.gl_box.sizePolicy().hasHeightForWidth())
self.gl_box.setSizePolicy(sizePolicy1)
font = QFont()
font.setPointSize(12)
self.gl_box.setFont(font)
self.horizontalLayout_4 = QHBoxLayout(self.gl_box)
#ifndef Q_OS_MAC
self.horizontalLayout_4.setSpacing(-1)
#endif
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
self.horizontalLayout_4.setContentsMargins(12, -1, -1, -1)
self.gridLayout.addWidget(self.gl_box, 0, 2, 12, 1)
self.groupBox_11 = QGroupBox(self.centralwidget)
self.groupBox_11.setObjectName(u"groupBox_11")
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.groupBox_11.sizePolicy().hasHeightForWidth())
self.groupBox_11.setSizePolicy(sizePolicy2)
self.groupBox_11.setMaximumSize(QSize(200, 16777215))
self.verticalLayout_7 = QVBoxLayout(self.groupBox_11)
self.verticalLayout_7.setObjectName(u"verticalLayout_7")
self.verticalLayout_7.setContentsMargins(5, 5, 5, 5)
self.sketch_list = QListWidget(self.groupBox_11)
self.sketch_list.setObjectName(u"sketch_list")
sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
sizePolicy3.setHorizontalStretch(0)
sizePolicy3.setVerticalStretch(0)
sizePolicy3.setHeightForWidth(self.sketch_list.sizePolicy().hasHeightForWidth())
self.sketch_list.setSizePolicy(sizePolicy3)
self.sketch_list.setSelectionRectVisible(True)
self.verticalLayout_7.addWidget(self.sketch_list)
self.groupBox_6 = QGroupBox(self.groupBox_11)
self.groupBox_6.setObjectName(u"groupBox_6")
sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
sizePolicy4.setHorizontalStretch(0)
sizePolicy4.setVerticalStretch(0)
sizePolicy4.setHeightForWidth(self.groupBox_6.sizePolicy().hasHeightForWidth())
self.groupBox_6.setSizePolicy(sizePolicy4)
self.gridLayout_6 = QGridLayout(self.groupBox_6)
self.gridLayout_6.setObjectName(u"gridLayout_6")
self.gridLayout_6.setContentsMargins(2, 2, 2, 2)
self.pb_edt_sktch = QPushButton(self.groupBox_6)
self.pb_edt_sktch.setObjectName(u"pb_edt_sktch")
self.gridLayout_6.addWidget(self.pb_edt_sktch, 1, 1, 1, 1)
self.pb_nw_sktch = QPushButton(self.groupBox_6)
self.pb_nw_sktch.setObjectName(u"pb_nw_sktch")
self.gridLayout_6.addWidget(self.pb_nw_sktch, 1, 0, 1, 1)
self.pb_del_sketch = QPushButton(self.groupBox_6)
self.pb_del_sketch.setObjectName(u"pb_del_sketch")
self.gridLayout_6.addWidget(self.pb_del_sketch, 1, 2, 1, 1)
self.verticalLayout_7.addWidget(self.groupBox_6)
self.gridLayout.addWidget(self.groupBox_11, 6, 0, 6, 1)
self.assembly_tools = QGroupBox(self.centralwidget)
self.assembly_tools.setObjectName(u"assembly_tools")
self.assembly_tools.setMinimumSize(QSize(0, 50))
self.gridLayout_12 = QGridLayout(self.assembly_tools)
self.gridLayout_12.setObjectName(u"gridLayout_12")
self.pb_compo_to_assembly = QPushButton(self.assembly_tools)
self.pb_compo_to_assembly.setObjectName(u"pb_compo_to_assembly")
self.pb_compo_to_assembly.setMinimumSize(QSize(50, 50))
self.pb_compo_to_assembly.setMaximumSize(QSize(50, 50))
self.gridLayout_12.addWidget(self.pb_compo_to_assembly, 0, 0, 1, 1)
self.pb_remove_compo_from_assembly = QPushButton(self.assembly_tools)
self.pb_remove_compo_from_assembly.setObjectName(u"pb_remove_compo_from_assembly")
self.pb_remove_compo_from_assembly.setEnabled(True)
sizePolicy4.setHeightForWidth(self.pb_remove_compo_from_assembly.sizePolicy().hasHeightForWidth())
self.pb_remove_compo_from_assembly.setSizePolicy(sizePolicy4)
self.pb_remove_compo_from_assembly.setMinimumSize(QSize(50, 50))
self.pb_remove_compo_from_assembly.setMaximumSize(QSize(50, 50))
self.pb_remove_compo_from_assembly.setLayoutDirection(Qt.LeftToRight)
self.gridLayout_12.addWidget(self.pb_remove_compo_from_assembly, 0, 1, 1, 1)
self.gridLayout.addWidget(self.assembly_tools, 13, 0, 1, 1)
self.compo_tool_box = QGroupBox(self.centralwidget)
self.compo_tool_box.setObjectName(u"compo_tool_box")
self.compo_tool_box.setMinimumSize(QSize(0, 50))
self.gridLayout_9 = QGridLayout(self.compo_tool_box)
self.gridLayout_9.setObjectName(u"gridLayout_9")
self.pb_new_compo = QPushButton(self.compo_tool_box)
self.pb_new_compo.setObjectName(u"pb_new_compo")
self.pb_new_compo.setMinimumSize(QSize(50, 50))
self.pb_new_compo.setMaximumSize(QSize(50, 50))
self.gridLayout_9.addWidget(self.pb_new_compo, 0, 0, 1, 1)
self.pb_del_compo = QPushButton(self.compo_tool_box)
self.pb_del_compo.setObjectName(u"pb_del_compo")
self.pb_del_compo.setEnabled(True)
sizePolicy4.setHeightForWidth(self.pb_del_compo.sizePolicy().hasHeightForWidth())
self.pb_del_compo.setSizePolicy(sizePolicy4)
self.pb_del_compo.setMinimumSize(QSize(50, 50))
self.pb_del_compo.setMaximumSize(QSize(50, 50))
self.pb_del_compo.setLayoutDirection(Qt.LeftToRight)
self.gridLayout_9.addWidget(self.pb_del_compo, 0, 1, 1, 1)
self.gridLayout.addWidget(self.compo_tool_box, 12, 0, 1, 1)
self.compo_box = QGroupBox(self.centralwidget)
self.compo_box.setObjectName(u"compo_box")
self.compo_box.setMinimumSize(QSize(0, 50))
self.gridLayout.addWidget(self.compo_box, 12, 1, 1, 2)
self.groupBox_12 = QGroupBox(self.centralwidget)
self.groupBox_12.setObjectName(u"groupBox_12")
sizePolicy2.setHeightForWidth(self.groupBox_12.sizePolicy().hasHeightForWidth())
self.groupBox_12.setSizePolicy(sizePolicy2)
self.groupBox_12.setMaximumSize(QSize(200, 16777215))
self.verticalLayout_8 = QVBoxLayout(self.groupBox_12)
self.verticalLayout_8.setObjectName(u"verticalLayout_8")
self.verticalLayout_8.setContentsMargins(5, 5, 5, 5)
self.connection_list = QListWidget(self.groupBox_12)
self.connection_list.setObjectName(u"connection_list")
self.connection_list.setSelectionRectVisible(True)
self.verticalLayout_8.addWidget(self.connection_list)
self.groupBox_13 = QGroupBox(self.groupBox_12)
self.groupBox_13.setObjectName(u"groupBox_13")
sizePolicy4.setHeightForWidth(self.groupBox_13.sizePolicy().hasHeightForWidth())
self.groupBox_13.setSizePolicy(sizePolicy4)
self.groupBox_13.setMaximumSize(QSize(200, 16777215))
self.gridLayout_13 = QGridLayout(self.groupBox_13)
self.gridLayout_13.setObjectName(u"gridLayout_13")
self.gridLayout_13.setContentsMargins(2, 2, 2, 2)
self.pb_del_connection = QPushButton(self.groupBox_13)
self.pb_del_connection.setObjectName(u"pb_del_connection")
self.gridLayout_13.addWidget(self.pb_del_connection, 0, 2, 1, 1)
self.pb_update_connection = QPushButton(self.groupBox_13)
self.pb_update_connection.setObjectName(u"pb_update_connection")
self.gridLayout_13.addWidget(self.pb_update_connection, 0, 0, 1, 1)
self.pb_edt_sktch_4 = QPushButton(self.groupBox_13)
self.pb_edt_sktch_4.setObjectName(u"pb_edt_sktch_4")
self.gridLayout_13.addWidget(self.pb_edt_sktch_4, 0, 1, 1, 1)
self.verticalLayout_8.addWidget(self.groupBox_13)
self.gridLayout.addWidget(self.groupBox_12, 6, 3, 6, 1)
self.groupBox_10 = QGroupBox(self.centralwidget)
self.groupBox_10.setObjectName(u"groupBox_10")
sizePolicy2.setHeightForWidth(self.groupBox_10.sizePolicy().hasHeightForWidth())
self.groupBox_10.setSizePolicy(sizePolicy2)
self.groupBox_10.setMaximumSize(QSize(200, 16777215))
self.verticalLayout_6 = QVBoxLayout(self.groupBox_10)
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
self.verticalLayout_6.setContentsMargins(5, 5, 5, 5)
self.body_list = QListWidget(self.groupBox_10)
self.body_list.setObjectName(u"body_list")
self.body_list.setSelectionRectVisible(True)
self.verticalLayout_6.addWidget(self.body_list)
self.groupBox_8 = QGroupBox(self.groupBox_10)
self.groupBox_8.setObjectName(u"groupBox_8")
sizePolicy4.setHeightForWidth(self.groupBox_8.sizePolicy().hasHeightForWidth())
self.groupBox_8.setSizePolicy(sizePolicy4)
self.groupBox_8.setMaximumSize(QSize(200, 16777215))
self.gridLayout_8 = QGridLayout(self.groupBox_8)
self.gridLayout_8.setObjectName(u"gridLayout_8")
self.gridLayout_8.setContentsMargins(2, 2, 2, 2)
self.pb_del_body = QPushButton(self.groupBox_8)
self.pb_del_body.setObjectName(u"pb_del_body")
self.gridLayout_8.addWidget(self.pb_del_body, 0, 2, 1, 1)
self.pb_update_body = QPushButton(self.groupBox_8)
self.pb_update_body.setObjectName(u"pb_update_body")
self.gridLayout_8.addWidget(self.pb_update_body, 0, 0, 1, 1)
self.pb_edt_sktch_3 = QPushButton(self.groupBox_8)
self.pb_edt_sktch_3.setObjectName(u"pb_edt_sktch_3")
self.gridLayout_8.addWidget(self.pb_edt_sktch_3, 0, 1, 1, 1)
self.verticalLayout_6.addWidget(self.groupBox_8)
self.gridLayout.addWidget(self.groupBox_10, 3, 3, 3, 1)
self.groupBox_2 = QGroupBox(self.centralwidget)
self.groupBox_2.setObjectName(u"groupBox_2")
sizePolicy4.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth())
self.groupBox_2.setSizePolicy(sizePolicy4)
self.groupBox_2.setMaximumSize(QSize(200, 16777215))
self.gridLayout_2 = QGridLayout(self.groupBox_2)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.gridLayout_2.setContentsMargins(10, -1, -1, -1)
self.pb_arc_tool = QPushButton(self.groupBox_2)
self.pb_arc_tool.setObjectName(u"pb_arc_tool")
self.pb_arc_tool.setCheckable(True)
self.gridLayout_2.addWidget(self.pb_arc_tool, 2, 0, 1, 1)
self.pb_rectool = QPushButton(self.groupBox_2)
self.pb_rectool.setObjectName(u"pb_rectool")
self.pb_rectool.setCheckable(True)
self.pb_rectool.setAutoExclusive(False)
self.gridLayout_2.addWidget(self.pb_rectool, 0, 1, 1, 1)
self.pb_circtool = QPushButton(self.groupBox_2)
self.pb_circtool.setObjectName(u"pb_circtool")
self.pb_circtool.setCheckable(True)
self.pb_circtool.setAutoExclusive(False)
self.gridLayout_2.addWidget(self.pb_circtool, 1, 0, 1, 1, Qt.AlignTop)
self.pb_enable_construct = QPushButton(self.groupBox_2)
self.pb_enable_construct.setObjectName(u"pb_enable_construct")
self.pb_enable_construct.setCheckable(True)
self.gridLayout_2.addWidget(self.pb_enable_construct, 4, 0, 1, 1)
self.pb_enable_snap = QPushButton(self.groupBox_2)
self.pb_enable_snap.setObjectName(u"pb_enable_snap")
self.pb_enable_snap.setIconSize(QSize(13, 16))
self.pb_enable_snap.setCheckable(True)
self.pb_enable_snap.setChecked(True)
self.gridLayout_2.addWidget(self.pb_enable_snap, 4, 1, 1, 1)
self.pb_linetool = QPushButton(self.groupBox_2)
self.pb_linetool.setObjectName(u"pb_linetool")
self.pb_linetool.setCheckable(True)
self.pb_linetool.setAutoExclusive(False)
self.gridLayout_2.addWidget(self.pb_linetool, 0, 0, 1, 1)
self.pb_slotool = QPushButton(self.groupBox_2)
self.pb_slotool.setObjectName(u"pb_slotool")
self.pb_slotool.setCheckable(True)
self.pb_slotool.setAutoExclusive(False)
self.gridLayout_2.addWidget(self.pb_slotool, 1, 1, 1, 1, Qt.AlignTop)
self.line = QFrame(self.groupBox_2)
self.line.setObjectName(u"line")
self.line.setFrameShape(QFrame.Shape.HLine)
self.line.setFrameShadow(QFrame.Shadow.Sunken)
self.gridLayout_2.addWidget(self.line, 3, 0, 1, 2)
self.pb_offset_tool = QPushButton(self.groupBox_2)
self.pb_offset_tool.setObjectName(u"pb_offset_tool")
self.gridLayout_2.addWidget(self.pb_offset_tool, 2, 1, 1, 1)
self.gridLayout.addWidget(self.groupBox_2, 1, 0, 1, 1)
self.groupBox_3 = QGroupBox(self.centralwidget)
self.groupBox_3.setObjectName(u"groupBox_3")
sizePolicy4.setHeightForWidth(self.groupBox_3.sizePolicy().hasHeightForWidth())
self.groupBox_3.setSizePolicy(sizePolicy4)
self.groupBox_3.setMaximumSize(QSize(200, 16777213))
self.gridLayout_4 = QGridLayout(self.groupBox_3)
self.gridLayout_4.setObjectName(u"gridLayout_4")
self.pb_con_ptpt = QPushButton(self.groupBox_3)
self.pb_con_ptpt.setObjectName(u"pb_con_ptpt")
self.pb_con_ptpt.setCheckable(True)
self.pb_con_ptpt.setAutoExclusive(False)
self.gridLayout_4.addWidget(self.pb_con_ptpt, 1, 0, 1, 1)
self.pb_con_vert = QPushButton(self.groupBox_3)
self.pb_con_vert.setObjectName(u"pb_con_vert")
self.pb_con_vert.setCheckable(True)
self.pb_con_vert.setAutoExclusive(False)
self.gridLayout_4.addWidget(self.pb_con_vert, 3, 1, 1, 1)
self.pb_con_sym = QPushButton(self.groupBox_3)
self.pb_con_sym.setObjectName(u"pb_con_sym")
self.pb_con_sym.setCheckable(True)
self.pb_con_sym.setAutoExclusive(False)
self.gridLayout_4.addWidget(self.pb_con_sym, 4, 1, 1, 1)
self.pb_con_mid = QPushButton(self.groupBox_3)
self.pb_con_mid.setObjectName(u"pb_con_mid")
self.pb_con_mid.setCheckable(True)
self.pb_con_mid.setAutoExclusive(False)
self.gridLayout_4.addWidget(self.pb_con_mid, 2, 0, 1, 1)
self.pb_con_line = QPushButton(self.groupBox_3)
self.pb_con_line.setObjectName(u"pb_con_line")
self.pb_con_line.setCheckable(True)
self.pb_con_line.setAutoExclusive(False)
self.gridLayout_4.addWidget(self.pb_con_line, 1, 1, 1, 1)
self.pb_con_horiz = QPushButton(self.groupBox_3)
self.pb_con_horiz.setObjectName(u"pb_con_horiz")
self.pb_con_horiz.setCheckable(True)
self.pb_con_horiz.setAutoExclusive(False)
self.gridLayout_4.addWidget(self.pb_con_horiz, 3, 0, 1, 1)
self.pb_con_dist = QPushButton(self.groupBox_3)
self.pb_con_dist.setObjectName(u"pb_con_dist")
self.pb_con_dist.setCheckable(True)
self.pb_con_dist.setAutoExclusive(False)
self.pb_con_dist.setAutoRepeatDelay(297)
self.gridLayout_4.addWidget(self.pb_con_dist, 4, 0, 1, 1)
self.pb_con_perp = QPushButton(self.groupBox_3)
self.pb_con_perp.setObjectName(u"pb_con_perp")
self.pb_con_perp.setCheckable(True)
self.pb_con_perp.setAutoExclusive(False)
self.gridLayout_4.addWidget(self.pb_con_perp, 2, 1, 1, 1)
self.pb_con_diameter = QPushButton(self.groupBox_3)
self.pb_con_diameter.setObjectName(u"pb_con_diameter")
self.gridLayout_4.addWidget(self.pb_con_diameter, 5, 0, 1, 1)
self.gridLayout.addWidget(self.groupBox_3, 2, 0, 1, 1)
self.groupBox_5 = QGroupBox(self.centralwidget)
self.groupBox_5.setObjectName(u"groupBox_5")
sizePolicy4.setHeightForWidth(self.groupBox_5.sizePolicy().hasHeightForWidth())
self.groupBox_5.setSizePolicy(sizePolicy4)
self.gridLayout_11 = QGridLayout(self.groupBox_5)
self.gridLayout_11.setObjectName(u"gridLayout_11")
self.gridLayout_11.setContentsMargins(12, 12, 12, 12)
self.label = QLabel(self.groupBox_5)
self.label.setObjectName(u"label")
self.gridLayout_11.addWidget(self.label, 5, 0, 1, 1)
self.pb_snap_vert = QPushButton(self.groupBox_5)
self.pb_snap_vert.setObjectName(u"pb_snap_vert")
self.pb_snap_vert.setCheckable(True)
self.pb_snap_vert.setAutoExclusive(False)
self.gridLayout_11.addWidget(self.pb_snap_vert, 2, 1, 1, 1)
self.line_2 = QFrame(self.groupBox_5)
self.line_2.setObjectName(u"line_2")
self.line_2.setFrameShape(QFrame.Shape.HLine)
self.line_2.setFrameShadow(QFrame.Shadow.Sunken)
self.gridLayout_11.addWidget(self.line_2, 4, 0, 1, 2)
self.label_2 = QLabel(self.groupBox_5)
self.label_2.setObjectName(u"label_2")
self.gridLayout_11.addWidget(self.label_2, 5, 1, 1, 1)
self.spinbox_snap_distance = QSpinBox(self.groupBox_5)
self.spinbox_snap_distance.setObjectName(u"spinbox_snap_distance")
self.spinbox_snap_distance.setMaximum(30)
self.spinbox_snap_distance.setValue(10)
self.gridLayout_11.addWidget(self.spinbox_snap_distance, 6, 0, 1, 1)
self.pushButton_7 = QPushButton(self.groupBox_5)
self.pushButton_7.setObjectName(u"pushButton_7")
self.pushButton_7.setCheckable(True)
self.pushButton_7.setAutoExclusive(False)
self.gridLayout_11.addWidget(self.pushButton_7, 3, 0, 1, 1)
self.pb_snap_horiz = QPushButton(self.groupBox_5)
self.pb_snap_horiz.setObjectName(u"pb_snap_horiz")
self.pb_snap_horiz.setCheckable(True)
self.pb_snap_horiz.setAutoExclusive(False)
self.gridLayout_11.addWidget(self.pb_snap_horiz, 2, 0, 1, 1)
self.spinbox_angle_steps = QSpinBox(self.groupBox_5)
self.spinbox_angle_steps.setObjectName(u"spinbox_angle_steps")
self.spinbox_angle_steps.setMaximum(180)
self.spinbox_angle_steps.setValue(15)
self.gridLayout_11.addWidget(self.spinbox_angle_steps, 6, 1, 1, 1)
self.pushButton_8 = QPushButton(self.groupBox_5)
self.pushButton_8.setObjectName(u"pushButton_8")
self.pushButton_8.setCheckable(True)
self.pushButton_8.setAutoExclusive(False)
self.gridLayout_11.addWidget(self.pushButton_8, 0, 0, 1, 1)
self.pb_snap_midp = QPushButton(self.groupBox_5)
self.pb_snap_midp.setObjectName(u"pb_snap_midp")
self.pb_snap_midp.setCheckable(True)
self.pb_snap_midp.setAutoExclusive(False)
self.gridLayout_11.addWidget(self.pb_snap_midp, 0, 1, 1, 1)
self.pb_snap_angle = QPushButton(self.groupBox_5)
self.pb_snap_angle.setObjectName(u"pb_snap_angle")
self.pb_snap_angle.setCheckable(True)
self.pb_snap_angle.setAutoExclusive(False)
self.gridLayout_11.addWidget(self.pb_snap_angle, 3, 1, 1, 1)
self.gridLayout.addWidget(self.groupBox_5, 3, 0, 1, 1)
self.groupBox = QGroupBox(self.centralwidget)
self.groupBox.setObjectName(u"groupBox")
self.gridLayout_3 = QGridLayout(self.groupBox)
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.pb_revop = QPushButton(self.groupBox)
self.pb_revop.setObjectName(u"pb_revop")
self.gridLayout_3.addWidget(self.pb_revop, 2, 1, 1, 1)
self.pb_extrdop = QPushButton(self.groupBox)
self.pb_extrdop.setObjectName(u"pb_extrdop")
self.gridLayout_3.addWidget(self.pb_extrdop, 0, 0, 1, 1)
self.pb_arrayop = QPushButton(self.groupBox)
self.pb_arrayop.setObjectName(u"pb_arrayop")
self.gridLayout_3.addWidget(self.pb_arrayop, 2, 0, 1, 1)
self.pb_cutop = QPushButton(self.groupBox)
self.pb_cutop.setObjectName(u"pb_cutop")
self.gridLayout_3.addWidget(self.pb_cutop, 0, 1, 1, 1)
self.pb_combop = QPushButton(self.groupBox)
self.pb_combop.setObjectName(u"pb_combop")
self.gridLayout_3.addWidget(self.pb_combop, 1, 0, 1, 1)
self.pb_moveop = QPushButton(self.groupBox)
self.pb_moveop.setObjectName(u"pb_moveop")
self.gridLayout_3.addWidget(self.pb_moveop, 1, 1, 1, 1)
self.gridLayout.addWidget(self.groupBox, 0, 3, 1, 1)
self.groupBox_4 = QGroupBox(self.centralwidget)
self.groupBox_4.setObjectName(u"groupBox_4")
self.verticalLayout_2 = QVBoxLayout(self.groupBox_4)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.pushButton_2 = QPushButton(self.groupBox_4)
self.pushButton_2.setObjectName(u"pushButton_2")
self.verticalLayout_2.addWidget(self.pushButton_2)
self.pb_export_step = QPushButton(self.groupBox_4)
self.pb_export_step.setObjectName(u"pb_export_step")
self.verticalLayout_2.addWidget(self.pb_export_step)
self.pb_export_iges = QPushButton(self.groupBox_4)
self.pb_export_iges.setObjectName(u"pb_export_iges")
self.verticalLayout_2.addWidget(self.pb_export_iges)
self.gridLayout.addWidget(self.groupBox_4, 2, 3, 1, 1)
fluencyCAD.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(fluencyCAD)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 2359, 24))
self.menuFile = QMenu(self.menubar)
self.menuFile.setObjectName(u"menuFile")
self.menuSettings = QMenu(self.menubar)
self.menuSettings.setObjectName(u"menuSettings")
fluencyCAD.setMenuBar(self.menubar)
self.statusbar = QStatusBar(fluencyCAD)
self.statusbar.setObjectName(u"statusbar")
fluencyCAD.setStatusBar(self.statusbar)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuSettings.menuAction())
self.menuFile.addAction(self.actionNew_Project)
self.menuFile.addAction(self.actionOpen_Project)
self.menuFile.addAction(self.actionSave_Project)
self.menuFile.addAction(self.actionSave_Project_As)
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionImport_File)
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionExport_Step)
self.menuFile.addAction(self.actionExport_Iges)
self.menuFile.addAction(self.actionExport_Stl)
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionExit)
self.retranslateUi(fluencyCAD)
self.InputTab.setCurrentIndex(0)
QMetaObject.connectSlotsByName(fluencyCAD)
# setupUi
def retranslateUi(self, fluencyCAD):
fluencyCAD.setWindowTitle(QCoreApplication.translate("fluencyCAD", u"fluencyCAD", None))
self.actionNew_Project.setText(QCoreApplication.translate("fluencyCAD", u"New Project", None))
#if QT_CONFIG(shortcut)
self.actionNew_Project.setShortcut(QCoreApplication.translate("fluencyCAD", u"Ctrl+N", None))
#endif // QT_CONFIG(shortcut)
self.actionOpen_Project.setText(QCoreApplication.translate("fluencyCAD", u"Open Project...", None))
#if QT_CONFIG(shortcut)
self.actionOpen_Project.setShortcut(QCoreApplication.translate("fluencyCAD", u"Ctrl+O", None))
#endif // QT_CONFIG(shortcut)
self.actionSave_Project.setText(QCoreApplication.translate("fluencyCAD", u"Save Project", None))
#if QT_CONFIG(shortcut)
self.actionSave_Project.setShortcut(QCoreApplication.translate("fluencyCAD", u"Ctrl+S", None))
#endif // QT_CONFIG(shortcut)
self.actionSave_Project_As.setText(QCoreApplication.translate("fluencyCAD", u"Save Project As...", None))
#if QT_CONFIG(shortcut)
self.actionSave_Project_As.setShortcut(QCoreApplication.translate("fluencyCAD", u"Ctrl+Shift+S", None))
#endif // QT_CONFIG(shortcut)
self.actionImport_File.setText(QCoreApplication.translate("fluencyCAD", u"Import STEP/IGES...", None))
self.actionExport_Step.setText(QCoreApplication.translate("fluencyCAD", u"Export STEP...", None))
self.actionExport_Iges.setText(QCoreApplication.translate("fluencyCAD", u"Export IGES...", None))
self.actionExport_Stl.setText(QCoreApplication.translate("fluencyCAD", u"Export STL...", None))
self.actionExit.setText(QCoreApplication.translate("fluencyCAD", u"Exit", None))
#if QT_CONFIG(shortcut)
self.actionExit.setShortcut(QCoreApplication.translate("fluencyCAD", u"Ctrl+Q", None))
#endif // QT_CONFIG(shortcut)
self.InputTab.setTabText(self.InputTab.indexOf(self.sketch_tab), QCoreApplication.translate("fluencyCAD", u"Sketch", None))
self.groupBox_7.setTitle(QCoreApplication.translate("fluencyCAD", u"Executive", None))
self.pushButton_5.setText(QCoreApplication.translate("fluencyCAD", u"Load Code", None))
self.pushButton_4.setText(QCoreApplication.translate("fluencyCAD", u"Save code", None))
self.pb_apply_code.setText(QCoreApplication.translate("fluencyCAD", u"Apply Code", None))
self.pushButton.setText(QCoreApplication.translate("fluencyCAD", u"Delete Code", None))
self.InputTab.setTabText(self.InputTab.indexOf(self.code_tab), QCoreApplication.translate("fluencyCAD", u"Code", None))
self.groupBox_9.setTitle(QCoreApplication.translate("fluencyCAD", u"Workplanes", None))
#if QT_CONFIG(tooltip)
self.pb_origin_wp.setToolTip(QCoreApplication.translate("fluencyCAD", u"<W>orking Plane at 0, 0, 0", None))
#endif // QT_CONFIG(tooltip)
self.pb_origin_wp.setText(QCoreApplication.translate("fluencyCAD", u"WP Origin", None))
#if QT_CONFIG(shortcut)
self.pb_origin_wp.setShortcut(QCoreApplication.translate("fluencyCAD", u"W", None))
#endif // QT_CONFIG(shortcut)
#if QT_CONFIG(tooltip)
self.pb_origin_face.setToolTip(QCoreApplication.translate("fluencyCAD", u"Working Plane >P<rojection at selected edges face", None))
#endif // QT_CONFIG(tooltip)
self.pb_origin_face.setText(QCoreApplication.translate("fluencyCAD", u" WP Face", None))
#if QT_CONFIG(shortcut)
self.pb_origin_face.setShortcut(QCoreApplication.translate("fluencyCAD", u"P", None))
#endif // QT_CONFIG(shortcut)
#if QT_CONFIG(tooltip)
self.pb_flip_face.setToolTip(QCoreApplication.translate("fluencyCAD", u"Flip >N<ormal of projected mesh.", None))
#endif // QT_CONFIG(tooltip)
self.pb_flip_face.setText(QCoreApplication.translate("fluencyCAD", u"WP Flip", None))
#if QT_CONFIG(shortcut)
self.pb_flip_face.setShortcut(QCoreApplication.translate("fluencyCAD", u"N", None))
#endif // QT_CONFIG(shortcut)
#if QT_CONFIG(tooltip)
self.pb_underlay.setToolTip(QCoreApplication.translate("fluencyCAD", u"Show / hide the construction lines projected from the source face", None))
#endif // QT_CONFIG(tooltip)
self.pb_underlay.setText(QCoreApplication.translate("fluencyCAD", u"Underlay", None))
#if QT_CONFIG(tooltip)
self.pb_clr_face.setToolTip(QCoreApplication.translate("fluencyCAD", u"Forget the picked source face (keep the workplane)", None))
#endif // QT_CONFIG(tooltip)
self.pb_clr_face.setText(QCoreApplication.translate("fluencyCAD", u"ClrFace", None))
#if QT_CONFIG(tooltip)
self.pb_to_sketch.setToolTip(QCoreApplication.translate("fluencyCAD", u"Convert projected construction lines into real sketch geometry", None))
#endif // QT_CONFIG(tooltip)
self.pb_to_sketch.setText(QCoreApplication.translate("fluencyCAD", u"ToSketch", None))
#if QT_CONFIG(tooltip)
self.pb_wp_new.setToolTip(QCoreApplication.translate("fluencyCAD", u"Create a new independent workplane (datum plane)", None))
#endif // QT_CONFIG(tooltip)
self.pb_wp_new.setText(QCoreApplication.translate("fluencyCAD", u"WP New", None))
#if QT_CONFIG(shortcut)
self.pb_wp_new.setShortcut(QCoreApplication.translate("fluencyCAD", u"Shift+W", None))
#endif // QT_CONFIG(shortcut)
self.assembly_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Assembly", None))
self.joint_tools.setTitle(QCoreApplication.translate("fluencyCAD", u"Joint Tools", None))
self.pb_remove_connector.setText(QCoreApplication.translate("fluencyCAD", u"- Cnct", None))
self.pb_add_connector.setText(QCoreApplication.translate("fluencyCAD", u"+ Cnct", None))
self.pb_add_connector_2.setText(QCoreApplication.translate("fluencyCAD", u"+Jnt", None))
self.pb_add_connector_3.setText(QCoreApplication.translate("fluencyCAD", u"-Jnt", None))
self.gl_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Model Viewer", None))
self.groupBox_11.setTitle(QCoreApplication.translate("fluencyCAD", u"Sketch", None))
self.groupBox_6.setTitle(QCoreApplication.translate("fluencyCAD", u"Tools", None))
self.pb_edt_sktch.setText(QCoreApplication.translate("fluencyCAD", u"Edt", None))
self.pb_nw_sktch.setText(QCoreApplication.translate("fluencyCAD", u"Add", None))
self.pb_del_sketch.setText(QCoreApplication.translate("fluencyCAD", u"Del", None))
self.assembly_tools.setTitle(QCoreApplication.translate("fluencyCAD", u"Assembly Tools", None))
self.pb_compo_to_assembly.setText(QCoreApplication.translate("fluencyCAD", u"Add", None))
self.pb_remove_compo_from_assembly.setText(QCoreApplication.translate("fluencyCAD", u"Rem", None))
self.compo_tool_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Component Tools", None))
self.pb_new_compo.setText(QCoreApplication.translate("fluencyCAD", u"New", None))
self.pb_del_compo.setText(QCoreApplication.translate("fluencyCAD", u"Del", None))
self.compo_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Components", None))
self.groupBox_12.setTitle(QCoreApplication.translate("fluencyCAD", u"Component Connections", None))
self.groupBox_13.setTitle(QCoreApplication.translate("fluencyCAD", u"Tools", None))
self.pb_del_connection.setText(QCoreApplication.translate("fluencyCAD", u"Del", None))
self.pb_update_connection.setText(QCoreApplication.translate("fluencyCAD", u"Upd", None))
self.pb_edt_sktch_4.setText(QCoreApplication.translate("fluencyCAD", u"Nothing", None))
self.groupBox_10.setTitle(QCoreApplication.translate("fluencyCAD", u"Bodys / Operations", None))
self.groupBox_8.setTitle(QCoreApplication.translate("fluencyCAD", u"Tools", None))
self.pb_del_body.setText(QCoreApplication.translate("fluencyCAD", u"Del", None))
self.pb_update_body.setText(QCoreApplication.translate("fluencyCAD", u"Upd", None))
self.pb_edt_sktch_3.setText(QCoreApplication.translate("fluencyCAD", u"Nothing", None))
self.groupBox_2.setTitle(QCoreApplication.translate("fluencyCAD", u"Drawing", None))
self.pb_arc_tool.setText(QCoreApplication.translate("fluencyCAD", u"Arc", None))
self.pb_rectool.setText(QCoreApplication.translate("fluencyCAD", u"Rctgl", None))
self.pb_circtool.setText(QCoreApplication.translate("fluencyCAD", u"Circle", None))
self.pb_enable_construct.setText(QCoreApplication.translate("fluencyCAD", u"Cstrct", None))
self.pb_enable_snap.setText(QCoreApplication.translate("fluencyCAD", u"Snap", None))
self.pb_linetool.setText(QCoreApplication.translate("fluencyCAD", u"Line", None))
#if QT_CONFIG(shortcut)
self.pb_linetool.setShortcut(QCoreApplication.translate("fluencyCAD", u"S", None))
#endif // QT_CONFIG(shortcut)
self.pb_slotool.setText(QCoreApplication.translate("fluencyCAD", u"Slot", None))
#if QT_CONFIG(tooltip)
self.pb_offset_tool.setToolTip(QCoreApplication.translate("fluencyCAD", u"Offset selected sketch face (duplicate + offset boundary)", None))
#endif // QT_CONFIG(tooltip)
self.pb_offset_tool.setText(QCoreApplication.translate("fluencyCAD", u"Offst", None))
self.groupBox_3.setTitle(QCoreApplication.translate("fluencyCAD", u"Constrain", None))
#if QT_CONFIG(tooltip)
self.pb_con_ptpt.setToolTip(QCoreApplication.translate("fluencyCAD", u"Poin to Point Constrain", None))
#endif // QT_CONFIG(tooltip)
self.pb_con_ptpt.setText(QCoreApplication.translate("fluencyCAD", u"Pt_Pt", None))
#if QT_CONFIG(tooltip)
self.pb_con_vert.setToolTip(QCoreApplication.translate("fluencyCAD", u"Vertical Constrain", None))
#endif // QT_CONFIG(tooltip)
self.pb_con_vert.setText(QCoreApplication.translate("fluencyCAD", u"Vert", None))
self.pb_con_sym.setText(QCoreApplication.translate("fluencyCAD", u"Symetrc", None))
#if QT_CONFIG(tooltip)
self.pb_con_mid.setToolTip(QCoreApplication.translate("fluencyCAD", u"Point to Middle Point Constrain", None))
#endif // QT_CONFIG(tooltip)
self.pb_con_mid.setText(QCoreApplication.translate("fluencyCAD", u"Pt_Mid_L", None))
#if QT_CONFIG(tooltip)
self.pb_con_line.setToolTip(QCoreApplication.translate("fluencyCAD", u"Point to Line Constrain", None))
#endif // QT_CONFIG(tooltip)
self.pb_con_line.setText(QCoreApplication.translate("fluencyCAD", u"Pt_Lne", None))
#if QT_CONFIG(tooltip)
self.pb_con_horiz.setToolTip(QCoreApplication.translate("fluencyCAD", u"Horizontal Constrain ", None))
#endif // QT_CONFIG(tooltip)
self.pb_con_horiz.setText(QCoreApplication.translate("fluencyCAD", u"Horiz", None))
#if QT_CONFIG(tooltip)
self.pb_con_dist.setToolTip(QCoreApplication.translate("fluencyCAD", u"Dimension of Line of Distance from Point to Line", None))
#endif // QT_CONFIG(tooltip)
self.pb_con_dist.setText(QCoreApplication.translate("fluencyCAD", u"Distnce", None))
#if QT_CONFIG(tooltip)
self.pb_con_perp.setToolTip(QCoreApplication.translate("fluencyCAD", u"Constrain Line perpendicular to another line.", None))
#endif // QT_CONFIG(tooltip)
self.pb_con_perp.setText(QCoreApplication.translate("fluencyCAD", u"Perp_Lne", None))
self.pb_con_diameter.setText(QCoreApplication.translate("fluencyCAD", u"Diameter", None))
self.groupBox_5.setTitle(QCoreApplication.translate("fluencyCAD", u"Snapping Points", None))
self.label.setText(QCoreApplication.translate("fluencyCAD", u"Snp Dst", None))
self.pb_snap_vert.setText(QCoreApplication.translate("fluencyCAD", u"Vert", None))
self.label_2.setText(QCoreApplication.translate("fluencyCAD", u"Angl Stps", None))
self.spinbox_snap_distance.setSuffix(QCoreApplication.translate("fluencyCAD", u"mm", None))
self.pushButton_7.setText(QCoreApplication.translate("fluencyCAD", u"Grid", None))
self.pb_snap_horiz.setText(QCoreApplication.translate("fluencyCAD", u"Horiz", None))
self.spinbox_angle_steps.setSuffix(QCoreApplication.translate("fluencyCAD", u"\u00b0", None))
self.pushButton_8.setText(QCoreApplication.translate("fluencyCAD", u"Pnt", None))
self.pb_snap_midp.setText(QCoreApplication.translate("fluencyCAD", u"MidP", None))
self.pb_snap_angle.setText(QCoreApplication.translate("fluencyCAD", u"Angles", None))
self.groupBox.setTitle(QCoreApplication.translate("fluencyCAD", u"Modify", None))
self.pb_revop.setText(QCoreApplication.translate("fluencyCAD", u"Rev", None))
self.pb_extrdop.setText(QCoreApplication.translate("fluencyCAD", u"Extrd", None))
self.pb_arrayop.setText(QCoreApplication.translate("fluencyCAD", u"Arry", None))
self.pb_cutop.setText(QCoreApplication.translate("fluencyCAD", u"Cut", None))
self.pb_combop.setText(QCoreApplication.translate("fluencyCAD", u"Comb", None))
self.pb_moveop.setText(QCoreApplication.translate("fluencyCAD", u"Mve", None))
self.groupBox_4.setTitle(QCoreApplication.translate("fluencyCAD", u"Export", None))
self.pushButton_2.setText(QCoreApplication.translate("fluencyCAD", u"STL", None))
self.pb_export_step.setText(QCoreApplication.translate("fluencyCAD", u"STEP", None))
self.pb_export_iges.setText(QCoreApplication.translate("fluencyCAD", u"IGES", None))
self.menuFile.setTitle(QCoreApplication.translate("fluencyCAD", u"File", None))
self.menuSettings.setTitle(QCoreApplication.translate("fluencyCAD", u"Settings", None))
# retranslateUi
-16
View File
@@ -1,16 +0,0 @@
Copyright (C) 2025 Thomas Herrmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-22
View File
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>main</string>
<key>CFBundleExecutable</key>
<string>main</string>
<key>CFBundleIdentifier</key>
<string>main</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>main</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More