I have made an object class and set the mouseEnter event on it. Object describes a process of creating a circle using opengl (here is drawing process function):
public void DrawCicrle()
{
GL.Begin(PrimitiveType.TriangleFan);
GL.Color4(Color_);
GL.Vertex2(X_, Y_);
for (int i = 0; i < 360; i++)
{
GL.Vertex2(X_ + Math.Cos(i) * Radius_, Y_ + Math.Sin(i) * Radius_);
}
GL.End();
}
Then I did a mouseEvent, but cant get the coordinates of cursor correctly. What are the correct conditions to get points in the arc of a circle?
This function returns a points, but with a little offset on the left side (X_ and Y_ are the center of a circle (double type) Radius_ is double type too):
public Point CursorLocation
{
get
{
return CursorLocation_;
}
set
{
this.CursorLocation_ = value;
for (int i = 0; i < 360; i++)
{
if (CursorLocation_.X <= X_ + Math.Cos(i) * Radius_ && CursorLocation_.Y<= Y_ + Math.Sin(i) * Radius_ && CursorLocation_.Y>=Y_-Radius_)
{
Enter(new Point(CursorLocation_.X, CursorLocation_.Y));
break;
}
}
}
}
The condition is dx * dx + dy * dy < R * R, where dx=Math.Abs(x-cx) and dy=Math.Abs(y-cy)
(x,y) is the cursor location and (cx,cy) the circle center
So you check the Euclidian distance between circle Center and some Point. To avoid square root calculation you just square both sides of comparison
Use <= if you also want to count-in the circle border
Related
everyone!
I have a problem with drawing a circle in C#. I need to illustrate the circle with the mouse in WindowsForm, that starts from certain points X and Y. Here is the code that I have, but the method Intersect() doesn't fit the needs of a circle to return the right illustration after that.
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace KursovaRabotaLibrary
{
[Serializable]
public class Circle : Shape
{
public override int Width { get; set; }
public override int Height { get; set; }
public override bool PointInShape(Point point)
{
return
Location.X <= point.X && point.X <= Location.X + Width &&
Location.Y <= point.Y && point.Y <= Location.Y + Height;
}
public override bool Intersect(Rectangle rectangle, Circle circle)
{
return
Location.X < circle.Location.X + circle.Width && circle.Location.X < Location.X + Width &&
Location.Y < circle.Location.Y + circle.Height && circle.Location.Y < Location.Y + Height;
}
}
}
Can you help me with defining better the method Intersect() to fit the needs of a circle?
Thank you in advance!
You can split this complex test to a sequence of three simple tests:
If bounds of both objects do not intersect, then objects also do not intersect.
If the circle center is inside the rectangle (or at it's border), they do intersect.
If any rectangle's corner is inside the circle, they do intersect.
If the circle is really a circle and not an ellipse (Width == Height), and if the Intersect method is supposed to test the intersection of rectangle and circle arguments (ignore it's instance variables), then the code might look like this (untested):
public override bool PointInShape(Point point)
{
var dx = point.X - Location.X;
var dy = point.Y - Location.Y;
// You can optimize the following
var distance = Math.Sqrt(dx * dx + dy * dy);
var radius = Width / 2;
return distance < radius;
}
public override bool Intersect(Rectangle rectangle, Circle circle)
{
var centerDistanceX = Math.Abs(circle.Location.X + circle.Width / 2 - (rectangle.Location.X + rectangle.Width / 2));
var centerDistanceY = Math.Abs(circle.Location.Y + circle.Height / 2 - (rectangle.Location.Y + rectangle.Height / 2));
var circleRadius = circle.Width / 2;
// Are centers too far (bounds do not intersect)?
if (centerDistanceX > (rectangle.Width / 2 + circleRadius))
return false;
if (centerDistanceY > (rectangle.Height / 2 + circleRadius))
return false;
// Is circle center inside the rectangle?
if (centerDistanceX <= (rectangle.Width / 2))
return true;
if (centerDistanceY <= (rectangle.Height / 2))
return true;
// Is rectangle corner inside the circle?
var dx = centerDistanceX - rectangle.Width / 2;
var dy = centerDistanceY - rectangle.Height / 2;
return dx * dx + dy * dy <= circleRadius * circleRadius;
}
I have the below algorithm which generates a number of points along the circumference of a circle for collision events in my program. (This works perfectly as far as I can tell).
bool Collision_True = false;
for (int Angle = 0; Angle <= 359; Angle += 5)
{
int X = (CentreX + (Radius * Math.Cos(Angle));
int Y = (CentreY + (Radius * Math.Sin(Angle));
Point point = new Point(X, Y);
if (Collision_True == false)
{
Collision_True = Player_Collisions(point);
}
}
return Collision_True;
However I want to change this so it only generates points on the bottom third of the circle, I tried changing the values in the for loop as follows:
for (int Angle = 120; Angle <= 240; Angle += 5)
{
...
}
But the points generated are still around the complete circumference of the circle instead of just the bottom third.
Any ideas? Thanks.
You need to convert to radians
for (int angleDegrees = 120; angleDegrees <= 240; angleDegrees += 5)
{
double angleRadians = angleDegrees / 180 * Math.PI;
int X = (CentreX + (Radius * Math.Cos(angleRadians));
int Y = (CentreY + (Radius * Math.Sin(angleRadians));
...
I have a picturebox with a picture as a background (infact a map), and on it I am spawning rectangles. These rectangles are supposed to move by given points. The rectangle is moving with assigned speed, and after reaching (or getting close) to one of the points, it starts moving to the next one. My problem however is, the rectangle doesnt move directly to the given point, it is just proceeding to get close to only one of the coordinates, so there are situations where the Y coordinate of the rectangle, and the Y coordinate of the point are the same, but the rectangle is like 60 pixels of and wont move.
Below I am adding a picture as an example of the movement. Blue is expected route, red is the actual one. I have checked the coordinates like a hundred times, they are correct, the rectangle is just moving elsewhere. Note: this only happens at some of the points.
Here is the code I am using to count the movement of the rectangle relative to axis X and Y.
public void Move_calculate(Graphics g)
{
if (points[passed].X == 0 || points[passed].Y == 0) // this happens when the rectangle reaches it final point - it stays where it is (working fine)
{
Redraw(g);
return;
}
speed = randomNumbers.Next(7, 13);
if (points[passed].X > x_coordinate && points[passed].Y > y_coordinate)
{
Bx = points[passed].X;
By = points[passed].Y;
distanceForAlfaX = Bx - x_coordinate; // x_coordinate is the x coordinate of the rectangle
distanceForAlfaY = By - y_coordinate;
if (distanceForAlfaX <= 20 || distanceForAlfaY <= 20) speed = 5; // slowing down when approaching the point
if (distanceForAlfaX + distanceForAlfaY <= 15) passed += 1;
alpha = (distanceForAlfaY / distanceForAlfaX); // tangent alpha
x_change = (int)(speed * (Math.Cos(alpha))); // get distance moved relative to axis X
y_change = (int)Math.Sqrt(((speed * speed) + (x_change * x_change))); // again distance for axis Y, using Pythagoras theorem
x_coordinate += x_change;
y_coordinate += y_change;
}
else if (points[passed].X > x_coordinate && points[passed].Y < y_coordinate)
{
Bx = points[passed].X;
By = points[passed].Y;
distanceForAlfaX = Bx - x_coordinate;
distanceForAlfaY = y_coordinate - By;
if (distanceForAlfaX <= 20 || distanceForAlfaY <= 20) speed = 5;
if (distanceForAlfaX + distanceForAlfaY <= 15) passed += 1;
alpha = (distanceForAlfaY / distanceForAlfaX);
x_change = (int)(speed * (Math.Cos(alpha)));
y_change = (int)Math.Sqrt(((speed * speed) + (x_change * x_change)));
x_coordinate += x_change;
y_coordinate -= y_change;
}
else if (points[passed].X < x_coordinate && points[passed].Y > y_coordinate)
{
Bx = points[passed].X;
By = points[passed].Y;
distanceForAlfaX = x_coordinate - Bx;
distanceForAlfaY = By - y_coordinate;
if (distanceForAlfaX <= 20 || distanceForAlfaY <= 20) speed = 5;
if (distanceForAlfaX+distanceForAlfaY <= 15) passed += 1;
alpha = (distanceForAlfaY / distanceForAlfaX);
x_change = (int)(speed * (Math.Cos(alpha)));
y_change = (int)Math.Sqrt(((speed * speed) + (x_change * x_change)));
x_coordinate -= x_change;
y_coordinate += y_change;
}
else if (points[passed].X < x_coordinate && points[passed].Y < y_coordinate)
{
Bx = points[passed].X;
By = points[passed].Y;
distanceForAlfaX = x_coordinate - Bx;
distanceForAlfaY = y_coordinate - By;
if (distanceForAlfaX <= 20 || distanceForAlfaY <= 20) speed = 5;
if (distanceForAlfaX + distanceForAlfaY <= 15) passed += 1;
alpha = (distanceForAlfaY / distanceForAlfaX);
x_change = (int)(speed * (Math.Cos(alpha)));
y_change = (int)Math.Sqrt(((speed * speed) + (x_change * x_change)));
x_coordinate -= x_change;
y_coordinate -= y_change;
}
else
{
MessageBox.Show("Something went wrong"); // just notify me that it isnt working again..
}
Pen p = new Pen(Color.Turquoise, 2);
r = new Rectangle(x_coordinate, y_coordinate, 5, 5); // redraw the rectangle
g.DrawRectangle(p, r);
p.Dispose();
}
I have no idea why this is happening, could anyone help with this?
P.S.
There is absolutely no need for the movement to be smooth, the positions of rectangles will be updated once per two seconds using a Timer. For now it is temporarily set to a button.
EDIT:
Here is the foreach code. The labels are just the coordinates shown next to the PictureBox
foreach (aircraft acft in aircrafts) // aircraft is an array aircrafts[]
{
label2.Text = "xp" + acft.points[acft.passed].X;
label3.Text = "yp" + acft.points[acft.passed].Y;
label4.Text = acft.passed.ToString();
label5.Text = "y" + acft.y_coordinate.ToString();
//MessageBox.Show(acft.points[0].X.ToString());
acft.Move_calculate(e.Graphics);
spawn = string.Empty;
}
EDIT2: All variables in aircraft class
public string callsign;
public int speed;
public double heading;
public bool moving = false;
public Point[] points;
public double alpha;
public int x_change;
public int y_change;
public int x_coordinate;
public int y_coordinate;
public int Bx;
public int By;
public double distanceForAlfaX;
public double distanceForAlfaY;
public int passed = 0;
public Rectangle r;
I guess, there's a math mistake in
y_change = (int)Math.Sqrt(((speed * speed) + (x_change * x_change)));
Moreover...
// again distance for axis Y, using Pythagoras theorem
Let Mr.Pythagoras be, I would rather use the same as for X axis
y_change = (int)(speed * (Math.Sin(alpha)));
Have you checked your coordinate system? (https://web.archive.org/web/20140710074441/http://bobpowell.net/coordinatesystems.aspx)
Sorry, wrong link for your issue. Try debugging using Control.PointToClient to make sure all coordinates are expressed in client space. (https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.pointtoclient)
You could try:
Point cPoint = this.PointToClient(new Point(x_coordinate, y_coordinate));
Size cSize = new Size(5,5);
r = new Rectangle(cPoint, cSize); // redraw the rectangle
g.DrawRectangle(p, r);
Could you post the data types of your variables to clarify your code? You might be losing precision somewhere, especially if you're using integer division.
(Note for DJ KRAZE, a -= b; in C# can also mean a = a - b; Context matters.)
What kind of math algorithm could I use to calculate the path to move a mouse? I simply want to have this type of function:
animateMouseDiag(int X, int Y){
//Move mouse 1 step towards goal, for loop most likely, from the current Mouse.Position
Thread.Sleep(1);
}
For example, if I give it animateMouseDiag(100,300), it would move the mouse 100 to the right and 300 down, but diagonally, not right-then-down in an 'L'. Similarly, if I gave it (-50,-200) it would move it to those relative coordinates (50 left and 200 up) along the diagonal path.
Thank you! (By the way, this is an alt account since I feel like an idiot asking about basic high school math on my main. I just can't translate it into programming.)
EDIT: I have come up with this:
public static void animateCursorTo(int toX, int toY)
{
double x0 = Cursor.Position.X;
double y0 = Cursor.Position.Y;
double dx = Math.Abs(toX-x0);
double dy = Math.Abs(toY-y0);
double sx, sy, err, e2;
if (x0 < toX) sx = 1;
else sx = -1;
if (y0 < toY) sy = 1;
else sy = -1;
err = dx-dy;
for(int i=0; i < toX; i++){
//setPixel(x0,y0)
e2 = 2*err;
if (e2 > -dy) {
err = err - dy;
x0 = x0 + sx;
}
if (e2 < dx) {
err = err + dx;
y0 = y0 + sy;
}
Cursor.Position = new Point(Convert.ToInt32(x0),Convert.ToInt32(y0));
}
}
This is Bresenham's line algorithm. Strangely though, the lines don't draw on a set angle. They seem to be gravitating towards the top left of the screen.
Store the position coordinates as floating point values, then you can represent the direction as a unit vector and multiply by a specific speed.
double mag = Math.Sqrt(directionX * directionX + directionY * directionY);
mouseX += (directionX / mag) * speed;
mouseY += (directionY / mag) * speed;
In another thread on XNA, Callum Rogers wrote some code which creates a texture with the outline of a circle, but I'm trying to create a circle filled with a color. What I have to modify on this code to fill the circle with color?
public Texture2D CreateCircle(int radius)
{
int outerRadius = radius*2 + 2; // So circle doesn't go out of bounds
Texture2D texture = new Texture2D(GraphicsDevice, outerRadius, outerRadius);
Color[] data = new Color[outerRadius * outerRadius];
// Colour the entire texture transparent first.
for (int i = 0; i < data.Length; i++)
data[i] = Color.Transparent;
// Work out the minimum step necessary using trigonometry + sine approximation.
double angleStep = 1f/radius;
for (double angle = 0; angle < Math.PI*2; angle += angleStep)
{
// Use the parametric definition of a circle: http://en.wikipedia.org/wiki/Circle#Cartesian_coordinates
int x = (int)Math.Round(radius + radius * Math.Cos(angle));
int y = (int)Math.Round(radius + radius * Math.Sin(angle));
data[y * outerRadius + x + 1] = Color.White;
}
texture.SetData(data);
return texture;
}
Don't use a texture for stuff like this (especially for things being in one single color!) - also don't try to do it pixel by pixel. You've got 3D acceleration for a reason.
Just draw the circle similar to a pie using a triangle fan. You'll need the following vertices.
Center of the circle
x points on the circle's border.
The first two points will define a line between the center of the circle and its border. The third vertex will define the first polygon. Vertices 1, 3 and 4 will then define the second polygon, etc.
To get the points on the circle's border use the formulas from your example. The first angle will be 0°, the following ones multiples of (360° / points on circle). To get a full circle you'll need one additional point that matches the second point (the first point on the border).
Depending on the number of vertices on the circle you'll get different n-gons. The more vertices you use the rounder the shape will look (at some performance cost):
(Less than 2 vertices aren't possible as a polygon requires at least 3 vertices to be drawn.)
Total of 4 points (3 points on circle) will result in a triangle.
Total of 5 points (4 point on circle) will result in a square.
Total of 6 points (5 points on circle) will result in a pentagon
...
Actually the XNA example for drawing primites show how to draw a circle (or n-gon) using a triangle fan.
well for anyone who wants to do it pixel by pixel ... i made a solution based on the information given. In your 2d texture method add the following code to fill the circle. I'm making a game and wanted to be able to make circles different colors and sizes. So inside CreateCircle(int radius) method, add the following code after the outline has been created :
bool finished = false;
int firstSkip = 0;
int lastSkip = 0;
for (int i = 0; i <= data.Length - 1; i++)
{
if (finished == false)
{
//T = transparent W = White;
//Find the First Batch of Colors TTTTWWWTTTT The top of the circle
if ((data[i] == Color.White) && (firstSkip == 0))
{
while (data[i + 1] == Color.White)
{
i++;
}
firstSkip = 1;
i++;
}
//Now Start Filling TTTTTTTTWWTTTTTTTT
//circle in Between TTTTTTW--->WTTTTTT
//transaparent blancks TTTTTWW--->WWTTTTT
// TTTTTTW--->WTTTTTT
// TTTTTTTTWWTTTTTTTT
if (firstSkip == 1)
{
if (data[i] == Color.White && data[i + 1] != Color.White)
{
i++;
while (data[i] != Color.White)
{
//Loop to check if its the last row of pixels
//We need to check this because of the
//int outerRadius = radius * 2 + -->'2'<--;
for (int j = 1; j <= outerRadius; j++)
{
if (data[i + j] != Color.White)
{
lastSkip++;
}
}
//If its the last line of pixels, end drawing
if (lastSkip == outerRadius)
{
break;
finished = true;
}
else
{
data[i] = Color.White;
i++;
lastSkip = 0;
}
}
while (data[i] == Color.White)
{
i++;
}
i--;
}
}
}
}
// Set the data when finished
//-- don't need to paste this part, already given up above
texture.SetData(data);
return texture;
If you need to do it from scratch (though I'm guessing there are easier ways), change the way you perform the rendering. Instead of iterating through angles and plotting pixels, iterate through pixels and determine where they are relative to the circle. If they are <R, draw as fill color. If they are ~= R, draw as border color.
I know that I'm a little late, but I modified your code to fill in the center
public static Texture2D CreateCircle(GraphicsDevice importedGraphicsDevice, int radius)
{
int outerRadius = radius * 2 + 2; // So circle doesn't go out of bounds
Texture2D texture = new Texture2D(importedGraphicsDevice, outerRadius, outerRadius);
Color[] data = new Color[outerRadius * outerRadius];
// Colour the entire texture transparent first.
for (int i = 0; i < data.Length; i++)
data[i] = Color.Transparent;
// Work out the minimum step necessary using trigonometry + sine approximation.
double angleStep = 1f / radius;
for (double angle = 0; angle < Math.PI * 2; angle += angleStep)
{
// Use the parametric definition of a circle: http://en.wikipedia.org/wiki/Circle#Cartesian_coordinates
int x = (int)Math.Round(radius + radius * Math.Cos(angle));
int y = (int)Math.Round(radius + radius * Math.Sin(angle));
data[y * outerRadius + x + 1] = Color.White;
}
//width
for (int i = 0; i < outerRadius; i++)
{
int yStart = -1;
int yEnd = -1;
//loop through height to find start and end to fill
for (int j = 0; j < outerRadius; j++)
{
if (yStart == -1)
{
if (j == outerRadius - 1)
{
//last row so there is no row below to compare to
break;
}
//start is indicated by Color followed by Transparent
if (data[i + (j * outerRadius)] == Color.White && data[i + ((j + 1) * outerRadius)] == Color.Transparent)
{
yStart = j + 1;
continue;
}
}
else if (data[i + (j * outerRadius)] == Color.White)
{
yEnd = j;
break;
}
}
//if we found a valid start and end position
if (yStart != -1 && yEnd != -1)
{
//height
for (int j = yStart; j < yEnd; j++)
{
data[i + (j * outerRadius)] = new Color(10, 10, 10, 10);
}
}
}
texture.SetData(data);
return texture;
}