Rotate image in pictureBox - c#

I am making an Analogue Clock in which i have to rotate the image in my pictureBox...
e.g. i want to rotate my image by 6 degrees every second.
what can i do for this?
Thanks....

I remember ever writing a Clock-like UserControl some time ago. Here's the fundamental code to do your request.
Private Sub Paint_Clock(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles Clock.Paint
Dim _independentHands as Boolean = False
Dim g As Graphics = e.Graphics
Dim centrePoint As Point = New Point(Clock.Width \ 2, Clock.Height \ 2)
Dim _time As New TimeSpan(5, 2, 15)
'pens'
Dim hourPen As New Pen(Color.Black, 3)
Dim minPen As New Pen(Color.Black, 2)
Dim secPen As New Pen(Color.Red, 1)
'clock hand lengths'
Dim halfClockWidth As Integer = Clock.Width \ 2
Dim hourLength As Integer = CInt(halfClockWidth * (4 / 6)) - 5
Dim minLength As Integer = CInt(halfClockWidth * (5 / 6)) - 5
Dim secLength As Integer = CInt(halfClockWidth * (5 / 6)) - 5
Dim secLength2 As Integer = CInt(halfClockWidth * (1 / 6))
'angles'
Dim secAngle As Single = CSng(_time.Seconds / 60) * 360
Dim secAngle2 As Single = secAngle - 180
Dim minAngle As Single = CSng(_time.Minutes / 60) * 360
Dim hrAngle As Single = CSng((_time.Hours - 12) / 12) * 360
If Not _independentHands Then minAngle += (secAngle / 60)
If Not _independentHands Then hrAngle += (minAngle / 12)
'centre point'
Dim pointPen As New Pen(Color.Black, 4)
Dim pointRect As New Rectangle(centrePoint.X - 2, centrePoint.Y - 2, 4, 4)
'antialias on'
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
'draw the background'
g.DrawImage(My.Resources.ClockBack, 0, 0, Clock.Width, Clock.Height)
'draw the hands'
g.DrawLine(hourPen, centrePoint, GetPoint2(centrePoint, hrAngle, hourLength))
g.DrawLine(minPen, centrePoint, GetPoint2(centrePoint, minAngle, minLength))
g.DrawLine(secPen, centrePoint, GetPoint2(centrePoint, secAngle, secLength))
g.DrawLine(secPen, centrePoint, GetPoint2(centrePoint, secAngle2, secLength2))
'draw the centre point'
g.DrawEllipse(pointPen, pointRect)
'draw the glass'
g.DrawImage(My.Resources.ClockGlass, 0, 0, Clock.Width, Clock.Height)
End Sub
Private Function GetPoint2(ByVal startPoint As Point, _
ByVal angle As Single, _
ByVal length As Integer) As Point
Dim x, y As Integer
Dim sp As Point = startPoint
'normalize'
Do While angle - 360 > 0
angle -= 360
Loop
Do While angle < 0
angle += 360
Loop
If angle = 360 Then angle = 0
Dim rad = angle * (Math.PI / 180) 'angle in radians'
'calc the new point'
x = CInt(length * Math.Sin(rad))
y = CInt(length * Math.Cos(rad))
Return New Point(sp.X + x, sp.Y - y)
End Function
Notes
1. Add a PictureBox with the name Clock to your form (or usercontrol)
2. Add a resource called ClockBack for the background of your clock (the clock's face).
3. Add a resource called ClockGlass for the clock's glassy face.
4. Drop the code above in your form.
5. Set a timer's interval to 1000 and have its Tick event Refresh or Invalidate the Clock [which is a PictureBox].
Please note that the variable _independentHands makes the clock's hands independent of each other when set to true.
For example, when set to False, 4:30 will have the hour hand halfway between 4 and 5. When True, the hour hand will be on 4 up till 4:59:59 and will 'jump' to 5 at 5:00:00.
I prefer to leave it to false so as to give the natural clock feel.

Here below links for question
C# Image/PictureBox Rotations - CodeProject
Rotating PictureBox Control - CodeProject

try this
pictureBox1.Image.RotateFlip((RotateFlipType.Rotate90FlipX));
or rotate this in a thread per 1000 ms

Related

Click in a shape WinForm

I am drawing a circle of _radius = 50 pixels in the center of the form:
g.FillEllipse(Brushes.Red, this.ClientRectangle.Width / 2 - _radius / 2, this.ClientRectangle.Height / 2 - _radius / 2, _radius, _radius);
Now I want to check if the user clicked in the form.
if (e.Button == MouseButtons.Left)
{
int w = this.ClientRectangle.Width;
int h = this.ClientRectangle.Height;
double distance = Math.Sqrt((w/2 - e.Location.X) ^ 2 + (h/2 - e.Location.Y) ^ 2);
....
if (distance <_radius)
return true;
else
return false;
}
Now I am ending up with wrong values. For instance if I click on the edge of the circle I at times get distance of ~10 or NaN at times. What am I doing wrong here?
You're performing integer division, which is coarser than floating-point division.
^ is not the "power-to" operator, it's the bitwise XOR operator, which is probably not what you want. Use Math.Pow or x*x instead.
You can simplify the last statement by simply doing return distance < _radius.
Try this:
Single w = this.ClientRectangle.Width;
Single h = this.ClientRectangle.Height;
Single distanceX = w / 2f - e.Location.X;
Single distanceY = h / 2f - e.Location.Y;
Single distance = Math.Sqrt( distanceX * distanceX + distanceY * distanceY );
return distance < this._radius;
(This code does not change any assumptions about the location of the circle).

How to calculate the orientation of a shape in wpf

The code snippet below generates a curve line and arrow at the end of the path, as seen in the image below in wpf using C#. All you have to do is supply the function a starting and end point. You'll see in the image below that the Red Arrow on the left is incorrectly aligned to the path. The Red Arrow on the right is aligned correctly, however I'm not sure how to calculate the correct orientation? Does anyone have advice or a solution on how i could do this? The green points in the image demonstrate the points being generated in the function.
Thank you.
// Return the shape's path and arrow geometry.
protected override Geometry DefiningGeometry
{
get
{
GeometryGroup group = new GeometryGroup();
// Used for curvey lines
GenerateCurvedLine(group);
//GeneratedCurvedArrow(group);
// Used for straight lines
//GeneratedStraightLine(group);
GenerateArrowHeadGeometry(group);
// Return cached geometry.
return group;
}
}
// Generate the geometry for a curved line connecting the start and end points.
private void GenerateCurvedLine(GeometryGroup geometryGroup)
{
//Calculate points between start and end plugs
Point secondPoint = new Point(this.Start.X, this.Start.Y + 50);
Point thirdPoint = new Point(this.End.X, this.End.Y - 50);
// Build geometry for the curvey line.
PathFigure curvedPath = new PathFigure();
curvedPath.IsClosed = false;
curvedPath.IsFilled = false;
curvedPath.StartPoint = this.Start;
curvedPath.Segments.Add(new BezierSegment(secondPoint, thirdPoint, this.End, true));
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(curvedPath);
geometryGroup.Children.Add(pathGeometry);
}
Generates the Arrow at the end of the path, while orienting it towards the starting point.
// Generate the geometry for the three optional arrow symbol at the end of the path.
private void GenerateArrowHeadGeometry(GeometryGroup geometryGroup)
{
EllipseGeometry ellipse = new EllipseGeometry(this.Start, DotSize, DotSize);
geometryGroup.Children.Add(ellipse);
Vector startDir = this.End - this.Start;
startDir.Normalize();
Point basePoint = this.End - (startDir * ArrowHeadLength);
Vector crossDir = new Vector(-startDir.Y, startDir.X);
Point[] arrowHeadPoints = new Point[3];
arrowHeadPoints[0] = this.End;
arrowHeadPoints[1] = basePoint - (crossDir * (ArrowHeadWidth / 2));
arrowHeadPoints[2] = basePoint + (crossDir * (ArrowHeadWidth / 2));
// Build geometry for the arrow head.
PathFigure arrowHeadFig = new PathFigure();
arrowHeadFig.IsClosed = true;
arrowHeadFig.IsFilled = true;
arrowHeadFig.StartPoint = arrowHeadPoints[1];
arrowHeadFig.Segments.Add(new LineSegment(arrowHeadPoints[0], true));
arrowHeadFig.Segments.Add(new LineSegment(arrowHeadPoints[2], true));
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(arrowHeadFig);
geometryGroup.Children.Add(pathGeometry);
}
DISCLAIMER: I'm NOT a math expert... so this could be all wrong.
You need to figure out the slope of the curve towards the end of the line. If you use the parametric equation for a Bezier curve at time t=0.95 (you may need to adjust this value) and then again at time t=1.0 (which is just this.End) and then subtract them, you will have what you need (the slope of the curve at the end).
To calculate it, see Quadratic Bezier Curve: Calculate Point - you'll want the cubic answer (2nd answer).
In GenerateCurvedLine, calculate the arrow direction like this:
var t = 0.95;
var x1 = (1 - t) * (1 - t) * (1 - t) * this.Start.X
+ 3 * (1 - t) * (1 - t) * t * secondPoint.X
+ 3 * (1 - t) * t * t * thirdPoint.X
+ t * t * t * this.End.X;
var y1 = (1 - t) * (1 - t) * (1 - t) * this.Start.Y
+ 3 * (1 - t) * (1 - t) * t * secondPoint.Y
+ 3 * (1 - t) * t * t * thirdPoint.Y
+ t * t * t * this.End.Y;
arrowDir = new Vector(this.End.X - x1, this.End.Y - y1);
In GenerateArrowHeadGeometry, use the arrowDir above instead of your startDir.
FYI - t (time) ranges from 0 to 1 for points on your curve. 0 will be this.Start and 1 will be this.End. So, t=0.95 would be towards the end of the curve.

OpenTK / OpenGL - Rotating camera with mouse

Background
I currently have an object that I am displaying that will always be at the origin. I have a function which increments my x and y angles and then calculates the new x,y,z coordinate for the camera:
Public Sub update_rotation()
If cam.manual_lookat = True Then
If camangley >= 360 Then
camangley = camangley - 360
End If
If camanglex >= 360 Then
camanglex = camanglex - 360
End If
If camangley < 0 Then
camangley = 360 + camangley
End If
If camanglex < 0 Then
camanglex = 360 + camanglex
End If
If camangley > 90 And camangley <= 270 Then
cam.invert_y = True
Else
cam.invert_y = False
End If
camx = distance * -Sin(camanglex * (PI / 180)) * Cos((camangley) * (PI / 180))
camy = distance * -Sin((camangley) * (PI / 180))
camz = distance * Cos((camanglex) * (PI / 180)) * Cos((camangley) * (PI / 180))
cam.Position.X = camx
cam.Position.Y = camy
cam.Position.Z = camz
cam.lookat.X = 0
cam.lookat.Y = 0
cam.lookat.Z = 0
' Label2.Text = camanglex & "," & camangley
End If
End Sub
I have this set up to use keyboard events.. the X button adds to the camanglex variable, the Y button adds to the camangley variable, and the Z button adds to the distance variable.
Everything works well doing it this way, using the keyboard.
Problem
I am trying to now use the mouse to handle the rotation instead of the keyboard. I believe this is simply a math question but how do I go about calculating either the new camanglex and camangley variables or directly calculating the new camx,camy,camz ones to establish my cameras new location?
I have a mouse function which will capture the mouse coordinates but am having trouble with the calculation part.
If you want to orbit around object you could trace the path your mouse goes on fake sphere (which is called trackball sometimes). There is a working example of orbit controls.
And here is a pseudocode sketch for something similiar:
mouseDownEventFunction(event) {
computeDragPoint (event.mouseX, event.mouseY, &oldDragPoint);
isMouseDown = true;
}
mouseUpEventFunction(event) {
isMouseDown = false;
}
mouseMoveEventFunction(event) {
if (isMouseDown) {
computeDragPoint (event.mouseX, event.mouseY, &newDragPoint);
rotateCamera (oldDragPoint, newDragPoint);
oldDragPoint = newDragPoint;
}
}
Here we find a point on trackball:
/* we want to ray trace a point on face side of fake sphere.
dragPoint* is our result*/
computeDragPoint(int x, int y, Vector3* dragPoint) {
/* normalize x and y to [-1, 1] so they match flat circle position on screen.
And assign this to dragPoint->x and dragPoint->y.
This part depends on what you want to achieve and input units of x, y.
Keep in mind aspect ratio */
dragPoint->x = (2*x/screenWidth - 0.5) * (screenHeight/screenWidth);
dragPoint->y = 2*y/screenHeight - 0.5;
dragPoint->x /= sqrt(dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y);
dragPoint->y /= sqrt(dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y);
/* Then having two values in [-1,1] compute corresponding z */
float tmp = dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y;
if (tmp > 1) {
dragPoint.x /= sqrt(tmp);
dragPoint.y /= sqrt(tmp);
}
dragPoint->z = -sqrt (1 - dragPoint->x^2 - dragPoint->y^2) || 0;
}
And rotation math can be done with quaternions (or just matrices from Euler angles if you don't want to use quats):
rotateCamera(oldDragPoint, newDragPoint) {
Quaternion quat = new Quaternion (Config.AngleX, Config.AngleY, Config.AngleZ);
quat.normalize();
Quaternion deltaQuat = new Quaternion();
deltaQuat = deltaQuat.setFromUnitVectors(oldDragPoint, newDragPoint);
quat = quat.multiply(deltaQuat);
quat.normalize();
Vector3 resultAngles = Vector3();
resultAngles.setFromQuaternion(quat);
setCameraPositionFromAngles(resultAngles);
}
And in setCameraPositionFromAngles(resultAngles) set your final X, Y, Z coordinates by applying three basic rotations to your initial camera position. So your main parameters are resultAngles. You renew angles and then set position.
Maybe this working example will explain better.

Draw 2D trail of ship. XNA

I've been looking for a solution to this for some time now and already have many elements to work with but not really how to piece them together.
Objective: Draw a trail for the player's ship.
So far: Since the ship's direction is unpredictable I have only the previous positions of the player's ship to work with. To draw the trail I could simply draw a pixel (or a texture) at the previous position of the player but this is memory expensive and it doesn't draw curves, it won't achieve a pleasing to the eye curved effect.
I've been looking into Beziers Paths and Cathmull Rom for solutions.
Now I can get the control points for a given point, then from 2 points and 2 control points calculate a curve, from here I make an array of VertexPositionColor with a distance between points to make a triangleStrip from the curve.
These are the main functions I have so far:
public Vector2[] GetControlPoints(Vector2 p0, Vector2 p1, Vector2 p2, float tension = 0.5f)
{
// get length of lines [p0-p1] and [p1-p2]
float d01 = Vector2.Distance(p0, p1);
float d12 = Vector2.Distance(p1, p2);
// calculate scaling factors as fractions of total
float sa = tension * d01 / (d01 + d12);
float sb = tension * d12 / (d01 + d12);
// left control point
float c1x = p1.X - sa * (p2.X - p0.X);
float c1y = p1.Y - sa * (p2.Y - p0.Y);
// right control point
float c2x = p1.X + sb * (p2.X - p0.X);
float c2y = p1.Y + sb * (p2.Y - p0.Y);
return new Vector2[] {new Vector2(c1x, c1y), new Vector2(c2x, c2y) };
}
// Given 2 points and 2 control points
public static VertexPositionColor[] bezierCurve(Vector2 start, Vector2 end, Vector2 c1, Vector2 c2)
{
VertexPositionColor[] points = new VertexPositionColor[SUBDIVISIONS + 2];
float fraction;
for (int i = 0; i < SUBDIVISIONS + 2; i++)
{
fraction = i * (1f / (float)SUBDIVISIONS);
points[i] = new VertexPositionColor(new Vector3((float)((start.X * Math.Pow((1 - fraction), 3))
+(c1.X * 3 * fraction * Math.Pow(1-fraction, 2))
+(c2.X * 3 * Math.Pow(fraction,2) * (1-fraction))
+(end.X * Math.Pow(fraction,3))),
(float)((start.Y * Math.Pow((1 - fraction), 3))
+ (c1.Y * 3 * fraction * Math.Pow(1 - fraction, 2))
+ (c2.Y * 3 * Math.Pow(fraction, 2) * (1 - fraction))
+ (end.Y * Math.Pow(fraction, 3))), 0), UNLIT);
}
return points;
}
/*
* This function treats the curve as a series of straight lines and calculates points on a line perpendicular to each point, resulting in two points THICKNESS appart.
* Requires THICKNESS to be set
*/
public static VertexPositionColor[] curveToStrip(VertexPositionColor[] curve)
{
VertexPositionColor[] strip = new VertexPositionColor[curve.Length * 2];
VertexPositionColor[] new1 = new VertexPositionColor[curve.Length];
VertexPositionColor[] new2 = new VertexPositionColor[curve.Length];
for (int i = 0; i < curve.Length; i++)
{
if (i < curve.Length-1)
{
Vector2 p1 = new Vector2(curve[i].Position.X, curve[i].Position.Y);
Vector2 p2 = new Vector2(curve[i + 1].Position.X, curve[i + 1].Position.Y);
Vector2 perpPoint = perpendicularPoint(p1, p2);
new1[i] = new VertexPositionColor(new Vector3(distanceToPoint(p1, perpPoint, THICKNESS / 2), 0), UNLIT);
new2[i] = new VertexPositionColor(new Vector3(distanceToPoint(p1, perpPoint, -1 * THICKNESS / 2), 0), UNLIT);
}
else
{
Vector2 p1 = new Vector2(curve[i].Position.X, curve[i].Position.Y);
Vector2 p2 = new Vector2(curve[i - 1].Position.X, curve[i - 1].Position.Y);
Vector2 perpPoint = perpendicularPoint(p1, p2);
new1[i] = new VertexPositionColor(new Vector3(distanceToPoint(p1, perpPoint, -1 * THICKNESS / 2), 0), UNLIT);
new2[i] = new VertexPositionColor(new Vector3(distanceToPoint(p1, perpPoint, THICKNESS / 2), 0), UNLIT);
}
}
I thought about calling the functions on the draw phase but this seems very expensive just to make a tiny curve and to draw a bigger Beziers path I imagine it worse. Since I would get a point at each frame, each function would be called to calculate the curve between points just to draw 1 curve of 3 pixels (or less).
How can I proceed? Any suggestions?
I am still a beginner on this kind of stuff!
All this I got from several sources:
CathmullRom
Beziers and Triangle strip
http://www.imagehosting.cz/images/trails.gif
I will just briefly explain how this works:
It is function that receives position, it is called each time you want add next segment of trail.
When function is called it adds two vertices on position, look at tangent vector from previous step, creates normal vector to current position and place vertices along that normal according to trail width.
Next it looks to at previous two vertexes and align them according to average of current and previous tangent, creating trapezoid.
I suggest to leave calculation of fading on GPU (effectively using approach of GPU particles).
If you know velocity vector of object when you are calling update of trail you can use it to optimize that algorithm. Use of dynamic vertex buffer is probably without saying (just use your own vertex format that will include current time at moment when you create those vertices so you can fade it on GPU).
One way could be that you create a list of trails/particles, and you init that on every frame or how much you like. i will try to explain in pseudo code below. i also rotate a bit every trail, and use different size and color of smoke texture, and added a bit of ofsset +- 5 pixels on init.
class Trail
position as vector2d
duration as single
velocity as vector2d
fade as integer = 1
active = true
end class
class Trails
inherits list of Trail
sub Init(position as vector2d, velocity as vector2d)
// add trail to list
end sub
sub Update()
for each trail in me.findAll(function(c) c.active))
position += velocity
fade -= .05 // or some value
end for
me.removeAll(function(c) not(c.active)) // remove from list when unused
end sub
sub Draw()
for each trail in me.findAll(function(c) c.active))
draw(smokeTexture, position, size, rotate, color * trail.fade)
end for
end sub
end class
by this i have achieved this effect, it's barely visible but it gives effect.

Image button CF.net

I have created a image button for my apps on windows mobile. There is a small problem though, when i have different screen resolutions,bigger for example, the image isn't automatic resized to fit in the control. How can this be done?
thanks in advance.
this is my code for the onPaint function
Dim gxOff As Graphics
'Offscreen graphics
Dim imgRect As Rectangle
'image rectangle
Dim backBrush As Brush
'brush for filling a backcolor
If m_bmpOffscreen Is Nothing Then
'Bitmap for doublebuffering
m_bmpOffscreen = New Bitmap(Me.Width, Me.Height)
End If
gxOff = Graphics.FromImage(m_bmpOffscreen)
gxOff.Clear(Me.BackColor)
If Not bPushed Then
backBrush = New SolidBrush(Parent.BackColor)
Else
backBrush = New SolidBrush(Color.Black)
'change the background when it's pressed
End If
gxOff.FillRectangle(backBrush, Me.ClientRectangle)
If m_image IsNot Nothing Then
'Center the image relativelly to the control
Dim imageLeft As Integer = (Me.Width - m_image.Width) / 2
Dim imageTop As Integer = (Me.Height - m_image.Height) / 2
If Not bPushed Then
imgRect = New Rectangle(imageLeft, imageTop, m_image.Width, m_image.Height)
Else
'The button was pressed
'Shift the image by one pixel
imgRect = New Rectangle(imageLeft + 1, imageTop + 1, m_image.Width, m_image.Height)
End If
'Set transparent key
Dim imageAttr As New Imaging.ImageAttributes()
imageAttr.SetColorKey(BackgroundImageColor(m_image), BackgroundImageColor(m_image))
'Draw image
gxOff.DrawImage(m_image, imgRect, 0, 0, m_image.Width, m_image.Height, GraphicsUnit.Pixel, imageAttr)
End If
If bPushed Then
'The button was pressed
'Prepare rectangle
Dim rc As Rectangle = Me.ClientRectangle
rc.Width -= 1
rc.Height -= 1
'Draw rectangle
gxOff.DrawRectangle(New Pen(Color.Black), rc)
End If
'Draw from the memory bitmap
e.Graphics.DrawImage(m_bmpOffscreen, 0, 0)
MyBase.OnPaint(e)
You need to scale image during OnPaint e.g.:
if (this._image != null)
{
int x = (this.Width - this._image.Width) / 2;
int y = (this.Height - this._image.Height) / 2;
var imgRect = new Rectangle(x, y, this._image.Width, this._image.Height);
var imageAttr = new ImageAttributes();
Color clr = this._image.GetPixel(0, 0);
imageAttr.SetColorKey(clr, clr);
gr2.DrawImage(this._image, imgRect, 0, 0, this._image.Width, this._image.Height, GraphicsUnit.Pixel, imageAttr);
}
Above example is how to draw image with transparent color based on first pixel. Now you need to ammend second 3 lines:
bool qvga = Screen.PrimaryScreen.Bounds.Height == 240 || Screen.PrimaryScreen.Bounds.Width == 240;
int x = (this.Width - (qvga ? this._image.Width : this._image.Width * 2)) / 2;
int y = (this.Height - (qvga ? this._image.Height : this._image.Height * 2)) / 2;
var imgRect = new Rectangle(x, y, (qvga ? this._image.Width : this._image.Width * 2), (qvga ? this._image.Height : this._image.Height * 2));
[Edit]
Seeing your code change is straight forward. Like I described in comment: For two main windows mobile resolutions, QVGA and VGA, we assuming that image is for QVGA size. Please convert my code to VB by yourself. So set qvga flag as I written:
bool qvga = Screen.PrimaryScreen.Bounds.Height == 240 || Screen.PrimaryScreen.Bounds.Width == 240;
now based on flag ammend following based on my above code:
Dim imageLeft As Integer = (Me.Width - m_image.Width) / 2
Dim imageTop As Integer = (Me.Height - m_image.Height) / 2
and then this ones:
If Not bPushed Then
imgRect = New Rectangle(imageLeft, imageTop, m_image.Width, m_image.Height)
Else
'The button was pressed
'Shift the image by one pixel
imgRect = New Rectangle(imageLeft + 1, imageTop + 1, m_image.Width, m_image.Height)
End If

Categories