From 2d3a9a6eb682660b7c3f342c3d7975da1e0a1bb5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C3=ABl=20El=20Kharroubi?=
 <michael.el-kharroubi@hesge.ch>
Date: Sun, 10 Oct 2021 20:11:18 +0200
Subject: [PATCH] Ajout du tp_vec2

---
 Makefile                                |   4 +
 practical_work/Makefile                 |  29 +++
 practical_work/MathJax.js               |   4 +
 practical_work/tp_vec.md                |  55 +++++
 practical_work/tp_vec2/Makefile         |  24 ++
 practical_work/tp_vec2/gfx/gfx.c        | 105 ++++++++
 practical_work/tp_vec2/gfx/gfx.h        |  41 ++++
 practical_work/tp_vec2/main.c           |  54 +++++
 practical_work/tp_vec2/vec2/vec2.c      |  74 ++++++
 practical_work/tp_vec2/vec2/vec2.h      |  41 ++++
 practical_work/tp_vec2/vec2/vec_tests.c | 309 ++++++++++++++++++++++++
 11 files changed, 740 insertions(+)
 create mode 100644 practical_work/Makefile
 create mode 100644 practical_work/MathJax.js
 create mode 100644 practical_work/tp_vec.md
 create mode 100644 practical_work/tp_vec2/Makefile
 create mode 100644 practical_work/tp_vec2/gfx/gfx.c
 create mode 100644 practical_work/tp_vec2/gfx/gfx.h
 create mode 100644 practical_work/tp_vec2/main.c
 create mode 100644 practical_work/tp_vec2/vec2/vec2.c
 create mode 100644 practical_work/tp_vec2/vec2/vec2.h
 create mode 100644 practical_work/tp_vec2/vec2/vec_tests.c

diff --git a/Makefile b/Makefile
index 2bf36f8..ed04ce3 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/practical_work/Makefile b/practical_work/Makefile
new file mode 100644
index 0000000..bb87bf8
--- /dev/null
+++ b/practical_work/Makefile
@@ -0,0 +1,29 @@
+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
+
diff --git a/practical_work/MathJax.js b/practical_work/MathJax.js
new file mode 100644
index 0000000..3c5458c
--- /dev/null
+++ b/practical_work/MathJax.js
@@ -0,0 +1,4 @@
+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)
diff --git a/practical_work/tp_vec.md b/practical_work/tp_vec.md
new file mode 100644
index 0000000..e2c4a9a
--- /dev/null
+++ b/practical_work/tp_vec.md
@@ -0,0 +1,55 @@
+---
+# 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
diff --git a/practical_work/tp_vec2/Makefile b/practical_work/tp_vec2/Makefile
new file mode 100644
index 0000000..a03093a
--- /dev/null
+++ b/practical_work/tp_vec2/Makefile
@@ -0,0 +1,24 @@
+#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
diff --git a/practical_work/tp_vec2/gfx/gfx.c b/practical_work/tp_vec2/gfx/gfx.c
new file mode 100644
index 0000000..cd6662f
--- /dev/null
+++ b/practical_work/tp_vec2/gfx/gfx.c
@@ -0,0 +1,105 @@
+/// @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
diff --git a/practical_work/tp_vec2/gfx/gfx.h b/practical_work/tp_vec2/gfx/gfx.h
new file mode 100644
index 0000000..45b91d8
--- /dev/null
+++ b/practical_work/tp_vec2/gfx/gfx.h
@@ -0,0 +1,41 @@
+#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
diff --git a/practical_work/tp_vec2/main.c b/practical_work/tp_vec2/main.c
new file mode 100644
index 0000000..ac27974
--- /dev/null
+++ b/practical_work/tp_vec2/main.c
@@ -0,0 +1,54 @@
+#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
diff --git a/practical_work/tp_vec2/vec2/vec2.c b/practical_work/tp_vec2/vec2/vec2.c
new file mode 100644
index 0000000..ad16ee4
--- /dev/null
+++ b/practical_work/tp_vec2/vec2/vec2.c
@@ -0,0 +1,74 @@
+#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
diff --git a/practical_work/tp_vec2/vec2/vec2.h b/practical_work/tp_vec2/vec2/vec2.h
new file mode 100644
index 0000000..ed04035
--- /dev/null
+++ b/practical_work/tp_vec2/vec2/vec2.h
@@ -0,0 +1,41 @@
+#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
diff --git a/practical_work/tp_vec2/vec2/vec_tests.c b/practical_work/tp_vec2/vec2/vec_tests.c
new file mode 100644
index 0000000..91b32f5
--- /dev/null
+++ b/practical_work/tp_vec2/vec2/vec_tests.c
@@ -0,0 +1,309 @@
+#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
-- 
GitLab