private void AnimateRestoreView() { FastDrawing = true; var restoreViewCurrentTime = DateTime.Now; var currentTime = restoreViewCurrentTime; var startTime = RestoreViewStartTime; var timeElapsed = currentTime.Subtract(startTime); var timeElapsedInMs = timeElapsed.TotalMilliseconds; var totalTimeOfAnimationInMs = RestoreViewTotalTime.TotalMilliseconds; double percentCompleted = timeElapsedInMs / totalTimeOfAnimationInMs; if (percentCompleted > 1) { // Animation is completed. Perform one last draw. percentCompleted = 1; IsInAnimatedRestoreView = false; View.UserInteractionEnabled = true; CameraIsAtInitialPosition = !ShouldStartRestoreToInitialPosition; AnimationTimer.Invalidate(); } // Get some data from the starting view Rhino.Geometry.Point3d sourceTarget = RestoreViewStartViewport.TargetPoint; Rhino.Geometry.Point3d sourceCamera = RestoreViewStartViewport.CameraLocation; double sourceDistance = sourceCamera.DistanceTo(sourceTarget); Rhino.Geometry.Vector3d sourceUp = RestoreViewStartViewport.CameraUp; sourceUp.Unitize(); // Get some data from the ending view Rhino.Geometry.Point3d targetTarget = RestoreViewFinishViewport.TargetPoint; Rhino.Geometry.Point3d targetCamera = RestoreViewFinishViewport.CameraLocation; double targetDistance = targetCamera.DistanceTo(targetTarget); Rhino.Geometry.Vector3d targetCameraDir = targetCamera - targetTarget; Rhino.Geometry.Vector3d targetUp = RestoreViewFinishViewport.CameraUp; targetUp.Unitize(); // Adjust the target camera location so that the starting camera to target distance // and the ending camera to target distance are the same. Doing this will calculate // a constant rotational angular momentum when tweening the camera location. // Further down we independently tween the camera to target distance. targetCameraDir.Unitize(); targetCameraDir *= sourceDistance; targetCamera = targetCameraDir + targetTarget; // calculate interim viewport values double frameDistance = ViewportInfoExtensions.CosInterp(sourceDistance, targetDistance, percentCompleted); Rhino.Geometry.Point3d frameTarget = new Rhino.Geometry.Point3d(); frameTarget.X = ViewportInfoExtensions.CosInterp(sourceTarget.X, targetTarget.X, percentCompleted); frameTarget.Y = ViewportInfoExtensions.CosInterp(sourceTarget.Y, targetTarget.Y, percentCompleted); frameTarget.Z = ViewportInfoExtensions.CosInterp(sourceTarget.Z, targetTarget.Z, percentCompleted); var origin = Rhino.Geometry.Point3d.Origin; Rhino.Geometry.Point3d frameCamera = origin + (ViewportInfoExtensions.Slerp((sourceCamera - origin), (targetCamera - origin), percentCompleted)); Rhino.Geometry.Vector3d frameCameraDir = frameCamera - frameTarget; // adjust the camera location along the camera direction vector to preserve the target location and the camera distance frameCameraDir.Unitize(); frameCameraDir *= frameDistance; frameCamera = frameCameraDir + frameTarget; Rhino.Geometry.Vector3d frameUp = new Rhino.Geometry.Vector3d(ViewportInfoExtensions.Slerp(sourceUp, targetUp, percentCompleted)); if (percentCompleted >= 1) { // put the last redraw at the exact end point to eliminate any rounding errors Camera.SetTarget(RestoreViewFinishViewport.TargetPoint, RestoreViewFinishViewport.CameraLocation, RestoreViewFinishViewport.CameraUp); } else { Camera.SetTarget(frameTarget, frameCamera, frameUp); } SetFrustum(Camera, App.Manager.CurrentModel.BBox); View.SetNeedsDisplay(); if (!IsInAnimatedRestoreView) { // FastDrawing is still enabled and we just scheduled a draw of the model at the final location. // This entirely completes the animation. Now schedule one more redraw of the model with FastDrawing disabled // and this redraw will be done at exactly the same postion. This prevents the final animation frame // from jumping to the final location because the final draw will take longer with FastDrawing disabled. PerformSelector(new Selector("RedrawDetailed"), null, 0.05); } }