Files
wg_cpso/vtkControl/vtkInteractorStyleControl.cs
2026-03-25 18:20:24 +08:00

1128 lines
48 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Kitware.VTK;
namespace vtkControl
{
public delegate double[] GetPickPointDelegate(out vtkActor pickedActor, int x, int y);
class vtkInteractorStyleControl : vtkInteractorStyleTrackballCamera
{
// Enum
private enum EventIds
{
NoEvent = 0,
AnyEvent,
DeleteEvent,
StartEvent,
EndEvent,
RenderEvent,
ProgressEvent,
PickEvent,
StartPickEvent,
EndPickEvent,
AbortCheckEvent,
ExitEvent,
LeftButtonPressEvent,
LeftButtonReleaseEvent,
MiddleButtonPressEvent,
MiddleButtonReleaseEvent,
RightButtonPressEvent,
RightButtonReleaseEvent,
EnterEvent,
LeaveEvent,
KeyPressEvent,
KeyReleaseEvent,
CharEvent,
ExposeEvent,
ConfigureEvent,
TimerEvent,
MouseMoveEvent,
MouseWheelForwardEvent,
MouseWheelBackwardEvent,
ResetCameraEvent,
ResetCameraClippingRangeEvent,
ModifiedEvent,
WindowLevelEvent,
StartWindowLevelEvent,
EndWindowLevelEvent,
ResetWindowLevelEvent,
SetOutputEvent,
ErrorEvent,
WarningEvent,
StartInteractionEvent, //mainly used
InteractionEvent,
EndInteractionEvent,
EnableEvent,
DisableEvent,
CreateTimerEvent,
DestroyTimerEvent,
PlacePointEvent,
PlaceWidgetEvent,
CursorChangedEvent,
ExecuteInformationEvent,
RenderWindowMessageEvent,
WrongTagEvent,
StartAnimationCueEvent, // used
AnimationCueTickEvent,
EndAnimationCueEvent,
VolumeMapperRenderProgressEvent,
VolumeMapperComputeGradientsEndEvent,
VolumeMapperComputeGradientsProgressEvent,
VolumeMapperComputeGradientsStartEvent,
WidgetModifiedEvent,
WidgetValueChangedEvent,
WidgetActivateEvent,
UserEvent = 1000
}
// Variables
public const int VTKIS_START = 0;
public const int VTKIS_NONE = 0;
public const int VTKIS_ROTATE = 1;
public const int VTKIS_PAN = 2;
public const int VTKIS_SPIN = 3;
public const int VTKIS_DOLLY = 4;
public const int VTKIS_ZOOM = 5;
public const int VTKIS_USCALE = 6;
public const int VTKIS_TIMER = 7;
public const int VTKIS_FORWARDFLY = 8;
public const int VTKIS_REVERSEFLY = 9;
public const int VTKIS_SELECTION = 10;
public const int VTKIS_ANIM_OFF = 0;
public const int VTKIS_ANIM_ON = 1;
//
private double _motionFactor;
private double[] _rotationCenterWorld;
private double[] _rotationCenterDisplay;
private int[] _clickPos;
private double[] _clickPosWorld;
private vtkProp _centerAnnotationActor;
private bool _rubberBandEnabled;
private bool _animating;
private System.Windows.Threading.DispatcherTimer _selectionTimer;
private int _x;
private int _y;
// Double click
protected int _lastX;
protected int _lastY;
protected int _numOfClicks;
protected DateTime _lastClickTime;
private TimeSpan _doubleClickTimeSpan = new TimeSpan(0, 0, 0, 0, SystemInformation.DoubleClickTime);
private int _doubleClickDisp = 5;
//
protected bool _leftMouseButtonPressed;
protected bool _rubberBandSelection;
protected bool _selectionCanceled;
protected vtkRenderer _selectionRenderer;
protected vtkRenderer _overlayRenderer;
protected vtkPolyDataMapper2D _selectionBackgroundMapper;
protected vtkActor2D _selectionBackgroundActor;
protected vtkActor2D _selectionBorderActor;
//
protected List<vtkMaxBorderWidget> _widgets;
protected List<vtkMaxBorderWidget> _reversedWidgets;
// Properties
public new const string MRFullTypeName = "Kitware.VTK.vtkInteractorStyleControl";
public bool RubberBandEnabled { get { return _rubberBandEnabled; } set { _rubberBandEnabled = value; } }
public bool Animating { get { return _animating; } set { _animating = value; } }
// Getters
public bool IsRubberBandActive { get { return _rubberBandSelection; } }
// Callbacks
public GetPickPointDelegate GetPickPoint;
// Events
public event Action<int, int, bool, int, int> PointPickedOnMouseMoveEvt;
public event Action<MouseEventArgs, bool, int, int> PointPickedOnLeftUpEvt;
public event Action ClearCurrentMouseSelection;
public event Action<object, MouseEventArgs> RightButtonPressEvent;
public event Action ZoomChangedEvent;
// Constructors
public vtkInteractorStyleControl()
{
_motionFactor = 10.0;
_rotationCenterWorld = null;
_animating = false;
_selectionTimer = new System.Windows.Threading.DispatcherTimer();
_selectionTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
_selectionTimer.Tick += _selectionTimer_Tick;
//
_lastX = int.MinValue;
_lastY = int.MinValue;
_lastClickTime = DateTime.Now;
//
_rubberBandEnabled = true;
_widgets = new List<vtkMaxBorderWidget>();
_reversedWidgets = new List<vtkMaxBorderWidget>();
//
this.LeftButtonPressEvt += vtkInteractorStyleControl_LeftButtonPressEvt;
this.LeftButtonReleaseEvt += vtkInteractorStyleControl_LeftButtonReleaseEvt;
this.MiddleButtonPressEvt += vtkInteractorStyleControl_MiddleButtonPressEvt;
this.MiddleButtonReleaseEvt += vtkInteractorStyleControl_MiddleButtonReleaseEvt;
this.RightButtonPressEvt += vtkInteractorStyleControl_RightButtonPressEvt;
this.RightButtonReleaseEvt += vtkInteractorStyleControl_RightButtonReleaseEvt;
this.MouseMoveEvt += vtkInteractorStyleControl_MouseMoveEvt;
this.MouseWheelForwardEvt += vtkInteractorStyleControl_MouseWheelForwardEvt;
this.MouseWheelBackwardEvt += vtkInteractorStyleControl_MouseWheelBackwardEvt;
this.KeyPressEvt += VtkInteractorStyleControl_KeyPressEvt;
}
new public static vtkInteractorStyleControl New()
{
return new vtkInteractorStyleControl();
}
// Event handlers
void vtkInteractorStyleControl_LeftButtonPressEvt(vtkObject sender, vtkObjectEventArgs e)
{
vtkRenderWindowInteractor rwi = this.GetInteractor();
//
int x = rwi.GetEventPosition()[0];
int y = rwi.GetEventPosition()[1];
//
_numOfClicks = 1;
// Double click
if (DateTime.Now - _lastClickTime < _doubleClickTimeSpan &&
Math.Abs(x - _lastX) < _doubleClickDisp &&
Math.Abs(y - _lastY) < _doubleClickDisp) _numOfClicks = 2;
// Set global variable
_clickPos = new int[] { x, y };
// World click pos
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
_clickPosWorld = DisplayToWorld(renderer, new double[] { x, y });
// Widgets
vtkMaxBorderWidget borderWidget = null;
MouseEventArgs mea = new MouseEventArgs(MouseButtons.Left, _numOfClicks, x, y, 0);
foreach (vtkMaxBorderWidget widget in _reversedWidgets)
{
if (widget.LeftButtonPress(mea))
{
borderWidget = widget;
break; // do not return here to set _lastX, lastY, _lastClickTime
}
}
//
if (borderWidget == null)
{
_leftMouseButtonPressed = true;
_rubberBandSelection = false;
_selectionCanceled = false;
// Area selection
vtkPoints backgroundPoints = _selectionBackgroundMapper.GetInput().GetPoints();
backgroundPoints.SetPoint(0, _clickPos[0], _clickPos[1], 0.0);
backgroundPoints.SetPoint(1, _clickPos[0], _clickPos[1], 0.0);
backgroundPoints.SetPoint(2, _clickPos[0], _clickPos[1], 0.0);
backgroundPoints.SetPoint(3, _clickPos[0], _clickPos[1], 0.0);
backgroundPoints.Modified();
}
//
_lastX = x;
_lastY = y;
_lastClickTime = DateTime.Now;
}
void vtkInteractorStyleControl_LeftButtonReleaseEvt(vtkObject sender, vtkObjectEventArgs e)
{
vtkRenderWindowInteractor rwi = this.GetInteractor();
//
int x = rwi.GetEventPosition()[0];
int y = rwi.GetEventPosition()[1];
// Widgets
if (!_rubberBandSelection)
{
foreach (vtkMaxBorderWidget widget in _reversedWidgets)
{
if (widget.LeftButtonRelease(x, y)) return;
}
}
if (!_selectionCanceled)
{
int[] mousePos = rwi.GetEventPosition();
//
if (PointPickedOnLeftUpEvt != null)
{
if (_clickPos == null) { }
else
{
MouseEventArgs mea = new MouseEventArgs(MouseButtons.Left, _numOfClicks, mousePos[0], mousePos[1], 0);
PointPickedOnLeftUpEvt(mea, _rubberBandSelection, _clickPos[0], _clickPos[1]);
}
}
}
//
_clickPos = null;
_clickPosWorld = null;
_leftMouseButtonPressed = false;
_rubberBandSelection = false;
//
_selectionBackgroundActor.VisibilityOff();
_selectionBorderActor.VisibilityOff();
//
rwi.Render();
}
//
void vtkInteractorStyleControl_MiddleButtonPressEvt(vtkObject sender, vtkObjectEventArgs e)
{
// Cancel rubber band
CancelRubberBandSelection();
//
base.OnLeftButtonDown();
//
vtkRenderWindowInteractor rwi = this.GetInteractor();
//
int x = rwi.GetEventPosition()[0];
int y = rwi.GetEventPosition()[1];
this.FindPokedRenderer(x, y);
//
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
//
_clickPos = rwi.GetEventPosition(); // set global variable
//
UpdateRotationCenterDisplay();
//
AddAnnotationForCenter3D(rwi, renderer);
// Widgets - middle pressed
foreach (vtkMaxBorderWidget widget in _widgets)
{
widget.MiddleButtonPress(x, y);
}
//
rwi.Render();
}
void vtkInteractorStyleControl_MiddleButtonReleaseEvt(vtkObject sender, vtkObjectEventArgs e)
{
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
// Remove first in order not to affect the bounds of the model
RemoveAnnotationForCenter(renderer);
//
vtkRenderWindowInteractor rwi = this.GetInteractor();
int[] currClickPos = rwi.GetEventPosition();
//
if (_clickPos != null && Math.Abs(_clickPos[0] - currClickPos[0]) + Math.Abs(_clickPos[0] - currClickPos[0]) < 2)
{
// Only click happened
if (GetPickPoint != null)
{
//vtkPropPicker picker = vtkPropPicker.New();
//renderer.Render(); // to redraw the first - BASE - layer of geometry again
//picker.Pick(currClickPos[0], currClickPos[1], 0, renderer);
//_rotationCenterWorld = picker.GetPickPosition();
vtkActor actor;
double[] pickPoint = GetPickPoint(out actor, currClickPos[0], currClickPos[1]);
if (pickPoint != null) _rotationCenterWorld = pickPoint;
//
if (actor == null) // picker.GetActor() == null
{
// The click was not a hit
// Use the center of the bounding box
double[] bounds = renderer.ComputeVisiblePropBounds();
_rotationCenterWorld[0] = (bounds[1] + bounds[0]) / 2;
_rotationCenterWorld[1] = (bounds[3] + bounds[2]) / 2;
_rotationCenterWorld[2] = (bounds[5] + bounds[4]) / 2;
}
else
{
// The click was a hit
vtkCamera camera = renderer.GetActiveCamera();
double[] center = camera.GetFocalPoint();
PanCamera(camera, center, _rotationCenterWorld);
AdjustCameraDistance(renderer, camera);
}
}
}
// Adjust the clipping range and lights
if (this.GetAutoAdjustCameraClippingRange() == 1) ResetClippingRange();
if (rwi.GetLightFollowCamera() == 1) renderer.UpdateLightsGeometryToFollowCamera();
// Widgets - middle released
foreach (vtkMaxBorderWidget widget in _widgets)
{
widget.MiddleButtonRelease(currClickPos[0], currClickPos[1]);
}
//
rwi.Modified();
//
_clickPos = null;
_clickPosWorld = null;
//
base.OnLeftButtonUp(); // left button is rotation by default
}
//
void vtkInteractorStyleControl_RightButtonPressEvt(vtkObject sender, vtkObjectEventArgs e)
{
vtkRenderWindowInteractor rwi = this.GetInteractor();
int x = rwi.GetEventPosition()[0];
int y = rwi.GetEventPosition()[1];
//
this.FindPokedRenderer(x, y);
//
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer != null)
{
int[] clickPos = rwi.GetEventPosition();
// Widgets - right pressed
vtkMaxBorderWidget clickedWidget = null;
MouseEventArgs mea = new MouseEventArgs(MouseButtons.Right, 1, x, y, 0);
//
foreach (vtkMaxBorderWidget widget in _widgets)
{
if (widget.RightButtonPress(x, y))
{
clickedWidget = widget;
break;
}
}
//
RightButtonPressEvent?.Invoke(clickedWidget, mea);
}
}
void vtkInteractorStyleControl_RightButtonReleaseEvt(vtkObject sender, vtkObjectEventArgs e)
{
}
//
void vtkInteractorStyleControl_MouseMoveEvt(vtkObject sender, vtkObjectEventArgs e)
{
_x = this.GetInteractor().GetEventPosition()[0];
_y = this.GetInteractor().GetEventPosition()[1];
// Widgets - Move
foreach (vtkMaxBorderWidget widget in _widgets)
{
if (widget.MouseMove(_x, _y))
{
this.GetInteractor().Render();
return;
}
}
//
switch (this.GetState())
{
case VTKIS_NONE:
//if (_selection)
{
_selectionTimer.Stop();
_selectionTimer.Start();
//
if (_rubberBandEnabled)
{
if (!_rubberBandSelection && _leftMouseButtonPressed && _clickPos != null &&
Math.Abs(_x - _clickPos[0]) > 1 && Math.Abs(_y - _clickPos[1]) > 1)
{
_rubberBandSelection = true;
}
if (_rubberBandSelection) DrawRubberBandSelection(_x, _y);
}
}
break;
case VTKIS_ROTATE:
this.FindPokedRenderer(_x, _y);
this.Rotate();
this.InvokeEvent((uint)EventIds.InteractionEvent, IntPtr.Zero);
break;
case VTKIS_PAN:
this.FindPokedRenderer(_x, _y);
this.Pan();
this.InvokeEvent((uint)EventIds.InteractionEvent, IntPtr.Zero);
break;
}
}
//
void vtkInteractorStyleControl_MouseWheelForwardEvt(vtkObject sender, vtkObjectEventArgs e)
{
if (this.GetState() == VTKIS_NONE)
{
int[] clickPos = this.GetInteractor().GetEventPosition();
this.FindPokedRenderer(clickPos[0], clickPos[1]);
vtkRenderer renderer = this.GetCurrentRenderer();
double[] worldPos = DisplayToWorld(renderer, new double[] { clickPos[0], clickPos[1] });
vtkCamera camera = renderer.GetActiveCamera();
double factor = Math.Pow(1.1, this._motionFactor * 0.2 * this.GetMouseWheelMotionFactor());
//factor = 1;
camera.SetParallelScale(camera.GetParallelScale() * factor);
double[] worldPosAfter = DisplayToWorld(renderer, new double[] { clickPos[0], clickPos[1] });
PanCamera(camera, worldPosAfter, worldPos);
// Rubber band
if (_rubberBandSelection) DrawRubberBandSelection(_x, _y);
// Widgets - mouse wheel scrolled
foreach (vtkMaxBorderWidget widget in _widgets)
{
widget.MouseWheelScrolled();
}
if (ZoomChangedEvent != null) ZoomChangedEvent();
this.GetInteractor().Modified();
this.GetInteractor().Render();
}
}
void vtkInteractorStyleControl_MouseWheelBackwardEvt(vtkObject sender, vtkObjectEventArgs e)
{
if (this.GetState() == VTKIS_NONE)
{
int[] clickPos = this.GetInteractor().GetEventPosition();
this.FindPokedRenderer(clickPos[0], clickPos[1]);
vtkRenderer renderer = this.GetCurrentRenderer();
double[] worldPos = DisplayToWorld(renderer, new double[] { clickPos[0], clickPos[1] });
vtkCamera camera = renderer.GetActiveCamera();
double factor = Math.Pow(1.1, this._motionFactor * 0.2 * this.GetMouseWheelMotionFactor());
//factor = 1.00;
camera.SetParallelScale(camera.GetParallelScale() / factor);
double[] worldPosAfter = DisplayToWorld(renderer, new double[] { clickPos[0], clickPos[1] });
PanCamera(camera, worldPosAfter, worldPos);
// Rubber band
if (_rubberBandSelection) DrawRubberBandSelection(_x, _y);
// Widgets - mouse wheel scrolled
foreach (vtkMaxBorderWidget widget in _widgets)
{
widget.MouseWheelScrolled();
}
if (ZoomChangedEvent != null) ZoomChangedEvent();
this.GetInteractor().Modified();
this.GetInteractor().Render();
}
}
//
private void VtkInteractorStyleControl_KeyPressEvt(vtkObject sender, vtkObjectEventArgs e)
{
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
//
vtkRenderWindowInteractor rwi = this.GetInteractor();
sbyte key = rwi.GetKeyCode();
// Arrow keys for rotation
if (key >= 37 && key <= 40)
{
CancelRubberBandSelection();
//
UpdateRotationCenterDisplay();
rwi.Modified();
//
double delta = 5;
if (key == 37) Rotate(+delta, 0); // left
else if (key == 39) Rotate(-delta, 0); // right
else if (key == 38) Rotate(0, -delta); // up
else if (key == 40) Rotate(0, +delta); // down
//
rwi.Modified();
rwi.Render();
}
// Escape key
else if (key == 27)
{
CancelRubberBandSelection();
}
}
// Public setters
public void SetSelectionRenderer(vtkRenderer renderer)
{
_selectionRenderer = renderer;
InitializeRubberBandSelection();
}
public void SetOverlayRenderer(vtkRenderer renderer)
{
_overlayRenderer = renderer;
}
// Methods
void _selectionTimer_Tick(object sender, EventArgs e)
{
_selectionTimer.Stop();
this.FindPokedRenderer(_x, _y);
this.Select(_x, _y);
}
public bool IsPositionOverWidget(int x, int y)
{
foreach (vtkMaxBorderWidget widget in _widgets)
{
if (widget.MouseOver(x, y)) return true;
}
return false;
}
//
public void AddVtkMaxWidget(vtkMaxBorderWidget widget)
{
_widgets.Add(widget);
_reversedWidgets.Insert(0, widget);
}
public void RemoveVtkMaxWidget(vtkMaxBorderWidget widget)
{
_widgets.Remove(widget);
_reversedWidgets.Remove(widget);
}
public void Reset()
{
_rotationCenterWorld = null;
}
private void UpdateRotationCenterDisplay()
{
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
if (_rotationCenterWorld == null)
{
// for the first time use the center of the bounding box
double[] bounds = renderer.ComputeVisiblePropBounds();
_rotationCenterWorld = new double[3];
_rotationCenterWorld[0] = (bounds[1] + bounds[0]) / 2;
_rotationCenterWorld[1] = (bounds[3] + bounds[2]) / 2;
_rotationCenterWorld[2] = (bounds[5] + bounds[4]) / 2;
}
// must update since zoom can also change
_rotationCenterDisplay = WorldToDisplay(renderer, _rotationCenterWorld);
}
public static double[] WorldToDisplay(vtkRenderer renderer, double[] worldPos)
{
IntPtr posOutPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(2 * 8);
ComputeWorldToDisplay(renderer, worldPos[0], worldPos[1], worldPos[2], posOutPtr);
double[] displayPos = new double[2];
System.Runtime.InteropServices.Marshal.Copy(posOutPtr, displayPos, 0, 2);
return displayPos;
}
public static double[] DisplayToWorld(vtkRenderer renderer, double[] displayPos)
{
IntPtr posOutPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(4 * 8);
ComputeDisplayToWorld(renderer, displayPos[0], displayPos[1], 0, posOutPtr);
double[] worldPos = new double[3];
System.Runtime.InteropServices.Marshal.Copy(posOutPtr, worldPos, 0, 3);
return worldPos;
}
public static double DisplayToWorldScale(vtkRenderer renderer, int size = 1)
{
int delta = 1 * size;
int x = 0;
int y = 0;
double[] p1 = vtkInteractorStyleControl.DisplayToWorld(renderer, new double[] { x, y });
double[] p2 = vtkInteractorStyleControl.DisplayToWorld(renderer, new double[] { x + delta, y });
return Math.Sqrt(Math.Pow(p1[0] - p2[0], 2)
+ Math.Pow(p1[1] - p2[1], 2)
+ Math.Pow(p1[2] - p2[2], 2));
}
public override void Pan()
{
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
//
vtkRenderWindowInteractor rwi = this.GetInteractor();
int[] clickPos = rwi.GetEventPosition();
//
double[] newPickPoint;
double[] oldPickPoint;
//
newPickPoint = DisplayToWorld(renderer, new double[] { clickPos[0], clickPos[1] });
oldPickPoint = DisplayToWorld(renderer, new double[] { rwi.GetLastEventPosition()[0], rwi.GetLastEventPosition()[1] });
//
vtkCamera camera = renderer.GetActiveCamera();
PanCamera(camera, newPickPoint, oldPickPoint);
//
if (rwi.GetLightFollowCamera() == 1) renderer.UpdateLightsGeometryToFollowCamera();
// Widgets - Pan
int dx;
int dy;
foreach (vtkMaxBorderWidget widget in _widgets)
{
// compute the delta
dx = clickPos[0] - rwi.GetLastEventPosition()[0];
dy = clickPos[1] - rwi.GetLastEventPosition()[1];
//
widget.MousePan(dx, dy);
}
rwi.Render();
}
private void PanCamera(vtkCamera camera, double[] posStart, double[] posEnd)
{
double[] motionVector = new double[3];
motionVector[0] = posEnd[0] - posStart[0];
motionVector[1] = posEnd[1] - posStart[1];
motionVector[2] = posEnd[2] - posStart[2];
//
double[] cPos = camera.GetPosition();
double[] fPos = camera.GetFocalPoint();
//
//System.Diagnostics.Debug.WriteLine(string.Format("cPos1 x: {0}, y: {1}, z: {2}", cPos[0], cPos[1], cPos[2]));
//
camera.SetPosition(cPos[0] + motionVector[0], cPos[1] + motionVector[1], cPos[2] + motionVector[2]);
camera.SetFocalPoint(fPos[0] + motionVector[0], fPos[1] + motionVector[1], fPos[2] + motionVector[2]);
//
AdjustCameraDistanceAndClipping();
}
//
public override void Rotate()
{
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
//
vtkRenderWindowInteractor rwi = this.GetInteractor();
int[] clickPos = rwi.GetEventPosition();
// Compute the angle
int dx = clickPos[0] - rwi.GetLastEventPosition()[0];
int dy = clickPos[1] - rwi.GetLastEventPosition()[1];
//
double delta_elevation = -20.0 / 500;
double delta_azimuth = -20.0 / 500;
//
double rxf = dx * delta_azimuth * this._motionFactor;
double ryf = dy * delta_elevation * this._motionFactor;
//
Rotate(rxf, ryf);
}
public void Rotate(double azimuthAngle, double elevationAngle, double rollAngle = 0)
{
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
//
vtkCamera camera = renderer.GetActiveCamera();
vtkRenderWindowInteractor rwi = this.GetInteractor();
//
if (azimuthAngle != 0) camera.Azimuth(azimuthAngle);
if (elevationAngle != 0) camera.Elevation(elevationAngle);
if (rollAngle != 0) camera.Roll(rollAngle);
camera.OrthogonalizeViewUp();
// Move the cameras focal point back to the display position of the first click - the opposite direction!
double[] wpa = DisplayToWorld(renderer, _rotationCenterDisplay);
double[] n = camera.GetViewPlaneNormal();
// Compute a plane through rotationWorldCenter and project the rotationDisplayCenter on it
double[] v = new double[3]; // vector from rotationWorldCenter to DisplayToWorld point
double[] rotCenter = _rotationCenterWorld;
if (rotCenter == null) rotCenter = new double[3];
v[0] = wpa[0] - rotCenter[0];
v[1] = wpa[1] - rotCenter[1];
v[2] = wpa[2] - rotCenter[2];
double d = n[0] * v[0] + n[1] * v[1] + n[2] * v[2]; // distance of DisplayToWorld point from plane
wpa[0] -= n[0] * d;
wpa[1] -= n[1] * d;
wpa[2] -= n[2] * d;
//
PanCamera(camera, wpa, rotCenter); // calls AdjustCameraDistanceAndClipping()
// Adjust the lights
if (rwi.GetLightFollowCamera() == 1) renderer.UpdateLightsGeometryToFollowCamera();
// Widgets - Rotate
foreach (vtkMaxBorderWidget widget in _widgets)
{
widget.MouseRotate(azimuthAngle, elevationAngle);
}
rwi.Modified();
rwi.Render();
}
//
private void Select(int x, int y)
{
if (PointPickedOnMouseMoveEvt != null)
{
vtkRenderer renderer = this.GetCurrentRenderer();
if (_clickPos != null && _clickPosWorld != null && renderer != null)
{
int[] clickPos = _clickPos;
if (_rubberBandSelection)
{
double[] clickPosD = WorldToDisplay(renderer, _clickPosWorld);
clickPos[0] = (int)clickPosD[0];
clickPos[1] = (int)clickPosD[1];
}
PointPickedOnMouseMoveEvt(x, y, _rubberBandSelection, clickPos[0], clickPos[1]);
}
else PointPickedOnMouseMoveEvt(x, y, _rubberBandSelection, 0, 0);
}
}
private void DrawRubberBandSelection(int x, int y)
{
if (_clickPosWorld == null) return;
//
vtkRenderer renderer = this.GetCurrentRenderer();
if (renderer == null) return;
//
double[] clickPos = WorldToDisplay(renderer, _clickPosWorld);
//
_selectionBackgroundActor.VisibilityOn();
_selectionBorderActor.VisibilityOn();
// Border
if (clickPos[0] > x)
{
_selectionBorderActor.GetProperty().SetColor(0.3, 1.0, 0.3);
_selectionBackgroundActor.GetProperty().SetColor(0.2, 1, 0.5);
//_selectionBorderActor.GetProperty().SetLineStipplePattern(65280);
}
else
{
_selectionBorderActor.GetProperty().SetColor(0.3, 0.3, 1.0);
_selectionBackgroundActor.GetProperty().SetColor(0.2, 0.5, 1);
//_selectionBorderActor.GetProperty().SetLineStipplePattern(0xffff);
}
//
vtkRenderWindowInteractor rwi = this.GetInteractor();
vtkPoints backgroundPoints = _selectionBackgroundMapper.GetInput().GetPoints();
//
int id1 = 1;
int id2 = 2;
int id3 = 3;
// Switch ids 1 and 3 if II or IV quadrant
if ((x < clickPos[0] && y > clickPos[1]) || (x > clickPos[0] && y < clickPos[1]))
{
id1 = 3;
id3 = 1;
}
//
backgroundPoints.SetPoint(0, clickPos[0], clickPos[1], 0.0);
backgroundPoints.SetPoint(id1, x, clickPos[1], 0.0);
backgroundPoints.SetPoint(id2, x, y, 0.0);
backgroundPoints.SetPoint(id3, clickPos[0], y, 0.0);
backgroundPoints.Modified();
//
rwi.Render();
}
private void CancelRubberBandSelection()
{
if (_rubberBandSelection)
{
_selectionCanceled = true;
_clickPos = null;
_clickPosWorld = null;
_rubberBandSelection = false;
//
_selectionBackgroundActor.VisibilityOff();
_selectionBorderActor.VisibilityOff();
//
ClearCurrentMouseSelection?.Invoke();
//
this.GetInteractor().Render();
}
}
//
private void AddAnnotationForCenter3D(vtkRenderWindowInteractor interactor, vtkRenderer renderer)
{
if (_centerAnnotationActor != null) RemoveAnnotationForCenter(renderer);
//
int[] size = renderer.GetSize();
double minSize = Math.Min(size[0], size[1]);
vtkCamera camera = renderer.GetActiveCamera();
double scale = camera.GetParallelScale();
double dMin = 30 / minSize * scale;
double dMax = 100 / minSize * scale;
//
vtkPoints points = vtkPoints.New();
points.InsertNextPoint(_rotationCenterWorld[0] + dMin, _rotationCenterWorld[1], _rotationCenterWorld[2]);
points.InsertNextPoint(_rotationCenterWorld[0] + dMax, _rotationCenterWorld[1], _rotationCenterWorld[2]);
//
points.InsertNextPoint(_rotationCenterWorld[0] - dMin, _rotationCenterWorld[1], _rotationCenterWorld[2]);
points.InsertNextPoint(_rotationCenterWorld[0] - dMax, _rotationCenterWorld[1], _rotationCenterWorld[2]);
//
points.InsertNextPoint(_rotationCenterWorld[0], _rotationCenterWorld[1] + dMin, _rotationCenterWorld[2]);
points.InsertNextPoint(_rotationCenterWorld[0], _rotationCenterWorld[1] + dMax, _rotationCenterWorld[2]);
//
points.InsertNextPoint(_rotationCenterWorld[0], _rotationCenterWorld[1] - dMin, _rotationCenterWorld[2]);
points.InsertNextPoint(_rotationCenterWorld[0], _rotationCenterWorld[1] - dMax, _rotationCenterWorld[2]);
//
points.InsertNextPoint(_rotationCenterWorld[0], _rotationCenterWorld[1], _rotationCenterWorld[2] + dMax * 1.3);
points.InsertNextPoint(_rotationCenterWorld[0], _rotationCenterWorld[1], _rotationCenterWorld[2] - dMax * 0.7);
//
vtkCellArray lineIndices = vtkCellArray.New();
for (int i = 0; i < 5; i++)
{
lineIndices.InsertNextCell(2);
lineIndices.InsertCellPoint(2 * i);
lineIndices.InsertCellPoint(2 * i + 1);
}
//
vtkPolyData pointsPolyData = vtkPolyData.New();
pointsPolyData.SetPoints(points);
pointsPolyData.SetLines(lineIndices);
// Visualize
vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
mapper.SetInput(pointsPolyData);
mapper.Update();
//
vtkActor actor = vtkActor.New();
actor.SetMapper(mapper);
actor.GetProperty().SetColor(1, 0.7, 0);
//actor.GetProperty().SetLineWidth(1);
renderer.AddActor(actor);
_centerAnnotationActor = actor;
}
private void RemoveAnnotationForCenter(vtkRenderer renderer)
{
if (_centerAnnotationActor != null)
{
renderer.RemoveActor(_centerAnnotationActor);
_centerAnnotationActor.Dispose();
_centerAnnotationActor = null;
}
}
public void AdjustCameraDistanceAndClipping()
{
vtkRenderer renderer = this.GetCurrentRenderer();
vtkCamera camera = renderer.GetActiveCamera();
//
AdjustCameraDistance(renderer, camera);
ResetClippingRange();
// Widgets - Modified
foreach (vtkMaxBorderWidget widget in _widgets)
{
widget.CameraModified();
}
}
private void AdjustCameraDistance(vtkRenderer renderer, vtkCamera camera)
{
// Camera should not be to close or to far
double[] b1 = renderer.ComputeVisiblePropBounds();
double[] b2 = _selectionRenderer.ComputeVisiblePropBounds();
double[] b3 = _overlayRenderer.ComputeVisiblePropBounds();
//
double[] b = new double[] { Math.Min(b1[0], Math.Min(b2[0], b3[0])), Math.Max(b1[1], Math.Max(b2[1], b3[1])),
Math.Min(b1[2], Math.Min(b2[2], b3[2])), Math.Max(b1[3], Math.Max(b2[3], b3[3])),
Math.Min(b1[4], Math.Min(b2[4], b3[4])), Math.Max(b1[5], Math.Max(b2[5], b3[5]))};
//
double r = 0.5 * Math.Sqrt(Math.Pow(b[0] - b[1], 2) + Math.Pow(b[2] - b[3], 2) + Math.Pow(b[4] - b[5], 2)); // radius
r *= 1.05;
double[] center = new double[] { (b[0] + b[1]) / 2, (b[2] + b[3]) / 2, (b[4] + b[5]) / 2 };
//
double[] pos = camera.GetPosition();
//
double[] delta = new double[3]; // vector from camera position to the geometry center
//
delta[0] = center[0] - pos[0];
delta[1] = center[1] - pos[1];
delta[2] = center[2] - pos[2];
//
double[] normal = camera.GetDirectionOfProjection();
double d = normal[0] * delta[0] + normal[1] * delta[1] + normal[2] * delta[2]; // distance to geometry center
double k = d - r;
//
double[] motionVector = new double[3];
motionVector[0] = k * normal[0];
motionVector[1] = k * normal[1];
motionVector[2] = k * normal[2];
//
//System.Diagnostics.Debug.WriteLine(string.Format("pos4 x: {0}, y: {1}, z: {2}", pos[0], pos[1], pos[2]));
//
double[] newPos = new double[3];
newPos[0] = pos[0] + motionVector[0];
newPos[1] = pos[1] + motionVector[1];
newPos[2] = pos[2] + motionVector[2];
camera.SetPosition(newPos[0], newPos[1], newPos[2]);
//
//System.Diagnostics.Debug.WriteLine(string.Format("pos5 x: {0}, y: {1}, z: {2}", newPos[0], newPos[1], newPos[2]));
//
//double[] focalPos = camera.GetFocalPoint();
//newPos[0] = focalPos[0] + motionVector[0];
//newPos[1] = focalPos[1] + motionVector[1];
//newPos[2] = focalPos[2] + motionVector[2];
newPos[0] += normal[0];
newPos[1] += normal[1];
newPos[2] += normal[2];
//
camera.SetFocalPoint(newPos[0], newPos[1], newPos[2]);
}
private void AdjustCameraDistance__(vtkRenderer renderer, vtkCamera camera)
{
double[] b = renderer.ComputeVisiblePropBounds();
double l = 0.01 * Math.Sqrt(Math.Pow(b[0] - b[1], 2) + Math.Pow(b[2] - b[3], 2) + Math.Pow(b[4] - b[5], 2));
double[] pos = camera.GetPosition();
double[] direction = camera.GetViewPlaneNormal();
double[] point = null;
if (direction[0] > 0 && direction[1] > 0 && direction[2] > 0) point = new double[] { b[1], b[3], b[5] };
else if (direction[0] <= 0 && direction[1] > 0 && direction[2] > 0) point = new double[] { b[0], b[3], b[5] };
else if (direction[0] <= 0 && direction[1] <= 0 && direction[2] > 0) point = new double[] { b[0], b[2], b[5] };
else if (direction[0] > 0 && direction[1] <= 0 && direction[2] > 0) point = new double[] { b[1], b[2], b[5] };
else if (direction[0] > 0 && direction[1] > 0 && direction[2] <= 0) point = new double[] { b[1], b[3], b[4] };
else if (direction[0] <= 0 && direction[1] > 0 && direction[2] <= 0) point = new double[] { b[0], b[3], b[4] };
else if (direction[0] <= 0 && direction[1] <= 0 && direction[2] <= 0) point = new double[] { b[0], b[2], b[4] };
else if (direction[0] > 0 && direction[1] <= 0 && direction[2] <= 0) point = new double[] { b[1], b[2], b[4] };
else throw new Exception();
double[] relDir = new double[] { point[0] - pos[0], point[1] - pos[1], point[2] - pos[2] };
// positive value means the camera distance
double d = -(direction[0] * relDir[0] + direction[1] * relDir[1] + direction[2] * relDir[2]);
d -= l;
double[] newPos = new double[3];
newPos[0] = pos[0] - d * direction[0];
newPos[1] = pos[1] - d * direction[1];
newPos[2] = pos[2] - d * direction[2];
camera.SetPosition(newPos[0], newPos[1], newPos[2]);
}
private void AdjustCameraDistance_(vtkRenderer renderer, vtkCamera camera)
{
double[] b = renderer.ComputeVisiblePropBounds();
double[] center = new double[] { (b[0] + b[1]) / 2, (b[2] + b[3]) / 2, (b[4] + b[5]) / 2 };
double R = Math.Sqrt(Math.Pow(b[0] - b[1], 2) + Math.Pow(b[2] - b[3], 2) + Math.Pow(b[4] - b[5], 2)) / 2;
double[] pos = camera.GetPosition();
double[] direction = camera.GetViewPlaneNormal();
double[] point = new double[] { center[0] + R * direction[0], center[1] + R * direction[1], center[2] + R * direction[2] };
double[] relDir = new double[] { point[0] - pos[0], point[1] - pos[1], point[2] - pos[2] };
// positive value means the camera will move forward
double d = -(direction[0] * relDir[0] + direction[1] * relDir[1] + direction[2] * relDir[2]);
d -= R * 0.01;
camera.SetDistance(d + 10);
double[] newPos = new double[3];
newPos[0] = pos[0] - d * direction[0];
newPos[1] = pos[1] - d * direction[1];
newPos[2] = pos[2] - d * direction[2];
camera.SetPosition(newPos[0], newPos[1], newPos[2]);
//System.Diagnostics.Debug.WriteLine(string.Format("newPos x: {0}, y: {1}, z: {1}", newPos[0], newPos[1], newPos[2]));
}
public void ResetClippingRange()
{
double min, max, minSel, maxSel, minOver, maxOver;
min = max = minSel = maxSel = minOver = maxOver = 0;
//
GetCurrentRenderer().ResetCameraClippingRange();
GetCurrentRenderer().GetActiveCamera().GetClippingRange(ref min, ref max);
//
_selectionRenderer.ResetCameraClippingRange();
_selectionRenderer.GetActiveCamera().GetClippingRange(ref minSel, ref maxSel);
//
_overlayRenderer.ResetCameraClippingRange();
_overlayRenderer.GetActiveCamera().GetClippingRange(ref minOver, ref maxOver);
// Near and far settng for the Z-buffer
GetCurrentRenderer().GetActiveCamera().SetClippingRange(Math.Min(min, Math.Min(minSel, minOver)),
Math.Max(max, Math.Max(maxSel, maxOver)));
//System.Diagnostics.Debug.WriteLine("Near: " + Math.Min(min, Math.Min(minSel, minOver)) + " " +
// "Far: " + Math.Max(max, Math.Max(maxSel, maxOver)));
}
private void InitializeRubberBandSelection()
{
vtkPoints backgroundPoints = vtkPoints.New();
backgroundPoints.SetNumberOfPoints(4);
backgroundPoints.SetPoint(0, 0.0, 0.0, 0.0);
backgroundPoints.SetPoint(1, 10.5, 0.0, 0.0);
backgroundPoints.SetPoint(2, 10.5, 10.5, 0.0);
backgroundPoints.SetPoint(3, 0.0, 10.5, 0.0);
vtkCellArray backgroundPolygon = vtkCellArray.New();
backgroundPolygon.InsertNextCell(4);
backgroundPolygon.InsertCellPoint(0);
backgroundPolygon.InsertCellPoint(1);
backgroundPolygon.InsertCellPoint(2);
backgroundPolygon.InsertCellPoint(3);
vtkPolyData backgroundPolyData = vtkPolyData.New();
backgroundPolyData.SetPoints(backgroundPoints);
backgroundPolyData.SetPolys(backgroundPolygon);
_selectionBackgroundMapper = vtkPolyDataMapper2D.New();
_selectionBackgroundMapper.SetInput(backgroundPolyData);
_selectionBackgroundActor = vtkActor2D.New();
_selectionBackgroundActor.SetMapper(_selectionBackgroundMapper);
_selectionBackgroundActor.GetProperty().SetOpacity(0.2);
_selectionBackgroundActor.VisibilityOff();
_selectionBackgroundActor.GetProperty().SetColor(0.2, 0.5, 1);
_selectionRenderer.AddActor(_selectionBackgroundActor);
vtkCellArray borderPolygon = vtkCellArray.New();
borderPolygon.InsertNextCell(5);
borderPolygon.InsertCellPoint(0);
borderPolygon.InsertCellPoint(1);
borderPolygon.InsertCellPoint(2);
borderPolygon.InsertCellPoint(3);
borderPolygon.InsertCellPoint(0);
vtkPolyData borderPolyData = vtkPolyData.New();
borderPolyData.SetPoints(backgroundPoints);
borderPolyData.SetLines(borderPolygon);
vtkPolyDataMapper2D borderMapper = vtkPolyDataMapper2D.New();
borderMapper.SetInput(borderPolyData);
_selectionBorderActor = vtkActor2D.New();
_selectionBorderActor.SetMapper(borderMapper);
_selectionBorderActor.GetProperty().SetColor(0.3, 0.3, 1.0);
_selectionBorderActor.VisibilityOff();
_selectionRenderer.AddActor(_selectionBorderActor);
}
private void DrawSphereOnLeft(vtkObject sender, vtkObjectEventArgs e)
{
vtkInteractorStyleControl interactor = (vtkInteractorStyleControl)sender;
vtkRenderer renderer = interactor.GetInteractor().GetRenderWindow().GetRenderers().GetFirstRenderer();
int[] clickPos = interactor.GetInteractor().GetEventPosition();
// Pick from this location.
vtkPropPicker picker = vtkPropPicker.New();
//vtkRendererCollection renderers = interactor.GetInteractor().GetRenderWindow().GetRenderers();
//interactor.GetInteractor().GetRenderWindow().RemoveRenderer(renderers.GetNextItem());
renderer.Render(); // to redraw the first layer of geometry
picker.Pick(clickPos[0], clickPos[1], 0, renderer);
double[] pos = picker.GetPickPosition();
Console.WriteLine("Pick position (world coordinates) is: " + pos[0].ToString() + " "
+ pos[1].ToString() + " "
+ pos[2].ToString());
//Console.WriteLine("Picked actor: " + picker.GetActor().ToString());
//Create a sphere
vtkSphereSource sphereSource = vtkSphereSource.New();
sphereSource.SetCenter(pos[0], pos[1], pos[2]);
sphereSource.SetRadius(1);
//Create a mapper and actor
vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
mapper.SetInputConnection(sphereSource.GetOutputPort());
vtkActor actor = vtkActor.New();
actor.SetMapper(mapper);
actor.PickableOff();
//this.GetInteractor().GetRenderWindow().GetRenderers().GetDefaultRenderer().AddActor(actor);
renderer.AddActor(actor);
// Forward events
interactor.OnLeftButtonUp();
this.GetInteractor().Render();
}
}
}