Bring the Plotly canvas in line with opstool's visualisation recipes. Camera / interaction: - frame the camera in plotly's normalized scene units, using the model bounds (grid excluded); a data-unit eye rendered the model as a speck - use turntable dragmode so Z stays up and the horizon stays level - align mouse bindings with the PyVista/VTK backend and document them in Help → Mouse Controls Visualisation: - colour deformed / modal shapes by response with a shared colourbar - scale load arrows by |F|, tint per load pattern, hover the magnitude, and fix cones rendering as oversized fins (sizemode scaled, not absolute) - draw DOF-accurate support glyphs (ported from opstool; see NOTICE) - add an undeformed-reference overlay on both canvas backends - play mode shapes with plotly frame animation in-page Tests: builder unit tests plus GUI regression tests for gestures, the deformed push, the undeformed reference and animation payloads.
61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
"""Smoke tests for the undeformed-reference overlay on both backends."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
pytest.importorskip("PySide6")
|
|
|
|
from otko.core import ElasticBeamColumn, ElasticSection, Node, Project
|
|
|
|
|
|
def _frame_project() -> Project:
|
|
b, h = 0.30, 0.50
|
|
return Project(
|
|
nodes=[
|
|
Node(id=1, coords=(0.0, 0.0, 0.0), restraint=(True, True, True, True, True, True)),
|
|
Node(id=2, coords=(6.0, 0.0, 0.0)),
|
|
],
|
|
sections=[
|
|
ElasticSection(
|
|
id=1,
|
|
name="Rect",
|
|
E=200e9,
|
|
A=b * h,
|
|
Iz=b * h**3 / 12.0,
|
|
Iy=h * b**3 / 12.0,
|
|
G=80e9,
|
|
J=1e-6,
|
|
)
|
|
],
|
|
elements=[ElasticBeamColumn(id=1, nodes=(1, 2), section_id=1)],
|
|
)
|
|
|
|
|
|
@pytest.mark.gui
|
|
def test_pyvista_undeformed_reference_overlay(qtbot) -> None: # type: ignore[no-untyped-def]
|
|
from otko.services.deformation import DeformationSource
|
|
from otko.views.canvas3d.model_canvas import ModelCanvas
|
|
from otko.views.canvas3d.model_renderer import RendererMode
|
|
|
|
canvas = ModelCanvas()
|
|
qtbot.addWidget(canvas)
|
|
canvas.show_project(_frame_project())
|
|
|
|
# In MODEL mode there is nothing to reference — the toggle must be a no-op.
|
|
canvas.set_show_undeformed(True)
|
|
assert canvas._renderer._undeformed_actor is None
|
|
|
|
# A deformed shape gets a ghost wireframe, removed again on toggle off.
|
|
src = DeformationSource(
|
|
displacements=np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 0.5]]),
|
|
node_id_to_row={1: 0, 2: 1},
|
|
)
|
|
canvas._renderer.set_mode(RendererMode.DEFORMED, src)
|
|
canvas.render()
|
|
canvas.set_show_undeformed(True)
|
|
assert canvas._renderer._undeformed_actor is not None
|
|
|
|
canvas.set_show_undeformed(False)
|
|
assert canvas._renderer._undeformed_actor is None
|