public void initialize() { this.selectedBrick = null; this.previousTap = null; this.blockTangibleLastInContact = null; this.lastFineCameraInformation = null; this.rotateOrZoom = false; this.holdingTouchPointID = -1; this.activeTouchPoints = new Dictionary<int, TouchPoint>(); this.holdingTouchPointIds = new List<int>(); this.lastCorkScrewOrientation = -1; Manipulations2D enabledManipulations = Manipulations2D.Rotate | Manipulations2D.Scale | Manipulations2D.Translate; manipulationProcessor = new ManipulationProcessor2D(enabledManipulations); manipulationProcessor.Pivot = new ManipulationPivot2D(); manipulationProcessor.Pivot.Radius = 10; manipulationProcessor.Started += OnManipulationStarted; manipulationProcessor.Delta += OnManipulationDelta; manipulationProcessor.Completed += OnManipulationCompleted; }

public void processTouchPoints(ReadOnlyTouchPointCollection touches, List<BlobPair> blobPairs, GameTime gameTime) { bool corkScrewOnTable = false; bool fineCameraOnTable = false; try { foreach (BlobPair bp in blobPairs) { switch (bp.thisBlobPairTangible.Name) { case ("Jenga Block"): processBlockTangible(bp); break; case ("Cork Screw"): processCorkScrewTangible(bp); corkScrewOnTable = true; break; case ("Fine Camera"): processFineCamera(bp); fineCameraOnTable = true; break; } } } catch (NullReferenceException e) { } if (!corkScrewOnTable) this.lastCorkScrewOrientation = -1; if (!fineCameraOnTable) this.lastFineCameraInformation = null; //========================================================================== foreach (TouchPoint t in touches) { if (t.IsTagRecognized) { switch (t.Tag.Value) { case JengaConstants.STACK_SIDE_0: _viewManager.rotateToSide(0,t); break; case JengaConstants.STACK_SIDE_1: _viewManager.rotateToSide(1, t); break; case JengaConstants.STACK_SIDE_2: _viewManager.rotateToSide(2, t); break; case JengaConstants.STACK_SIDE_3: _viewManager.rotateToSide(3, t); break; case JengaConstants.STACK_SIDE_4: _viewManager.rotateToSide(4, t); break; } } } //========================================================================== //Get center positions of all finger touchpoints float x = 0, y = 0; int count = 0; int firstID = -1; foreach (TouchPoint activeTouchPoint in touches) { if (activeTouchPoint.IsFingerRecognized){ x += activeTouchPoint.X; y += activeTouchPoint.Y; firstID = activeTouchPoint.Id; count++; } } x = x / count; y = y / count; Tuple<SolidThing, Quaternion, float, Vector3> middleBlock = null; if (count > 0) middleBlock = getTouchedBlock(x, y); //Rotation or zoom block if (selectedBrick != null && middleBlock != null && selectedBrick.Item1.Equals(middleBlock.Item1) && activeTouchPoints.Count > 1) { //holdingTouchPointID = -1; List<Manipulator2D> manipulatorList = new List<Manipulator2D>(); foreach (TouchPoint t in touches) { if (t.IsFingerRecognized) manipulatorList.Add(new Manipulator2D(t.Id, t.X, t.Y)); } Manipulator2D[] manipulators = null; manipulators = manipulatorList.ToArray(); try { rotateOrZoom = true; manipulationProcessor.Pivot.X = selectedBrick.Item1.Position.X; manipulationProcessor.Pivot.Y = selectedBrick.Item1.Position.Y; manipulationProcessor.ProcessManipulators(Timestamp, manipulators); //TODO FIXED COLLECTION MODIFIED } catch (NullReferenceException e) { } catch (InvalidOperationException e) { } } //Otherwise if we arent moving the block, move camera else if (holdingTouchPointID == -1) { rotateOrZoom = false; if (activeTouchPoints.Count > 0 && count > 0) { Manipulator2D[] manipulators = null; manipulators = new Manipulator2D[]{new Manipulator2D(firstID, x, y)}; try { manipulationProcessor.ProcessManipulators(Timestamp, manipulators); } catch (NullReferenceException e) { } catch (InvalidOperationException e) { } } } }

private void processFineCamera(BlobPair bp) { bool leftRightDisabled = false; if (this.lastFineCameraInformation != null) { float deltaDegrees = MathHelper.ToDegrees(bp.Orientation - this.lastFineCameraInformation.Orientation); deltaDegrees = deltaDegrees > 180 ? (float)(deltaDegrees - 360) : deltaDegrees; deltaDegrees = deltaDegrees < -180 ? (float)(deltaDegrees + 360) : deltaDegrees; deltaDegrees *= -1; float deltaX = bp.CenterX - this.lastFineCameraInformation.CenterX; float deltaY = bp.CenterY - this.lastFineCameraInformation.CenterY; float newHeightAngle = MathHelper.ToRadians((MathHelper.ToDegrees(_viewManager.HeightAngle) + (JengaConstants.HEIGHT_REVERSED * deltaY / JengaConstants.PAN_SPEED_DIVISOR))); float newRotationAngle; if (leftRightDisabled) { newRotationAngle = (float)(Math.PI - bp.Orientation); } else { newRotationAngle = MathHelper.ToRadians((MathHelper.ToDegrees(_viewManager.RotationAngle) + (JengaConstants.ROTATE_REVERSED * deltaX) / JengaConstants.PAN_SPEED_DIVISOR) + deltaDegrees); } _viewManager.updateCameraPosition(newRotationAngle, newHeightAngle, _viewManager.CameraDistance); } this.lastFineCameraInformation = bp; }

private void processCorkScrewTangible(BlobPair bp) { if (this.selectedBrick != null) { selectedBrick.Item1.LinearVelocity = Vector3.Zero; if (this.lastCorkScrewOrientation != -1) { float deltaDegrees = MathHelper.ToDegrees(bp.Orientation - this.lastCorkScrewOrientation); deltaDegrees = deltaDegrees > 180 ? (float)(deltaDegrees - 360) : deltaDegrees; deltaDegrees = deltaDegrees < -180 ? (float)(deltaDegrees + 360) : deltaDegrees; Vector3 newPosition = selectedBrick.Item1.Position; Vector3 direction = _viewManager.Position - selectedBrick.Item1.Position; direction.Normalize(); float deltaAdd = deltaDegrees * JengaConstants.TANGIBLE_ZOOM_SCALE_FACTOR; newPosition = Vector3.Add(Vector3.Multiply(direction, deltaAdd), selectedBrick.Item1.Position); if (Vector3.Subtract(_viewManager.Position, newPosition).Length() > JengaConstants.MIN_CAMERA_DISTANCE || Vector3.Subtract(_viewManager.Position, newPosition).Length() > Vector3.Subtract(_viewManager.Position, selectedBrick.Item1.Position).Length()) { selectedBrick.Item1.IsActive = true; selectedBrick.Item1.SetWorld(newPosition, selectedBrick.Item2); } } } this.lastCorkScrewOrientation = bp.Orientation; }

private void processBlockTangible(BlobPair bp) { this.blockTangibleLastInContact = new Tuple<BlobPair, long>(bp, Timestamp); if (selectedBrick != null) { Quaternion q = selectedBrick.Item1.Orientation; double yaw = Math.Atan2(2.0 * (q.Y * q.Z + q.W * q.X), q.W * q.W - q.X * q.X - q.Y * q.Y + q.Z * q.Z); double pitch = Math.Asin(-2.0 * (q.X * q.Z - q.W * q.Y)); double roll = Math.Atan2(2.0 * (q.X * q.Y + q.W * q.Z), q.W * q.W + q.X * q.X - q.Y * q.Y - q.Z * q.Z); float scaleFactor = ((Timestamp - begin) / JengaConstants.TIME_FOR_BLOCK_TO_CENTER); scaleFactor = scaleFactor > 1 ? 1 : scaleFactor; scaleFactor = 1 - scaleFactor; //float scaleFactor = 0; float totalRotation; //roll = roll < 0 ? (roll + (2 * Math.PI)) : roll; //totalRotation = (float)(((bp.Orientation - roll) * scaleFactor) + roll); float cameraRotationOffset = MathHelper.ToDegrees(_viewManager.RotationAngle) % 360; cameraRotationOffset = cameraRotationOffset < 0 ? 360 + cameraRotationOffset : cameraRotationOffset; cameraRotationOffset = 360 - cameraRotationOffset; totalRotation = MathHelper.ToRadians(MathHelper.ToDegrees(bp.Orientation) - cameraRotationOffset); Quaternion finalOrientation = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1.0f), totalRotation); Segment s; s.P1 = _game.GraphicsDevice.Viewport.Unproject(new Vector3(bp.CenterX, bp.CenterY, 0f), _viewManager.Projection, _viewManager.DefaultView, Matrix.Identity); s.P2 = _game.GraphicsDevice.Viewport.Unproject(new Vector3(bp.CenterX, bp.CenterY, 1f), _viewManager.Projection, _viewManager.DefaultView, Matrix.Identity); Vector3 diff, point; Vector3.Subtract(ref s.P2, ref s.P1, out diff); Vector3.Multiply(ref diff, this.selectedBrick.Item3, out diff); //TODO FIX NULL REFERENCE(selectedblock) Vector3.Add(ref s.P1, ref diff, out point); Vector3 offset = Vector3.Multiply(this.selectedBrick.Item4, scaleFactor); Vector3 position = Vector3.Add(point, offset); Vector3 directionVector = _viewManager.Position - this.selectedBrick.Item1.Position; directionVector.Normalize(); Vector3 differenceVector = this.selectedBrick.Item1.Position - position; float distance = Vector3.Dot(directionVector, differenceVector); Vector3 additionOntoCurrent = Vector3.Multiply(directionVector, distance); Vector3 finalVector = Vector3.Add(position, additionOntoCurrent); position = finalVector; //******************************************************* //Uncomment this for snapping to middle of tangible block //******************************************************* /*if (!((_viewManager.Position - position).Length() > JengaConstants.MIN_CAMERA_DISTANCE && JengaConstants.TAP_BLOCK_TO_RAISE)){ Vector3 newItem4 = Vector3.Subtract(this.selectedBrick.Item1.Position, point); Vector3 direction = Vector3.Subtract(_viewManager.Position, point); direction.Normalize(); Vector3 newOffset = direction * (Vector3.Dot(direction, newItem4)); position = Vector3.Add(point, newOffset); }*/ //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //Uncomment this for snapping to middle of tangible block //******************************************************* if (!(Vector3.Subtract(position, selectedBrick.Item1.Position).Length() > JengaConstants.MAX_TANGIBLE_DISTANCE)) { selectedBrick = new Tuple<SolidThing, Quaternion, float, Vector3> (selectedBrick.Item1, finalOrientation, selectedBrick.Item3, selectedBrick.Item4); selectedBrick.Item1.SetVelocity(Vector3.Zero, Vector3.Zero); selectedBrick.Item1.SetWorld(position, selectedBrick.Item2); selectedBrick.Item1.IsActive = true; } } }