I need to move a rectangle using angles. Actually I want to change the direction of my moving rectangle when it reaches the location I have given in my code in if statement!
I just need the way I can find out how to move my rectangle at 60, 30, 60, 120, 150, 270 degrees!
Suppose that if
circle.Y>=this.Height-80
See this:
I really actually need to change the direction of rectangle movement using angles! so that at certain location reaches I can change the rectangle direction according to angle of my own choice!
such that:
if(circle.Y>=this.Height-80)
move in the direction of 90 degrees
if(circle.X>=this.Width-80)
move in the direction of 60 degree
as you can see in the screen shot!
What I have been trying is:
public partial class Form1 : Form
{
Rectangle circle;
double dx = 2;
double dy = 2;
public Form1()
{
InitializeComponent();
circle = new Rectangle(10, 10, 40, 40);
}
private void Form1_Load(object sender, EventArgs e)
{
this.Refresh();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillEllipse(new SolidBrush(Color.Red), circle);
}
private void timer_Tick(object sender, EventArgs e)
{
circle.X += (int)dx;
circle.Y += (int)dy;
if (circle.Y>=this.Height-80)
{
dy = -Math.Acos(0) * dy/dy; //here i want to change the direction of circle at 90 degrees so that it should go up vertically straight with same speed
}
this.Refresh();
}
}
The Problem is that I have been trying changing my conditions to:
dy = -Math.Asin(1) * dy;
dx = Math.Acos(0) * dx ;
but in both cases nothing is happening and the direction remains same!
I just want to move the circle in inverted upward direction at 90 degrees when it reach at
circle.Y>=this.Height-80
You need to draw the rectangle again to some image for it to display. I created this code for moving and drawing rectangle on pictureBox1, using your already defined circle-rectangle:
Moving the rectangle:
public void MoveRectangle(ref Rectangle rectangle, double angle, double distance)
{
double angleRadians = (Math.PI * (angle) / 180.0);
rectangle.X = (int)((double)rectangle.X - (Math.Cos(angleRadians) * distance));
rectangle.Y = (int)((double)rectangle.Y - (Math.Sin(angleRadians) * distance));
}
Drawing the rectangle and displaying it in the PictureBox:
public void DrawRectangle(Rectangle rectangle)
{
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.FillEllipse(new SolidBrush(Color.Red), rectangle);
}
pictureBox1.Image = bmp;
}
Demo it with a button click:
private void Button1_Click(object sender, EventArgs e)
{
MoveRectangle(ref circle, 90, 5);
DrawRectangle(circle);
}
Math.Asin(1) * dy is a constant value. Thus, you should use, for example, an instance variable that increments in each Tick of your timer.
...And *dy/dy is irrelevant.
public partial class Form1 : Form
{
Rectangle circle;
double dx = 2;
double dy = 2;
acum=0; //the new variable
...
private void timer_Tick(object sender, EventArgs e)
{
circle.X += (int)dx;
circle.Y += (int)dy;
if (circle.Y>=this.Height-300)
{
dy = -Math.Acos(acum);
acum+=1; //your accumulator
}
this.Refresh();
}
acos and asin are the inverse of sin and cos so the output of those two functions is an angle (usually in radians). This makes the code incorrect.
I strongly suggest that you read up on vector and matrix maths as using Euler angles can get quite messy.
So, you will have a position vector P and a movement vector M and the current position is:
P' = P + M.t
where t is time, P is the original position and P' is the current position.
Then, when you want to change direction, you create a rotation matrix and multiply the movement vector M by this rotation matrix.
The advantage here is that you can step from a 2D system to a 3D system by adding a Z component to your vectors and increasing the size of your matrices.
Related
I have a picturebox with an image in it. The image contains two ellipses face to face (black & blue).
What I want is to rotate the picturebox in a timer (for the effect) so the image to be "upside down" would look much more like they've changed place, which basically it's just rotating the picturebox like how the erath is moving around it's axis.
There are various kinds of rotations from a globe, depending on how you look at it.
If you look at it from above the poles it spins like a disk or a gear and you can find code for it here. This has the advantage that you can use any image and rotate it.
If you look at it from the side, facing the equator you can't easily use bitmaps, but using just two colors it will still look nice..
Here is an example of a 'globe-like' spinning rotation:
float angle = 0f;
float aSpeed = 4f; // <-- set your speed
Brush brush1 = Brushes.CadetBlue; // and your..
Brush brush2 = Brushes.DarkSlateBlue; // ..colors
private void timer1_Tick(object sender, EventArgs e)
{
angle += aSpeed;
if (angle + aSpeed > 360)
{
angle -= 360f;
Brush temp = brush1;
brush1 = brush2;
brush2 = temp;
}
pictureBox1.Invalidate();
}
private void pictureBox1_Click(object sender, EventArgs e)
{
timer1.Enabled = !timer1.Enabled;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
Rectangle r = pictureBox1.ClientRectangle;
Rectangle r2 = r; // see below..
r.Inflate(-20, -20); // a little smaller than the panel or pBox
if (angle < 180)
{
e.Graphics.FillEllipse(brush1, r);
e.Graphics.FillPie(brush2, r, 270, 180);
r.Inflate(-(int)(r.Width * angle / 360f), 0);
e.Graphics.FillEllipse(brush2, r);
}
else
{
e.Graphics.FillEllipse(brush2, r);
e.Graphics.FillPie(brush1, r, 90, 180);
r.Inflate(-(int)(r.Width * angle / 360f), 0);
e.Graphics.FillEllipse(brush1, r);
}
}
}
This is created by three DrawXXX calls: a circle of one color and an ellipse and an arc, set to display a half circle of the same, second color.
Note: To make the angular speed uniform you may want to play with a little Math.Sin and/or an angle table..
If you look at it from any other angle and if you need to show rotating bitmaps in 3D you can't easily draw it but will need to resort to displaying frames..
But you can combine the disk rotation from the link with the code above and will get rather complex rotations, that look a lot like a 3D sphere.. Simply add the code before the drawing..
float bw2 = r2.Width / 2f;
float bh2 = r2.Height / 2f;
e.Graphics.TranslateTransform(bw2, bh2);
e.Graphics.RotateTransform(angle / 3);
e.Graphics.TranslateTransform(-bw2, -bh2);
..use the drawing from above instead of the DrawImage line and move the ResetTransform to the end. You will want to use a different or scaled angle!
I have this code
Graphics g;
g.FillRectangle(new SolidBrush(Color.Red), _Location.X - 2, _Location.Y - 2, 10, 10);
and the rectangle is shot at an angle to some direction, how can I get the rectangle to rotate while moving or rotate at all.
This should rotate a rectangle moving across the screen.
private int _angle = 0;
private Point _location = new Point(0, 0);
private void _timer_Tick(object sender, System.EventArgs e)
{
// nothing interesting here, moving the top left co-ordinate of the
// rectangle at constant rate
_location = new System.Drawing.Point(_location.X + 2, _location.Y + 2);
_angle += 5; // our current rotation angle
this.Invalidate();
}
void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
// rebase the co-ordinate system so our current x,y is 0, 0 and that is
// the center of the rotation
g.TranslateTransform(_location.X, _location.Y, MatrixOrder.Append);
g.RotateTransform(_angle); // do the rotation
// make sure the centre of the rectangle is the centre of rotation (0, 0)
g.FillRectangle(new SolidBrush(Color.Red), -5, -5, 10, 10);
}
I've figured it out right before I saw #steve16351 's response, but his code was still useful. What I did was switch from using PointF to Rectangle, because the Rectangle has a property which holds the value of the upper left corner's coordinates, so I can increment/decrement that at a stable rate, in my game loop, to make it rotate.
I need a simple mouse pointer highlighter in the form of a circle centered at the mouse pointer. Using Invalidate() in the below code causes rear circles along the path as flickers. They are hardly noticeable. Moreover, it doesn't draw the circle at the moment i rest the mouse.
What event should I consider to draw the circle at the position the mouse pointer is rested (tried other mouse events as well)?
Is there a way to refresh the drawing without using invalidate()?
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
SolidBrush myBrush = new SolidBrush(Color.Yellow);
Graphics gg = this.CreateGraphics();
Point p = new Point();
p = e.Location;
int radius = 10;
float x = p.X - radius;
float y = p.Y - radius;
float width = 5 * radius;
float height = 5 * radius;
gg.FillEllipse(myBrush, x, y, width, height);
gg.dispose();
Invalidate();
}
First turn on DoubleBuffered = true;
Then this should do:
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
float radius = 10f;
Point pt = PointToClient(Cursor.Position);
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.FillEllipse(Brushes.Yellow, pt.X - radius,
pt.Y - radius, radius * 2, radius * 2);
}
Since you are trying to highlight a spot on the background you may want to use a semi-transparent Color like this:
using (SolidBrush brush = new SolidBrush(Color.FromArgb(160, Color.Yellow)))
e.Graphics.FillEllipse(brush, pt.X - radius, pt.Y - radius, radius * 2, radius * 2);
You may want to play with other values for alpha than 160.
I am trying to make a triangle move back and forth over an arc, the triangle shoud rotate while moving.
I have made a picture to explain it better:
https://app.box.com/s/mt9p66zlmtkkgkdvtb5h
The math looks right to me, can anyone tell me what I am doing wrong?
public partial class Form1 : Form
{
bool turn = false;
double angle = 0;
public Form1()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Brush solidBlackBrush = new SolidBrush(Color.Black); //En solid svart brush som brukes flere steder
Pen solidBackPen = new Pen(solidBlackBrush);//En solid svart pen som brukes flere steder
//Trekant = Norwegian for Triangle, Trekant is a class that draws a polygon shaped as a Triangle.
Trekant tre = new Trekant();
e.Graphics.DrawArc(solidBackPen, new Rectangle(new Point(50,50), new Size(100,100)) , 180, 180);
//X = a + r*Cos(angle) | Y = b + r*Sin(angle)
double x = (50+(100/2)) + (100/2) * Math.Cos(Trekant.DegreeToRadian(angle));
double y = (50+(100/2)) - (100/2) * Math.Sin(Trekant.DegreeToRadian(angle));
e.Graphics.TranslateTransform((float)x - 15, (float)y - 40);//Flytter 0 slik at pistolen havner på rett sted
e.Graphics.RotateTransform((float)-Trekant.RadianToDegree(Trekant.DegreeToRadian(angle-90)));
tre.Draw(e.Graphics);
}
private void timer1_Tick(object sender, EventArgs e)
{
if (angle == 0)
{
turn = false;
}
if (angle == 180)
{
turn = true;
}
if (turn)
{
angle -= 10;
}
if (!turn)
{
angle += 10;
}
this.Invalidate();
}
}
Without going into coding let's first set up the math..
Let say the half ellipse in the picture has a width of 2w and a height of h. And lets assume you want the movement to happen in n steps.
Then at each step s the rotation angle is s * 180f/n. The rotation point's x stays at w plus whatever offset ox the ellipse has, but will have to move its y vertically from offset oy, first by (w-h) * 2f / n down on each step and then up again by the same amounts..
The Drawing itself moves accordingly.
So you have a TranslateTransform for the rotation point, the RotateTransform, then another TranslateTransform to place the image, then the DrawImage and finally a ResetTransform.
I hope that helps. If that doesn't work, please update the question and we'll can get it right, I'm sure..
I have a program that prints the cube and which can be rotated. Here's the code.
public partial class ProjectorForm : Form
{
Projector projector;
Cube cube;
float deltaRot;
public ProjectorForm()
{
InitializeComponent();
}
private void ProjectorForm_Load(object sender, EventArgs e)
{
deltaRot = 0.01f;
projector = new Projector();
cube = new Cube(Vector3.UnitZ * 20*10, 10*10, 10*10, 15*10);
updateTimer.Start();
}
private void updateTimer_Tick(object sender, EventArgs e)
{
if (rotXBox.Checked)
cube.RotateX(deltaRot);
if (rotYBox.Checked)
cube.RotateY(deltaRot);
if (rotZBox.Checked)
cube.RotateZ(deltaRot);
doubleBufferedPanel1.Invalidate();
}
private void doubleBufferedPanel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
cube.Draw(projector, Color.Black, doubleBufferedPanel1.ClientSize.Width, doubleBufferedPanel1.ClientSize.Height, e.Graphics);
}
private void button1_Click(object sender, EventArgs e)
{
deltaRot = float.Parse(deltaRotBox.Text);
}
}
class Projector
{
public Vector3 cameraPosition;
public float planeDistance;
ProjectorForm n = new ProjectorForm();
public Projector()
{
cameraPosition = Vector3.Zero;
planeDistance = 256; //Here, multiply by 2 and the scaled cube, how to make that scale when you press the button.
}
public PointF Project(Vector3 point, float width, float height)
{
float x = cameraPosition.X + ((cameraPosition.Z + planeDistance) / (point.Z - cameraPosition.Z)) * (point.X - cameraPosition.X) + width / 2;
float y = cameraPosition.Y + ((cameraPosition.Z + planeDistance) / (point.Z - cameraPosition.Z)) * (point.Y - cameraPosition.Y) + height / 2;
return new PointF(x, y);
}
public void DrawLine(Color color, Vector3 p1, Vector3 p2, float width, float height, Graphics g)
{
g.DrawLine(new Pen(color), Project(p1, width, height), Project(p2, width, height));
}
public void FillPolygon(Color color, Vector3[] vertices, float width, float height, Graphics g)
{
PointF[] points = new PointF[vertices.Length];
for (int i = 0; i < points.Length; i++)
points[i] = Project(vertices[i], width, height);
g.FillPolygon(new SolidBrush(color), points);
}
}
How to make a cube can be scaled by pressing a button. I found the variable planeDistance in the class Projector, when it increased by 2 times the cube is scaled, but I do not know how it can be increased by means of a button.
The field planeDistance is public, so you can change it from outside the class. i.e. just add something like the following to the event handler of a button:
projector.planeDistance += 10; // Change 10 as appropriate
It's worth noting that this doesn't change the size of the cube, it changes how far away the camera is from it. So, while the cube appears to be changing in size, that's just because the camera is moving closer / further away.
To actually change the size of the cube you would have to change fields in the cube class.
Since the size is defined by the vectors created in the constructor you don't really have an easy way of changing them once the cube is created.
You could create a new cube whenever you want to change the size (keep track of the size in another variable on the form).
You could add a method to the cube class that creates new vectors that define the new size (it would look a bit like the constructor, only populating the arrays, not creating them).
You could add a size field to your cube, always create a unit cube (1, 1, 1) then when rendering multiply each vector by your size.