Skip to content
Snippets Groups Projects
Commit dd11ca09 authored by orestis.malaspin's avatar orestis.malaspin
Browse files

Merge branch 'tp_vec' into 'master'

Ajout du tp_vec2

See merge request !13
parents 2b080a28 2d3a9a6e
Branches
No related tags found
No related merge requests found
......@@ -61,9 +61,13 @@ deploy: all
cp cours.html phys/index.html
cp cours.pdf phys/cours.pdf
make -C exercices
make -C practical_work
mkdir -p phys/exercices
cp exercices/*.html phys/exercices
cp exercices/*.pdf phys/exercices
mkdir -p phys/practical_work
cp practical_work/*.html phys/practical_work
cp practical_work/*.pdf phys/practical_work
clean:
rm -f *.html *.pdf $(MARKDOWN) $(PDF) $(TEX) $(HTML)
......
OPTIONS = --filter=pandoc-numbering
OPTIONS += --filter=pandoc-crossref
PDFOPTIONS = --highlight-style kate
PDFOPTIONS += --pdf-engine pdflatex
PDFOPTIONS += --number-sections
PDFOPTIONS += --template=./default.latex
HTMLOPTIONS += -t html5
HTMLOPTIONS += -c ../css/tufte-css/tufte.css
HTMLOPTIONS += --self-contained
HTMLOPTIONS += --mathjax=MathJax.js
MD=$(wildcard *.md)
HTML=$(MD:%.md=%.html)
PDF=$(MD:%.md=%.pdf)
all: $(HTML) $(PDF)
%.pdf: %.md Makefile
pandoc -s $(OPTIONS) $(PDFOPTIONS) -o $@ $<
%.html: %.md Makefile
pandoc -s $(OPTIONS) $(HTMLOPTIONS) -o $@ $<
clean:
rm -rf *.html *.pdf
var fileref=document.createElement('script')
fileref.setAttribute("type","text/javascript")
fileref.setAttribute("src", "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML")
document.getElementsByTagName("head")[0].appendChild(fileref)
---
# author:
# - El Kharroubi Michaël
title: "Travail pratique : implémentation des vecteurs en deux dimensions en C"
autoSectionLabels: true
autoEqnLabels: false
eqnPrefix:
- "éq."
- "éqs."
chapters: true
numberSections: false
chaptersDepth: 1
sectionsDepth: 3
lang: fr
documentclass: article
papersize: A4
cref: false
pandoc-numbering:
- category: exercice
urlcolor: blue
---
# But
- Rappel sur les opérations vectorielles de base en deux dimensions.
- Implémenter une librairie en C, qui pourra être réutilisée par la suite.
# Énoncé
Dans le cadre de ce travail pratique, vous serez amené à compléter le code fourni, afin de satisfaire l'ensemble des tests. Vous pouvez retrouver les formules nécessaires, ainsi qu'un rappel théorique sur le site du cours [malaspinas.academy/phys](http://malaspinas.academy/phys/index.html#vecteurs). Si la formule pour l'une des fonctions ne se trouve pas dans le cours, c'est à vous de trouver la solution.
Joint à cet énoncé, vous trouverez un dossier nommé `tp_vec2` sur **\textcolor{red}{(À compléter par tes soins)}**. Ce dossier contient les fichiers suivants :
```
tp_vec2
|-- gfx # Librairie graphique simple gfx
| |-- gfx.c
| |-- gfx.h
|-- main.c #Exemple d'utilisation de la librairie gfx & vec2
|-- Makefile
|-- vec2 # Librairie vecteurs 2d
|-- vec2.c # Fichier à compléter
|-- vec2.h
|-- vec_tests.c # Programme de test
```
Le fichier `vec2.c` contient 12 fonctions à compléter. Deux d'entre elles le sont déjà. Chaque fonction possède un entête et une signature, vous devez la compléter en les respectant. **Attention**, vous **ne devez pas** modifier la signature des fonctions (nom et arguments).
Le travail pratique est terminé, lorsque que l'ensemble des tests passent. Vous pouvez exécuter les tests à tout moment en effectuant la commande `make run_tests` dans le répertoire `tp_vec2`.
Une fois que tous les tests passent avec succès, vous pouvez parcourir le fichier `main.c`. Essayez de comprendre ce qui y est fait. Dans un second temps, commencez par installer la librairie SDL2 (`libsdl2-dev` sur ubuntu). Puis, exécutez la commande `make main`, suivie de `./main` afin d'afficher le résultat.
# Travail à rendre
**\textcolor{red}{(À compléter par tes soins)}**
\ No newline at end of file
#The compiler
CC:=gcc
#The flags passed to the compiler
CFLAGS:=-g -O3 -Wall -Wextra -fsanitize=address -fsanitize=leak -std=gnu11
#The flags passed to the linker
LDFLAGS:=-lm -lSDL2
#Path to the lib Vec2
VPATH:=vec2 gfx
run_tests: tests
./$<
main: main.o vec2.o gfx.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
tests: vec_tests.o vec2.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
vec2.o: vec2.h
gfx.o: gfx.h
clean:
rm -f *.o main tests
/// @file gfx.c
/// @author Florent Gluck
/// @date November 6, 2016
/// Helper routines to render pixels in fullscreen graphic mode.
/// Uses the SDL2 library.
#include "gfx.h"
#include <assert.h>
/// Create a fullscreen graphic window.
/// @param title Title of the window.
/// @param width Width of the window in pixels.
/// @param height Height of the window in pixels.
/// @return a pointer to the graphic context or NULL if it failed.
struct gfx_context_t *gfx_create(char *title, uint32_t width, uint32_t height)
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
goto error;
SDL_Window *window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_RESIZABLE);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, width, height);
uint32_t *pixels = malloc(width * height * sizeof(uint32_t));
struct gfx_context_t *ctxt = malloc(sizeof(struct gfx_context_t));
if (!window || !renderer || !texture || !pixels || !ctxt)
goto error;
ctxt->renderer = renderer;
ctxt->texture = texture;
ctxt->window = window;
ctxt->width = width;
ctxt->height = height;
ctxt->pixels = pixels;
SDL_ShowCursor(SDL_DISABLE);
gfx_clear(ctxt, COLOR_BLACK);
return ctxt;
error:
return NULL;
}
/// Draw a pixel in the specified graphic context.
/// @param ctxt Graphic context where the pixel is to be drawn.
/// @param column X coordinate of the pixel.
/// @param row Y coordinate of the pixel.
/// @param color Color of the pixel.
void gfx_putpixel(struct gfx_context_t *ctxt, uint32_t column, uint32_t row, uint32_t color)
{
if (column < ctxt->width && row < ctxt->height)
ctxt->pixels[ctxt->width * row + column] = color;
}
/// Clear the specified graphic context.
/// @param ctxt Graphic context to clear.
/// @param color Color to use.
void gfx_clear(struct gfx_context_t *ctxt, uint32_t color)
{
int n = ctxt->width * ctxt->height;
while (n)
ctxt->pixels[--n] = color;
}
/// Display the graphic context.
/// @param ctxt Graphic context to clear.
void gfx_present(struct gfx_context_t *ctxt)
{
SDL_UpdateTexture(
ctxt->texture, NULL, ctxt->pixels, ctxt->width * sizeof(uint32_t));
SDL_RenderCopy(ctxt->renderer, ctxt->texture, NULL, NULL);
SDL_RenderPresent(ctxt->renderer);
}
/// Destroy a graphic window.
/// @param ctxt Graphic context of the window to close.
void gfx_destroy(struct gfx_context_t *ctxt)
{
SDL_ShowCursor(SDL_ENABLE);
SDL_DestroyTexture(ctxt->texture);
SDL_DestroyRenderer(ctxt->renderer);
SDL_DestroyWindow(ctxt->window);
free(ctxt->pixels);
ctxt->texture = NULL;
ctxt->renderer = NULL;
ctxt->window = NULL;
ctxt->pixels = NULL;
SDL_Quit();
free(ctxt);
}
/// If a key was pressed, returns its key code (non blocking call).
/// List of key codes: https://wiki.libsdl.org/SDL_Keycode
/// @return the key that was pressed or 0 if none was pressed.
SDL_Keycode gfx_keypressed()
{
SDL_Event event;
if (SDL_PollEvent(&event))
{
if (event.type == SDL_KEYDOWN)
return event.key.keysym.sym;
}
return 0;
}
\ No newline at end of file
#ifndef _GFX_H_
#define _GFX_H_
#include "vec2/vec2.h"
#include <SDL2/SDL.h>
#include <stdbool.h>
#include <stdint.h>
#define MAKE_COLOR(r, g, b) \
((uint32_t)b | ((uint32_t)g << 8) | ((uint32_t)r << 16))
#define COLOR_GET_B(color) (color & 0xff)
#define COLOR_GET_G(color) ((color >> 8) & 0xff)
#define COLOR_GET_R(color) ((color >> 16) & 0xff)
#define COLOR_BLACK 0x00000000
#define COLOR_RED 0x00FF0000
#define COLOR_GREEN 0x0000FF00
#define COLOR_BLUE 0x000000FF
#define COLOR_WHITE 0x00FFFFFF
#define COLOR_YELLOW 0x00FFFF00
struct gfx_context_t
{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
uint32_t *pixels;
uint32_t width;
uint32_t height;
};
extern void gfx_putpixel(
struct gfx_context_t *ctxt, uint32_t column, uint32_t row, uint32_t color);
extern void gfx_clear(struct gfx_context_t *ctxt, uint32_t color);
extern struct gfx_context_t *gfx_create(char *text, uint32_t width, uint32_t height);
extern void gfx_destroy(struct gfx_context_t *ctxt);
extern void gfx_present(struct gfx_context_t *ctxt);
extern SDL_Keycode gfx_keypressed();
#endif
#include "gfx/gfx.h"
#include "vec2/vec2.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
double rand_dbl()
{
return ((double)rand()) / RAND_MAX;
}
int main()
{
srand(time(NULL));
struct gfx_context_t *ctxt =
gfx_create("Vec2 demo", SCREEN_WIDTH, SCREEN_HEIGHT);
if (!ctxt)
{
fprintf(stderr, "Graphics initialization failed!\n");
return EXIT_FAILURE;
}
vec2 center = vec2_create(0.5, 0.5);
double radius = 0.5;
for (int i = 0; i < 250000; i++)
{
vec2 r = vec2_create(rand_dbl(), rand_dbl());
//Draw pixel if in circle
if (vec2_norm(vec2_sub(r, center)) < radius)
{
coordinates pixel = vec2_to_coordinates(r, SCREEN_WIDTH, SCREEN_HEIGHT);
//Random color (not black)
uint32_t color = rand() % 0xFFFFFF;
gfx_putpixel(ctxt, pixel.column, pixel.row, color);
}
}
gfx_present(ctxt);
while (true)
{
if (gfx_keypressed() == SDLK_ESCAPE)
{
break;
}
}
gfx_destroy(ctxt);
return EXIT_SUCCESS;
}
\ No newline at end of file
#include "vec2.h"
#include <math.h>
#include <stdio.h>
/// Create a 2d vector.
/// @param x_ The first component.
/// @param y_ The second component.
/// @return The newly created vector.
vec2 vec2_create(double x_, double y_) {}
/// Create a zero 2d vector.
/// @return The newly created zero vector.
vec2 vec2_create_zero() { vec2_create(0.0, 0.0); }
/// Add two vectors.
/// @param lhs The left operand.
/// @param rhs The right operand.
/// @return The sum in a new vector.
vec2 vec2_add(vec2 lhs, vec2 rhs) {}
/// Substract two vectors.
/// @param lhs The left operand.
/// @param rhs The right operand.
/// @return The difference in a new vector.
vec2 vec2_sub(vec2 lhs, vec2 rhs) {}
/// Multiply a vector by a scalar.
/// @param scalar The left operand, a scalar.
/// @param rhs The right operand, a vector.
/// @return The product in a new vector.
vec2 vec2_mul(double scalar, vec2 rhs) {}
/// Compute the dot product (scalar product) between two vectors.
/// @param lhs The left operand.
/// @param rhs The right operand.
/// @return The dot product.
double vec2_dot(vec2 lhs, vec2 rhs) {}
/// Compute the square of the euclidean norm of a given vector.
/// @param v The vector.
/// @return The square of the norm.
double vec2_norm_sqr(vec2 v) {}
/// Compute the euclidean norm of a given vector.
/// @param v The vector.
/// @return The norm.
double vec2_norm(vec2 v) {}
/// Compute the normalization of a given vector.
/// @param v The vector.
/// @return The new normalized vector.
vec2 vec2_normalize(vec2 v) {}
/// Check whether two vectors are approximately equals within a given tolerance.
/// @param lhs The left operand.
/// @param rhs The right operand.
/// @param eps The tolerance.
/// @return The dot product.
bool vec2_is_approx_equal(vec2 lhs, vec2 rhs, double eps) {}
/// Compute the coordinates of a 2d vector (with components between 0 and 1)
/// in a given screen matrix.
/// @param v The 2d vector.
/// @param width The screen width.
/// @param height The screen height.
/// @return The coordinates (rwo, column).
coordinates vec2_to_coordinates(vec2 v, uint32_t width, uint32_t height) {}
/// Print a vector in the standard output.
/// @param v The vector.
void vec2_print(vec2 v)
{
printf("x = %g, y = %g\n", v.x, v.y);
}
\ No newline at end of file
#ifndef _VEC2_H_
#define _VEC2_H_
#include <stdbool.h>
#include <stdint.h>
typedef struct _vec2
{
double x, y;
} vec2;
typedef struct _coordinates
{
uint32_t row, column;
} coordinates;
vec2 vec2_create(double x_, double y_);
vec2 vec2_create_zero();
vec2 vec2_add(vec2 lhs, vec2 rhs);
vec2 vec2_sub(vec2 lhs, vec2 rhs);
vec2 vec2_mul(double scalar, vec2 rhs);
double vec2_dot(vec2 lhs, vec2 rhs);
double vec2_norm_sqr(vec2 v);
double vec2_norm(vec2 v);
vec2 vec2_normalize(vec2 v);
bool vec2_is_approx_equal(vec2 lhs, vec2 rhs, double eps);
coordinates vec2_to_coordinates(vec2 v, uint32_t width, uint32_t height);
void vec2_print(vec2 v);
#endif
#include "vec2.h"
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
typedef struct _test_result
{
bool passed;
const char *name;
} test_result;
typedef test_result (*unit_test_t)(void);
void print_in_color(char *color, char *text)
{
printf("\033%s", color);
printf("%s", text);
printf("\033[0m");
}
void print_in_red(char *text)
{
print_in_color("[0;31m", text);
}
void print_in_green(char *text)
{
print_in_color("[0;32m", text);
}
bool dbl_eq(double a, double b)
{
return fabs(a - b) < 1e-6;
}
/*
*
* Write your tests here
*
*/
/* TODO
vec2 vec2_create(double x_, double y_); -- Ok
vec2 vec2_create_zero(); -- Ok
vec2 vec2_add(vec2 lhs, vec2 rhs); -- Ok
vec2 vec2_sub(vec2 lhs, vec2 rhs); -- Ok
vec2 vec2_mul(double scalar, vec2 lhs); -- Ok
double vec2_dot(vec2 lhs, vec2 rhs); -- Ok
double vec2_norm_sqr(vec2 v); -- Ok
double vec2_norm(vec2 v); -- Ok
vec2 vec2_normalize(vec2 v); -- Ok
bool vec2_is_approx_equal(vec2 lhs, vec2 rhs, double eps);
coordinates vec2_to_coordinates(vec2 v, uint32_t width, uint32_t height);
*/
const double u_x[] = {1.25, 3.53, 2.64, 8.8};
const double u_y[] = {3.42, 7.22, 5.32, 2.44};
const double v_x[] = {4.32, 6.21, 7.42, 9.32};
const double v_y[] = {5.22, 3.56, 8.65, 6.44};
const uint32_t nb_tests = sizeof(u_x) / sizeof(double);
test_result t_vec2_create_0()
{
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 v = vec2_create(u_x[i], u_y[i]);
if (u_x[i] != v.x || u_y[i] != v.y)
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_create 0"};
}
test_result t_vec2_create_zero_0()
{
vec2 v = vec2_create_zero();
return (test_result){.passed = (v.x == 0.0 && v.y == 0.0),
.name = "Test vec2_create_zero 0"};
}
test_result t_vec2_add_0()
{
double r_x[] = {5.57, 9.74, 10.06, 18.12};
double r_y[] = {8.64, 10.78, 13.97, 8.88};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 u = vec2_create(u_x[i], u_y[i]);
vec2 v = vec2_create(v_x[i], v_y[i]);
vec2 r = vec2_add(u, v);
if (!(dbl_eq(r.x, r_x[i]) && dbl_eq(r.y, r_y[i])))
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_add 0"};
}
test_result t_vec2_sub_0()
{
double r_x[] = {-3.07, -2.68, -4.78, -0.52};
double r_y[] = {-1.80, 3.66, -3.33, -4.00};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 u = vec2_create(u_x[i], u_y[i]);
vec2 v = vec2_create(v_x[i], v_y[i]);
vec2 r = vec2_sub(u, v);
if (!(dbl_eq(r.x, r_x[i]) && dbl_eq(r.y, r_y[i])))
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_sub 0"};
}
test_result t_vec2_mul_0()
{
double r_x[] = {5.40, 21.9213, 19.5888, 82.016};
double r_y[] = {14.7744, 44.8362, 39.4744, 22.740800};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
double alpha = v_x[i];
vec2 u = vec2_create(u_x[i], u_y[i]);
vec2 r = vec2_mul(alpha, u);
if (!(dbl_eq(r.x, r_x[i]) && dbl_eq(r.y, r_y[i])))
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_mul 0"};
}
test_result t_vec2_dot_0()
{
double r[] = {23.2524, 47.6245, 65.6068, 97.7296};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 u = vec2_create(u_x[i], u_y[i]);
vec2 v = vec2_create(v_x[i], v_y[i]);
double res = vec2_dot(u, v);
if (!dbl_eq(res, r[i]))
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_dot 0"};
}
test_result t_vec2_norm_sqr_0()
{
double r[] = {13.2589, 64.5893, 35.272, 83.3936};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 u = vec2_create(u_x[i], u_y[i]);
double res = vec2_norm_sqr(u);
if (!dbl_eq(res, r[i]))
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_norm_sqr 0"};
}
test_result t_vec2_norm_0()
{
double r[] = {3.641277, 8.036747, 5.939023, 9.132010};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 u = vec2_create(u_x[i], u_y[i]);
double res = vec2_norm(u);
if (!dbl_eq(res, r[i]))
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_norm 0"};
}
test_result t_vec2_normalize_0()
{
double r_x[] = {0.343286, 0.439232, 0.444518, 0.963643};
double r_y[] = {0.939231, 0.898373, 0.895770, 0.267192};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 u = vec2_create(u_x[i], u_y[i]);
vec2 r = vec2_normalize(u);
if (!(dbl_eq(r.x, r_x[i]) && dbl_eq(r.y, r_y[i])))
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_normalize 0"};
}
test_result t_vec2_is_approx_equal_0()
{
bool r[] = {true, true, false, false};
double t_x[] = {u_x[0], u_x[1] + 1e-4, u_x[2] + 15.0, u_x[3] + 1e-2};
double t_y[] = {u_y[0], u_y[1] - 1e-4, u_y[2] + 15.0, u_y[3] + 1e-2};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 u = vec2_create(u_x[i], u_y[i]);
vec2 t = vec2_create(t_x[i], t_y[i]);
if (vec2_is_approx_equal(u, t, 1e-3) != r[i])
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_is_approx_equal 0"};
}
test_result t_vec2_to_coordinates_0()
{
uint32_t height = 300;
uint32_t width = 100;
double t_x[] = {0.25, 0.5, 0.75, 1};
double t_y[] = {0, 1.0 / 3.0, 2.0 / 3.0, 1};
uint32_t r_col[] = {25, 50, 74, 99};
uint32_t r_row[] = {0, 100, 199, 299};
bool passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
vec2 t = vec2_create(t_x[i], t_y[i]);
coordinates r = vec2_to_coordinates(t, width, height);
if (r.row != r_row[i] || r.column != r_col[i])
{
passed = false;
break;
}
}
return (test_result){.passed = passed,
.name = "Test vec2_to_coordinates 0"};
}
//Add or remove your test function name here
const unit_test_t tests[] = {
t_vec2_create_0,
t_vec2_create_zero_0,
t_vec2_add_0,
t_vec2_sub_0,
t_vec2_mul_0,
t_vec2_dot_0,
t_vec2_norm_sqr_0,
t_vec2_norm_0,
t_vec2_normalize_0,
t_vec2_is_approx_equal_0,
t_vec2_to_coordinates_0};
int main()
{
uint32_t nb_tests = sizeof(tests) / sizeof(unit_test_t);
char message[256];
bool all_passed = true;
for (uint32_t i = 0; i < nb_tests; i++)
{
printf("Running test n°%d: ...\n", i);
test_result r = tests[i]();
if (r.passed)
{
sprintf(message, "\t- %s : OK", r.name);
print_in_green(message);
}
else
{
all_passed = false;
sprintf(message, "\t- %s : FAILED", r.name);
print_in_red(message);
}
printf("\n");
}
if (all_passed)
print_in_green("\nTests suite result : OK\n");
else
print_in_red("\nTests suite result : FAILED\n");
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment