diff --git a/charge/charge.c b/charge/charge.c index 094735c7d437cfb64f2cdd831555ded691a23b90..d76e4544be707d158f1298b072e91adb79def1b4 100644 --- a/charge/charge.c +++ b/charge/charge.c @@ -10,6 +10,25 @@ */ #include "charge.h" +bool pos_contrain_in_universe(vec2 pos) { + return (pos.x <= UNIV_MAX_X && pos.x >= UNIV_MIN_X && pos.y <= UNIV_MAX_Y && + pos.y >= UNIV_MIN_Y); +} + +vec2 position_to_coordinates(int width, int height, vec2 pos) { + return vec2_create((int)round(width * (pos.x - UNIV_MIN_X)), + (int)round(height * (pos.y - UNIV_MIN_Y))); +} + +bool pos_not_too_close(vec2 p, charge_t *c, int num_charges) { + for (int i = 0; i < num_charges; i++) { + double norm = vec2_norm(vec2_sub(p, c[i].pos)); + if (norm < EPS) + return false; + } + return true; +} + bool compute_e(charge_t c, vec2 p, double eps, vec2 *e) { vec2 qP = vec2_sub(p, c.pos); double norm = vec2_norm(qP); @@ -42,7 +61,7 @@ bool compute_p_next(charge_t *charges, int num_charges, double eps, v = vec2_div(vec2_mul(v, delta), vec2_norm(v)); // P ± deltax * E / ||E|| - *p = vec2_sub(*p, vec2_mul(v, opposed ? -1 : 1)); + *p = vec2_add(*p, vec2_mul(v, opposed ? -1 : 1)); return can_draw; } @@ -50,99 +69,4 @@ bool compute_p_next(charge_t *charges, int num_charges, double eps, charge_t charge_create(double q, vec2 pos) { charge_t c = {.q = q, .pos = pos}; return c; -} - -bool pos_contrain_in_universe(vec2 pos) { - return (pos.x <= UNIV_MAX_X && pos.x >= UNIV_MIN_X && pos.y <= UNIV_MAX_Y && - pos.y >= UNIV_MIN_Y); -} - -coordinates_t position_to_coordinates(int width, int height, vec2 pos) { - return coordinates_create((int)round(height * (pos.y - UNIV_MIN_Y)), - (int)round(width * (pos.x - UNIV_MIN_X))); -} - -bool pos_not_too_close(vec2 p, charge_t *c, int num_charges) { - for (int i = 0; i < num_charges; i++) { - double norm = vec2_norm(vec2_sub(p, c[i].pos)); - if (norm < EPS) - return false; - } - return true; -} - -bool field_line_segment(charge_t *charges, int num_charges, double dx, int w, - int h, vec2 p, vec2 next, bool side) { - while (pos_contrain_in_universe(next) && - pos_not_too_close(next, charges, num_charges)) { - coordinates_t old_coord = position_to_coordinates(w, h, p); - coordinates_t p_coord = position_to_coordinates(w, h, next); - - glBegin(GL_LINES); - glColor3f(255, 255, 255); - glVertex2f(p_coord.row, p_coord.column); - glVertex2f(old_coord.row, old_coord.column); - glEnd(); - - p = next; // Save current point - compute_p_next(charges, num_charges, EPS, dx, &next, side); - } - - return true; -} - -void draw_field_line(charge_t *charges, int num_charges, double dx, vec2 pos0, - int w, int h) { - vec2 pos1 = pos0; - - field_line_segment(charges, num_charges, dx, w, h, pos0, pos1, true); - field_line_segment(charges, num_charges, dx, w, h, pos0, pos1, false); -} - -void draw_charges(charge_t *charges, int num_charges, int w, int h) { - // Center coordinates - coordinates_t c; - - // Charges coordinates - coordinates_t ch0; - coordinates_t ch1; - - int chargePadding = CHARGE_RADIUS / 2; - - // Draw charges - for (int i = 0; i < num_charges; i++) { - coordinates_t chCoord = position_to_coordinates(w, h, charges[i].pos); - - // Draw sign according to charge value - if (charges[i].q < 0) { - glBegin(GL_LINES); - glColor3f(0, 0, 255); - glVertex2f(chCoord.row - chargePadding, chCoord.column); - glVertex2f(chCoord.row + chargePadding, chCoord.column); - glEnd(); - } else { - glBegin(GL_LINES); - glColor3f(255, 0, 0); - glVertex2f(chCoord.row, chCoord.column - chargePadding); - glVertex2f(chCoord.row, chCoord.column + chargePadding); - glVertex2f(chCoord.row - chargePadding, chCoord.column); - glVertex2f(chCoord.row + chargePadding, chCoord.column); - glEnd(); - } - - draw_circle(chCoord, CHARGE_RADIUS, charges[i].q < 0 ? 0 : 255, 0, - charges[i].q < 0 ? 255 : 0); - } -} - -void generate_points(vec2 points[], int nb_points, int w, int h) { - double x = 0; - double y = 0; - - for (int i = 0; i < nb_points; i++) { - x = rand_one(); - y = rand_one(); - - points[i] = vec2_create(x, y); - } } \ No newline at end of file diff --git a/charge/charge.h b/charge/charge.h index cfbbaf01b5e3885911ad8e5c65dee0a1352f0bc6..71fd6a4a50aa4cff1a5c0c16ea3e1c607c85c1e5 100644 --- a/charge/charge.h +++ b/charge/charge.h @@ -11,7 +11,6 @@ #ifndef _CHARGE_H_ #define _CHARGE_H_ -#include "../draw/draw.h" #include "../utilities/utils.h" #include "../vec2/vec2.h" #include <GL/freeglut.h> @@ -34,6 +33,36 @@ typedef struct _charge_t { vec2 pos; } charge_t; +/** + * @brief Check whether a pos is in the universe or not + * + * @param pos + * @return true + * @return false + */ +bool pos_contrain_in_universe(vec2 pos); + +/** + * @brief Convert a position ([0, 1]x[0, 1]) to a screen position + * + * @param width + * @param height + * @param pos + * @return vec2 + */ +vec2 position_to_coordinates(int width, int height, vec2 pos); + +/** + * @brief Check whether a position is too close to a charge or not + * + * @param p + * @param c + * @param num_charges + * @return true + * @return false + */ +bool pos_not_too_close(vec2 p, charge_t *c, int num_charges); + /** * @brief Compute E*qP/norm(qP) * @@ -82,54 +111,4 @@ bool compute_p_next(charge_t *charges, int num_charges, double eps, */ charge_t charge_create(double q, vec2 pos); -/** - * @brief Draw a segment of a field line between two given points - * - * @param charges All the charges - * @param num_charges Number of charges - * @param dx Distance between next point and current point - * @param w Window width - * @param h Window height - * @param p Current pos - * @param next Next pos - * @param side Side of the line - * @return true - * @return false - */ -bool field_line_segment(charge_t *charges, int num_charges, double dx, int w, - int h, vec2 p, vec2 next, bool side); - -/** - * @brief Draw a field line - * - * @param charges All the charges in action - * @param num_charges Number of charges - * @param dx Distance between current and next point to draw line - * @param pos0 Line starting point (will draw on both side of the point) - * @param w Window width - * @param h Window height - */ -void draw_field_line(charge_t *charges, int num_charges, double dx, vec2 pos0, - int w, int h); - -/** - * @brief Draw all charges - * A circle with a minus sign for negative charges - * A circle with a plus sign for positive charges - * - * @param charges All the charges - * @param num_charges Number of charges in action - * @param w Window width - * @param h Window height - */ -void draw_charges(charge_t *charges, int num_charges, int w, int h); - -/** - * @brief Generate a given amount of points - * - * @param points Points array - * @param nb_points Number of point to generate - */ -void generate_points(vec2 points[], int nb_points, int w, int h); - #endif \ No newline at end of file diff --git a/draw/draw.c b/draw/draw.c index 6d4f8753dbb406a40842f38ce9a11511e25fce3f..2082674b2beb282b818234a328185b4b15c94796 100644 --- a/draw/draw.c +++ b/draw/draw.c @@ -10,14 +10,17 @@ */ #include "draw.h" -#include <math.h> -coordinates_t coordinates_create(int row_, int column_) { - coordinates_t c = {.row = row_, .column = column_}; - return c; -} - -void draw_circle(coordinates_t c, int rad, int r, int g, int b) { +//===================== +// PRIVATE +//===================== +/** + * @brief Draw a circle + * + * @param center + * @param rad + */ +void draw_circle(vec2 center, int rad) { int i; int lineAmount = 100; //# of triangles used to draw circle @@ -25,10 +28,73 @@ void draw_circle(coordinates_t c, int rad, int r, int g, int b) { GLfloat twicePi = 2.0f * 3.141592; glBegin(GL_LINE_LOOP); - glColor3f(r, g, b); for (i = 0; i <= lineAmount; i++) { - glVertex2f(c.row + (rad * cos(i * twicePi / lineAmount)), - c.column + (rad * sin(i * twicePi / lineAmount))); + glVertex2f(center.x + (rad * cos(i * twicePi / lineAmount)), + center.y + (rad * sin(i * twicePi / lineAmount))); } glEnd(); +} + +/** + * @brief Draw a line + * + * @param start + * @param end + */ +void draw_line(vec2 start, vec2 end) { + glBegin(GL_LINES); + glVertex2f(start.x, start.y); + glVertex2f(end.x, end.y); + glEnd(); +} + +//===================== +// PUBLIC +//===================== +void draw_field_line_segment(charge_t *charges, int num_charges, double dx, + int w, int h, vec2 p, vec2 next, bool side) { + while (pos_contrain_in_universe(next) && + pos_not_too_close(next, charges, num_charges)) { + vec2 old_coord = position_to_coordinates(w, h, p); + vec2 p_coord = position_to_coordinates(w, h, next); + + glColor3f(255, 255, 255); + draw_line((vec2){p_coord.x, p_coord.y}, + (vec2){old_coord.x, old_coord.y}); + + p = next; // Save current point + compute_p_next(charges, num_charges, EPS, dx, &next, side); + } +} + +void draw_field_line(charge_t *charges, int num_charges, double dx, vec2 pos0, + int w, int h) { + vec2 pos1 = pos0; + + draw_field_line_segment(charges, num_charges, dx, w, h, pos0, pos1, true); + draw_field_line_segment(charges, num_charges, dx, w, h, pos0, pos1, false); +} + +void draw_charges(charge_t *charges, int num_charges, int w, int h) { + int chargePadding = CHARGE_RADIUS / 2; + + // Draw charges + for (int i = 0; i < num_charges; i++) { + vec2 chCoord = position_to_coordinates(w, h, charges[i].pos); + + // Draw sign according to charge value + if (charges[i].q < 0) { + glColor3f(0, 0, 255); + draw_line((vec2){chCoord.x - chargePadding, chCoord.y}, + (vec2){chCoord.x + chargePadding, chCoord.y}); + } else { + glColor3f(255, 0, 0); + draw_line((vec2){chCoord.x, chCoord.y - chargePadding}, + (vec2){chCoord.x, chCoord.y + chargePadding}); + draw_line((vec2){chCoord.x - chargePadding, chCoord.y}, + (vec2){chCoord.x + chargePadding, chCoord.y}); + } + + draw_circle(chCoord, CHARGE_RADIUS); + } } \ No newline at end of file diff --git a/draw/draw.h b/draw/draw.h index 521a85bd1bd8a0a2ca0bec8a4f1ce090b1793483..8bd579884918e110035e4695ec0c94a3834c4e80 100644 --- a/draw/draw.h +++ b/draw/draw.h @@ -12,25 +12,53 @@ #ifndef _DRAW_H_ #define _DRAW_H_ +#include "../charge/charge.h" +#include "../vec2/vec2.h" #include <GL/freeglut.h> #include <GL/gl.h> +#include <math.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> -typedef struct { - uint32_t row; - uint32_t column; -} coordinates_t; /** - * @brief Create a coordinate + * @brief Draw a segment of a field line between two given points * - * @param row_ Row number - * @param column_ Column number - * @return coordinates_t + * @param charges All the charges + * @param num_charges Number of charges + * @param dx Distance between next point and current point + * @param w Window width + * @param h Window height + * @param p Current pos + * @param next Next pos + * @param side Side of the line */ -coordinates_t coordinates_create(int row_, int column_); +void draw_field_line_segment(charge_t *charges, int num_charges, double dx, + int w, int h, vec2 p, vec2 next, bool side); -void draw_circle(coordinates_t c, int radius, int r, int g, int b); +/** + * @brief Draw a field line + * + * @param charges All the charges in action + * @param num_charges Number of charges + * @param dx Distance between current and next point to draw line + * @param pos0 Line starting point (will draw on both side of the point) + * @param w Window width + * @param h Window height + */ +void draw_field_line(charge_t *charges, int num_charges, double dx, vec2 pos0, + int w, int h); + +/** + * @brief Draw all charges + * A circle with a minus sign for negative charges + * A circle with a plus sign for positive charges + * + * @param charges All the charges + * @param num_charges Number of charges in action + * @param w Window width + * @param h Window height + */ +void draw_charges(charge_t *charges, int num_charges, int w, int h); #endif diff --git a/main.c b/main.c index 7381c46c0e7f9e061435239bb062025f8c9ead8e..639a635a4440445f0dc53d911269a2c756f2a09e 100644 --- a/main.c +++ b/main.c @@ -9,6 +9,7 @@ * */ #include "charge/charge.h" +#include "draw/draw.h" #include "utilities/utils.h" #include <GL/freeglut.h> #include <GL/glut.h> @@ -22,11 +23,31 @@ #define WINDOW_HEIGHT 500 #define NB_CHARGES 5 #define NB_POINTS 200 +#define MAXIMUM_CHARGES 30 // Can be replace by a dynamic array #define DELTA (1 / sqrt(pow(WINDOW_WIDTH, 2) + pow(WINDOW_HEIGHT, 2))) int charge_count = NB_CHARGES; -vec2 pos[30]; -double chs[30]; +vec2 starting_points[NB_POINTS]; +vec2 default_charges_pos[MAXIMUM_CHARGES]; +double default_charges[MAXIMUM_CHARGES]; + +/** + * @brief Generate a given set of points in the [0, 1]x[0, 1] universe + * + * @param points + * @param nb_points + */ +void generate_points(vec2 points[], int nb_points) { + double x = 0; + double y = 0; + + for (int i = 0; i < nb_points; i++) { + x = rand_one(); + y = rand_one(); + + points[i] = vec2_create(x, y); + } +} /** * @brief Display function of Glut @@ -39,16 +60,13 @@ void display() { // Generate all the charges charge_t charges[charge_count]; for (int i = 0; i < charge_count; i++) - charges[i] = charge_create(chs[i], pos[i]); + charges[i] = charge_create(default_charges[i], default_charges_pos[i]); draw_charges(charges, charge_count, WINDOW_WIDTH, WINDOW_HEIGHT); - // Generate all the points - vec2 points[NB_POINTS]; - generate_points(points, NB_POINTS, WINDOW_WIDTH, WINDOW_HEIGHT); for (int i = 0; i < NB_POINTS; i++) { - draw_field_line(charges, charge_count, DELTA, points[i], WINDOW_WIDTH, - WINDOW_HEIGHT); + draw_field_line(charges, charge_count, DELTA, starting_points[i], + WINDOW_WIDTH, WINDOW_HEIGHT); } glutSwapBuffers(); @@ -68,9 +86,9 @@ void handle_mouse_input(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON) { charge_count += 1; - pos[charge_count - 1] = - vec2_create((double)y / WINDOW_WIDTH, (double)x / WINDOW_HEIGHT); - chs[charge_count - 1] = rand_one() / (rand_one() * 10 - 5); + default_charges_pos[charge_count - 1] = + vec2_create((double)x / WINDOW_WIDTH, (double)y / WINDOW_HEIGHT); + default_charges[charge_count - 1] = rand_one() / (rand_one() * 10 - 5); } glutPostRedisplay(); @@ -86,11 +104,16 @@ void handle_mouse_input(int button, int state, int x, int y) { int main(int argc, char **argv) { srand(time(NULL)); + // Generate all default charges for (int i = 0; i < charge_count; i++) { - chs[i] = rand_one() / (rand_one() * 10 - 5); - pos[i] = vec2_create(rand_one(), rand_one()); + default_charges[i] = rand_one() / (rand_one() * 10 - 5); + default_charges_pos[i] = vec2_create(rand_one(), rand_one()); } + // Generate all field lines starting points + generate_points(starting_points, NB_POINTS); + + // Window initialization glutInit(&argc, argv); glutSetOption(GLUT_MULTISAMPLE, 16); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | @@ -108,6 +131,7 @@ int main(int argc, char **argv) { glutMainLoop(); + // Object destroy glutDestroyWindow(window); return EXIT_SUCCESS; } \ No newline at end of file diff --git a/utilities/utils.h b/utilities/utils.h index ec8a0f3205ac2398087fa9486d3b530a61d9960b..c59b53f541054e0b3c13aa30b8862e2fdfc4c621 100644 --- a/utilities/utils.h +++ b/utilities/utils.h @@ -1,8 +1,6 @@ #ifndef _UTILS_H_ #define _UTILS_H_ -#include "../draw/draw.h" -#include "../vec2/vec2.h" #include <stdint.h> #include <stdlib.h>