public override void Draw(Android.Graphics.Canvas canvas)
        {
            base.Draw(canvas);

            var rect = new RectF(0,0,300,300);
            switch (TheShape)
            {
                case Shape.Circle:
                    canvas.DrawOval(rect, new Paint() { Color = Color.Aqua });
                    break;
                case Shape.Square:
                    canvas.DrawRect(rect, new Paint() { Color = Color.Red });
                    break;
                case Shape.Triangle:
                    var path = new Path();
                    path.MoveTo(rect.CenterX(), 0);
                    path.LineTo(0, rect.Height());
                    path.LineTo(rect.Width(), rect.Height());
                    path.Close();

                    var paint = new Paint() {Color = Color.Magenta};
                    paint.SetStyle(Paint.Style.Fill);
                    canvas.DrawPath(path, paint);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    public Transition(RectF srcRect, RectF dstRect, long duration, IInterpolator interpolator) {
        if (!MathUtils.HaveSameAspectRatio(srcRect, dstRect)) {
            throw new IncompatibleRatioException();
        }
        _mSrcRect = srcRect;
        _mDstRect = dstRect;
        _mDuration = duration;
        _mInterpolator = interpolator;

        // Precomputes a few variables to avoid doing it in onDraw().
        _mWidthDiff = dstRect.Width() - srcRect.Width();
        _mHeightDiff = dstRect.Height() - srcRect.Height();
        _mCenterXDiff = dstRect.CenterX() - srcRect.CenterX();
        _mCenterYDiff = dstRect.CenterY() - srcRect.CenterY();
    }
Beispiel #3
0
        protected override void Draw(Canvas canvas, Rect bounds)
        {
            RectF arcBounds = mTempBounds;

            arcBounds.Set(bounds);
            arcBounds.Inset(mStrokeInset, mStrokeInset);
            mCurrentBounds.Set(arcBounds);

            int saveCount = canvas.Save();

            //draw circle trim
            float startAngle = (mStartTrim + mRotation) * 360;
            float endAngle   = (mEndTrim + mRotation) * 360;
            float sweepAngle = endAngle - startAngle;

            if (sweepAngle != 0)
            {
                mPaint.Color = new Color(mColor);
                mPaint.SetStyle(Paint.Style.Stroke);
                canvas.DrawArc(arcBounds, startAngle, sweepAngle, false, mPaint);
            }

            //draw water wave
            if (mWaveProgress < 1.0f)
            {
                var nColor = new Color(mColor);


                mPaint.Color = Color.Argb((int)(Color.GetAlphaComponent(mColor) * (1.0f - mWaveProgress)), Color.GetRedComponent(mColor), Color.GetGreenComponent(mColor), Color.GetBlueComponent(mColor));

                mPaint.SetStyle(Paint.Style.Stroke);
                float radius = Math.Min(arcBounds.Width(), arcBounds.Height()) / 2.0f;
                canvas.DrawCircle(arcBounds.CenterX(), arcBounds.CenterY(), radius * (1.0f + mWaveProgress), mPaint);
            }
            //draw ball bounce
            if (mPathMeasure != null)
            {
                mPaint.Color = new Color(mBallColor);
                mPaint.SetStyle(Paint.Style.Fill);
                canvas.DrawCircle(mCurrentPosition[0], mCurrentPosition[1], mSkipBallSize * mScale, mPaint);
            }

            canvas.RestoreToCount(saveCount);
        }
        protected override void Draw(Canvas canvas, Rect bounds)
        {
            int saveCount = canvas.Save();

            mTempBounds.Set(bounds);
            mTempBounds.Inset(mStrokeInset, mStrokeInset);
            mCurrentBounds.Set(mTempBounds);

            float outerCircleRadius = Math.Min(mTempBounds.Height(), mTempBounds.Width()) / 2.0f;
            float interCircleRadius = outerCircleRadius / 2.0f;
            float centerRingWidth   = interCircleRadius - mStrokeWidth / 2;

            mPaint.SetStyle(Paint.Style.Stroke);
            mPaint.Color       = new Color(mColor);
            mPaint.StrokeWidth = mStrokeWidth;
            canvas.DrawCircle(mTempBounds.CenterX(), mTempBounds.CenterY(), outerCircleRadius, mPaint);
            mPaint.SetStyle(Paint.Style.Fill);
            canvas.DrawCircle(mTempBounds.CenterX(), mTempBounds.CenterY(), interCircleRadius * mScale, mPaint);

            if (mRotation != 0)
            {
                mPaint.Color = new Color(mArcColor);
                mPaint.SetStyle(Paint.Style.Stroke);
                //strokeWidth / 2.0f + mStrokeWidth / 2.0f is the center of the inter circle width
                mTempBounds.Inset(centerRingWidth / 2.0f + mStrokeWidth / 2.0f, centerRingWidth / 2.0f + mStrokeWidth / 2.0f);
                mPaint.StrokeWidth = centerRingWidth;
                canvas.DrawArc(mTempBounds, RING_START_ANGLE, mRotation, false, mPaint);
            }

            mPaint.Color = new Color(mColor);
            mPaint.SetStyle(Paint.Style.Fill);
            for (int i = 0; i < NUM_POINTS; i++)
            {
                canvas.Rotate(i * DANCE_INTERVAL_ANGLE, POINT_X[i], POINT_Y[i]);
                RectF rectF = new RectF(POINT_X[i] - mDanceBallRadius - mShapeChangeWidth / 2.0f, POINT_Y[i] - mDanceBallRadius - mShapeChangeHeight / 2.0f, POINT_X[i] + mDanceBallRadius + mShapeChangeWidth / 2.0f, POINT_Y[i] + mDanceBallRadius + mShapeChangeHeight / 2.0f);
                canvas.DrawOval(rectF, mPaint);
                canvas.Rotate(-i * DANCE_INTERVAL_ANGLE, POINT_X[i], POINT_Y[i]);
            }

            canvas.RestoreToCount(saveCount);
        }
        /// <summary>
        /// Coordinates are approximate, you have better cooperate with the designer's design draft
        /// </summary>
        private Path CreateBalloonPath(RectF balloonRect, float progress)
        {
            Path path = new Path();

            path.MoveTo(balloonRect.CenterX(), balloonRect.Bottom);

            float progressWidth  = balloonRect.Width() * progress;
            float progressHeight = balloonRect.Height() * progress;
            //draw left half
            float leftIncrementX1 = progressWidth * -0.48f;
            float leftIncrementY1 = progressHeight * 0.75f;
            float leftIncrementX2 = progressWidth * -0.03f;
            float leftIncrementY2 = progressHeight * -1.6f;
            float leftIncrementX3 = progressWidth * 0.9f;
            float leftIncrementY3 = progressHeight * -1.0f;

            path.CubicTo(balloonRect.Left + balloonRect.Width() * 0.25f + leftIncrementX1, balloonRect.CenterY() - balloonRect.Height() * 0.4f + leftIncrementY1, balloonRect.Left - balloonRect.Width() * 0.20f + leftIncrementX2, balloonRect.CenterY() + balloonRect.Height() * 1.15f + leftIncrementY2, balloonRect.Left - balloonRect.Width() * 0.4f + leftIncrementX3, balloonRect.Bottom + leftIncrementY3);

            //        the results of the left final transformation
            //        path.cubicTo(balloonRect.left - balloonRect.width() * 0.13f, balloonRect.CenterY() + balloonRect.height() * 0.35f,
            //                balloonRect.left - balloonRect.width() * 0.23f, balloonRect.CenterY() - balloonRect.height() * 0.45f,
            //                balloonRect.left + balloonRect.width() * 0.5f, balloonRect.bottom - balloonRect.height());

            //draw right half
            float rightIncrementX1 = progressWidth * 1.51f;
            float rightIncrementY1 = progressHeight * -0.05f;
            float rightIncrementX2 = progressWidth * 0.03f;
            float rightIncrementY2 = progressHeight * 0.5f;
            float rightIncrementX3 = 0.0f;
            float rightIncrementY3 = 0.0f;

            path.CubicTo(balloonRect.Left - balloonRect.Width() * 0.38f + rightIncrementX1, balloonRect.CenterY() - balloonRect.Height() * 0.4f + rightIncrementY1, balloonRect.Left + balloonRect.Width() * 1.1f + rightIncrementX2, balloonRect.CenterY() - balloonRect.Height() * 0.15f + rightIncrementY2, balloonRect.Left + balloonRect.Width() * 0.5f + rightIncrementX3, balloonRect.Bottom + rightIncrementY3);

            //        the results of the right final transformation
            //        path.cubicTo(balloonRect.left + balloonRect.width() * 1.23f, balloonRect.CenterY() - balloonRect.height() * 0.45f,
            //                balloonRect.left + balloonRect.width() * 1.13f, balloonRect.CenterY() + balloonRect.height() * 0.35f,
            //                balloonRect.left + balloonRect.width() * 0.5f, balloonRect.bottom);

            return(path);
        }
        droidGraphics.Matrix ComputeStretchMatrix()
        {
            droidGraphics.Matrix matrix = new droidGraphics.Matrix();

            // Get the drawable bounds decreased by stroke thickness
            droidGraphics.RectF drawableBounds = new droidGraphics.RectF(drawable.Bounds);
            float halfStrokeWidth = drawable.Paint.StrokeWidth / 2;

            drawableBounds.Left   += halfStrokeWidth;
            drawableBounds.Top    += halfStrokeWidth;
            drawableBounds.Right  -= halfStrokeWidth;
            drawableBounds.Bottom -= halfStrokeWidth;

            switch (stretch)
            {
            case Stretch.None:
                break;

            case Stretch.Fill:
                matrix.SetRectToRect(pathFillBounds, drawableBounds, droidGraphics.Matrix.ScaleToFit.Fill);
                break;

            case Stretch.Uniform:
                matrix.SetRectToRect(pathFillBounds, drawableBounds, droidGraphics.Matrix.ScaleToFit.Center);
                break;

            case Stretch.UniformToFill:
                float widthScale  = drawableBounds.Width() / pathFillBounds.Width();
                float heightScale = drawableBounds.Height() / pathFillBounds.Height();
                float maxScale    = Math.Max(widthScale, heightScale);

                matrix.SetScale(maxScale, maxScale);
                matrix.PostTranslate(drawableBounds.Left - maxScale * pathFillBounds.Left,
                                     drawableBounds.Top - maxScale * pathFillBounds.Top);
                break;
            }
            return(matrix);
        }
		Bitmap GetImage (Color strokeColor, Color fillColor, System.Drawing.SizeF size, float scale, 
		                 bool shouldCrop = true, bool keepAspectRatio = true)
		{
			if (size.Width == 0 || size.Height == 0 || scale <= 0)
				return null;

			float uncroppedScale;
			RectF croppedRectangle = new RectF ();

			System.Drawing.PointF [] cachedPoints;

			if (shouldCrop && (cachedPoints = Points).Any ()) {
				croppedRectangle = getCroppedRectangle (cachedPoints);

				if (croppedRectangle.Left >= 5)
					croppedRectangle.Left -= 5;
				if (croppedRectangle.Right <= size.Width - 5)
					croppedRectangle.Right += 5;
				if (croppedRectangle.Top >= 5)
					croppedRectangle.Top -= 5;
				if (croppedRectangle.Bottom <= size.Height - 5)
					croppedRectangle.Bottom += 5;

				float scaleX = (croppedRectangle.Right - croppedRectangle.Left) / Width;
				float scaleY = (croppedRectangle.Bottom - croppedRectangle.Top) / Height;
				uncroppedScale = 1 / Math.Max (scaleX, scaleY);
			} else {
				uncroppedScale = scale;
			}

			Bitmap image;
			if (keepAspectRatio)
				image = Bitmap.CreateBitmap ((int)size.Width, (int)size.Height, 
					Bitmap.Config.Argb8888);
			else
				image = Bitmap.CreateBitmap ((int)(croppedRectangle.Width () * uncroppedScale), (int)(croppedRectangle.Height () * uncroppedScale),
					Bitmap.Config.Argb8888);
			Canvas canvas = new Canvas (image);
			canvas.Scale (uncroppedScale, uncroppedScale);

			DrawStrokesOnCanvas (canvas, strokeColor, fillColor, shouldCrop, croppedRectangle);

			return image;
		}
Beispiel #8
0
 public static XIR.Rectangle RemoteRepresentation(this AG.RectF rectangle)
 => new XIR.Rectangle(
     rectangle.Left,
     rectangle.Top,
     rectangle.Width(),
     rectangle.Height());
Beispiel #9
0
 public static RectangleF ToEto(this ag.RectF rect)
 {
     return(new RectangleF(rect.Left, rect.Top, rect.Width(), rect.Height()));
 }
        public void Setup(Matrix m, Rect imageRect, RectF cropRect, bool maintainAspectRatio)
        {
            matrix = new Matrix(m);

            this.cropRect = cropRect;
            this.imageRect = new RectF(imageRect);
            this.maintainAspectRatio = maintainAspectRatio;

            initialAspectRatio = cropRect.Width() / cropRect.Height();
            DrawRect = computeLayout();

            focusPaint.SetARGB(125, 50, 50, 50);
            noFocusPaint.SetARGB(125, 50, 50, 50);
            outlinePaint.StrokeWidth = 3;
            outlinePaint.SetStyle(Paint.Style.Stroke);
            outlinePaint.AntiAlias = true;

            mode = ModifyMode.None;
            init();
        }
        // Grows the cropping rectange by (dx, dy) in image space.
        private void growBy(float dx, float dy)
        {
            if (maintainAspectRatio)
            {
                if (dx != 0)
                {
                    dy = dx / initialAspectRatio;
                }
                else if (dy != 0)
                {
                    dx = dy * initialAspectRatio;
                }
            }

            // Don't let the cropping rectangle grow too fast.
            // Grow at most half of the difference between the image rectangle and
            // the cropping rectangle.
            RectF r = new RectF(cropRect);
            if (dx > 0F && r.Width() + 2 * dx > imageRect.Width())
            {
                float adjustment = (imageRect.Width() - r.Width()) / 2F;
                dx = adjustment;
                if (maintainAspectRatio)
                {
                    dy = dx / initialAspectRatio;
                }
            }
            if (dy > 0F && r.Height() + 2 * dy > imageRect.Height())
            {
                float adjustment = (imageRect.Height() - r.Height()) / 2F;
                dy = adjustment;
                if (maintainAspectRatio)
                {
                    dx = dy * initialAspectRatio;
                }
            }

            r.Inset(-dx, -dy);

            // Don't let the cropping rectangle shrink too fast.
            float widthCap = 25F;
            if (r.Width() < widthCap)
            {
                r.Inset(-(widthCap - r.Width()) / 2F, 0F);
            }
            float heightCap = maintainAspectRatio
                ? (widthCap / initialAspectRatio)
                    : widthCap;
            if (r.Height() < heightCap)
            {
                r.Inset(0F, -(heightCap - r.Height()) / 2F);
            }

            // Put the cropping rectangle inside the image rectangle.
            if (r.Left < imageRect.Left)
            {
                r.Offset(imageRect.Left - r.Left, 0F);
            }
            else if (r.Right > imageRect.Right)
            {
                r.Offset(-(r.Right - imageRect.Right), 0);
            }
            if (r.Top < imageRect.Top)
            {
                r.Offset(0F, imageRect.Top - r.Top);
            }
            else if (r.Bottom > imageRect.Bottom)
            {
                r.Offset(0F, -(r.Bottom - imageRect.Bottom));
            }

            cropRect.Set(r);
            DrawRect = computeLayout();
            context.Invalidate();
        }
Beispiel #12
0
		Bitmap GetImage (Color strokeColor, Color fillColor, System.Drawing.SizeF size, float scale, 
		                 bool shouldCrop = true)
		{
			if (size.Width == 0 || size.Height == 0 || scale <= 0)
				return null;

			float uncroppedScale;
			System.Drawing.SizeF uncroppedSize;
			RectF croppedRectangle;

			if (shouldCrop && Points.Count () != 0) {
				croppedRectangle = getCroppedRectangle ();
				float scaleX = (croppedRectangle.Right - croppedRectangle.Left) / Width;
				float scaleY = (croppedRectangle.Bottom - croppedRectangle.Top) / Height;
				uncroppedScale = 1 / Math.Max (scaleX, scaleY);
				//uncroppedScale = 1 / getScaleFromSize (croppedRectangle.Size, Bounds);
				uncroppedSize = getSizeFromScale (uncroppedScale, size.Width, size.Height);
			} else {
				uncroppedScale = scale;
				uncroppedSize = size;
			}

			Bitmap image = Bitmap.CreateBitmap ((int)uncroppedSize.Width, (int)uncroppedSize.Height, 
			                                    Bitmap.Config.Argb8888);
			Canvas canvas = new Canvas (image);
			canvas.Scale (uncroppedScale, uncroppedScale);

			DrawStrokesOnCanvas (canvas, strokeColor, fillColor);
	
			if (shouldCrop && Points.Count () != 0) {
				croppedRectangle = getCroppedRectangle ();
				RectF scaledRectangle = new RectF (croppedRectangle.Left * uncroppedScale,
				                                   croppedRectangle.Top * uncroppedScale,
				                                   croppedRectangle.Right * uncroppedScale,
				                                   croppedRectangle.Bottom * uncroppedScale);

				if (scaledRectangle.Left >= 5)
					scaledRectangle.Left -= 5;
				if (scaledRectangle.Right <= uncroppedSize.Width - 5)
					scaledRectangle.Right += 5;
				if (scaledRectangle.Top >= 5)
					scaledRectangle.Top -= 5;
				if (scaledRectangle.Bottom <= uncroppedSize.Height - 5)
					scaledRectangle.Bottom += 5;
				image = Bitmap.CreateBitmap (image, 
				                             (int) scaledRectangle.Left, 
				                             (int) scaledRectangle.Top,
				                             (int) scaledRectangle.Width (),
				                             (int) scaledRectangle.Height ());
			}
			return image;
		}
		internal static float GetRectRatio(RectF rect)
		{
			return rect.Width() / rect.Height();
		}
		public override void Draw (Canvas canvas)
		{
			base.Draw (canvas);

			if (!scaled) {

				density = Resources.DisplayMetrics.Density;

				padding *= density;

				lineWidth *= density;

				fontSize *= density;

				scaled = true;
			}


			_highTemps = null;
			_lowTemps = null;

			_hourlyTemps = null;


			if (Forecasts.Count == 0 || Hourly.Count == 0) return;


			graphRect = new RectF (padding, padding, canvas.Width - padding, canvas.Height - padding);// CGRect (rect.X + padding, rect.Y + padding, rect.Width - (padding * 2), rect.Height - (padding * 2));

			var days = Hourly.GroupBy (h => h.FCTTIME.mday).Select (g => g.First ().FCTTIME.weekday_name_abbrev).ToList ();

			var dayCount = hourly ? days.Count : Forecasts.Count;


			var xAxisScale = (graphRect.Width () + padding / 2) / dayCount;

			inset = xAxisScale / 2;


			var highest = (float)(hourly ? HourlyTemps.Max () : HighTemps.Max ());
			var lowest = (float)(hourly ? HourlyTemps.Min () : LowTemps.Min ());


			scaleHigh = (float)Math.Round (highest, MidpointRounding.AwayFromZero);
			scaleLow = lowest < 0 ? (float)Math.Round (lowest, MidpointRounding.AwayFromZero) : (float)Math.Round (lowest);

			var rangePadding = Settings.UomTemperature.IsImperial () ? scalePadding : (scalePadding / 2);


			scaleHigh += rangePadding;
			scaleLow -= rangePadding;

			scaleRange = scaleHigh - scaleLow;


			var scaleIncrement = scaleRange / dividerCount;

			scaleX = (graphRect.Width () - inset) / (hourly ? HourlyTemps.Count : Forecasts.Count);
			scaleY = graphRect.Height () / dividerCount;


			float x, y;

			var white = Color.White;


			// Draw x and y axis
			var paint = new Paint ();
			paint.Color = white;
			paint.StrokeWidth = 1;

			using (Path path = new Path ()) {

				path.MoveTo (graphRect.Left, graphRect.Top);

				path.LineTo (graphRect.Left, graphRect.Bottom);
				path.LineTo (graphRect.Right, graphRect.Bottom);

				paint.SetStyle (Paint.Style.Stroke);

				canvas.DrawPath (path, paint);
			}


			Color translucentBlack = Color.Argb (20, 0, 0, 0);

			paint.Color = translucentBlack;

			paint.SetStyle (Paint.Style.Fill);

			// Draw horizontal gridlines
			for (int i = 1; i < dividerCount; i += 2) {

				y = graphRect.Bottom - ((i + 1) * scaleY);

				using (RectF grid = new RectF (padding, y, graphRect.Right, y + scaleY))
					canvas.DrawRect (grid, paint);
			}


			drawLines (canvas, paint);

			float labelPadding = 6 * density;

			float yStep = scaleLow;

			// Draw y-axis labels
			for (int i = dividerCount; i >= 0; i--) {

				y = padding + (i * scaleY);

				var step = Math.Round (yStep).ToString ();

				drawLabel (canvas, graphRect.Left - labelPadding, y, Paint.Align.Right, step, true);

				yStep += scaleIncrement;
			}


			// Draw x-axis labels
			for (int i = 0; i < dayCount; i++) {

				x = padding + (i * xAxisScale);

				drawLabel (canvas, x, graphRect.Bottom + labelPadding, Paint.Align.Left, hourly ? days [i] : Forecasts [i]?.date?.weekday_short);
			}
		}
Beispiel #15
0
        droidGraphics.LinearGradient CreateLinearGradient(LinearGradientBrush xamBrush,
                                                          droidGraphics.RectF pathBounds,
                                                          droidGraphics.Matrix stretchMatrix)
        {
            if (Path == null)
            {
                return(null);
            }

            int[]   colors  = new int[xamBrush.GradientStops.Count];
            float[] offsets = new float[xamBrush.GradientStops.Count];

            for (int index = 0; index < xamBrush.GradientStops.Count; index++)
            {
                colors[index]  = ConvertColor(xamBrush.GradientStops[index].Color);
                offsets[index] = (float)xamBrush.GradientStops[index].Offset;
            }

            droidGraphics.Shader.TileMode tilemode = droidGraphics.Shader.TileMode.Clamp;

            switch (xamBrush.SpreadMethod)
            {
            case GradientSpreadMethod.Pad:
                tilemode = droidGraphics.Shader.TileMode.Clamp;
                break;

            case GradientSpreadMethod.Refect:
                tilemode = droidGraphics.Shader.TileMode.Mirror;
                break;

            case GradientSpreadMethod.Repeat:
                tilemode = droidGraphics.Shader.TileMode.Repeat;
                break;
            }

            // pathBounds has already been stretched
            using (droidGraphics.RectF xformedBounds = new droidGraphics.RectF(pathBounds))
            {
                if (xamBrush.Transform != null)
                {
                    // But the brush transform offsets needs to be stretched
                    droidGraphics.Matrix transform = xamBrush.Transform.GetNativeObject() as droidGraphics.Matrix;

                    float[] stretchValues = new float[9];
                    stretchMatrix.GetValues(stretchValues);

                    float[] transformValues = new float[9];
                    transform.GetValues(transformValues);

                    // Scale x-offset by stretch
                    transformValues[2] *= stretchValues[0];

                    // Scale y-offset by stretch
                    transformValues[5] *= stretchValues[4];

                    using (droidGraphics.Matrix matx = new droidGraphics.Matrix())
                    {
                        matx.SetValues(transformValues);

                        float[] a2 = new float[9];
                        matx.GetValues(a2);

                        matx.MapRect(xformedBounds);
                    }
                }

                return(new droidGraphics.LinearGradient((float)xamBrush.StartPoint.X * xformedBounds.Width() + xformedBounds.Left,
                                                        (float)xamBrush.StartPoint.Y * xformedBounds.Height() + xformedBounds.Top,
                                                        (float)xamBrush.EndPoint.X * xformedBounds.Width() + xformedBounds.Left,
                                                        (float)xamBrush.EndPoint.Y * xformedBounds.Height() + xformedBounds.Top,
                                                        colors, offsets, tilemode));
            }
        }
		/**
		 * Generates a random rect that can be fully contained within {@code drawableBounds} and
		 * has the same aspect ratio of {@code viewportRect}. The dimensions of this random rect
		 * won't be higher than the largest rect with the same aspect ratio of {@code viewportRect}
		 * that {@code drawableBounds} can contain. They also won't be lower than the dimensions
		 * of this upper rect limit weighted by {@code MIN_RECT_FACTOR}.
		 * @param drawableBounds the bounds of the drawable that will be zoomed and panned.
		 * @param viewportRect the bounds of the view that the drawable will be shown.
		 * @return an arbitrary generated rect with the same aspect ratio of {@code viewportRect}
		 * that will be contained within {@code drawableBounds}.
		 */
		private RectF GenerateRandomRect(RectF drawableBounds, RectF viewportRect)
		{
			float drawableRatio = MathUtils.GetRectRatio(drawableBounds);
			float viewportRectRatio = MathUtils.GetRectRatio(viewportRect);
			RectF maxCrop;

			if (drawableRatio > viewportRectRatio)
			{
				float r = (drawableBounds.Height() / viewportRect.Height()) * viewportRect.Width();
				float b = drawableBounds.Height();
				maxCrop = new RectF(0, 0, r, b);
			}
			else
			{
				float r = drawableBounds.Width();
				float b = (drawableBounds.Width() / viewportRect.Width()) * viewportRect.Height();
				maxCrop = new RectF(0, 0, r, b);
			}

			float randomFloat = MathUtils.Truncate((float)_mRandom.NextDouble(), 2);
			float factor = MIN_RECT_FACTOR + ((1 - MIN_RECT_FACTOR) * randomFloat);

			float width = factor * maxCrop.Width();
			float height = factor * maxCrop.Height();
			int widthDiff = (int)(drawableBounds.Width() - width);
			int heightDiff = (int)(drawableBounds.Height() - height);
			int left = widthDiff > 0 ? _mRandom.Next(widthDiff) : 0;
			int top = heightDiff > 0 ? _mRandom.Next(heightDiff) : 0;
			return new RectF(left, top, left + width, top + height);
		}
        protected internal override void ComputeRender(float renderProgress)
        {
            float radius = Math.Min(mCurrentBounds.Height(), mCurrentBounds.Width()) / 2.0f;
            //the origin coordinate is the centerLeft of the field mCurrentBounds
            float originCoordinateX = mCurrentBounds.Left;
            float originCoordinateY = mCurrentBounds.Top + radius;

            if (renderProgress <= BALL_FORWARD_END_ENTER_DURATION_OFFSET && renderProgress > BALL_FORWARD_START_ENTER_DURATION_OFFSET)
            {
                float ballForwardEnterProgress = (renderProgress - BALL_FORWARD_START_ENTER_DURATION_OFFSET) / (BALL_FORWARD_END_ENTER_DURATION_OFFSET - BALL_FORWARD_START_ENTER_DURATION_OFFSET);

                mShapeChangeHeight = (0.5f - ballForwardEnterProgress) * mDanceBallRadius / 2.0f;
                mShapeChangeWidth  = -mShapeChangeHeight;
                //y = k(x - r)--> k = tan(angle)
                //(x - r)^2 + y^2 = r^2
                // compute crossover point --> (k(x -r)) ^ 2 + (x - )^2 = r^2
                // so x --> [r + r / sqrt(k ^ 2 + 1), r - r / sqrt(k ^ 2 + 1)]
                for (int i = 0; i < NUM_POINTS; i++)
                {
                    float k = (float)Math.Tan((DANCE_START_ANGLE + DANCE_INTERVAL_ANGLE * i) / 360.0f * (2.0f * Math.PI));
                    // progress[-1, 1]
                    float progress = (ACCELERATE_INTERPOLATOR.GetInterpolation(ballForwardEnterProgress) / 2.0f - 0.5f) * 2.0f * DIRECTION[i];
                    POINT_X[i] = (float)(radius + progress * (radius / Math.Sqrt(Math.Pow(k, 2.0f) + 1.0f)));
                    POINT_Y[i] = k * (POINT_X[i] - radius);

                    POINT_X[i] += originCoordinateX;
                    POINT_Y[i] += originCoordinateY;
                }
            }

            if (renderProgress <= RING_FORWARD_END_ROTATE_DURATION_OFFSET && renderProgress > RING_FORWARD_START_ROTATE_DURATION_OFFSET)
            {
                float forwardRotateProgress = (renderProgress - RING_FORWARD_START_ROTATE_DURATION_OFFSET) / (RING_FORWARD_END_ROTATE_DURATION_OFFSET - RING_FORWARD_START_ROTATE_DURATION_OFFSET);
                mRotation = DEGREE_360 * MATERIAL_INTERPOLATOR.GetInterpolation(forwardRotateProgress);
            }

            if (renderProgress <= CENTER_CIRCLE_FORWARD_END_SCALE_DURATION_OFFSET && renderProgress > CENTER_CIRCLE_FORWARD_START_SCALE_DURATION_OFFSET)
            {
                float centerCircleScaleProgress = (renderProgress - CENTER_CIRCLE_FORWARD_START_SCALE_DURATION_OFFSET) / (CENTER_CIRCLE_FORWARD_END_SCALE_DURATION_OFFSET - CENTER_CIRCLE_FORWARD_START_SCALE_DURATION_OFFSET);

                if (centerCircleScaleProgress <= 0.5f)
                {
                    mScale = 1.0f + DECELERATE_INTERPOLATOR.GetInterpolation(centerCircleScaleProgress * 2.0f) * 0.2f;
                }
                else
                {
                    mScale = 1.2f - ACCELERATE_INTERPOLATOR.GetInterpolation((centerCircleScaleProgress - 0.5f) * 2.0f) * 0.2f;
                }
            }

            if (renderProgress <= BALL_FORWARD_END_EXIT_DURATION_OFFSET && renderProgress > BALL_FORWARD_START_EXIT_DURATION_OFFSET)
            {
                float ballForwardExitProgress = (renderProgress - BALL_FORWARD_START_EXIT_DURATION_OFFSET) / (BALL_FORWARD_END_EXIT_DURATION_OFFSET - BALL_FORWARD_START_EXIT_DURATION_OFFSET);
                mShapeChangeHeight = (ballForwardExitProgress - 0.5f) * mDanceBallRadius / 2.0f;
                mShapeChangeWidth  = -mShapeChangeHeight;
                for (int i = 0; i < NUM_POINTS; i++)
                {
                    float k        = (float)Math.Tan((DANCE_START_ANGLE + DANCE_INTERVAL_ANGLE * i) / 360.0f * (2.0f * Math.PI));
                    float progress = (DECELERATE_INTERPOLATOR.GetInterpolation(ballForwardExitProgress) / 2.0f) * 2.0f * DIRECTION[i];
                    POINT_X[i] = (float)(radius + progress * (radius / Math.Sqrt(Math.Pow(k, 2.0f) + 1.0f)));
                    POINT_Y[i] = k * (POINT_X[i] - radius);

                    POINT_X[i] += originCoordinateX;
                    POINT_Y[i] += originCoordinateY;
                }
            }

            if (renderProgress <= RING_REVERSAL_END_ROTATE_DURATION_OFFSET && renderProgress > RING_REVERSAL_START_ROTATE_DURATION_OFFSET)
            {
                float scaledTime = (renderProgress - RING_REVERSAL_START_ROTATE_DURATION_OFFSET) / (RING_REVERSAL_END_ROTATE_DURATION_OFFSET - RING_REVERSAL_START_ROTATE_DURATION_OFFSET);
                mRotation = DEGREE_360 * MATERIAL_INTERPOLATOR.GetInterpolation(scaledTime) - 360;
            }
            else if (renderProgress > RING_REVERSAL_END_ROTATE_DURATION_OFFSET)
            {
                mRotation = 0.0f;
            }

            if (renderProgress <= BALL_REVERSAL_END_ENTER_DURATION_OFFSET && renderProgress > BALL_REVERSAL_START_ENTER_DURATION_OFFSET)
            {
                float ballReversalEnterProgress = (renderProgress - BALL_REVERSAL_START_ENTER_DURATION_OFFSET) / (BALL_REVERSAL_END_ENTER_DURATION_OFFSET - BALL_REVERSAL_START_ENTER_DURATION_OFFSET);
                mShapeChangeHeight = (0.5f - ballReversalEnterProgress) * mDanceBallRadius / 2.0f;
                mShapeChangeWidth  = -mShapeChangeHeight;

                for (int i = 0; i < NUM_POINTS; i++)
                {
                    float k        = (float)Math.Tan((DANCE_START_ANGLE + DANCE_INTERVAL_ANGLE * i) / 360.0f * (2.0f * Math.PI));
                    float progress = (0.5f - ACCELERATE_INTERPOLATOR.GetInterpolation(ballReversalEnterProgress) / 2.0f) * 2.0f * DIRECTION[i];
                    POINT_X[i] = (float)(radius + progress * (radius / Math.Sqrt(Math.Pow(k, 2.0f) + 1.0f)));
                    POINT_Y[i] = k * (POINT_X[i] - radius);

                    POINT_X[i] += originCoordinateX;
                    POINT_Y[i] += originCoordinateY;
                }
            }

            if (renderProgress <= CENTER_CIRCLE_REVERSAL_END_SCALE_DURATION_OFFSET && renderProgress > CENTER_CIRCLE_REVERSAL_START_SCALE_DURATION_OFFSET)
            {
                float centerCircleScaleProgress = (renderProgress - CENTER_CIRCLE_REVERSAL_START_SCALE_DURATION_OFFSET) / (CENTER_CIRCLE_REVERSAL_END_SCALE_DURATION_OFFSET - CENTER_CIRCLE_REVERSAL_START_SCALE_DURATION_OFFSET);

                if (centerCircleScaleProgress <= 0.5f)
                {
                    mScale = 1.0f + DECELERATE_INTERPOLATOR.GetInterpolation(centerCircleScaleProgress * 2.0f) * 0.2f;
                }
                else
                {
                    mScale = 1.2f - ACCELERATE_INTERPOLATOR.GetInterpolation((centerCircleScaleProgress - 0.5f) * 2.0f) * 0.2f;
                }
            }

            if (renderProgress <= BALL_REVERSAL_END_EXIT_DURATION_OFFSET && renderProgress > BALL_REVERSAL_START_EXIT_DURATION_OFFSET)
            {
                float ballReversalExitProgress = (renderProgress - BALL_REVERSAL_START_EXIT_DURATION_OFFSET) / (BALL_REVERSAL_END_EXIT_DURATION_OFFSET - BALL_REVERSAL_START_EXIT_DURATION_OFFSET);
                mShapeChangeHeight = (ballReversalExitProgress - 0.5f) * mDanceBallRadius / 2.0f;
                mShapeChangeWidth  = -mShapeChangeHeight;

                for (int i = 0; i < NUM_POINTS; i++)
                {
                    float k        = (float)Math.Tan((DANCE_START_ANGLE + DANCE_INTERVAL_ANGLE * i) / 360.0f * (2.0f * Math.PI));
                    float progress = (0.0f - DECELERATE_INTERPOLATOR.GetInterpolation(ballReversalExitProgress) / 2.0f) * 2.0f * DIRECTION[i];
                    POINT_X[i] = (float)(radius + progress * (radius / Math.Sqrt(Math.Pow(k, 2.0f) + 1.0f)));
                    POINT_Y[i] = k * (POINT_X[i] - radius);

                    POINT_X[i] += originCoordinateX;
                    POINT_Y[i] += originCoordinateY;
                }
            }
        }
        /// <summary>
        /// Center as much as possible in one or both axis.  Centering is
        /// defined as follows:  if the image is scaled down below the
        /// view's dimensions then center it (literally).  If the image
        /// is scaled larger than the view and is translated out of view
        /// then translate it back into view (i.e. eliminate black bars).
        /// </summary>
        protected void Center(bool horizontal, bool vertical)
        {
            //return;
            if (bitmapDisplayed.Bitmap == null)
            {
                return;
            }

            Matrix m = GetImageViewMatrix();

            RectF rect = new RectF(0, 0,
                                   bitmapDisplayed.Bitmap.Width,
                                   bitmapDisplayed.Bitmap.Height);

            m.MapRect(rect);

            float height = rect.Height();
            float width = rect.Width();

            float deltaX = 0, deltaY = 0;

            if (vertical)
            {
                int viewHeight = Height;
                if (height < viewHeight)
                {
                    deltaY = (viewHeight - height) / 2 - rect.Top;
                }
                else if (rect.Top > 0)
                {
                    deltaY = -rect.Top;
                }
                else if (rect.Bottom < viewHeight)
                {
                    deltaY = Height - rect.Bottom;
                }
            }

            if (horizontal)
            {
                int viewWidth = _width; //Width;
                if (width < viewWidth)
                {
                    deltaX = (viewWidth - width) / 2 - rect.Left;
                }
                else if (rect.Left > 0)
                {
                    deltaX = -rect.Left;
                }
                else if (rect.Right < viewWidth)
                {
                    deltaX = viewWidth - rect.Right;
                }
            }

            PostTranslate(deltaX, deltaY);
            ImageMatrix = GetImageViewMatrix();
        }