Points on a circle by angle not spaced evenly [duplicate] - c#

This question already has an answer here:
Finding Points On Perimeter Of a Circle
(1 answer)
Closed 10 years ago.
Given:
x = originX + radius * Cos(angle);
y = originY + radius * Sin(angle);
Why would the points not be evenly distributed around the edge of the circle?
Image of the result:
class Circle
{
public Vector2 Origin { get; set; }
public float Radius { get; set; }
public List<Vector2> Points { get; set; }
private Texture2D _texture;
public Circle(float radius, Vector2 origin, ContentManager content)
{
Radius = radius;
Origin = origin;
_texture = content.Load<Texture2D>("pixel");
Points = new List<Vector2>();
//i = angle
for (int i = 0; i < 360; i++)
{
float x = origin.X + radius * (float)Math.Cos(i);
float y = origin.Y + radius * (float)Math.Sin(i);
Points.Add(new Vector2(x, y));
}
}
public void Draw(SpriteBatch spriteBatch)
{
for (int i = 0; i < Points.Count; i++)
spriteBatch.Draw(_texture, Points[i], new Rectangle(0, 0, _texture.Width, _texture.Height), Color.Red);
}
}

Math.Cos and Math.Sin take the angle in radians as opposed to degrees, your code should be:
float x = origin.X + radius * (float)Math.Cos(i*Math.PI/180.0);
float y = origin.Y + radius * (float)Math.Sin(i*Math.PI/180.0);

Points:
1) Math.Trig functions use Radians, not Degrees.
2) For this kind of precision, you would be better off using double instead of float.
3) The computer graphics/gaming pros avoid expensive functions like Sin and Cos, and instead use incremental integer pixel oriented approaches, like Bresenham's Algorithms, that give results as good or better than the straight-forward trigonometric math calculations and are much faster.

Related

How to divide by Quaternion in Unity

Using this tutorial https://www.youtube.com/watch?v=waEsGu--9P8&list=PLzDRvYVwl53uhO8yhqxcyjDImRjO9W722 and Quaternions I've made a function, that finds the World Position of the grid tiles for Isometric Tilemap.
private Vector3 GetWorldPosition(int x, int y, int r, int u, int f) {
return Quaternion.AngleAxis(u, Vector3.up) * Quaternion.AngleAxis(r, Vector3.right)
* Quaternion.AngleAxis(f, Vector3.forward) * new Vector3(x, y) * cellSize;
}
It works perfectly well. It rotates a 2D grid to fit Unity isometric Tilemap. Now i need to do the opposite - get the tile, if i know the worldPosition. I supposed, if in the previous case I multiplied the Quaternions, now i need to divide the worldPosition.x and worldPosition.y by them. But this code
private void GetXY(Vector3 worldPosition, out int x, out int y, int r = 60, int u = 0, int f = 45) {
Quaternion rotation = Quaternion.AngleAxis(u, Vector3.up) * Quaternion.AngleAxis(r, Vector3.right)
* Quaternion.AngleAxis(f, Vector3.forward);
x = Mathf.FloorToInt(worldPosition.x / rotation / cellSize);
y = Mathf.FloorToInt(worldPosition.y / rotation / cellSize); }
does not even run, because of the mistake
"Operator '/' cannot be applied to operands of type 'Quaternion' and
'float'"
So why could I multiply Quaternion and float cellSize in the first case, but can not divide or multiply them in the second case?
And how to do the opposite operation?
Thank you for trying to help, but Inverse did not work out.
So I had 2D grid, that was rotated -45 degrees Z and 60 degrees X. It made the grid isometric. So because it was rotated X by 60 degr., in 2D vision this grid had more than 90 degrees between its own X and Y (the tiles were rhombus). And i found out the exact angles, which i can use for the coordinates - different for x and y. This function got the tiles right for me.
private Vector2Int GetXY(Vector3 worldPosition) {
Vector3 positionX = Quaternion.AngleAxis(-65, Vector3.forward) * worldPosition / cellSize;
Vector3 positionY = Quaternion.AngleAxis(-26, Vector3.forward) * worldPosition / cellSize;
return new Vector2Int(Mathf.FloorToInt(positionX.x * 1.55f), Mathf.FloorToInt(positionY.y * 1.55f));
}

Instantiate in circle objects look to center

A little bit confused - math is really not my strong point, so I'm not sure how to achieve.
Currently the objects instantiate, but I have no control over the distance from center or the rotation of each spawned object
public void instantiateInCircle()
{
for (int i = 0; i < amount; i++)
{
float radius = spawnDistance;
float angle = i * Mathf.PI * 2f / radius;
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
//Rotate objects to look at the center
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
//How to adjust the width of the radius, how far away from the center?
//Parent instantiated objects to disk
instantiatedObject.transform.parent = spawnAroundThis.transform;
instantiatedObject.transform.localScale = new Vector3(scale, scale, scale);
}
}
How to make the distance adjustable, move cubes in closer to center...?
Currently, you do not access the instantiated object, but the prefab instead. Cache the object and call the LookAt on them.
Since I do not know what type itemToSpawn is, I assumed it is a GameObject. You may want to use your type instead.
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
If you want to control the distance from center of the rotation:
for (int i = 0; i < amount; i++)
{
float radius = spawnDistance;
float angle = i * Mathf.PI * 2f / (float)amount; // divide by amount, NOT radius
// manipulate radius here as you want
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
...
}

Finding Circle-Line collision (as points, not bools) C#

So unlike everyone here, I'm trying to find the intersections from circle-line collision.
The points are taken from the user input.
float cx; //circle center x
float cy; //circle center y
float px; //point x
float py; //point y
float vx; //vector x
float vy; //vector y
float vySq = vy * vy;
float vxSq = vx * vx;
float cxSq = cx * cx;
float rSq = r * r;
float thatPart = ( ( (vy * px) / vx) + py - cy); //so I don't have to re-type it 3 different times
float a = 1 + (vySq/vxSq);
float b = (2 * cx) + ( (2 * vy) * thatPart / vx);
float c = cxSq + ( thatPart * thatPart ) - rSq;
float x1 = QUADRATIC(a, b, c, true);
float x2 = QUADRATIC(a, b, c, false);
float y1 = ((vy * x1) - (vy * px) + (vx * py)) / vx;
float y2 = ((vy * x2) - (vy * px) + (vx * py)) / vx;
My QUADRATIC function 100% works, so I am not worried about that.
It's a, b, and c. I receive the wrong values for them. And all this math is based on a pdf given in math class. (here)
So... what am I doing wrong?
Thanks.
The equations in both the PDF and the source code seem unnecessarily complicated, so I will re-establish them in a clenear way (or at least one that pleases me).
The vector from the center of the circle to any point S on the line can be written as
CS = CP + t V
where t is an arbitrary parameter.
S belongs to the circle when
CS² = R² = (CP + t V)²
giving the quadratic equation in t:
V² t² + 2 CP.V t + CP² - R² = 0
When you have the values of t, plug in the first equation.
Math Treatment
You have a line with coordinates (x,y) = (px + vx*t, py + vy*t) where t is an arbitrary parameter.
The line intersects the circle when its coordinates solve x^2 + y^2 = r^2.
This leads to the following quadratic equation, to be solved for t.
t^2 + 2*t*b + a = 0
a = (px^2+py^2-r^2)/(vx^2+vy^2)
b = (px*vx+py*vy)/(vx^2+vy^2)
The two solutions are:
t = -b ± sqrt(b^2-a)
Use the two t values into (x,y) to get the coordinates.
Sample Code
static class Program
{
static void Main(string[] args)
{
var ray = new Ray() {
Point = new Vector2(-3, 1),
Direction = new Vector2(2, 0.5f)
};
var circle = new Circle
{
Center = new Vector2(1, 1),
Radius = 4
};
var points = Geometry.Intersect(circle, ray);
if(points.Length>0)
{
foreach(var point in points)
{
Console.WriteLine(point.ToString());
}
}
else
{
Console.WriteLine("Circle and Ray do not intersect");
}
}
}
Object Oriented Models
public class Circle
{
public Vector2 Center { get; set; }
public float Radius { get; set; }
}
public class Ray
{
public Vector2 Point { get; set; }
public Vector2 Direction { get; set; }
public Vector2 Along(float t)
{
return Point + t*Direction;
}
}
public static class Geometry
{
public static Vector2[] Intersect(Circle circle, Ray ray)
{
float a = (ray.Point.LengthSquared()-circle.Radius*circle.Radius)/ray.Direction.LengthSquared();
float b = Vector2.Dot(ray.Point, ray.Direction)/ray.Direction.LengthSquared();
if(b*b-a>0)
{
// two intersection points
float t1 = -b-(float)Math.Sqrt(b*b-a);
float t2 = -b+(float)Math.Sqrt(b*b-a);
return new Vector2[] {
ray.Along(t1),
ray.Along(t2),
};
}
else if(b*b-a==0)
{
// one intersection point
float t = -b;
return new Vector2[] { ray.Along(t) };
}
else
{
// no intersection, return empty array
return new Vector2[0];
}
}
}
NOTE: Code uses System.Numerics library

How can I fix this imperfect circle I made using LineRenderer?

So I made this shape which I applied to a sprite via this script:
using UnityEngine;
using System.Collections;
public class CircleShapeGenerator : MonoBehaviour
{
public int segments = 100;
public float radius = 1;
public Color c1 = new Color( 1, 1, 1, 0.1f );
public Color c2 = new Color( 1, 1, 1, 0.1f );
LineRenderer line;
void Start ()
{
line = gameObject.AddComponent<LineRenderer>();
line.material = new Material(Shader.Find("Particles/Additive"));
line.SetWidth(0.05F, 0.05F);
line.SetVertexCount (segments + 1);
line.useWorldSpace = false;
}
void Update()
{
line.SetColors(c1, c2);
float angle = 20f;
for (int i = 0; i < (segments + 1); i++)
{
float x = Mathf.Sin (Mathf.Deg2Rad * angle) * radius;
float y = Mathf.Cos (Mathf.Deg2Rad * angle) * radius;
line.SetPosition( i, new Vector3( x,y,0) );
angle += (360f / segments);
}
}
}
As you can see in the screenshot, the start and end do not connect as they should. How can I fix this? I found this snippet of code on the entire internet but all give this result. Can somebody fix this or provide, perhaps, a spline solution? I think its overkill to go to a Shader solution (0 experience with shaders).
This solution could be a little bit complicated. But it'll works.
The idea is
1) Draw first segment as small segmented area.
2) Draw from seconds to last -1 segments as big segment.
3) Draw last segment as small segmented area too.
It makes seamless edge between the start segment and the end segment.
And total segment's count is not too many.
total segment = segment + 2 * subsegment
This is sample code.
using UnityEngine;
using System.Collections;
public class CircleShapeGenerator : MonoBehaviour {
public int segments = 100;
public int edgeSegments = 10;
public float radius = 1f;
int vertCount;
float increAngle, increAngleEdge;
public Color c1 = new Color( 1, 1, 1, 1f );
public Color c2 = new Color( 1, 1, 1, 1f );
LineRenderer line;
void Start ()
{
vertCount = segments + 2*edgeSegments - 2 + 1;
increAngle = 360f / segments;
increAngleEdge = increAngle/edgeSegments;
line = gameObject.AddComponent<LineRenderer>();
line.material = new Material(Shader.Find("Particles/Additive"));
line.SetWidth(0.05F, 0.05F);
line.SetVertexCount (vertCount);
line.useWorldSpace = false;
}
void Update()
{
line.SetColors(c1, c2);
//draw first segment
float angle = 0;
for (int i = 0; i < edgeSegments; i++)
{
float x = Mathf.Sin (Mathf.Deg2Rad * angle) * radius;
float y = Mathf.Cos (Mathf.Deg2Rad * angle) * radius;
line.SetPosition( i, new Vector3(x, y, 0) );
angle += increAngleEdge;
}
//draw from seconds to last-1 segment
angle -= increAngleEdge;
for (int i = 0; i < segments-2; i++)
{
angle += increAngle;
float x = Mathf.Sin (Mathf.Deg2Rad * angle) * radius;
float y = Mathf.Cos (Mathf.Deg2Rad * angle) * radius;
line.SetPosition( edgeSegments + i, new Vector3(x, y, 0) );
}
//draw last segment
for (int i = 0; i < edgeSegments+1; i++)
{
angle += increAngleEdge;
float x = Mathf.Sin (Mathf.Deg2Rad * angle) * radius;
float y = Mathf.Cos (Mathf.Deg2Rad * angle) * radius;
line.SetPosition( edgeSegments + segments - 2 + i, new Vector3(x, y, 0) );
}
}
}

Stuck with collision detection in circle pong in xna

I am making clone of Circle pong game in xna. I am not able to get collision of rotating pad with ball. I can't use farseer physics in this game as it is in mono game.
I found one method for it but it also not seem to work.
private void EllasticCollisionPhysics(Ball ball, GoScreen pad)
{
//find normal vector
Vector2 normal = new Vector2(pad.padV.X - ball.ballRectangle.X, pad.padV.Y - ball.ballRectangle.Y);
//find normal vector's modulus, i.e. length
float normalmod = (float)Math.Sqrt(Math.Pow(normal.X, 2) + Math.Pow(normal.Y, 2));
//find unitnormal vector
Vector2 unitnormal = new Vector2((pad.padV.X - ball.ballRectangle.X) / normalmod, (pad.padV.Y - ball.ballRectangle.Y) / normalmod);
//find tangent vector
Vector2 unittan = new Vector2(-1 * unitnormal.Y, unitnormal.X);
//first ball normal speed before collision
float inormalspeedb = unitnormal.X * velocity.X + unitnormal.Y * velocity.Y;
//first ball tangential speed
float itanspeed = unittan.X * velocity.X + unittan.Y * velocity.Y;
//Calculate normal speeds after the collision
//Calculate first ball Velocity vector components (tangential and normal)
Vector2 inormala = new Vector2(unitnormal.X * inormalspeedb, unitnormal.Y * inormalspeedb);
Vector2 itana = new Vector2(unittan.X * itanspeed, unittan.Y * itanspeed);
//Add Vector components to each balls' Velocity
velocity = Vector2.Add(inormala, itana);
You don't need farseer physics for that, what you need is circle to rectangle collisition funciton.
// circle is object with x,y,r parameters
bool intersects(CircleType circle, RectType rect)
{
circleDistance.x = abs(circle.x - rect.x);
circleDistance.y = abs(circle.y - rect.y);
if (circleDistance.x > (rect.width/2 + circle.r)) { return false; }
if (circleDistance.y > (rect.height/2 + circle.r)) { return false; }
if (circleDistance.x <= (rect.width/2)) { return true; }
if (circleDistance.y <= (rect.height/2)) { return true; }
cornerDistance_sq = (circleDistance.x - rect.width/2)^2 +
(circleDistance.y - rect.height/2)^2;
return (cornerDistance_sq <= (circle.r^2));
}
Added CircleType and RectType
public class CircleType
{
public int x;
public int y;
public decimal r;
}
public class RectType
{
public int x;
public int y;
public int width;
public int height;
}

Categories