Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a1361ecc58 |
Generated
+32
-10
@@ -4,16 +4,13 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="8f0bafd6-58a0-4b20-aa2b-ddc3ba278873" name="Changes" comment="- Render improvements, camera plane, update">
|
||||
<list default="true" id="8f0bafd6-58a0-4b20-aa2b-ddc3ba278873" name="Changes" comment="- added contrain context menu - improved line pickability.">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/gui.ui" beforeDir="false" afterPath="$PROJECT_DIR$/gui.ui" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/gui_ui.py" beforeDir="false" afterPath="$PROJECT_DIR$/gui_ui.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/fluency/geometry_occ/kernel.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/geometry_occ/kernel.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/fluency/models/data_model.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/models/data_model.py" 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/ui/dialogs.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/ui/dialogs.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" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -72,6 +69,7 @@
|
||||
"Python.side_fluency.executor": "Run",
|
||||
"Python.simple_mesh.executor": "Run",
|
||||
"Python.sketch.executor": "Run",
|
||||
"Python.surface_modifier.executor": "Run",
|
||||
"Python.vtk_widget.executor": "Run",
|
||||
"Python.vulkan.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
@@ -80,7 +78,7 @@
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||
"codeWithMe.voiceChat.enabledByDefault": "false",
|
||||
"git-widget-placeholder": "feature/occ-migration",
|
||||
"git-widget-placeholder": "feature/surface-modifier-pyramid-patterns",
|
||||
"last_opened_file_path": "/Volumes/Data_drive/Programming/fluency",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
@@ -442,7 +440,31 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1783976498520</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="41" />
|
||||
<task id="LOCAL-00041" summary="Improved render previews">
|
||||
<option name="closed" value="true" />
|
||||
<created>1784408804224</created>
|
||||
<option name="number" value="00041" />
|
||||
<option name="presentableId" value="LOCAL-00041" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1784408804224</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00042" summary="- added contrain context menu - improved line pickability.">
|
||||
<option name="closed" value="true" />
|
||||
<created>1784452692776</created>
|
||||
<option name="number" value="00042" />
|
||||
<option name="presentableId" value="LOCAL-00042" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1784452692776</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00043" summary="- added contrain context menu - improved line pickability.">
|
||||
<option name="closed" value="true" />
|
||||
<created>1784470032428</created>
|
||||
<option name="number" value="00043" />
|
||||
<option name="presentableId" value="LOCAL-00043" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1784470032428</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="44" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -463,8 +485,6 @@
|
||||
<ignored-roots>
|
||||
<path value="$PROJECT_DIR$/pythonProject" />
|
||||
</ignored-roots>
|
||||
<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 - Cut working - Edit sketch working" />
|
||||
@@ -488,6 +508,8 @@
|
||||
<MESSAGE value="- added renderer" />
|
||||
<MESSAGE value="- added renderer - Added undo" />
|
||||
<MESSAGE value="- Render improvements, camera plane, update" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="- Render improvements, camera plane, update" />
|
||||
<MESSAGE value="Improved render previews" />
|
||||
<MESSAGE value="- added contrain context menu - improved line pickability." />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="- added contrain context menu - improved line pickability." />
|
||||
</component>
|
||||
</project>
|
||||
@@ -501,6 +501,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QPushButton" name="pb_surface_mod">
|
||||
<property name="toolTip">
|
||||
<string>Apply surface modifier (pyramid pattern for grips)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SrfMod</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -1098,32 +1108,6 @@
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" rowspan="5">
|
||||
<widget class="QGroupBox" name="gl_box">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>4</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Model Viewer</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<widget class="QGroupBox" name="groupBox_12">
|
||||
<property name="sizePolicy">
|
||||
@@ -1312,6 +1296,32 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="5">
|
||||
<widget class="QGroupBox" name="gl_box">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>4</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Model Viewer</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
|
||||
@@ -289,6 +289,11 @@ class Ui_fluencyCAD(object):
|
||||
|
||||
self.gridLayout_3.addWidget(self.pb_moveop, 1, 1, 1, 1)
|
||||
|
||||
self.pb_surface_mod = QPushButton(self.groupBox)
|
||||
self.pb_surface_mod.setObjectName(u"pb_surface_mod")
|
||||
|
||||
self.gridLayout_3.addWidget(self.pb_surface_mod, 3, 0, 1, 1)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.groupBox, 0, 4, 1, 1)
|
||||
|
||||
@@ -601,25 +606,6 @@ class Ui_fluencyCAD(object):
|
||||
|
||||
self.gridLayout.addWidget(self.InputTab, 0, 1, 5, 1)
|
||||
|
||||
self.gl_box = QGroupBox(self.centralwidget)
|
||||
self.gl_box.setObjectName(u"gl_box")
|
||||
sizePolicy5 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||
sizePolicy5.setHorizontalStretch(0)
|
||||
sizePolicy5.setVerticalStretch(4)
|
||||
sizePolicy5.setHeightForWidth(self.gl_box.sizePolicy().hasHeightForWidth())
|
||||
self.gl_box.setSizePolicy(sizePolicy5)
|
||||
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, 3, 5, 1)
|
||||
|
||||
self.groupBox_12 = QGroupBox(self.centralwidget)
|
||||
self.groupBox_12.setObjectName(u"groupBox_12")
|
||||
sizePolicy2.setHeightForWidth(self.groupBox_12.sizePolicy().hasHeightForWidth())
|
||||
@@ -706,6 +692,25 @@ class Ui_fluencyCAD(object):
|
||||
|
||||
self.gridLayout.addWidget(self.groupBox_10, 3, 4, 1, 1)
|
||||
|
||||
self.gl_box = QGroupBox(self.centralwidget)
|
||||
self.gl_box.setObjectName(u"gl_box")
|
||||
sizePolicy5 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||
sizePolicy5.setHorizontalStretch(0)
|
||||
sizePolicy5.setVerticalStretch(4)
|
||||
sizePolicy5.setHeightForWidth(self.gl_box.sizePolicy().hasHeightForWidth())
|
||||
self.gl_box.setSizePolicy(sizePolicy5)
|
||||
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, 5, 1)
|
||||
|
||||
fluencyCAD.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QMenuBar(fluencyCAD)
|
||||
self.menubar.setObjectName(u"menubar")
|
||||
@@ -863,6 +868,10 @@ class Ui_fluencyCAD(object):
|
||||
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))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.pb_surface_mod.setToolTip(QCoreApplication.translate("fluencyCAD", u"Apply surface modifier (pyramid pattern for grips)", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.pb_surface_mod.setText(QCoreApplication.translate("fluencyCAD", u"SrfMod", None))
|
||||
self.compo_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Components", None))
|
||||
self.compo_tool_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Component Tools", None))
|
||||
self.pb_new_compo.setText(QCoreApplication.translate("fluencyCAD", u"New", None))
|
||||
@@ -902,7 +911,6 @@ class Ui_fluencyCAD(object):
|
||||
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.gl_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Model Viewer", 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))
|
||||
@@ -913,6 +921,7 @@ class Ui_fluencyCAD(object):
|
||||
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.gl_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Model Viewer", None))
|
||||
self.menuFile.setTitle(QCoreApplication.translate("fluencyCAD", u"File", None))
|
||||
self.menuSettings.setTitle(QCoreApplication.translate("fluencyCAD", u"Settings", None))
|
||||
# retranslateUi
|
||||
|
||||
@@ -780,3 +780,67 @@ class OCGeometryKernel(GeometryKernel):
|
||||
|
||||
cg = props.CentreOfMass()
|
||||
return Point3D(cg.X(), cg.Y(), cg.Z())
|
||||
|
||||
def apply_surface_modifier(
|
||||
self,
|
||||
body_geometry: GeometryObject,
|
||||
modifier_type: str = 'pyramid',
|
||||
height: float = 2.0,
|
||||
radius: float = 3.0,
|
||||
spacing: float = 8.0,
|
||||
num_rings: int = 3,
|
||||
) -> Optional[GeometryObject]:
|
||||
"""Apply a surface modifier to a body geometry.
|
||||
|
||||
Args:
|
||||
body_geometry: The OCCGeometryObject to modify
|
||||
modifier_type: Type of modifier ('pyramid', 'bump')
|
||||
height: Height/depth of the pattern features
|
||||
radius: Base radius of pattern features
|
||||
spacing: Distance between pattern features
|
||||
num_rings: Number of concentric rings
|
||||
|
||||
Returns:
|
||||
Modified geometry, or None on failure
|
||||
"""
|
||||
from fluency.geometry_occ.surface_modifier import SurfaceModifier
|
||||
|
||||
shape = self._get_shape(body_geometry)
|
||||
if shape is None:
|
||||
logger.error("No geometry found in body")
|
||||
return None
|
||||
|
||||
modifier = SurfaceModifier()
|
||||
|
||||
try:
|
||||
if modifier_type == 'pyramid':
|
||||
result_shape = modifier.apply_pyramid_pattern(
|
||||
shape,
|
||||
pyramid_height=height,
|
||||
base_radius=radius,
|
||||
spacing=spacing,
|
||||
num_rings=num_rings,
|
||||
direction=(0, 0, 1),
|
||||
)
|
||||
elif modifier_type == 'bump':
|
||||
result_shape = modifier.apply_bump_pattern(
|
||||
shape,
|
||||
bump_height=height,
|
||||
bump_radius=radius,
|
||||
spacing=spacing,
|
||||
num_rings=num_rings,
|
||||
)
|
||||
else:
|
||||
logger.error(f"Unknown modifier type: {modifier_type}")
|
||||
return None
|
||||
|
||||
if result_shape is None:
|
||||
logger.error("Surface modifier application failed")
|
||||
return None
|
||||
|
||||
# Return the modified shape wrapped in OCCGeometryObject
|
||||
return OCCGeometryObject(result_shape)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error applying surface modifier: {e}", exc_info=True)
|
||||
return None
|
||||
|
||||
@@ -4,16 +4,12 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import math
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Tuple
|
||||
|
||||
from PySide6.QtCore import Qt, QPoint, QPointF
|
||||
from PySide6.QtGui import QColor, QFont, QKeySequence
|
||||
from PySide6.QtWidgets import (
|
||||
QButtonGroup,
|
||||
QCheckBox,
|
||||
QComboBox,
|
||||
QDialog,
|
||||
QDialogButtonBox,
|
||||
QDoubleSpinBox,
|
||||
QFormLayout,
|
||||
QFrame,
|
||||
@@ -24,7 +20,6 @@ from PySide6.QtWidgets import (
|
||||
QPushButton,
|
||||
QRadioButton,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -265,6 +260,95 @@ class OffsetDialog(QDialog):
|
||||
return (self.distance_input.value(), self.inward_checkbox.isChecked())
|
||||
|
||||
|
||||
class SurfaceModifierDialog(QDialog):
|
||||
"""Dialog for surface modifier settings."""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Surface Modifier")
|
||||
self.setMinimumWidth(400)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Pattern type selection
|
||||
pattern_layout = QGridLayout()
|
||||
|
||||
self._pattern_group = QButtonGroup(self)
|
||||
patterns = [
|
||||
("Pyramid Pattern", "pyramid"),
|
||||
("Bump Pattern", "bump"),
|
||||
]
|
||||
for idx, (label, pattern_type) in enumerate(patterns):
|
||||
btn = QRadioButton(label)
|
||||
btn.setChecked(idx == 0)
|
||||
self._pattern_group.addButton(btn, idx)
|
||||
btn.pattern_type = pattern_type
|
||||
pattern_layout.addWidget(btn, 0, idx)
|
||||
layout.addLayout(pattern_layout)
|
||||
|
||||
# Parameters for pyramid/bump patterns
|
||||
param_layout = QFormLayout()
|
||||
|
||||
self.height_input = QDoubleSpinBox()
|
||||
self.height_input.setDecimals(2)
|
||||
self.height_input.setRange(0.1, 50.0)
|
||||
self.height_input.setValue(2.0)
|
||||
self.height_input.setSuffix(" mm")
|
||||
param_layout.addRow("Height:", self.height_input)
|
||||
|
||||
self.radius_input = QDoubleSpinBox()
|
||||
self.radius_input.setDecimals(2)
|
||||
self.radius_input.setRange(0.5, 20.0)
|
||||
self.radius_input.setValue(3.0)
|
||||
self.radius_input.setSuffix(" mm")
|
||||
param_layout.addRow("Base Radius:", self.radius_input)
|
||||
|
||||
self.spacing_input = QDoubleSpinBox()
|
||||
self.spacing_input.setDecimals(1)
|
||||
self.spacing_input.setRange(1.0, 50.0)
|
||||
self.spacing_input.setValue(8.0)
|
||||
self.spacing_input.setSuffix(" mm")
|
||||
param_layout.addRow("Spacing:", self.spacing_input)
|
||||
|
||||
layout.addLayout(param_layout)
|
||||
|
||||
# Number of rings
|
||||
self.rings_input = QSpinBox()
|
||||
self.rings_input.setMinimum(1)
|
||||
self.rings_input.setMaximum(20)
|
||||
self.rings_input.setValue(3)
|
||||
param_layout.addRow("Number of Rings:", self.rings_input)
|
||||
|
||||
line = QFrame()
|
||||
line.setFrameShape(QFrame.HLine)
|
||||
layout.addWidget(line)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
ok_button = QPushButton("Apply")
|
||||
ok_button.clicked.connect(self.accept)
|
||||
cancel_button = QPushButton("Cancel")
|
||||
cancel_button.clicked.connect(self.reject)
|
||||
button_layout.addWidget(ok_button)
|
||||
button_layout.addWidget(cancel_button)
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
def get_values(self) -> dict:
|
||||
"""Return the modifier settings."""
|
||||
pattern_type = None
|
||||
for btn in self._pattern_group.buttons():
|
||||
if btn.isChecked():
|
||||
pattern_type = getattr(btn, 'pattern_type', None)
|
||||
break
|
||||
|
||||
return {
|
||||
'type': pattern_type or 'pyramid',
|
||||
'height': self.height_input.value(),
|
||||
'radius': self.radius_input.value(),
|
||||
'spacing': self.spacing_input.value(),
|
||||
'num_rings': self.rings_input.value(),
|
||||
}
|
||||
|
||||
|
||||
class WorkplaneOrientationDialog(QDialog):
|
||||
"""Modal dialog to choose the orientation of a new workplane.
|
||||
|
||||
@@ -404,7 +488,6 @@ class WorkplaneOrientationDialog(QDialog):
|
||||
def _on_ok(self):
|
||||
"""Compute the final orientation and accept."""
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
if self._custom_radio.isChecked():
|
||||
# Custom: start from XY normal and rotate by the two angles.
|
||||
@@ -454,7 +537,6 @@ class WorkplaneOrientationDialog(QDialog):
|
||||
whether called before or after ``_on_ok``.
|
||||
"""
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
if self._custom_radio.isChecked():
|
||||
ax = math.radians(self._angle_x.value())
|
||||
|
||||
@@ -717,6 +717,8 @@ class MainWindow(QMainWindow):
|
||||
self._btn_move = ui.pb_moveop
|
||||
self._btn_revolve = ui.pb_revop
|
||||
self._btn_array = ui.pb_arrayop
|
||||
# ── Surface Modifier ──
|
||||
self._btn_surface_mod = ui.pb_surface_mod
|
||||
# ── Export ──
|
||||
self._btn_export_stl = ui.pushButton_2
|
||||
self._btn_export_step = ui.pb_export_step
|
||||
@@ -772,14 +774,14 @@ class MainWindow(QMainWindow):
|
||||
if panel == "viewer":
|
||||
# Viewer 2/3, sketch 1/3 — more room for 3D work, sketch stays visible.
|
||||
self._grid.setColumnStretch(1, 1)
|
||||
self._grid.setColumnStretch(2, 2)
|
||||
self._grid.setColumnStretch(3, 2)
|
||||
elif panel == "sketch":
|
||||
# Sketch 2/3, viewer 1/3 — comfortable sketching, 3D stays visible.
|
||||
self._grid.setColumnStretch(1, 2)
|
||||
self._grid.setColumnStretch(2, 1)
|
||||
self._grid.setColumnStretch(3, 1)
|
||||
else: # equal
|
||||
self._grid.setColumnStretch(1, 1)
|
||||
self._grid.setColumnStretch(2, 1)
|
||||
self._grid.setColumnStretch(3, 1)
|
||||
logger.info(f"Panel focus -> {self._panel_focus}")
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
@@ -832,6 +834,7 @@ class MainWindow(QMainWindow):
|
||||
self._btn_cut.clicked.connect(self._boolean_cut)
|
||||
self._btn_combine.clicked.connect(self._boolean_union)
|
||||
self._btn_revolve.clicked.connect(self._revolve_sketch)
|
||||
self._btn_surface_mod.clicked.connect(self._open_surface_modifier_dialog)
|
||||
|
||||
self._btn_add_sketch.clicked.connect(self._add_sketch_to_component)
|
||||
self._btn_edit_sketch.clicked.connect(self._edit_sketch)
|
||||
@@ -3994,6 +3997,56 @@ class MainWindow(QMainWindow):
|
||||
logger.exception(f"Boolean union failed: {e}")
|
||||
QMessageBox.critical(self, "Error", f"Boolean union failed: {e}")
|
||||
|
||||
def _open_surface_modifier_dialog(self):
|
||||
"""Open the surface modifier dialog and apply to selected body."""
|
||||
if not self._current_component or not self._selected_body:
|
||||
QMessageBox.warning(self, "No Selection", "Please select a body first")
|
||||
return
|
||||
|
||||
# Create and show the dialog
|
||||
dialog = SurfaceModifierDialog(self)
|
||||
accepted = dialog.exec()
|
||||
|
||||
if not accepted:
|
||||
logger.info("Surface modifier dialog cancelled")
|
||||
return
|
||||
|
||||
# Get the settings from the dialog
|
||||
settings = dialog.get_values()
|
||||
logger.info(f"Surface modifier settings: {settings}")
|
||||
|
||||
try:
|
||||
# Apply the surface modifier to the selected body
|
||||
result_geom = self._kernel.apply_surface_modifier(
|
||||
self._selected_body.geometry,
|
||||
**settings
|
||||
)
|
||||
|
||||
if result_geom is not None:
|
||||
# Update the body geometry
|
||||
self._selected_body.geometry = result_geom
|
||||
self._mark_dirty()
|
||||
|
||||
logger.debug("Adding shape to OCC viewer")
|
||||
shape = self._kernel._get_shape(result_geom)
|
||||
self._selected_body.render_object = self._viewer_3d.show_shape(
|
||||
shape, self._selected_body.color, self._selected_body.name
|
||||
)
|
||||
logger.info(f"Render object: {self._selected_body.render_object}")
|
||||
|
||||
self._refresh_lists()
|
||||
self._update_component_thumbnail(self._get_active_component_index())
|
||||
self._viewer_3d.fit_camera()
|
||||
logger.info("Surface modifier applied successfully")
|
||||
else:
|
||||
QMessageBox.warning(
|
||||
self, "Error", "Failed to apply surface modifier"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Surface modifier failed: {e}")
|
||||
QMessageBox.critical(self, "Error", f"Surface modifier failed: {e}")
|
||||
|
||||
def _delete_body(self):
|
||||
selected = self._body_list.currentItem()
|
||||
if not selected or not self._current_component:
|
||||
|
||||
Reference in New Issue
Block a user