Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VTK] optional interactive orientation widget #1635

Merged
merged 5 commits into from
Oct 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion examples/reference/panes/VTK.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@
" \n",
" The mouse must be over the pane to work\n",
" <br>**Warning**: These keybindings may not work as expected in a notebook context, if they interact with already bound keys\n",
"* **``orientation_widget``** (bool): A boolean to activate/deactivate the orientation widget in the 3D pane. This widget is clickable and allows to rotate the scene in one of the orthographic projections.\n",
"* **``orientation_widget``** (bool): A boolean to activate/deactivate the orientation widget in the 3D pane.\n",
"* **``ìnteractive_orientation_widget``** (bool): If True the orientation widget is clickable and allows to rotate the scene in one of the orthographic projections.\n",
" <br>**Warning**: if set to True, synchronization capabilities of `VTKRenderWindowSynchronized` panes could not work.\n",
"* **``object``** (object): Must be a ``vtkRenderWindow`` instance.\n",
"\n",
"#### Properties:\n",
Expand Down
3 changes: 2 additions & 1 deletion examples/reference/panes/VTKJS.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
" \n",
" The mouse must be over the pane to work.\n",
" <br>**Warning**: These keybindings may not work as expected in a notebook context, if they interact with already bound keys.\n",
"* **``orientation_widget``** (bool): A boolean to activate/deactivate the orientation widget in the 3D pane. This widget is clickable and allows to rotate the scene in one of the orthographic projections.\n",
"* **``orientation_widget``** (bool): A boolean to activate/deactivate the orientation widget in the 3D pane.\n",
"* **``ìnteractive_orientation_widget``** (bool): If True the orientation widget is clickable and allows to rotate the scene in one of the orthographic projections.\n",
"* **``object``** (str or object): Can be a string pointing to a local or remote file with a `.vtkjs` extension.\n",
"___"
]
Expand Down
4 changes: 3 additions & 1 deletion panel/models/vtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from bokeh.core.enums import enumeration
from bokeh.models import HTMLBox, Model, ColorMapper

vtk_cdn = "https://unpkg.com/vtk.js@13.18.0/dist/vtk.js"
vtk_cdn = "https://unpkg.com/vtk.js@14.16.4/dist/vtk.js"

class VTKAxes(Model):
"""
Expand Down Expand Up @@ -64,6 +64,8 @@ class AbstractVTKPlot(HTMLBox):

orientation_widget = Bool(default=False)

interactive_orientation_widget = Bool(default=False)

width = Override(default=300)


Expand Down
9 changes: 3 additions & 6 deletions panel/models/vtk/util.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import {linspace} from "@bokehjs/core/util/array"

import {Follower} from "./vtkfollower"
import {RenderWindowInteractor} from "./vtkrenderwindowinteractor"

export const ARRAY_TYPES = {
uint8: Uint8Array,
int8: Int8Array,
Expand Down Expand Up @@ -30,7 +27,7 @@ if (vtk) {
vtkns["CubeSource"] = vtk.Filters.Sources.vtkCubeSource
vtkns["DataAccessHelper"] = vtk.IO.Core.DataAccessHelper
vtkns["DataArray"] = vtk.Common.Core.vtkDataArray
vtkns["Follower"] = Follower
vtkns["Follower"] = vtk.Rendering.Core.vtkFollower
vtkns["FullScreenRenderWindow"] = vtk.Rendering.Misc.vtkFullScreenRenderWindow
vtkns["Glyph3DMapper"] = vtk.Rendering.Core.vtkGlyph3DMapper
vtkns["HttpSceneLoader"] = vtk.IO.Core.vtkHttpSceneLoader
Expand Down Expand Up @@ -60,7 +57,7 @@ if (vtk) {
vtkns["Property"] = vtk.Rendering.Core.vtkProperty
vtkns["Renderer"] = vtk.Rendering.Core.vtkRenderer
vtkns["RenderWindow"] = vtk.Rendering.Core.vtkRenderWindow
vtkns["RenderWindowInteractor"] = RenderWindowInteractor
vtkns["RenderWindowInteractor"] = vtk.Rendering.Core.vtkRenderWindowInteractor
vtkns["SphereMapper"] = vtk.Rendering.Core.vtkSphereMapper
vtkns["SynchronizableRenderWindow"] =
vtk.Rendering.Misc.vtkSynchronizableRenderWindow
Expand All @@ -86,7 +83,7 @@ if (vtk) {
)
vtkObjectManager.setTypeMapping(
"vtkFollower",
Follower.newInstance,
vtkns.Follower.newInstance,
vtkObjectManager.genericUpdater
)
}
Expand Down
132 changes: 0 additions & 132 deletions panel/models/vtk/vtkfollower.ts

This file was deleted.

2 changes: 1 addition & 1 deletion panel/models/vtk/vtkjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class VTKJSPlotView extends AbstractVTKView {
setTimeout(() => {
if (this._axes == null && this.model.axes) this._set_axes()
this._set_camera_state()
this.model.properties.camera.change.emit()
this._get_camera_state()
}, 100),
100
)
Expand Down
59 changes: 26 additions & 33 deletions panel/models/vtk/vtklayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {vtkns, VolumeType, majorAxis, applyStyle, CSSProperties} from "./util"
import {VTKColorBar} from "./vtkcolorbar"
import {VTKAxes} from "./vtkaxes"

const INFO_DIV_STYLE: CSSProperties = {
const INFO_DIV_STYLE: CSSProperties = {
padding: "0px 2px 0px 2px",
maxHeight: "150px",
height: "auto",
Expand All @@ -35,7 +35,7 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {
protected _vtk_container: HTMLDivElement
protected _vtk_renwin: any
protected _widgetManager: any

initialize(): void {
super.initialize()
this._camera_callbacks = []
Expand All @@ -49,7 +49,7 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {
if (old_info_div)
this.el.removeChild(old_info_div)
if (this.model.color_mappers.length < 1) return

const info_div = document.createElement("div")
const expand_width = "350px"
const collapsed_width = "30px"
Expand Down Expand Up @@ -110,15 +110,17 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {
this.init_vtk_renwin()
set_size(this._vtk_container, this.model)
this.el.appendChild(this._vtk_container)
this._connect_interactions_to_model()
// update camera model state only at the end of the interaction
// with the scene (avoid bouncing events and large amount of events)
this._vtk_renwin.getInteractor().onEndAnimation(() => this._get_camera_state())
this._remove_default_key_binding()
this._bind_key_events()
this.plot()
this._add_colorbars()
this.model.renderer_el = this._vtk_renwin
} else {
set_size(this._vtk_container, this.model)
// warning if _vtk_renwin contain controllers or other elements
// warning if _vtk_renwin contain controllers or other elements
// we must attach them to the new el
this.el.appendChild(this._vtk_container)
}
Expand Down Expand Up @@ -146,7 +148,7 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {
abstract init_vtk_renwin(): void

abstract plot(): void //here goes the specific implementation pour all concrete model based on vtk-js

get _vtk_camera_state(): any {
const vtk_camera = this._vtk_renwin.getRenderer().getActiveCamera()
let state: any
Expand All @@ -159,13 +161,6 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {
delete state.flattenedDepIds
delete state.managedInstanceId
delete state.directionOfProjection
delete state.projectionMatrix
delete state.viewMatrix
delete state.physicalTranslation
delete state.physicalScale
delete state.physicalViewUp
delete state.physicalViewNorth
delete state.mtime
}
return state
}
Expand Down Expand Up @@ -228,19 +223,6 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {
})
}

_connect_interactions_to_model(): void {
// update camera model state only at the end of the interaction
// with the scene (avoid bouncing events and large amount of events)

const update_model_camera = () => {
this._get_camera_state()
this.model.properties.camera.change.emit()
}
const interactor = this._vtk_renwin.getInteractor()
const event_list = ["LeftButtonRelease", "RightButtonRelease", "EndAnimation"]
event_list.forEach((event) => interactor['on' + event](update_model_camera))
}

_create_orientation_widget(): void {
const axes = vtkns.AxesActor.newInstance()

Expand All @@ -256,10 +238,16 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {
this._orientationWidget.setViewportSize(0.15)
this._orientationWidget.setMinPixelSize(75)
this._orientationWidget.setMaxPixelSize(300)
if (this.model.interactive_orientation_widget)
this._make_orientation_widget_interactive()
this._orientation_widget_visibility(this.model.orientation_widget)
}

_make_orientation_widget_interactive(): void {
this._widgetManager = vtkns.WidgetManager.newInstance()
this._widgetManager.setRenderer(this._orientationWidget.getRenderer())

const axes = this._orientationWidget.getActor()
const widget = vtkns.InteractiveOrientationWidget.newInstance()
widget.placeWidget(axes.getBounds())
widget.setBounds(axes.getBounds())
Expand Down Expand Up @@ -292,10 +280,11 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {

this._vtk_renwin.getRenderer().resetCameraClippingRange()
this._vtk_render()
this._get_camera_state()
})
this._orientation_widget_visibility(this.model.orientation_widget)
}


_delete_axes(): void {
if (this._axes) {
Object.keys(this._axes).forEach((key) =>
Expand Down Expand Up @@ -323,8 +312,10 @@ export abstract class AbstractVTKView extends PanelHTMLBoxView {

_orientation_widget_visibility(visibility: boolean): void {
this._orientationWidget.setEnabled(visibility)
if (visibility) this._widgetManager.enablePicking()
else this._widgetManager.disablePicking()
if (this._widgetManager != null){
if (visibility) this._widgetManager.enablePicking()
else this._widgetManager.disablePicking()
}
this._vtk_render()
}

Expand Down Expand Up @@ -394,6 +385,7 @@ export namespace AbstractVTKPlot {
enable_keybindings: p.Property<boolean>
orientation_widget: p.Property<boolean>
color_mappers: p.Property<ColorMapper[]>
interactive_orientation_widget: p.Property<boolean>
}
}

Expand All @@ -415,10 +407,11 @@ export abstract class AbstractVTKPlot extends HTMLBox {

static init_AbstractVTKPlot(): void {
this.define<AbstractVTKPlot.Props>({
axes: [ p.Instance ],
camera: [ p.Instance ],
color_mappers: [ p.Array, [] ],
orientation_widget: [ p.Boolean, false ],
axes: [ p.Instance ],
camera: [ p.Instance ],
color_mappers: [ p.Array, [] ],
orientation_widget: [ p.Boolean, false ],
interactive_orientation_widget: [ p.Boolean, false ],
})

this.override({
Expand Down
Loading