I HAVE to draw a circle with the following code
(check if point is on the circle).
int rad=10;
// i=x,j=y
for (int j=ymid-rad;j<=ymid+rad;j++){
for (int i=xmid-rad;i<=xmid+rad;i++){
if (((i-xmid)*(i-xmid)+(j-ymid)*(j-ymid)) == rad*rad)
Image1->Canvas->Pixels[i][j]=clRed;
}
}
However it only draws a few points of the circle.
What am I doing wrong?
Thank you.
You're doing all of this in integer arithmetic; there are very few integer solutions to x^2 + y^2 == r^2 (for a fixed r).
I suggest using something like the midpoint circle algorithm instead.
Range based version would work like this:
bool RangeCheck(float val, float r1, float r2) {
return val >= r1 && val <= r2;
}
bool Circle(float x, float y, float rad) {
return RangeCheck(sqrtf(x*x+y*y), rad-0.8, rad+0.8);
}
bool CircleWithCenter(float x, float y, float cx, float cy, float rad) {
x-=cx; y-=cy;
return Circle(x,y,rad);
}
This kind of range is how they can draw isolines in weather forecasts, but works also for circles.
Related
So I'm writting a function that takes a point and rotates it around another point at a certain angle, so when I draw a rectangle, I want that rectangle to be rotated as well,but it's distorted.I'm also drawing two colored rectangles, one without rotation and one rotated by the angle provided, like in this picture:
The purple outline should look like the red one.
This is the code for the rotation
double d2r(double d)
{
return (d / 180.0) * ((double)M_PI);
}
double sind(double x)
{
return std::sin(d2r(x));
}
double cosd(double x)
{
return std::cos(d2r(x));
}
std::pair<double, double> rotate_around(double x, double y, double o_x, double o_y, double angle)
{
x = o_x + (x - o_x) * cosd(angle) - (y - o_y) * sind(angle);
y = o_y + (y - o_y) * cosd(angle) + (x - o_x) * sind(angle);
return std::pair<double, double>(x, y);
}
The function rotate_around is called with the following parameters
(original x, original y , middle x of the rectangle, middle y of the rectangle, angle of the rectangle)
Can someone please tell me what am I doing wrong here?
x-= o_x; y-= o_y;
angle= d2r(angle);
double c= std::cos(angle), s= std::sin(angle);
return std::pair<double, double>(o_x + x * c - y * s, o_y + y * c + x * s);
will work.
Problem
I am writing a ray tracer as a use case for a specific machine learning approach in Computer Graphics.
My problem is that, when I try to find the intersection between a ray and a surface, the result is not exact.
Basically, if I am scattering a ray from point O towards a surface located at (x,y,z), where z = 81, I would expect the solution to be something like S = (x,y,81). The problem is: I get a solution like (x,y,81.000000005).
This is of course a problem, because following operations depend on that solution, and it needs to be the exact one.
Question
My question is: how do people in Computer Graphics deal with this problem? I tried to change my variables from float to double and it does not solve the problem.
Alternative solutions
I tried to use the function std::round(). This can only help in specific situations, but not when the exact solution contains one or more significant digits.
Same for std::ceil() and std::floor().
EDIT
This is how I calculate the intersection with a surface (rectangle) parallel to the xz axes.
First of all, I calculate the distance t between the origin of my Ray and the surface. In case my Ray, in that specific direction, does not hit the surface, t is returned as 0.
class Rectangle_xy: public Hitable {
public:
float x1, x2, y1, y2, z;
...
float intersect(const Ray &r) const { // returns distance, 0 if no hit
float t = (y - r.o.y) / r.d.y; // ray.y = t* dir.y
const float& x = r.o.x + r.d.x * t;
const float& z = r.o.z + r.d.z * t;
if (x < x1 || x > x2 || z < z1 || z > z2 || t < 0) {
t = 0;
return 0;
} else {
return t;
}
....
}
Specifically, given a Ray and the id of an object in the list (that I want to hit):
inline Vec hittingPoint(const Ray &r, int &id) {
float t; // distance to intersection
if (!intersect(r, t, id))
return Vec();
const Vec& x = r.o + r.d * t;// ray intersection point (t calculated in intersect())
return x ;
}
The function intersect() in the previous snippet of code checks for every Rectangle in the List rect if I intersect some object:
inline bool intersect(const Ray &r, float &t, int &id) {
const float& n = NUMBER_OBJ; //Divide allocation of byte of the whole scene, by allocation in byte of one single element
float d;
float inf = t = 1e20;
for (int i = 0; i < n; i++) {
if ((d = rect[i]->intersect(r)) && d < t) { // Distance of hit point
t = d;
id = i;
}
}
// Return the closest intersection, as a bool
return t < inf;
}
The coordinate is then obtained using the geometric interpolation between a line and a surface in the 3D space:
Vec& x = r.o + r.d * t;
where:
r.o: it represents the ray origin. It's defined as a r.o : Vec(float a, float b, float c)
r.d : this is the direction of the ray. As before: r.d: Vec(float d, float e, float f).
t: float representing the distance between the object and the origin.
You could look into using std::numeric_limits<T>::epsilon for your float/double comparison. And see if your result is in the region +-epsilon.
An alternative would be to not ray trace towards a point. Maybe just place relatively small box or sphere there.
I have a function that is supposed to return true if two circles are colliding and false otherwise, and to help while developing I have also added a part within the function to draw the hitbox only when they're not colliding.
My issue is even when they are colliding it will continue to draw the hitbox, and say they're not colliding, indicating that the function isn't working properly.
int colliding(int x, int y, int r, int x1, int y1, int r1)
{
//compare the distance to combined radii
int dx = x1 - x;
int dy = y1 - y;
int radii = r + r1;
if ((dx * dx) + (dy * dy) < radii * radii)
{
return true;
}
else
{
player.hitbox.draw();
return false;
}
}
int main()
{
while (true)
{
player.draw();
int cx = 300;
int cy = 300;
int cr = 50;
al_draw_filled_circle(camera.getScreenPosX(cx), camera.getScreenPosY(cy), cr, al_map_rgb(0, 0, 0));
colliding(player.hitbox.posX, player.hitbox.posY, player.hitbox.radius, cx, cy, cr);
al_flip_display();
al_clear_to_color(al_map_rgb(255, 255, 255));
}
}
I would assume that camera.getScreenPosX/Y() transforms your cx/cy/cr circle into another space than the one where player.hitbox.posx/y are. I cannot be sure however, because implementation of player.hitbox.draw() is not given.
Your collision function seems fine, so I'd go and check whether player.hitpox.posx/y and cx/cy are in the same coordinate space.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I'm trying to calculate multiple points on an angle (circle segment) so that I can store it as a VBO of Vector3 and render it in OpenGL.
Imagine each of those points on the dotted line as a coordinate I want to calculate
I know I can find the magnitude of the angle using the dot product, and in 2 dimensions I would be able to calculate the points on the angle just using sin and cos of this angle. But how do I apply this in 3 dimensions?
I thought maybe I should split the angle down into components, but then wasn't sure how to calculate magnitudes in that situation.
So what is the best method for calculating those points, and how do I do it?
I'm working in C# but of course pseudo code or just methods would do.
normalize and scale both vectors and then slerp between them
slerp stands for spherical linear interpolation and is referenced mostly for quaternions but is valid here as well
vec3 slerp(vec3 a, vec3 b, float t){
float dotp = dot(a,b);
if (dotp > DOT_THRESHOLD) {
// If the inputs are too close for comfort, linearly interpolate
// and normalize the result to avoid division by near 0
vec3 result = v0 + t*(v1 – v0);
result.normalize();
return result;
}
float theta = acos(dotp);
return (sin(theta*(1-t))*a + sin(theta*t)*b)/sin(theta);
}
The trick is to compute the dots as if your two vectors are the unit vectors. Just a half circle. But then instead of writing it as (x,y) = (0,0,1)*x + (0,1,0)*y... just put in your two red and green vectors as a new base.
Compute your 2d x,y circle points. Then the 3d point is redvector*x + greenvector*y.
Here is a C++ DLL for your C# project(tested but angles are not uniform but there is no division by zero as long as vectors have a magnitude):
Usage:
[DllImport("angle.dll")]
extern static void anglePoints(
float x1,
float y1,
float z1,
float x2,
float y2,
float z2,
float [] points
);
İnside of DLL:
class float3
{
public:
float x,y,z;
float3(float X, float Y, float Z)
{
x=X; y=Y; z=Z;
}
float3 sub(float X, float Y, float Z)
{
float3 tmp(0,0,0);
tmp.x=x-X;
tmp.y=y-Y;
tmp.z=z-Z;
return tmp;
}
float3 sub(float3 b)
{
float3 tmp(0,0,0);
tmp.x=x-b.x;
tmp.y=y-b.y;
tmp.z=z-b.z;
return tmp;
}
float3 add(float3 b)
{
float3 tmp(0,0,0);
tmp.x=x+b.x;
tmp.y=y+b.y;
tmp.z=z+b.z;
return tmp;
}
void normalize()
{
float r=sqrt(x*x+y*y+z*z);
x/=r;
y/=r;
z/=r;
}
void scale(float s)
{
x*=s;y*=s;z*=s;
}
void set(float3 v)
{
x=v.x;y=v.y;z=v.z;
}
};
extern "C" __declspec(dllexport) void anglePoints(
float x1,
float y1,
float z1,
float x2,
float y2,
float z2,
float * points
)
{
float3 A(x1,y1,z1);
float3 B(x2,y2,z2);
float3 tmp(0,0,0);
float3 diff(0,0,0);
for(int i=0;i<10;i++)
{
tmp.set(A);
diff.set(B.sub(A));
diff.scale(0.1*((float)i)); // simple and not efficient :P
diff.set(diff.add(tmp));
diff.normalize(); // normalized values so you can
points[i*3+0]=diff.x; // simply use them
points[i*3+1]=diff.y;
points[i*3+2]=diff.z;
}
}
Example:
float[] tmp = new float[30];
anglePoints(0,1,1,10,10,10,tmp);
for (int i = 0; i < 30; i++)
{
Console.WriteLine(tmp[i]);
}
Output:
0 // starts as 0,1,1 normalized
0,7071068
0,7071068
0,34879
0,6627011
0,6627011
0,4508348
0,6311687
0,6311687
0,4973818
0,6134375
0,6134375
0,5237828
0,6023502
0,6023502
0,540738
0,5948119
0,5948119
0,5525321
0,5893675
0,5893675
0,5612046
0,5852562
0,5852562
0,5678473
0,5820435
0,5820435
0,5730973 //ends as 10,10,10 but normalized
0,579465
0,579465
I'm no mathematician, but I need to draw a filled in circle.
My approach was to use someone else's math to get all the points on the circumference of a circle, and turn them into a triangle fan.
I need the vertices in a vertex array, no immediate mode.
The circle does appear. However, when I try and overlay circles strange things happen. They appear only a second and then disappear. When I move my mouse out of the window a triangle sticks out from nowhere.
Here's the class:
class circle
{
//every coordinate with have an X and Y
private:
GLfloat *_vertices;
static const float DEG2RAD = 3.14159/180;
GLfloat _scalex, _scaley, _scalez;
int _cachearraysize;
public:
circle(float scalex, float scaley, float scalez, float radius, int numdegrees)
{
//360 degrees, 2 per coordinate, 2 coordinates for center and end of triangle fan
_cachearraysize = (numdegrees * 2) + 4;
_vertices = new GLfloat[_cachearraysize];
for(int x= 2; x < (_cachearraysize-2); x = x + 2)
{
float degreeinRadians = x*DEG2RAD;
_vertices[x] = cos(degreeinRadians)*radius;
_vertices[x + 1] = sin(degreeinRadians)*radius;
}
//get the X as X of 0 and X of 180 degrees, subtract to get diameter. divide
//by 2 for radius and add back to X of 180
_vertices[0]= ((_vertices[2] - _vertices[362])/2) + _vertices[362];
//same idea for Y
_vertices[1]= ((_vertices[183] - _vertices[543])/2) + _vertices[543];
//close off the triangle fan at the same point as start
_vertices[_cachearraysize -1] = _vertices[0];
_vertices[_cachearraysize] = _vertices[1];
_scalex = scalex;
_scaley = scaley;
_scalez = scalez;
}
~circle()
{
delete[] _vertices;
}
void draw()
{
glScalef(_scalex, _scaley, _scalez);
glVertexPointer(2,GL_FLOAT, 0, _vertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, _cachearraysize);
}
};
That's some ugly code, I'd say - lots of magic numbers et cetera.
Try something like:
struct Point {
Point(float x, float y) : x(x), y(y) {}
float x, y;
};
std::vector<Point> points;
const float step = 0.1;
const float radius = 2;
points.push_back(Point(0,0));
// iterate over the angle array
for (float a=0; a<2*M_PI; a+=step) {
points.push_back(cos(a)*radius,sin(a)*radius);
}
// duplicate the first vertex after the centre
points.push_back(points.at(1));
// rendering:
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2,GL_FLOAT,0, &points[0]);
glDrawArrays(GL_TRIANGLE_FAN,0,points.size());
It's up to you to rewrite this as a class, as you prefer. The math behind is really simple, don't fear to try and understand it.