//------------------------------------------------------------------
//
// The following article discusses the mechanics behind this
// trackball implementation: http://viewport3d.com/trackball.htm
//
// Reading the article is not required to use this sample code,
// but skimming it might be useful.
//
// For licensing information and to get the latest version go to:
// http://workspaces.gotdotnet.com/3dtools
//
//------------------------------------------------------------------
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Controls;
using Petzold.Media3D;
namespace Xenki.DefaultRenderer
{
public class CameraControl
{
private FrameworkElement _eventSource;
private Point _previousPosition2D;
private Vector3D _previousPosition3D = new Vector3D(0, 0, 1);
private Transform3DGroup _transform;
private ScaleTransform3D _scale = new ScaleTransform3D();
private AxisAngleRotation3D _rotation = new AxisAngleRotation3D();
private TranslateTransform3D _translate = new TranslateTransform3D();
private Vector3D _cameraLookDirection = new Vector3D(128, 128, 10);
private PerspectiveCamera _camera;
private Point3D _cameraLookPoint;
private RotateTransform3D _rotationTransform = new RotateTransform3D();
ModelVisual3D clickedVisual;
private TranslateTransform3D _clickedTranslate = new TranslateTransform3D();
bool isTracking = false;
public CameraControl(PerspectiveCamera camera)
{
_camera = camera;
_rotationTransform.Rotation = _rotation;
_transform = new Transform3DGroup();
//_transform.Children.Add(_translate);
_transform.Children.Add(_rotationTransform);
// _transform.Children.Add(_scale);
}
///
/// A transform to move the camera or scene to the trackball's
/// current orientation and scale.
///
public Transform3DGroup Transform
{
get { return _transform; }
}
#region Event Handling
///
/// The FrameworkElement we listen to for mouse events.
///
public FrameworkElement EventSource
{
get { return _eventSource; }
set
{
if (_eventSource != null)
{
_eventSource.MouseWheel -= _eventSource_MouseWheel;
_eventSource.MouseUp -= this.OnMouseUp;
_eventSource.MouseMove -= this.OnMouseMove;
_eventSource.MouseLeftButtonDown -= _eventSource_MouseLeftButtonDown;
}
_eventSource = value;
_eventSource.MouseWheel += _eventSource_MouseWheel;
_eventSource.MouseLeftButtonDown += new MouseButtonEventHandler(_eventSource_MouseLeftButtonDown);
_eventSource.MouseUp += this.OnMouseUp;
_eventSource.MouseMove += this.OnMouseMove;
}
}
void _eventSource_MouseWheel(object sender, MouseWheelEventArgs e)
{
double scale = e.Delta / 1200.00;
double distance = Point3D.Subtract(_cameraLookPoint, _camera.Position).Length;
if (distance > 1024 || distance <= 0.5)
{
if (touch == false)
{
touch = true;
}
}
else
{
touch = false;
}
if (touch == true)
scale = -scale;
_camera.Position = new Point3D(_camera.Position.X - scale * _cameraLookDirection.X, _camera.Position.Y - scale * _cameraLookDirection.Y, _camera.Position.Z - scale * _cameraLookDirection.Z);
_camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position);
}
void _eventSource_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(EventSource, CaptureMode.Element);
Point pclick = e.GetPosition(EventSource);
HitTestResult hitresult = VisualTreeHelper.HitTest(EventSource, pclick);
RayMeshGeometry3DHitTestResult result3d = hitresult as RayMeshGeometry3DHitTestResult;
if (result3d == null)
return;
ModelVisual3D visul3d = result3d.VisualHit as ModelVisual3D;
if (visul3d == null)
return;
_clickedTranslate = visul3d.Transform as TranslateTransform3D;
if (_clickedTranslate == null)
return;
clickedVisual = visul3d;
clickedVisual.Transform = _clickedTranslate;
Petzold.Media3D.LineRange line;
Petzold.Media3D.ViewportInfo.Point2DtoPoint3D(_eventSource as Viewport3D, pclick, out line);
_cameraLookPoint = line.PointFromY(visul3d.Content.Bounds.Y);
_rotationTransform.CenterX = _cameraLookPoint.X;
_rotationTransform.CenterY = _cameraLookPoint.Y;
_rotationTransform.CenterZ = _cameraLookPoint.Z;
_cameraLookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position);
_camera.LookDirection = _cameraLookDirection;
isTracking = true;
_eventSource.CaptureMouse();
_eventSource.Focus();
e.Handled = true;
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
Mouse.Capture(EventSource, CaptureMode.None);
isTracking = false;
_eventSource.ReleaseMouseCapture();
_eventSource.Cursor = Cursors.Arrow;
string mmm = mm;
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
Point currentPosition = e.GetPosition(EventSource);
if (e.RightButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)))
{
LookUpDown(currentPosition);
}
else if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)))
{
if (isTracking)
{
_eventSource.Cursor = Cursors.None;
Focus(currentPosition);
}
}
else if (e.RightButton == MouseButtonState.Pressed && Keyboard.IsKeyDown(Key.Q))
{
CameraPanUP(currentPosition);
}
else if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
{
PanObject(currentPosition);
}
_previousPosition2D = currentPosition;
}
private void PanObject(Point currentPosition)
{
double scale = currentPosition.Y - _previousPosition2D.Y;
scale = scale / 5;
LineRange range;
ViewportInfo.Point2DtoPoint3D(_eventSource as Viewport3D, currentPosition, out range);
Point3D pointNew = range.PointFromZ(clickedVisual.Content.Bounds.X);
//Vector3D v = pointNew- new Point3D(clickedVisual.Content.Bounds.X,clickedVisual.Content.Bounds.Y,clickedVisual.Content.Bounds.Z);
Vector3D vectMouse = pointNew - _cameraLookPoint;
_clickedTranslate.OffsetX = _clickedTranslate.OffsetX + vectMouse.X;
_clickedTranslate.OffsetY = _clickedTranslate.OffsetY + vectMouse.Y;
_clickedTranslate.OffsetZ = _clickedTranslate.OffsetZ + vectMouse.Z;
//_camera.LookDirection = new Vector3D(_camera.LookDirection.X, _camera.LookDirection.Y, _camera.LookDirection.Z + scale);
}
#endregion Event Handling
private void LookUpDown(Point currentPosition)
{
double scale = currentPosition.Y- _previousPosition2D.Y;
scale = scale/5;
_camera.LookDirection = new Vector3D(_camera.LookDirection.X, _camera.LookDirection.Y, _camera.LookDirection.Z + scale);
}
string mm = "";
bool touch = false;
private void Focus(Point currentPosition)
{
double yDelta = currentPosition.Y - _previousPosition2D.Y;
double scale = yDelta / 100;
//Maybe this part need replaced by collision detection method
double distance = Point3D.Subtract(_cameraLookPoint, _camera.Position).Length;
if (distance > 1024 || distance <= 0.5)
{
if (touch == false)
touch = true;
}
else
{
touch = false;
}
if (touch == true)
scale = -scale;
_camera.Position = new Point3D(_camera.Position.X - scale * _cameraLookDirection.X, _camera.Position.Y - scale * _cameraLookDirection.Y, _camera.Position.Z - scale * _cameraLookDirection.Z);
//_translate.OffsetX -= scale * _cameraLookDirection.X;// _camera.LookDirection.X;
//_translate.OffsetY -= scale * _cameraLookDirection.Y;//_camera.LookDirection.Y;
//_translate.OffsetZ -= scale * _cameraLookDirection.Z;//_camera.LookDirection.Z;
_camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position);
double axisAngle = currentPosition.X - _previousPosition2D.X;
double angletimes = axisAngle;
if (angletimes > 360 || angletimes < -360)
angletimes = 0;
if (angletimes + _rotation.Angle >= 360)
_rotation.Angle = 0;
_rotation.Axis = new Vector3D(0, 0, 1);
_rotation.Angle += axisAngle;
}
public HitTestResultBehavior HitTestCallback(HitTestResult result)
{
if (result.VisualHit != null)
{
return HitTestResultBehavior.Stop;
}
return HitTestResultBehavior.Continue;
}
private void CameraPanUP(Point currentPosition)
{
double yDelta = currentPosition.Y - _previousPosition2D.Y;
double xDelta = currentPosition.X - _previousPosition2D.X;
double scale = yDelta / 10;
_camera.Position = new Point3D(_camera.Position.X, _camera.Position.Y, _camera.Position.Z + scale);
}
}
}