feat: PyOpticL Layout export and STEP component preview#94
Open
beneaze wants to merge 12 commits into
Open
Conversation
When a component is created via STEP import in the Component Editor, the original STEP file is now copied into a step/ subfolder within the component's library folder and referenced in component.json. The path propagates through definitions_loader, ComponentFactory, canvas sync, type_registry serialization, and scene export so the PyOpticL exporter can locate the 3-D model. Also wires up the Export PyOpticL menu action in the main window. Co-authored-by: Cursor <cursoragent@cursor.com>
# Conflicts: # src/optiverse/ui/views/component_editor_dialog.py
Previously the export wrote a loose .py file plus STEP files but omitted the
per-model <name>.json descriptor that PyOpticL.utils.import_model requires,
so models failed to load in FreeCAD. The exporter now writes a folder shaped
like real PyOpticL Designs:
<export>/<export>.py
<export>/models/<stem>/<stem>.step
<export>/models/<stem>/<stem>.json (identity transforms)
Stems are sanitised so the script's import_model("<stem>") always matches
the on-disk filename. The file dialog now picks a directory, and the menu
label changes from "Export PyOpticL Script" to "Export PyOpticL Layout".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add act_export_pyopticl to MainWindow typed-attribute list - Add OCP.* and pyqtgraph.* to mypy ignore_missing_imports overrides - cast() the np.ndarray return in _rotation_from_gl_view to satisfy warn_return_any - Drop unused btn_export / btn_cancel locals in MissingStepWarningDialog - Wrap a few over-100-char lines in step_renderer / step_preview_dialog / pyopticl_exporter - Auto-fixes from `ruff --fix`: drop extraneous f-prefixes on literals, unused test imports, quote-style consistency Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
VIEW_FRONT is intentionally a rotation matrix that maps a Z-up model into pyqtgraph's camera frame for the "front" view (looking along -Y), per the inline comment in step_renderer. It is not the identity, and asserting it should be is wrong. Orthogonality and |det| = 1 are already covered by the remaining tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…cripts
- Resolve portable step_file_path (@component/..., @library/..., relative)
back to absolute paths before export; fall back to scanning library roots
by filename when the default resolution produces a non-existent path
- Use mesh class variable instead of shape() method for STEP-imported
components, matching PyOpticL v2's import_model convention
- Wire metric option through to set_measurement_system("metric")
- Add fix_relative_imports() call for robust FreeCAD macro execution
- Add beam_block -> Stop() interface mapping
- Generate primitive-geometry definitions for no-STEP components with
interfaces so beam path simulation still works
- Pre-compute beam splitter diagonal inside dim() instead of dim() * 1.414
- Add orientation note in generated JSON and script comments
- Show success dialog after export (consistent with other export formats)
- Change file dialog from directory picker to save-as for better UX
- Add diagnostic logging to export pipeline
- Update and expand test suite (36 tests)
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Execute the exported layout script from a moved folder with stub PyOpticL modules and assert import_model resolves the copied STEP and metadata under the relocated models directory. Co-Authored-By: Codex <noreply@openai.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PyOpticL/Designs/*folders:<name>.py+models/<stem>/<stem>.step+<stem>.json(identity transforms). Drops in directly to FreeCAD with the PyOpticL workbench. The script's only path reference isimport_model("<stem>", directory="models"), resolved relative to the script file, so the folder is portable.ComponentRecordand persisted to the library so it can be re-emitted at export time. A warning dialog lists any components without an attached STEP before export.cad/module with a STEP preview dialog and renderer used by the Component Editor.Addresses #85, #70, and #38.
Test plan
pytest tests/export tests/core- 225 tests pass (28 in pyopticl exporter, 3 new for the folder layout)uv run --extra dev pytest tests/core/test_component_registry.py tests/services/test_storage_service.py -quv run --extra dev pytest tests/export tests/core tests/services/test_storage_service.py tests/ui/test_component_editor.py::test_cancel_step_import_keeps_component_editor_open tests/ui/test_theme_stylesheets.py tests/ui/test_interface_tree_widget.py -quv run --extra dev pytest tests/export/test_pyopticl_exporter.py -quv run --extra dev ruff check src/optiverse/objects/definitions_loader.py src/optiverse/services/storage_service.py src/optiverse/ui/views/component_editor_dialog.py src/optiverse/ui/widgets/interface_widgets.py src/optiverse/ui/styles/light_theme.qss src/optiverse/ui/styles/dark_theme.qss src/optiverse/ui/theme_manager.py tests/core/test_component_registry.py tests/services/test_storage_service.py tests/ui/test_component_editor.py tests/ui/test_theme_stylesheets.py tests/ui/test_interface_tree_widget.pyimport_model(..., directory="models")resolves the relocatedmodels/<stem>/<stem>.stepand.jsonfiles, with no absolute source/export paths embedded in the script<name>.pyand run it; verify each model loads frommodels/<stem>/<stem>.step(no "Model info file not found" or "Model not found in directory" errors)Note: A FreeCAD.app is present locally, but its headless CLI/Python probes did not return reliably in this Codex environment, and PyOpticL workbench availability could not be confirmed. The FreeCAD runtime smoke therefore remains a manual reviewer check. The moved-folder behavior now has automated script-execution coverage without FreeCAD.
Generated with Claude Code and Codex.