236 lines
8.4 KiB
C#
236 lines
8.4 KiB
C#
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// DrawingObject.cs
|
|
//
|
|
// This class handles manipulation of the drawing object (rectangle) as a
|
|
// response to multi-touch gestures
|
|
//
|
|
// Initially, we define rectangle to be in the middle of the client area.
|
|
// Whenever user resizes the window the rectangle is placed in the middle of the
|
|
// client area with the width set to a half of the width of the client area and
|
|
// height set to a half of the height of the client area. The rectangle is placed
|
|
// in the center of the client area.
|
|
//
|
|
// Through the gestures user can zoom in, zoom out, move or rotate the rectangle.
|
|
// By invoking two finger tap the user can add/remove diagonals from the drawing.
|
|
//
|
|
// DrawingObject class holds information about the rectangle. Instead of storing
|
|
// two oposite corner points we do calculate them dynamically by using the other
|
|
// information that we store in this class about the rectangle. This way we do
|
|
// not get deformation of the rectangle due to precission issues.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Drawing;
|
|
|
|
namespace Microsoft.Samples.Touch.MTGestures
|
|
{
|
|
public class DrawingObject
|
|
{
|
|
// This is an array of colors that we will shift through when enduser
|
|
// generates press and tap gesture
|
|
static private Color[] _arrColors = new Color[] {
|
|
Color.Black,
|
|
Color.Yellow,
|
|
Color.Red,
|
|
Color.Green,
|
|
Color.Blue
|
|
};
|
|
|
|
// We do retain client area rectangle
|
|
private Rectangle _rcClient;
|
|
|
|
// We do retain center point of the rectangle (diagonals intersection)
|
|
private Point _ptCenter;
|
|
|
|
// Then we keep information about size of the rectangle
|
|
private Size _szRectangle;
|
|
|
|
// Zooming in/out will scale the width and the height by some factor
|
|
private double _dScalingFactor;
|
|
|
|
// Here we store total rotation angle of the rectangle (from x-axis)
|
|
private double _dRotationAngle;
|
|
|
|
// This variable triggers drawing of diagonals if set to true
|
|
bool _bDrawDiagonals;
|
|
|
|
// This variable defines the color of the rectangle (index)
|
|
int _iColorIndex;
|
|
|
|
// Constructor
|
|
public DrawingObject()
|
|
{
|
|
// The main window form is responsible to invoke ResetObject
|
|
// method to initialize variables. This is done in
|
|
// OnSizeChanged method of MTGesturesForm class
|
|
}
|
|
|
|
// This method shifts color index by one
|
|
public void ShiftColor()
|
|
{
|
|
_iColorIndex++;
|
|
_iColorIndex %= _arrColors.Length;
|
|
}
|
|
|
|
// This method resets the rectangle object information and it is called
|
|
// by the main app whenever the user resizes the client area
|
|
// in:
|
|
// rcClient - client area rectangle
|
|
public void ResetObject(Rectangle rcClient)
|
|
{
|
|
// Save client area rectangle
|
|
_rcClient = rcClient;
|
|
|
|
// Initial positon of the rectangle is the center of the client area
|
|
_ptCenter.X = _rcClient.Width / 2;
|
|
_ptCenter.Y = _rcClient.Height / 2;
|
|
|
|
// Initial width and height are half of the size of the client area
|
|
_szRectangle.Width = _rcClient.Width / 2;
|
|
_szRectangle.Height = _rcClient.Height / 2;
|
|
|
|
// Initial scaling factor is 1.0 (no scaling)
|
|
_dScalingFactor = 1.0;
|
|
|
|
// Initial rotation angle is 0.0 (no rotation)
|
|
_dRotationAngle = 0.0; // no rotation intially
|
|
|
|
_bDrawDiagonals = false; // no drawing of the diagonals
|
|
|
|
_iColorIndex = 0; // set initial color to black
|
|
}
|
|
|
|
// This mehod will be called by the MTGesturesForm whenever OnPaint event
|
|
// handler is invoked. It is responsible to redraw the rectangle. Here we
|
|
// calculate the positon of the rectangle corners.
|
|
// in:
|
|
// graphics - Graphics object
|
|
public void Paint(Graphics graphics)
|
|
{
|
|
if (null == graphics)
|
|
{
|
|
// this code should never be executed
|
|
throw new Exception("Invalid graphic object!");
|
|
}
|
|
|
|
// create new pen
|
|
Pen p = new Pen(_arrColors[_iColorIndex]);
|
|
|
|
// first create a polyline that describes the rectangle scaled by the
|
|
// scaling factor
|
|
Point[] arrPts = new Point[5];
|
|
|
|
// upper left cofner
|
|
arrPts[0].X = -(int)(_dScalingFactor * _szRectangle.Width / 2);
|
|
arrPts[0].Y = -(int)(_dScalingFactor * _szRectangle.Height / 2);
|
|
|
|
// upper right corner
|
|
arrPts[1].X = (int)(_dScalingFactor * _szRectangle.Width / 2);
|
|
arrPts[1].Y = arrPts[0].Y;
|
|
|
|
// lower right corner
|
|
arrPts[2].X = arrPts[1].X;
|
|
arrPts[2].Y = (int)(_dScalingFactor * _szRectangle.Height / 2);
|
|
|
|
// lower left corner
|
|
arrPts[3].X = arrPts[0].X;
|
|
arrPts[3].Y = arrPts[2].Y;
|
|
|
|
// upper left corner, we are closing the rectangle
|
|
arrPts[4] = arrPts[0];
|
|
|
|
// now we should rotate and translate the rectangle
|
|
double dCos = Math.Cos(_dRotationAngle);
|
|
double dSin = Math.Sin(_dRotationAngle);
|
|
|
|
for (int j = 0; j < 5; j++)
|
|
{
|
|
int idx = arrPts[j].X;
|
|
int idy = arrPts[j].Y;
|
|
|
|
// rotation
|
|
arrPts[j].X = (int)(idx * dCos + idy * dSin);
|
|
arrPts[j].Y = (int)(idy * dCos - idx * dSin);
|
|
|
|
// translation
|
|
arrPts[j].X += _ptCenter.X;
|
|
arrPts[j].Y += _ptCenter.Y;
|
|
}
|
|
|
|
graphics.DrawLines(p, arrPts);
|
|
|
|
if(_bDrawDiagonals)
|
|
{
|
|
// draw diagonals
|
|
graphics.DrawLine(p, arrPts[0], arrPts[2]);
|
|
graphics.DrawLine(p, arrPts[1], arrPts[3]);
|
|
}
|
|
}
|
|
|
|
// This method is responsible for translating the center of the rectangle.
|
|
// in:
|
|
// deltaX - shift of the x-coordinate
|
|
// deltaY - shift of the y-coordinate
|
|
public void Move(int deltaX,int deltaY)
|
|
{
|
|
_ptCenter.X += deltaX;
|
|
_ptCenter.Y += deltaY;
|
|
}
|
|
|
|
// This method toggles the drawing of the diagonals
|
|
public void ToggleDrawDiagonals()
|
|
{
|
|
_bDrawDiagonals = !_bDrawDiagonals;
|
|
}
|
|
|
|
// This method zooms the rectangle in/out
|
|
// in:
|
|
// zoomFactor - scaling factor of the zoom
|
|
// coefficientX - x coordinate of the zoom center
|
|
// coefficientY - y coordinate of the zoom center
|
|
public void Zoom(double zoomFactor,int coefficientX,int coefficientY)
|
|
{
|
|
_ptCenter.X = RoundAndCastValue(coefficientX*(1.0-zoomFactor)+_ptCenter.X*zoomFactor);
|
|
_ptCenter.Y = RoundAndCastValue(coefficientY*(1.0-zoomFactor)+_ptCenter.Y*zoomFactor);
|
|
|
|
_dScalingFactor *= zoomFactor;
|
|
}
|
|
|
|
// This method rotates the rectangle
|
|
// in:
|
|
// angle - angle of rotation in radians
|
|
// centerX - x-coordinate of the rotation center
|
|
// centerY - y-coordinate of the rotation center
|
|
//
|
|
// Note that during the rotation gesture the user defines center of rotation.
|
|
// This is going to move the center of the rectangle too. That is why we have to
|
|
// recalculate new center of the rectangle.
|
|
public void Rotate(double angle,int centerX,int centerY)
|
|
{
|
|
double dCos = Math.Cos(angle);
|
|
double dSin = Math.Sin(angle);
|
|
|
|
int idx = _ptCenter.X - centerX;
|
|
int idy = _ptCenter.Y - centerY;
|
|
|
|
_ptCenter.X = centerX + RoundAndCastValue(idx * dCos + idy * dSin);
|
|
_ptCenter.Y = centerY + RoundAndCastValue(idy * dCos - idx * dSin);
|
|
|
|
_dRotationAngle += angle;
|
|
}
|
|
|
|
// This macro is used to round double and cast it to int
|
|
static protected int RoundAndCastValue(double number)
|
|
{
|
|
return (int)(Math.Floor(0.5 + number));
|
|
}
|
|
}
|
|
}
|