Drawing pixels which connect 2 points - c

I'm trying to draw the direction of my player on a minimap. I have the ending point of where to draw and the starting point. I'd like to connect the two to actually draw the direction the player is facing.
I have found the ending point using the player direction X and Y.
I'm working with pixels.
I'm only allowed to use my school's library for drawing into a window.
Here's how I get the endpoint and starting point (x and y being the player's coordinate (int), dir_x and dir_y are doubles for the direction (double), start.x and y are (ints)).
start.x = x * MAP_ELEM_PX_SIZE + MAP_PLAYER_PX_SIZE / 2 + (MAP_PLAYER_PX_SIZE + 5) * pos.dir_x;
start.y = y * MAP_ELEM_PX_SIZE + MAP_PLAYER_PX_SIZE / 2 + (MAP_PLAYER_PX_SIZE + 5) * pos.dir_y;
end.x = x * MAP_ELEM_PX_SIZE + MAP_PLAYER_PX_SIZE / 2;
end.y = y * MAP_ELEM_PX_SIZE + MAP_PLAYER_PX_SIZE / 2;
I first tried by just iterating over the x and y at the same time like in this method
int draw_dir_ray(t_coord start, t_coord end, t_win *win)
{
int i;
int j;
i = 0;
j = 0;
if (start.x < end.x)
i = 1;
else if (start.x > end.x)
i = -1;
if (start.y < end.y)
j = 1;
else if (start.y > end.y)
j = -1;
while (start.x != end.x || start.y != end.y)
{
set_pixel(win, start.x, start.y, 0x009E00);
if (start.x != end.x)
start.x += i;
if (start.y != end.y)
start.y += j;
}
return (1);
}
Here are a few screenshots of what it's rendering. As you can see it's not really the expected result...
(Though I tried to give the most informations I can provide some more if needed)

Thanks to you guys I searched at the Bresenham's line algorithm and implemented it this way !
int draw_dir_ray(t_coord start, t_coord end, t_win *win)
{
int dx;
int dy;
int sx;
int sy;
int err;
int e2;
dx = abs(end.x - start.x);
dy = -abs(end.y - start.y);
sx = start.x < end.x ? 1 : -1;
sy = start.y < end.y ? 1 : -1;
err = dx + dy;
while (1)
{
set_pixel(win, start.x, start.y, 0xFF0000);
set_pixel(win, start.x - 1, start.y, 0xFF0000);
set_pixel(win, start.x, start.y - 1, 0xFF0000);
set_pixel(win, start.x - 1, start.y - 1, 0xFF0000);
if (start.y == end.y && start.x == end.x)
break ;
e2 = 2 * err;
if (e2 >= dy)
{
err += dy;
start.x += sx;
}
if (e2 <= dx)
{
err += dx;
start.y += sy;
}
}
return (1);

Related

Fisheye Raycasting

I'm trying to build simple raycasting game. I'm rendering wall based on light length. Wall size is calculated based on natural log formula.
Problem is fisheye! I tries cos formula but it's not applicable to my architecture.
Here's the code:
void draw_3d(t_cub3d *this, double len, int num_of_ray, double start)
{
double height;
double width;
double x;
double y;
height = 720 / log10(len + 1);
if (height > 720)
height = 720;
width = 1280.0 / 640;
y = (720 - height) / 2;
while (y < height)
{
x = 2 * num_of_ray;
while(x < 2 + width * num_of_ray)
{
my_mlx_pixel_put(this, (int)x, (int)y, 0xfffff);
x++;
}
y++;
}
}
int raycast(t_cub3d *this)
{
double start = this->raycast->pa - this->raycast->fov;
double end = this->raycast->pa + this->raycast->fov;
double ray_p_x;
double ray_p_y;
double len;
int num_of_ray;
num_of_ray = 0;
while (start <= end)
{
ray_p_x = this->raycast->px;
ray_p_y = this->raycast->py;
while (this->gameinfo->map[(int) ray_p_y / 30][(int) ray_p_x / 30] != '1' && this->gameinfo->map[(int) ray_p_y / 30][(int) ray_p_x / 30] != ' ')
{
ray_p_x += cos(start);
ray_p_y += sin(start);
}
len = fabs(this->raycast->px - ray_p_x) / fabs(cos(start));
len *= cos(this->raycast->pa - start);
start += this->raycast->fov / 320;
draw_3d(this, len, num_of_ray, start);
num_of_ray++;
}
mlx_put_image_to_window(this->mlx_info->mlx, this->mlx_info->mlx_win, this->img->img, 0, 0);
return (0);
}
How to fix fisheye distortion if cos formula doesn't apply to my case.
How it looks like
How it looks like

How can I turn this function implementation into a threaded version?

I need to turn the following implementation of this function into a threaded one.
Yet, I have absolutely no clue on how to do so nor how to approach the problem.
Any tips or orientation is much appreciated.
void compute_target_pixel(int x, int y) {
int i, j, sum = 0;
int delta = (KLEN - 1) / 2;
for (i = -delta; i <= delta; ++i)
for (j = -delta; j <= delta; ++j)
if (0 <= x + i && x + i < WIDTH && 0 <= y + j && y + j < HEIGHT)
sum += filter.values[(i + delta) * KLEN + (j + delta)] * pixels[(x + i) * HEIGHT + (y + j)];
if(filter.sum > 0) target[x * HEIGHT + y] = sum / filter.sum;
else target[x * HEIGHT + y] = sum;
}

Game of Life problem with board update function in C

I need help with my Game of Life implementation in C. Other posts on Stackoverflow lead me to believe that my problem was to do with dangling pointers, but after modifying my program to use a global 2D array for the game grid instead of passing it to functions which return new 2D arrays, I realized that it was a problem with my update function.
I have tried hard-coding a number of simple patterns, including gliders and oscillators, and the grid doesn't update correctly. The patterns do update the same way every time the program is run, so I don't think it's a problem of uninitialized memory causing problems. I also know that there are no cells which contain values greater than 1. Therefore, the problem must lie in my mechanisms for updating the grid.
Can someone help me find the problem? I can't find anything wrong with my code and I believe I have programmed the rules correctly.
Here are my neighbors and update functions, along with the relevant variable and constant declarations.
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
int grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int dx, dy, dstx, dsty;
int n = 0;
for (dy = -1; dy <= 1; ++dy) {
for (dx = -1; dx <= 1; ++dx) {
dsty = y + dy;
dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X)
n += !!grid[dsty][dstx]; /* use !! so that non-zero values eval to 1 */
}
}
/* (n > 0) ? printf("Point (%d,%d) has %d neighbors!\n", x, y, n) : 0; */
return n;
}
void update(void) {
int new[MAX_Y][MAX_X];
memset(new, 0, sizeof(int) * MAX_Y * MAX_X);
int i, j, n;
for (i = 0; i < MAX_Y; ++i) {
for (j = 0; j < MAX_X; ++j) {
n = neighbors(i, j);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
if (grid[i][j] && (n == 2 || n == 3))
new[i][j] = 1;
else if (!grid[i][j] && n == 3)
new[i][j] = 1;
else
new[i][j] = 0;
}
}
memcpy(grid, new, sizeof grid);
}
In your neighbors function, you need to think carefully about the loop iteration where dx and dy are both zero. Conway's Game of Life does not consider a cell to be neighbor of itself, so you need to avoid counting it.
You're also confusing yourself by using the letters i and j. You're allowing j to go all the way up to MAX_X, but then you are using j as the y coordinate when you call neighbors, so that will cause overflows and incorrect calculations. (Starting with the easier case of a 10x10 grid would sometimes save you from bugs like this.)
You should adjust the neighbors() function to omit the cell itself.
Here is a modified version:
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
unsigned char grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int n = -!!grid[y][x];
for (int dy = -1; dy <= 1; ++dy) {
for (int dx = -1; dx <= 1; ++dx) {
int dsty = y + dy;
int dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X && grid[dsty][dstx])
n++;
}
}
return n;
}
void update(void) {
int new[MAX_Y][MAX_X] = { 0 };
for (int y = 0; y < MAX_Y; ++y) {
for (int x = 0; x < MAX_X; ++x) {
int n = neighbors(y, x);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
new[y][x] = (grid[y][x] && n == 2) || n == 3;
}
}
memcpy(grid, new, sizeof grid);
}
The neighbors() function can be simplified with fewer tests:
int neighbors(int x, int y) {
int n = -(grid[y][x] != 0);
int x1 = x - (x > 0);
int x2 = x + (x < MAX_X - 1);
int y1 = y - (y > 0);
int y2 = y + (y < MAX_Y - 1);
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
n += grid[y][x] != 0;
}
}
return n;
}

Convex hull length in C

Im making a program to calculate convex hull length of 2D points.
On the input there is a number of points n and then the coordinates of each point.
for example:
6
-8 -3
-6 1
-5 -2
-3 1
-3 4
2 18
and output is simply the length of the convex hull.
my code looks like this so far:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct point
{
double x;
double y;
}POINT,VECTOR;
POINT b[1000];
VECTOR normal;
int n;
int upper_lower(int i, VECTOR ab, double c) {
double x, y,result;
y = b[i].y;
x = normal.x*b[i].x;
result = -(x + c) / normal.y;
if (y>result) return 1;
if (y == result) return 0;
else
return -1;
}
int ccw(VECTOR v,VECTOR v2)
{
double cp;
cp = v2.x*v.y - v2.y*v.x;
if (cp == abs(cp)) return 1;
else
return -1;
}
double vector_length(VECTOR v)
{
return sqrt(pow(v.x, 2) + pow(v.y, 2));
}
int cmp_points(const void *p1, const void *p2)
{
const POINT *pt1 = p1;
const POINT *pt2 = p2;
// do primary compare on x
if (pt1->x > pt2->x)
return 1;
if (pt1->x < pt2->x)
return -1;
// pt1->x == pt2->x - do secondary compare on y...
if (pt1->y > pt2->y)
return 1;
if (pt1->y < pt2->y)
return -1;
// pt1 == pt2
return 0;
}
int main()
{
int i,poloha,upper[1000],lower[1000],h=0,d=0;
scanf("%d", &n);
if (n <= 0 && n > 1000) return 0;
for (i = 0; i < n; i++)
{
scanf("%lf %lf", &b[i].x, &b[i].y);
}
qsort(b, n, sizeof(POINT), cmp_points);
//split in half
VECTOR ab;
double c;
ab.x = b[n - 1].x - b[0].x;
ab.y = b[n - 1].y - b[0].y;
normal.x = -ab.y;
normal.y = ab.x;
c = -normal.x*b[0].x - (normal.y*b[0].y);
for (i = 0; i < n; i++)
{
poloha = upper_lower(i,ab,c);
if (poloha == 1) upper[h++] = i;
if (poloha == -1) lower[d++]=i;
if (poloha == 0)
{
upper[h++] = i;
lower[d++] = i;
}
}
int j = 0;
double v, length = 0;
VECTOR v1, v2, v3,v4;
v3.x = 0; v3.y = 0;
//lower part
for (i = 0; ; i++)
{
int in = 0;
if (lower[i + 2] < 0)
{
v1.x = b[lower[i + 1]].x - b[lower[0]].x;
v1.y = b[lower[i + 1]].y - b[lower[0]].y;
v2.x = b[lower[i]].x - b[lower[i + 1]].x;
v2.y = b[lower[i]].y - b[lower[i + 1]].y;
lenght += vector_length(v1);
length += vector_length(v2);
break;
}
v1.x = b[lower[i + 1]].x - b[lower[i]].x;
v1.y = b[lower[i + 1]].y - b[lower[i]].y;
v2.x = b[lower[i + 2]].x - b[lower[i]].x;
v2.y = b[lower[i + 2]].y - b[lower[i]].y;
in = ccw(v1, v2);
if (in == 1)
{
length += vector_length(v1);
v3 = v2;
v4 = v1;
}
if (in == -1)
{
length -= vector_length(v4);
if (v3.x != 0 && v3.y != 0)
{
length += vector_length(v3);
v3.x = 0; v3.y = 0;
}
else
{
length += vector_length(v2);
}
}
}
printf("%.3lf", length);
return 0;
}
the problem is that in the last part where I try to compute the length...I just dont know how to finish it..no matter what I try it never works as I want to. Could you guys give me some advice?
I can't see a standard answer, so here's the algorithm:
Choose a point roughly in the centre of your point cloud. Then sort the points radially, by angle from the centre. The topmost point must be in the convex hull, so define it as having an angle of 0.0 and being first in the list.
Now go though. Put point 2 in the "tentative" hull list. Then check point 3. If the angle P1-P2-P3 is concave (relative to the centre point), remove P2 from the list, if it is convex, keep it. Continue like this, backtracking and removing points if they go concave. You only need two points in your "tentative" list, once you have three, they become definite.
You stop when you go full circle and get back to P1.
There are many known convex hull algorithms, one of the simplest of which is the gift wrapping algorithm. Here's an implementation that fits in your program where the points have been input and sorted:
int j = 0; // after sorting, b[0] is leftmost point, must be on an edge
double length = 0;
VECTOR v1, v2, vv;
v1.x = 0, v1.y = 1; // start by measuring angles from vertical
int iv; // index of next edge point
do // find next egde point by minimum angle
{
double lv1 = vector_length(v1), lv2, lv;
double cv = -1; // minimal possible cosine value
for (i = 0; i < n; ++i) if (i != j)
{ // compute cosine of angle between v1 and (b[j]-->b[i]) = v2
v2.x = b[i].x-b[j].x, v2.y = b[i].y-b[j].y;
double c = (v1.x*v2.x + v1.y*v2.y) / lv1 / (lv2 = vector_length(v2));
if (c > cv) cv = c, iv = i, lv = lv2, vv = v2; // new maximum cosine
}
if (v == -1) break;
// printf("%d:%f,%f-->%d:%f,%f = %f\n", j, b[j], iv, b[iv], lv);
length += lv;
v1 = vv; // found edge is new reference edge
} while (j = iv); // repeat while not at start again
printf("%.3lf\n", length);

Triangulation algorithm

I've decided to create a simple demo, dividing a polygon into triangle set. Here what i've got so far:
A sequential vertex list is given (P1) forming polygon edges (polygon is not convex in most cases); a triangle set is needed
Loop through all the vertices within the polygon P1 and find the one (v), which will satisfy next clauses:
remove v from polygon and save the new one to P2 previous vertex to v
connected to its next one form a
line which do not cross any of P2
edges
v is not inside P2
If these are satisfied, we can replace P1 with (P2 + triangle( prev(v), v, next(v)) ) and repeat this action until P1 contains more than 3 vertices.
So, the questions are: is this algorithm correct and how it could be implemented using C / C++ using the most obvious and simple way?
I think you're describing the ear clipping method. There's code for that method at http://cs.smith.edu/~orourke/books/ftp.html ; it's the code described in the book Computational Geometry in C.
Seems that i'm done with this algorithm implementation. Please, verify it someone. Thanks!
typedef struct Point
{
float x, y;
};
class MooPolygon
{
private:
vector<Point> points;
int isVertexEar(int n, const vector<Point> &p)
{
return (isVertexInsideNewPoly(n, p) && !isEdgeIntersect(n, p));
}
int isEdgeIntersect(int n, const vector<Point> &p)
{
Point v = p[n];
vector<Point> a;
for (size_t i = 0; i < p.size(); i++)
if (i != n)
a.push_back(p[i]);
int c = 0, cnt = a.size(), prev = (cnt + (n - 1)) % cnt, next = n % cnt;
Point v1 = a[prev], v2 = a[next];
for (size_t i = 0, j = cnt - 1; i < cnt; j = i++)
{
if (prev == i || prev == j || next == i || next == j)
continue;
Point v4 = a[j], v3 = a[i];
float denominator = ((v4.y - v3.y) * (v2.x - v1.x)) - ((v4.x - v3.x) * (v2.y - v1.y));
if (!denominator)
continue;
float ua = (((v4.x - v3.x) * (v1.y - v3.y)) - ((v4.y - v3.y) * (v1.x - v3.x))) / denominator;
float ub = (((v2.x - v1.x) * (v1.y - v3.y)) - ((v2.y - v1.y) * (v1.x - v3.x))) / denominator;
//float x = v1.x + (ua * (v2.x - v1.x)), y = v1.y + (ua * (v2.y - v1.y));
if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
{
c = 1;
break;
}
}
return c;
}
int isVertexInsideNewPoly(int n, const vector<Point> &p)
{
Point v = p[n];
vector<Point> a;
for (size_t i = 0; i < p.size(); i++)
if (i != n)
a.push_back(p[i]);
int c = 1;
for (size_t i = 0, j = a.size() - 1; i < a.size(); j = i++)
{
if ((((a[i].y <= v.y) && (v.y < a[j].y)) || ((a[j].y <= v.y) && (v.y < a[i].y))) && (v.x > (a[j].x - a[i].x) * (v.y - a[i].y) / (a[j].y - a[i].y) + a[i].x))
c = !c;
}
return c;
}
float dist(Point a, Point b)
{
return sqrt( ((a.x - b.x) * (a.x - b.x)) + (((a.y - b.y) * (a.y - b.y))) );
}
public:
void push(const Point &p)
{
for (size_t i = 0; i < points.size(); i++)
{
if (dist(points[i], p) < 7.f)
{
points.push_back(points[i]);
return;
}
}
points.push_back(p);
}
void pop()
{
if (points.size() > 0)
points.pop_back();
}
void clear()
{
points.clear();
}
Point v(int index)
{
return points[index];
}
size_t size()
{
return points.size();
}
void triangulate()
{
vector<Point> a;
for (size_t i = 0; i < points.size(); i++)
{
a.push_back(points[i]);
}
points.clear();
for (size_t t = a.size() - 1, i = 0, j = 1; i < a.size(); t = i++, j = (i + 1) % a.size())
{
if (a.size() == 3)
{
points.push_back(a[0]);
points.push_back(a[1]);
points.push_back(a[2]);
break;
}
if (isVertexEar(i, a))
{
points.push_back(a[t]);
points.push_back(a[i]);
points.push_back(a[j]);
a.erase(a.begin() + i, a.begin() + i + 1);
t = a.size() - 1;
i = 0;
j = 1;
}
}
}
};
The code has an error on the line below. The line is in the for loop in the push() function of your class:
points.push_back(points[i]);
You are not passing the pushed Point, but an empty element of the vector itself. I changed the line to
points.push_back(p);
and it worked.

Resources