Select Git revision
charge.c 3.41 KiB
#include "charge.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "gfx/gfx.h"
#include "utils.h"
#include "vector2.h"
const double K = 8.988e9;
const double ELEMENTARY_CHARGE = 1.602e-19;
const double THRESHOLD_CHARGES_DISTANCES = 0.5;
const double EPSILON = 0.05;
double compute_delta_x(int width, int height) {
return 1.0 / sqrt((width * width) + (height * height));
}
bool compute_next_point(charge_t *charges, int num_charges, vector2_t current_pos, double eps, vector2_t *new_pos, double dx) {
vector2_t electric_field;
if (compute_total_normalized_e(charges, num_charges, current_pos, eps, &electric_field)) {
*new_pos = vector2_add(current_pos, vector2_multiply(electric_field, dx));
return true;
}
return false;
}
bool is_out_of_bounds(vector2_t position, double x0, double x1, double y0, double y1) {
return position.x < x0 || position.x > x1 || position.y < y0 || position.y > y1;
}
charge_t charge_create(double q, vector2_t pos) {
charge_t c = {.q = q, .pos = pos};
return c;
}
bool compute_e(charge_t c, vector2_t p, double eps, vector2_t *e) {
*e = vector2_create_zero();
vector2_t r = vector2_substract(c.pos, p);
double norm_r = vector2_norm(r);
double E_i = K * (fabs(c.q) / (norm_r * norm_r));
*e = vector2_multiply(vector2_normalize(r), E_i);
if (c.q > 0) {
*e = vector2_multiply(*e, -1);
}
return norm_r >= eps;
}
bool compute_total_normalized_e(charge_t *charges, int num_charges, vector2_t p, double eps, vector2_t *e) {
*e = vector2_create_zero();
for (int i = 0; i < num_charges; i += 1) {
vector2_t tmp;
if (!compute_e(charges[i], p, eps, &tmp)) {
return false;
}
*e = vector2_add(*e, tmp);
}
*e = vector2_normalize(*e);
return true;
}
void draw_field_line(struct gfx_context_t *ctxt, charge_t *charges, int num_charges, double dx, vector2_t pos0, double x0, double x1, double y0, double y1) {
vector2_t current_pos = pos0;
while (true) {
vector2_t new_pos;
if (!compute_next_point(charges, num_charges, current_pos, 4.5e-2, &new_pos, dx)) {
break;
}
if (is_out_of_bounds(new_pos, x0, x1, y0, y1)) {
break;
}
coordinates_t current_coordinates = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, x0, x1, y0, y1, current_pos);
coordinates_t new_coordinates = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, x0, x1, y0, y1, new_pos);
gfx_draw_line(ctxt, current_coordinates, new_coordinates, COLOR_BLUE);
current_pos = new_pos;
}
}
void draw_charges(struct gfx_context_t *ctxt, charge_t *charges, int num_charges, double x0, double x1, double y0, double y1) {
for (int32_t i = 0; i < num_charges; i += 1) {
coordinates_t c = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, x0, x1, y0, y1, charges[i].pos);
int32_t radius = 20;
gfx_draw_circle(ctxt, c, radius, COLOR_WHITE);
int32_t color = charges[i].q > 0 ? COLOR_RED : COLOR_BLUE;
int32_t half_length = (int32_t)(radius * .6);
gfx_draw_line(ctxt, coordinates_create(c.row, c.column - half_length), coordinates_create(c.row, c.column + half_length), color);
if (charges[i].q > 0) {
gfx_draw_line(ctxt, coordinates_create(c.row - half_length, c.column), coordinates_create(c.row + half_length, c.column), color);
}
}
}