// // (C) Copyright 2003-2019 by Autodesk, Inc. // // Permission to use, copy, modify, and distribute this software in // object code form for any purpose and without fee is hereby granted, // provided that the above copyright notice appears in all copies and // that both that copyright notice and the limited warranty and // restricted rights notice below appear in all supporting // documentation. // // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE // UNINTERRUPTED OR ERROR FREE. // // Use, duplication, or disclosure by the U.S. Government is subject to // restrictions set forth in FAR 52.227-19 (Commercial Computer // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. // using System; using System.Collections.Generic; using System.Text; using System.Drawing; using Autodesk.Revit.DB; using System.Windows.Forms; using Point = System.Drawing.Point; namespace Revit.SDK.Samples.NewHostedSweep.CS { /// /// This class is intent to convenience the geometry transformations. /// It can produce rotation and scale transformations. /// public class TrackBall { /// /// Canvas width. /// private float m_canvasWidth; /// /// Canvas height. /// private float m_canvasHeight; /// /// Previous position in 2D. /// private Point m_previousPosition2D; /// /// Previous position in 3D. /// private XYZ m_previousPosition3D; /// /// Current rotation transform. /// private Transform m_rotation = Transform.Identity; /// /// Current scale transform. /// private double m_scale; /// /// Current rotation transform. /// public Transform Rotation { get { return m_rotation; } set { m_rotation = value; } } /// /// Current scale transform. /// public double Scale { get { return m_scale; } set { m_scale = value; } } /// /// Project canvas 2D point to the track ball. /// /// Canvas width /// Canvas height /// 2D point /// Projected point in track ball private XYZ ProjectToTrackball(double width, double height, Point point) { double x = point.X / (width / 2); // Scale so bounds map to [0,0] - [2,2] double y = point.Y / (height / 2); x = x - 1; // Translate 0,0 to the center y = 1 - y; // Flip so +Y is up instead of down double d, t, z; d = Math.Sqrt(x * x + y * y); if (d < 0.70710678118654752440) { /* Inside sphere */ z = Math.Sqrt(1 - d * d); } else { /* On hyperbola */ t = 1 / 1.41421356237309504880; z = t * t / d; } return new XYZ(x, y, z); } /// /// Yield the rotation transform according to current 2D point in canvas. /// /// 2D point in canvas private void Track(Point currentPosition) { XYZ currentPosition3D = ProjectToTrackball( m_canvasWidth, m_canvasHeight, currentPosition); XYZ axis = m_previousPosition3D.CrossProduct(currentPosition3D); if (axis.GetLength() == 0) return; double angle = m_previousPosition3D.AngleTo(currentPosition3D); m_rotation = Transform.CreateRotation(axis, -angle); m_previousPosition3D = currentPosition3D; } /// /// Yield the scale transform according to current 2D point in canvas. /// /// 2D point in canvas private void Zoom(Point currentPosition) { double yDelta = currentPosition.Y - m_previousPosition2D.Y; double scale = Math.Exp(yDelta / 100); // e^(yDelta/100) is fairly arbitrary. m_scale = scale; } /// /// Mouse down, initialize the transformation to identity. /// /// Canvas width /// Canvas height /// public void OnMouseDown(float width, float height, MouseEventArgs e) { m_rotation = Transform.Identity; m_scale = 1.0; m_canvasWidth = width; m_canvasHeight = height; m_previousPosition2D = e.Location; m_previousPosition3D = ProjectToTrackball(m_canvasWidth, m_canvasHeight, m_previousPosition2D); } /// /// Mouse move with left button press will yield the rotation transform, /// with right button press will yield scale transform. /// /// public void OnMouseMove(MouseEventArgs e) { Point currentPosition = e.Location; // avoid any zero axis conditions if (currentPosition == m_previousPosition2D) return; // Prefer tracking to zooming if both buttons are pressed. if (e.Button == MouseButtons.Left) { Track(currentPosition); } else if (e.Button == MouseButtons.Right) { Zoom(currentPosition); } m_previousPosition2D = currentPosition; } /// /// Arrows key down will also yield the rotation transform. /// /// public void OnKeyDown(KeyEventArgs e) { XYZ axis = new XYZ(1.0, 0, 0); double angle = 0.1; switch (e.KeyCode) { case Keys.Down: break; case Keys.Up: angle = -angle; break; case Keys.Left: axis = new XYZ(0, 1.0, 0); angle = -angle; break; case Keys.Right: axis = new XYZ(0, 1.0, 0); break; default: break; } m_rotation = Transform.CreateRotation(axis, angle); } } }