Пример #1
0
 /// <summary>
 /// Change orientation of bubble surface or tube
 /// </summary>
 /// <param name="e">Event arguments</param>
 private void ChangeLevelOrientation(DeviceOrientationChangedEventArgs e)
 {
     _bubbleSpeed = new Simple3DVector();
     if (DeviceOrientationHelper.IsFlat(e.CurrentOrientation))
     {
         SurfaceShown = true;
         DeviceOrientationInfo priorDoi = DeviceOrientationHelper.GetDeviceOrientationInfo(e.PreviousOrientation);
         _bubblePosition = new Simple3DVector(priorDoi.NormalGravityVector.X, priorDoi.NormalGravityVector.Y, 0);
     }
     else
     {
         DeviceOrientationInfo doi = DeviceOrientationHelper.GetDeviceOrientationInfo(e.CurrentOrientation);
         if (DeviceOrientationHelper.IsFlat(e.PreviousOrientation) || (e.PreviousOrientation == DeviceOrientation.Unknown))
         {
             MoveLevel.Angle = doi.AngleOnXYPlan;
             _bubblePosition = new Simple3DVector();
             SurfaceShown    = false;
         }
         double accumulatedLoops = MoveLevel.Angle / 360;
         accumulatedLoops          = Math.Floor(accumulatedLoops + 0.5);
         _tubeRotationAnimation.To = 360 * accumulatedLoops + doi.AngleOnXYPlan;
         if ((_tubeRotationAnimation.To - MoveLevel.Angle) > 180)
         {
             _tubeRotationAnimation.To -= 360;
         }
         if ((_tubeRotationAnimation.To - MoveLevel.Angle) < -180)
         {
             _tubeRotationAnimation.To += 360;
         }
         _tubeRotationStoryboard.Begin();
         _bubbleDirection = doi.HorizontalAxisPolarity;
     }
     _levelOrientation = e.CurrentOrientation;
 }
Пример #2
0
        /// <summary>
        /// Update the tube level visuals
        /// </summary>
        private void UpdateTubeBubble(AccelerometerHelperReadingEventArgs e)
        {
            // ANGLE TEXT
            // ----------

            // Use filtered accelemeter data (st5ady)
            double x = e.OptimallyFilteredAcceleration.X;
            double y = e.OptimallyFilteredAcceleration.Y;
            double horizontalAcceleration;
            double verticalAcceleration;

            // Choose appropriate axis based on orientation of level
            horizontalAcceleration = _bubbleDirection * (DeviceOrientationHelper.IsPortrait(_levelOrientation) ? x : y);
            verticalAcceleration   = _bubbleDirection * (DeviceOrientationHelper.IsPortrait(_levelOrientation) ? y : -x); // rotate XY plan by -90

            // Convert acceleration vector coordinates to Angles and Magnitude
            // Update reading on screen of instant inclination assuming steady device (gravity = measured acceleration)
            double magnitudeXYZ = e.OptimallyFilteredAcceleration.Magnitude;
            double angle        = 0.0;

            if (magnitudeXYZ != 0.0)
            {
                angle = Math.Asin(horizontalAcceleration / magnitudeXYZ) * 180.0 / Math.PI;
            }
            _angle = angle;
            // Display angles as if they were buoyancy force instead of gravity (opposite) since it is
            // more natural to match targeted bubble location
            _angleText = String.Format("{0:0.0}°", _angle);

            // BUBBLE POSITION
            // ---------------

            // ----------------------------------------------------------
            // For simplicity we are approximating that the bubble experiences a lateral attraction force
            // proportional to the distance to its target location (top of the glass based on inclination).
            // We will neglect the vertical speed of the bubble since the radius of the glass curve is much greater
            // than the radius of radius of usable glass surface

            // Assume tube curve has a 1m radius
            // Destination position is x and y
            // Current position is _bubblePosition.X (use only one dimension)

            // Update Buoyancy
            double lateralAcceleration = (horizontalAcceleration - _bubblePosition.X) * BuoyancyCoef * StandardGravityInMetric;

            // Update drag:
            double drag = _bubbleSpeed.X * (-ViscosityCoef);

            // Update speed:
            lateralAcceleration += drag;
            lateralAcceleration /= AccelerometerRefreshRate; // impulse
            _bubbleSpeed        += new Simple3DVector(lateralAcceleration, 0, 0);

            // Update position
            _bubblePosition += (_bubbleSpeed / AccelerometerRefreshRate);

            double edgeRadius = Math.Sin(EdgeGlassAngle);

            // Get resulting direction and magnitude of bubble position given X
            double magnitudeFlat = Math.Abs(_bubblePosition.X);
            double direction     = Math.Sign(_bubblePosition.X);

            bool atEdge = false;

            if (magnitudeFlat > edgeRadius)
            { // Bubble reaches the edge
                magnitudeFlat = edgeRadius;
                // lossy bouncing when reaching edges
                // change direction
                _bubbleSpeed *= -EdgeBouncingLossCoef;
                // limit bubble position to edge
                _bubblePosition = new Simple3DVector(magnitudeFlat * direction, 0, 0);
                atEdge          = true;
            }

            // Calculate position of bubble
            MoveBubble.X = (_bubblePosition.X / edgeRadius) * ((UsableLateralAmplitude / 2) - (BubbleCanvas.Width / 4));

            // Change bubble shape
            double stretchRatio;

            if (atEdge)
            {
                TubeBubbleSkew.AngleX  = 0;
                stretchRatio           = 1.0 + (Math.Abs(Math.Sin(angle / 180.0 * Math.PI)) - Math.Sin(EdgeGlassAngle)) * AngleBasedTubeBubbleStrechingAtEdgeCoef;
                TubeBubbleScale.ScaleX = 1.0 / stretchRatio;
                TubeBubbleScale.ScaleY = SideWayBubbleAtEdgeBoostOnYAxis * stretchRatio;
            }
            else
            {
                double horizontalSpeed     = Math.Abs(_bubbleSpeed.X);
                double horizontalDirection = Math.Sign(_bubbleSpeed.X);
                // Stretch is proportional to horizontal speed
                stretchRatio = Math.Min(horizontalSpeed * SpeedBubbleStrechingCoef, MaximumBubbleXYStretchRatio - 1.0) + 1.0;
                if (stretchRatio < MinimumStretchRatio)
                {
                    stretchRatio = MinimumStretchRatio;
                }
                TubeBubbleSkew.AngleX = MaximumTubeBubbleSkew * (stretchRatio - 1.0) / (MaximumBubbleXYStretchRatio - 1.0) * horizontalDirection;
                // Stretch is also proportional to buoyancy
                stretchRatio -= TubeBubbleStretchBuoyancyCoef * ((verticalAcceleration / magnitudeXYZ) - MedianVerticalAcceleration);
                if (stretchRatio < MinimumStretchRatio)
                {
                    stretchRatio = MinimumStretchRatio;
                }
                TubeBubbleScale.ScaleX = 1.0 / stretchRatio;
                TubeBubbleScale.ScaleY = MaximumBubbleXYStretchRatio * stretchRatio;
            }
        }