Drawing polygons using random points? - c++

I am trying to generate a set of points that I will connect to make polygon. The data has to be generated in a systematic way.
I am trying to generate the point set by randomly deriving radial coordinate r and evenly incrementing angular coordinate theta such that all the points are linked orderly without crossing with each other. I followed the correct formulas and I increment the angle but the data comes out negative because of sin and cos. I wanted to know if I'm doing this correctly.
struct Point2D {
int x;
int y;
};
Point2D poly[10];
int N = 80;
int x = (rand() % N + 1) * 5;
int y = (rand() % N + 1) * 5;
int r = sqrt(x*x + y*y);
int theta = int(atan ((float)y/(float)x) * 180 / PI);
cout << "x " << x << " y " << y << " r " << r << " theta " << theta << endl;
for (int i = 0; i < 10; i++) {
Point2D p;
p.x = x;
p.y = y;
poly[i] = p;
theta += 20;
x = r * sin(theta);
y = r * cos(theta);
cout << "x " << x << " y " << y << endl;
}

sin and cos return points on a unit circle centered around (0, 0), as paddy pointed out. To have no negative values in the points on your own polygon, you'll need to shift the origin of that circle. You're already changing its size, with r * sin(theta); you can accomplish a minimum translation with:
x = r * cos(theta) + r;
y = r * cos(theta) + r;
When I make this change to your program, I don't get negative values anymore.
Having said that, I suspect that you're not incrementing theta the way you intend. If you're trying to divide the circle into 10 equal angles, then theta should be a float or double and incremented like this:
theta += (2 * M_PI / 10);
theta is in radians, so 2 * M_PI is once around the unit circle.

Related

c++ - Vector2D math not giving me the right results

I'm trying to create a vector2D class for my game but I think I'm getting the math wrong.
When I create a new vector2d object it automatically sets its x and y to 1, 1 in the constructor.
Vector2D vec;
std::cout << " x: " << vec.GetX() << " y: " << vec.GetY() << " angle rad: " << vec.GetAngleRad() << " magnitude: " << vec.GetMagnitude() << std::endl;
system("pause");
return 0;
and it outputs:
x: 1
y: 1
angle in rad: 0.785398
magnitude: 1.41421
(which is exactly what i expect)
but the problem is when I parse anything to the setAngle funciton, I get some wired results.
For example:
Vector2D vec;
vec.SetAngleRad(3);
std::cout << " x: " << vec.GetX() << " y: " << vec.GetY() << " angle rad: " << vec.GetAngleRad() << " magnitude: " << vec.GetMagnitude() << std::endl;
system("pause");
return 0;
I would expect it to output angle in rad: 3
but instead I get
angle in rad: 0.141593.
This is the vector2D class (I've tried to comment my code so you can see my what I was thinking when I wrote it):
#include "Vector2D.h"
Vector2D::Vector2D():
_x(1.0f),
_y(1.0f)
{
}
Vector2D::~Vector2D()
{
}
void Vector2D::SetX(float x)
{
_x = x;
}
float Vector2D::GetX()
{
return _x;
}
void Vector2D::SetY(float y)
{
_y = y;
}
float Vector2D::GetY()
{
return _y;
}
void Vector2D::SetAngleRad(float angle)
{
float hypotenuse = GetMagnitude();
SetX( cos(angle) * hypotenuse); // cos of angle = x / hypotenuse
// so x = cos of angle * hypotenuse
SetY( sin(angle) * hypotenuse); //sin of angle = y / hypotenuse
// so y = sin of angle * hypotenuse
}
float Vector2D::GetAngleRad()
{
float hypotenuse = GetMagnitude();
return asin( _y / hypotenuse ); // if sin of angle A = y / hypotenuse
// then asin of y / hypotenuse = angle
}
void Vector2D::SetMagnitude(float magnitude)
{
float angle = GetAngleRad();
float hypotenuse = GetMagnitude();
SetX( (cos(angle) * hypotenuse) * magnitude ); // cos of angle = x / hypotenuse
// so cos of angle * hypotenuse = x
// multiplied by the new magnitude
SetY( (sin(angle) * hypotenuse) * magnitude); //sin of angle = y / hypotenuse
// so sin of angle * hypotenuse = y
// multipied by the new magnitude
}
float Vector2D::GetMagnitude()
{
return sqrt( (_x * _x) + (_y * _y) ); // a^2 + b^2 = c^2
//so c = sqrt( a^2 + b^2 )
}
So I'd really appreciate it if someone could explain to me what I'm doing wrong here :)
To get angle in full circle range, you have to use both y and x components with atan2 function
return atan2( _y, _x );
Note result range -Pi..Pi and correct negative one by +2*Pi if you need range 0..2*Pi
Another issue: :SetMagnitude method really multiplies current magnitude by magnitude multiplier, while name assumes that method should set it (so vector length 2 after applying SetMagnitude(2) will have magnitude 4)).
So it would better to remove *hypotenuse multiplication (or change method name)

Dividing circle into n equal parts to get coordinates of each dividing point

I have read this and I tried to implement it in C++, but the output is quite different. I have no idea what is wrong.
The code I used:
double cordinate_print()
{
int x, y;
int number_of_chunks = 5;
double angle=0;
double x_p[5] ; // number of chunks
double y_p[5]; // number of chunks
//double x0, y0 = radious;
double rad = 150;
for (int i = 0; i < number_of_chunks; i++)
{
angle = i * (360 / number_of_chunks);
float degree = (angle * 180 / M_PI);
x_p[i] = 0 + rad * cos(degree);
y_p[i] = 0 + rad * sin(degree);
//printf("x-> %d y-> %d \n", x_p[i], y_p[i]);
cout << "x -> " << x_p[i] << "y -> " << y_p[i] << "\n";
}
//printing x and y values
printf("\n \n");
return 0;
}
Output
x -> 150 y -> 0
x -> -139.034 y -> -56.2983
x -> 107.74 y -> 104.365
x -> -60.559 y -> -137.232
x -> 4.77208 y -> 149.924
The correct output
(150,0)
(46,142)
(-121,88)
(-121,-88)
(46,-142)
Issue with the conversion of degree into radian
float degree = (angle * 180 / M_PI);
The correct conversion formula is
float radian = (angle * M_PI / 180);
Also as mentioned in the comment use the good name to avoid any confusion.
Since your default angles are in degrees, you need to convert them to radians first before using sin() and cos(), then multiplying it to the radius.
double cordinate_print()
{
int number_of_chunks = 5;
double degrees = 0; // <-- correction
double x_p[5]; // number of chunks
double y_p[5]; // number of chunks
double radius = 150; // <-- correction
for (int i = 0; i < number_of_chunks; i++)
{
degrees = i * (360 / number_of_chunks); // <-- correction
float radian = (degrees * (M_PI / 180)); // <-- correction
x_p[i] = radius * cos(radian); // <-- correction
y_p[i] = radius * sin(radian); // <-- correction
cout << "x -> " << x_p[i] << "y -> " << y_p[i] << "\n";
}
//printing x and y values
printf("\n \n");
return 0;
}

Issue inverting 2D matrix

I am working on a function in a class to store images. The purpose of this function is the perform linear transformations using a 2D matrix (I don't plan on supporting translation). The way I wanted to do it was to test transform the coordinates of the corners of the original image and use the extreme values to calculate the necessary size for the resulting transformed image.
One I have the new image I wanted to loop over all the pixels in the new image and use the inverse transform the calculate where on the original image the new pixels should get their color from (using bilinear interpolation).
I started writing the following function. It does not yet do anything to the image. The issue is that when I pass a set of coordinates through the transform function and then pass those new coordinates through the inverse function I expect to get the original values back. However I am not getting back the original values.
Image Image::matrix_transform(float m11, float m12, float m21, float m22) const
{
float det = m11 * m22 - m12 * m21;
img_assert(det, "Matrix not invertible.");
//inverse matrix values
float im11 = m22 / det;
float im22 = m11 / det;
float im21 = -m21 / det;
float im12 = -m12 / det;
//transformation
const auto t = [m11, m12, m21, m22](float& x, float& y)
{
x = x * m11 + y * m12;
y = x * m21 + y * m22;
};
//inverse
const auto ti = [im11, im12, im21, im22](float& x, float& y)
{
x = x * im11 + y * im12;
y = x * im21 + y * im22;
};
float x00 = 0.0f, y00 = 0.0f;
float x11 = w, y11 = h;
float x10 = 0.0f, y10 = h;
float x01 = w, y01 = 0.0f;
std::cout << x00 << " " << y00 << std::endl;
std::cout << x01 << " " << y01 << std::endl;
std::cout << x10 << " " << y10 << std::endl;
std::cout << x11 << " " << y11 << std::endl;
t(x00, y00);
t(x11, y11);
t(x10, y10);
t(x01, y01);
ti(x00, y00);
ti(x11, y11);
ti(x10, y10);
ti(x01, y01);
std::cout << x00 << " " << y00 << std::endl;
std::cout << x01 << " " << y01 << std::endl;
std::cout << x10 << " " << y10 << std::endl;
std::cout << x11 << " " << y11 << std::endl;
return *this;
}
Here is how I am calling the function (a simple rotation matrix).
img.matrix_transform(cos(angle), -sin(angle), sin(angle), cos(angle));
Here is the output I get...
0 0
2500 0
0 1655
2500 1655
0 0
1975.95 -722.386
-743.978 629.455
1231.97 -92.9314
I was expecting the top set of coordinates to match the bottom.
Here
x = x * m11 + y * m12;
y = x * m21 + y * m22;
the second assignment uses the already modified x value. Change it to
auto newx = x * m11 + y * m12;
y = x * m21 + y * m22;
x = newx;

Given two points (x1,y1) (x2,y2), how can I compute N different points evenly lying on the line between the given points

I have two points and I would like to compute n evenly distributed points on top of the line created by the given line. How could I perform this in c++?
Linear interpolation (affectionately called lerp by the Graphics community) is what you want. Given the end points it can generate the points lying in between with a parameter t.
Let the end points be A (Ax, Ay) and B (Bx, By). The vector spanning from A to B would be given by
V = B − A = <Vx, Vy>
L(t) = A + tV
This essentially means that starting from the point A, we scale the vector V with the scalar t; the point A is displaced by this scaled vector and thus the point we get depends on the value of t, the parameter. When t = 0, we get back A, if t = 1 we get B, if it's 0.5 we get the point midway between A and B.
line A----|----|----|----B
t 0 ¼ ½ ¾ 1
It works for any line (slope doesn't matter). Now coming to your problem of N stops. If you need N to be 10, then you'd have t vary by 1/N, so t = i/10, where i would be the loop iterator.
i = 0, t = 0
i = 1, t = 0.1
i = 2, t = 0.2
⋮
i = 9, t = 0.9
i = 10, t = 1.0
Here's one way to implement it:
#include <iostream>
struct Point {
float x, y;
};
Point operator+ (Point const &pt1, Point const &pt2) {
return { pt1.x + pt2.x, pt1.y + pt2.y };
}
Point operator- (Point const &pt1, Point const &pt2) {
return { pt1.x - pt2.x, pt1.y - pt2.y };
}
Point scale(Point const &pt, float t) {
return { pt.x * t, pt.y * t };
}
std::ostream& operator<<(std::ostream &os, Point const &pt) {
return os << '(' << pt.x << ", " << pt.y << ')';
}
void lerp(Point const &pt1, Point const &pt2, float stops) {
Point const v = pt2 - pt1;
float t = 0.0f;
for (float i = 0.0f; i <= stops; ++i) {
t = i / stops;
Point const p = pt1 + scale(v, t);
std::cout << p << '\n';
}
}
int main() {
lerp({0.0, 0.0}, {5.0f, 5.0f}, 5.0f);
}
Output
(0, 0)
(1, 1)
(2, 2)
(3, 3)
(4, 4)
(5, 5)
Aside
Notice that on every iteration t gets incremented by Δt = 1 / N. Thus another way to update t in a loop would be
t₀ = 0
t₁ = t₀ + Δt
t₂ = t₁ + Δt
⋮
t₉ = t₈ + Δt
t₁₀ = t₉ + Δt
However, this isn't very parallelizable since every iteration of the loop would depend on the previous iteration.
You can use the following give_uniform_points_between(M, N, num_points) which gives a number of #num_points points between M and N. I assume here that the line is not vertical (see below if the line can be vertical).
std::vector<Point> give_uniform_points_between(const Point& M, const Point& N, const unsigned num_points) {
std::vector<Point> result;
// get equation y = ax + b
float a = (N.y - M.y) / (N.x - M.x);
float b = N.y - a * N.x;
float step = std::fabs(M.x - N.x) / num_points;
for (float x = std::min(M.x, N.x); x < std::max(M.x, N.x); x += step) {
float y = a*x+b;
result.push_back(Point{x,y});
}
return result;
}
Demo : Live on Coliru
and result is :
(-3,9);(-2.3,7.6);(-1.6,6.2);(-0.9,4.8);(-0.2,3.4);(0.5,2);(1.2,0.6);(1.9,-0.8);(2.6,-2.2);(3.3,-3.6);
Explanation
From two points (x1,y1) and (x2,y2) you can guess the line equation which pass through these points.
This equation takes the form a*x + b*y + c = 0 or simply y = a*x + b if you cannot have vertical line
where a = (y2 - y1) / (x2 - x1) and you deduce b as shown in the code.
Then you can just vary x or y along your line starting for the point with a minimum value coordinate.
All these (x,y) points you find are on your line and should be uniformely distributed (thanks to the fixed step).
View the line as (x1,y1) + λ(x2-x1,y2-y1), i.e. the first point, plus a multiple of the vector between them.
When λ=0 you have the first point and when λ=1 you have the second.
So you just want to take n equally distributed values of λ between 0 and 1.
How you do this depends on what you mean by between: are the end points included or not?
For example you could take λ=0/(n-1), λ=1/(n-1), λ=2/(n-1), ... λ=(n-1)/(n-1).
That would give n equally distributed points including the endpoints.
Or you could take λ=1/(n+1), λ=2/(n+1), ... λ=n/(n+1).
That would give n equally distributed points not including the endpoints.
Not so mcuh math though...
vector<Rect> Utils::createReactsOnLine(Point pt1, Point pt2, int numRects, int height, int width){
float x1 = pt1.x;
float y1 = pt1.y;
float x2 = pt2.x;
float y2 = pt2.y;
float x_range = std::abs(x2 - x1);
float y_range = std::abs(y2 - y1);
// Find center points of rects on the line
float x_step_size = x_range / (float)(numRects-1);
float y_step_size = y_range / (float)(numRects-1);
float x_min = std::min(x1,x2);
float y_min = std::min(x1,x2);
float x_max = std::max(x1,x2);
float y_max = std::max(x1,x2);
cout << numRects << endl;
float next_x = x1;
float next_y = y1;
cout << "Next x, y: "<< next_x << "," << next_y << endl;
for(int i = 0; i < numRects-1; i++){
if (x1 < x2)
next_x = next_x + x_step_size;
else
next_x = next_x - x_step_size;
if (y1 < y2)
next_y = next_y + y_step_size;
else
next_y = next_y - y_step_size;
cout << "Next x, y: "<< next_x << "," << next_y << endl;
}
return vector<Rect>();
}

How to get sampling points by rotating a direction in a for loop?

I need to loop over a given number of sampling points. Those sampling points are normalized vectors representing directions. They should be calculate them in code. Starting with a forward vector 1, 0, I want to rotate around the origin so that I came up with the given number of directions.
for(int i = 0; i < number_of_sampling_points; ++i)
{
// get direction vector based on i and number_of_sampling_points
// ...
}
For example, with number_of_sampling_points is 4 inside the loop I want to get the value pairs 1, 0, 0, 1, -1, 0, 0, -1. The order doesn't matter.
Try this:
const double PI = 3.14159265358979323846;
const int number_of_sampling_points = 4;
for (int i = 0; i < number_of_sampling_points; ++i)
{
const double a = PI * 2 * (1.0 - i) / number_of_sampling_points;
double x = sin(a);
double y = cos(a);
cout << "(" << x << " , " << y << ")" << endl;
}
Output (rounded):
(1 , 0)
(0 , 1)
(-1 , 0)
(0 , -1)
Use trig:
double x = std::cos(pi * 2 * (double)i / (double)number_of_sampling_points);
double y = std::sin(pi * 2 * (double)i / (double)number_of_sampling_points);