From e78974f84812dc3eafdde3754b843f03eedb1578 Mon Sep 17 00:00:00 2001
From: unknown <david.antunes-da-silva@irit.fr>
Date: Tue, 21 Jun 2022 14:38:03 +0200
Subject: [PATCH] Add randomants example + add 2DContinousGrid as environment +
 add 2DCycling Scheduler + Add UI options to create Swing GUIs for our MAS

---
 .idea/.gitignore                              |   0
 .idea/misc.xml                                |   6 +
 .idea/modules.xml                             |   8 +
 .idea/vcs.xml                                 |   6 +
 .idea/workspace.xml                           | 126 +++++
 src/example/philosophes/Dechets.java          |  10 +-
 src/example/philosophes/MainPhilosophe.java   |  20 +-
 src/example/philosophes/Philosophe.java       |  14 +-
 src/example/randomants/Ant.java               |  95 ++++
 src/example/randomants/AntHill.java           |  31 ++
 src/example/randomants/MainAnt.java           |  34 ++
 src/example/randomants/ressources/ant.png     | Bin 0 -> 352 bytes
 .../randomants/ressources/ant_dead.png        | Bin 0 -> 214 bytes
 src/mas/core/Agent.java                       |   6 +-
 src/mas/core/Cyclable.java                    |   2 +-
 src/mas/environment/TwoDContinuosGrid.java    |  16 +
 .../base/schedulers/AsyncCycling.java         |   4 +-
 .../base/schedulers/FairCycling.java          |  43 +-
 .../base/schedulers/TwoDCycling.java          |  57 +-
 src/mas/ui/SchedulerToolbar.java              |   1 -
 src/mas/ui/VUI.java                           | 507 ++++++++++++++++++
 src/mas/ui/drawables/Drawable.java            | 396 ++++++++++++++
 src/mas/ui/drawables/DrawableCircle.java      |  22 +
 src/mas/ui/drawables/DrawableImage.java       |  66 +++
 src/mas/ui/drawables/DrawableLine.java        |  38 ++
 src/mas/ui/drawables/DrawableOval.java        |  22 +
 src/mas/ui/drawables/DrawablePoint.java       |  12 +
 src/mas/ui/drawables/DrawableRectangle.java   |  21 +
 src/mas/ui/drawables/DrawableString.java      |  26 +
 29 files changed, 1515 insertions(+), 74 deletions(-)
 create mode 100644 .idea/.gitignore
 create mode 100644 .idea/misc.xml
 create mode 100644 .idea/modules.xml
 create mode 100644 .idea/vcs.xml
 create mode 100644 .idea/workspace.xml
 create mode 100644 src/example/randomants/Ant.java
 create mode 100644 src/example/randomants/AntHill.java
 create mode 100644 src/example/randomants/MainAnt.java
 create mode 100644 src/example/randomants/ressources/ant.png
 create mode 100644 src/example/randomants/ressources/ant_dead.png
 create mode 100644 src/mas/ui/VUI.java
 create mode 100644 src/mas/ui/drawables/Drawable.java
 create mode 100644 src/mas/ui/drawables/DrawableCircle.java
 create mode 100644 src/mas/ui/drawables/DrawableImage.java
 create mode 100644 src/mas/ui/drawables/DrawableLine.java
 create mode 100644 src/mas/ui/drawables/DrawableOval.java
 create mode 100644 src/mas/ui/drawables/DrawablePoint.java
 create mode 100644 src/mas/ui/drawables/DrawableRectangle.java
 create mode 100644 src/mas/ui/drawables/DrawableString.java

diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..a818314
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" project-jdk-name="17" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..2bc891e
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/core.iml" filepath="$PROJECT_DIR$/core.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..8d61c8e
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="AutoImportSettings">
+    <option name="autoReloadType" value="SELECTIVE" />
+  </component>
+  <component name="ChangeListManager">
+    <list default="true" id="d7618c8d-68f5-4749-ad72-9e4faa130ff9" name="Changes" comment="">
+      <change afterPath="$PROJECT_DIR$/src/example/randomants/Ant.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/example/randomants/AntHill.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/example/randomants/MainAnt.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/example/randomants/ressources/ant.png" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/example/randomants/ressources/ant_dead.png" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/VUI.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/drawables/Drawable.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/drawables/DrawableCircle.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/drawables/DrawableImage.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/drawables/DrawableLine.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/drawables/DrawableOval.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/drawables/DrawablePoint.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/drawables/DrawableRectangle.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/mas/ui/drawables/DrawableString.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/example/philosophes/Dechets.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/example/philosophes/Dechets.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/example/philosophes/MainPhilosophe.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/example/philosophes/MainPhilosophe.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/example/philosophes/Philosophe.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/example/philosophes/Philosophe.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/mas/core/Agent.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/mas/core/Agent.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/mas/core/Cyclable.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/mas/core/Cyclable.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/mas/environment/TwoDContinuosGrid.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/mas/environment/TwoDContinuosGrid.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/mas/implementation/base/schedulers/AsyncCycling.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/mas/implementation/base/schedulers/AsyncCycling.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/mas/implementation/base/schedulers/FairCycling.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/mas/implementation/base/schedulers/FairCycling.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/mas/implementation/base/schedulers/TwoDCycling.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/mas/implementation/base/schedulers/TwoDCycling.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/mas/ui/SchedulerToolbar.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/mas/ui/SchedulerToolbar.java" afterDir="false" />
+    </list>
+    <option name="SHOW_DIALOG" value="false" />
+    <option name="HIGHLIGHT_CONFLICTS" value="true" />
+    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+    <option name="LAST_RESOLUTION" value="IGNORE" />
+  </component>
+  <component name="Git.Settings">
+    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
+  </component>
+  <component name="MarkdownSettingsMigration">
+    <option name="stateVersion" value="1" />
+  </component>
+  <component name="ProjectId" id="2AsSPACnMPcfJVj1FTH6jpS1pV5" />
+  <component name="ProjectViewState">
+    <option name="hideEmptyMiddlePackages" value="true" />
+    <option name="showLibraryContents" value="true" />
+  </component>
+  <component name="PropertiesComponent"><![CDATA[{
+  "keyToString": {
+    "RunOnceActivity.OpenProjectViewOnStart": "true",
+    "RunOnceActivity.ShowReadmeOnStart": "true",
+    "WebServerToolWindowFactoryState": "false",
+    "last_opened_file_path": "C:/Users/David/Desktop/AmakGit/core/src/mas",
+    "node.js.detected.package.eslint": "true",
+    "node.js.detected.package.tslint": "true",
+    "node.js.selected.package.eslint": "(autodetect)",
+    "node.js.selected.package.tslint": "(autodetect)",
+    "nodejs_package_manager_path": "npm"
+  }
+}]]></component>
+  <component name="RecentsManager">
+    <key name="CopyFile.RECENT_KEYS">
+      <recent name="C:\Users\David\Desktop\AmakGit\core\src\mas" />
+      <recent name="C:\Users\David\Desktop\AmakGit\core\src\example\randomants" />
+    </key>
+  </component>
+  <component name="RunManager" selected="Application.MainAnt">
+    <configuration name="MainAnt" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
+      <option name="MAIN_CLASS_NAME" value="example.randomants.MainAnt" />
+      <module name="core" />
+      <extension name="coverage">
+        <pattern>
+          <option name="PATTERN" value="example.randomants.*" />
+          <option name="ENABLED" value="true" />
+        </pattern>
+      </extension>
+      <method v="2">
+        <option name="Make" enabled="true" />
+      </method>
+    </configuration>
+    <configuration name="Philosophes" type="Application" factoryName="Application">
+      <option name="MAIN_CLASS_NAME" value="example.philosophes.MainPhilosophe" />
+      <module name="core" />
+      <method v="2">
+        <option name="Make" enabled="true" />
+      </method>
+    </configuration>
+    <list>
+      <item itemvalue="Application.Philosophes" />
+      <item itemvalue="Application.MainAnt" />
+    </list>
+    <recent_temporary>
+      <list>
+        <item itemvalue="Application.MainAnt" />
+      </list>
+    </recent_temporary>
+  </component>
+  <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
+  <component name="TaskManager">
+    <task active="true" id="Default" summary="Default task">
+      <changelist id="d7618c8d-68f5-4749-ad72-9e4faa130ff9" name="Changes" comment="" />
+      <created>1655796773469</created>
+      <option name="number" value="Default" />
+      <option name="presentableId" value="Default" />
+      <updated>1655796773469</updated>
+      <workItem from="1655796774853" duration="87000" />
+      <workItem from="1655796884483" duration="12176000" />
+    </task>
+    <servers />
+  </component>
+  <component name="TypeScriptGeneratedFilesManager">
+    <option name="version" value="3" />
+  </component>
+  <component name="Vcs.Log.Tabs.Properties">
+    <option name="TAB_STATES">
+      <map>
+        <entry key="MAIN">
+          <value>
+            <State />
+          </value>
+        </entry>
+      </map>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/src/example/philosophes/Dechets.java b/src/example/philosophes/Dechets.java
index 465901d..9a6028d 100644
--- a/src/example/philosophes/Dechets.java
+++ b/src/example/philosophes/Dechets.java
@@ -3,13 +3,11 @@ package example.philosophes;
 import mas.core.Cyclable;
 import mas.core.Schedulable;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
 public class Dechets implements Cyclable {
 
     private int id;
 
-    Schedulable scheduleur = null;
+    Schedulable scheduler = null;
 
     public Dechets(int _id){
         id = _id;
@@ -17,7 +15,7 @@ public class Dechets implements Cyclable {
     }
         @Override
     public void cycle() {
-        System.out.println("je suis le dechet n°" + id);
+        /*System.out.println("je suis le dechet n°" + id);*/
     }
 
     @Override
@@ -26,8 +24,8 @@ public class Dechets implements Cyclable {
     }
 
     @Override
-    public void setScheduleur(Schedulable _scheduleur) {
-        scheduleur = _scheduleur;
+    public void setScheduler(Schedulable _scheduler) {
+        scheduler = _scheduler;
     }
 
     @Override
diff --git a/src/example/philosophes/MainPhilosophe.java b/src/example/philosophes/MainPhilosophe.java
index c1b976f..83acbcb 100644
--- a/src/example/philosophes/MainPhilosophe.java
+++ b/src/example/philosophes/MainPhilosophe.java
@@ -1,9 +1,7 @@
 package example.philosophes;
 
 import mas.core.Schedulable;
-import mas.implementation.base.schedulers.TwoDCycling;
-import mas.ui.MainWindow;
-import mas.ui.SchedulerToolbar;
+import mas.implementation.base.schedulers.FairCycling;
 
 public class MainPhilosophe {
 
@@ -29,16 +27,16 @@ public class MainPhilosophe {
             philosophes[i].setRightPhilosophe(philosophes[(i+1) % nAgents]);
         }
 
-        Schedulable scheduleur = new FairCycling(philosophes);
-        //scheduleur.setSleep(500);
-        scheduleur.start();
+        Schedulable scheduler = new FairCycling(philosophes);
+        scheduler.setSleep(2);
+        scheduler.start();
 
         try {
             Thread.sleep(2000);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }
-        scheduleur.pause();
+        scheduler.pause();
 
         try {
             Thread.sleep(2000);
@@ -46,18 +44,18 @@ public class MainPhilosophe {
             throw new RuntimeException(e);
         }
 
-        scheduleur.resume();
+        scheduler.resume();
 
         try {
-            Thread.sleep(2000);
+            Thread.sleep(5000);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }
 
-        scheduleur.stop();
+        scheduler.stop();
 
 
         final long endTime = System.nanoTime();
-        System.out.println("Total execution time: " + (endTime / 1000000 - startTime / 1000000) + " microseconds");*/
+        System.out.println("Total execution time: " + (endTime / 1000000 - startTime / 1000000) + " microseconds");
     }
 }
diff --git a/src/example/philosophes/Philosophe.java b/src/example/philosophes/Philosophe.java
index 761f717..8e69a2f 100644
--- a/src/example/philosophes/Philosophe.java
+++ b/src/example/philosophes/Philosophe.java
@@ -32,7 +32,7 @@ public class Philosophe extends Agent {
      */
     private int id;
 
-    private Schedulable scheduleur;
+    private Schedulable scheduler;
 
     /**
      * States philosophers can be in
@@ -120,7 +120,7 @@ public class Philosophe extends Agent {
         //System.out.println("Philospher n°" + id + " / State " + state);
         System.out.println(
                 "\tPhilosopher num " + id + " : " + state + " / " + criticallity + " / " + eatenPastas
-                 /*+ "\n\t\t Right Fk : " + rightFork.getTakenBy().getId() + " / Left Fk : " + leftFork.getTakenBy().getId()*/
+                /* + "\n\t\t Right Fk : " + rightFork.getTakenBy().getId() + " / Left Fk : " + leftFork.getTakenBy().getId()*/
         );
     }
 
@@ -147,7 +147,7 @@ public class Philosophe extends Agent {
     @Override
     public void act() {
         //System.out.println("Philosopher num " + id + " act");
-        scheduleur.addCyclable(new Dechets(id));
+        scheduler.addCyclable(new Dechets(id));
     }
 
     @Override
@@ -195,12 +195,12 @@ public class Philosophe extends Agent {
         this.rightPhilosophe = rightPhilosophe;
     }
 
-    public void setScheduleur(Schedulable scheduleur) {
-        this.scheduleur = scheduleur;
+    public void setScheduler(Schedulable scheduler) {
+        this.scheduler = scheduler;
     }
 
-    public Schedulable getScheduleur() {
-        return scheduleur;
+    public Schedulable getScheduler() {
+        return scheduler;
     }
 
     @Override
diff --git a/src/example/randomants/Ant.java b/src/example/randomants/Ant.java
new file mode 100644
index 0000000..5f64c99
--- /dev/null
+++ b/src/example/randomants/Ant.java
@@ -0,0 +1,95 @@
+package example.randomants;
+
+import mas.core.Agent;
+import mas.environment.TwoDContinuosGrid;
+import mas.ui.VUI;
+import mas.ui.drawables.DrawableImage;
+
+import java.util.Random;
+
+public class Ant extends Agent {
+
+    private static int numberOfAnts = 0;
+
+    public int id;
+    /**
+     * X coordinate of the ant in the world
+     */
+    public double dx;
+    /**
+     * Y coordinate of the ant in the world
+     */
+    public double dy;
+
+    public boolean mustDie = false;
+    /**
+     * Angle in radians
+     */
+    private double angle = Math.random() * Math.PI * 2;
+    private DrawableImage image;
+
+    TwoDContinuosGrid environnement;
+
+    /**
+     * Constructor of the ant
+     *
+     * @param startX
+     *            Initial X coordinate
+     * @param startY
+     *            Initial Y coordinate
+     */
+    public Ant(int _id, double startX, double startY, TwoDContinuosGrid _environnement) {
+        numberOfAnts++;
+        id = _id;
+        dx = startX;
+        dy = startY;
+        environnement = _environnement;
+        image = VUI.get().createImage(dx, dy, "src/example/randomants/ressources/ant.png");
+    }
+
+    /**
+     * Move in a random direction
+     */
+    @Override
+    public void decide() {
+        double random = new Random().nextGaussian();
+
+        angle += random * 0.1;
+        dx += Math.cos(angle);
+        dy += Math.sin(angle);
+        while (dx >= environnement.getWidth() / 2)
+            dx -= environnement.getWidth();
+        while (dy >= environnement.getHeight() / 2)
+            dy -= environnement.getHeight();
+        while (dx < -environnement.getWidth() / 2)
+            dx += environnement.getWidth();
+        while (dy < -environnement.getHeight() / 2)
+            dy += environnement.getHeight();
+    }
+
+    @Override
+    public boolean terminate() {
+        return mustDie;
+    }
+
+    @Override
+    public void act() {
+        image.move(dx,dy);
+        image.setAngle(angle);
+
+        if (new Random().nextDouble() < 0.001) {
+            scheduler.addCyclable(new Ant(id * 10,dx, dy, environnement));
+        }
+
+        if (new Random().nextDouble() < 0.001) {
+            image.setFilename("src/example/randomants/ressources/ant_dead.png");
+            numberOfAnts--;
+            mustDie = true;
+        }
+        //System.out.println("Ant n°" + id + " / x = " + dx + " / y = " + dy);
+    }
+
+    public static int getNumberOfAnts() {
+        return numberOfAnts;
+    }
+}
diff --git a/src/example/randomants/AntHill.java b/src/example/randomants/AntHill.java
new file mode 100644
index 0000000..771a213
--- /dev/null
+++ b/src/example/randomants/AntHill.java
@@ -0,0 +1,31 @@
+package example.randomants;
+
+import mas.ui.VUI;
+import mas.ui.drawables.DrawableRectangle;
+import mas.ui.drawables.DrawableString;
+
+import java.awt.*;
+
+public class AntHill {
+
+    public DrawableString antsCountLabel;
+
+    public AntHill(int _weight, int _height){
+
+        DrawableRectangle d = VUI.get().createRectangle(0, 0, _weight, _height);
+        d.setStrokeOnly();
+
+        VUI.get().createRectangle(90, 20, 180, 40).setColor(new Color(0.9f, 0.9f, 0.9f, 0.8f)).setFixed().setLayer(5);
+
+        VUI.get().createImage(20, 20, "src/example/randomants/ressources/ant.png").setFixed().setLayer(10);
+        antsCountLabel = (DrawableString) VUI.get().createString(45, 25, "Ants count").setFixed().setLayer(10);
+    }
+
+    public DrawableString getAntsCountLabel() {
+        return antsCountLabel;
+    }
+
+    public void setAntsCountLabel(DrawableString _antsCountLabel) {
+        antsCountLabel = _antsCountLabel;
+    }
+}
diff --git a/src/example/randomants/MainAnt.java b/src/example/randomants/MainAnt.java
new file mode 100644
index 0000000..9afcb72
--- /dev/null
+++ b/src/example/randomants/MainAnt.java
@@ -0,0 +1,34 @@
+package example.randomants;
+
+import mas.core.Agent;
+import mas.environment.TwoDContinuosGrid;
+import mas.implementation.base.schedulers.TwoDCycling;
+import mas.ui.MainWindow;
+import mas.ui.SchedulerToolbar;
+
+public class MainAnt {
+
+    public static void main(String[] args) {
+
+        int widht = 800;
+        int height = 600;
+
+
+        AntHill hill = new AntHill(widht, height);
+
+        TwoDContinuosGrid env = new TwoDContinuosGrid(widht, height);
+
+        int nAgents = 50;
+
+        Agent[] ants = new Ant[nAgents];
+
+        for(int i = 0; i<nAgents ; i++){
+            ants[i] = new Ant(i+1,0,0,env);
+        }
+
+        TwoDCycling scheduler = new TwoDCycling(ants);
+
+        MainWindow.instance();
+        MainWindow.addToolbar(new SchedulerToolbar("Amas", scheduler));
+    }
+}
diff --git a/src/example/randomants/ressources/ant.png b/src/example/randomants/ressources/ant.png
new file mode 100644
index 0000000000000000000000000000000000000000..913a361085cac804f7afe2e16cf7bbbf7ad273c4
GIT binary patch
literal 352
zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBq0kV_;y&es0^yz`(##?Bp53!NI{%!;#X#
zz`(#+;1OBOz`%C|gc+x5^GP!>Fi4iTMwA5Sr<If^7Ns(jmzV2h=4BTrCl;jY<rk&T
zerF@az`$_V)5S4FV`A^6wSLZy0;~_#+jDZB*w)k{z|%A<Nt;9QrEo}6fDI$3C-1uc
z3rjrX85>_PGlcSTID{x=1#ryD(tD(&cUg6(x};%x`nh*AWp8ZmREuh~_Pnz4k;cLN
zWc8~Pger~|&P)mkO5shmc_3DM=OL&0e*K-tWP(e$YGWmow2zdZh<Dz1$nx9<R{4br
zZX#z2LgzS!U8)xf^<ffcjd%Ljs#=wC<wFPCwNH+`Pws_DJQSM$Y441OOy4VxE52DI
zn|JfL;{(6{n=c$wDve+(-J|+r>wfRxiT{tW)iLlbG~KH3e|jYY0|SGntDnm{r-UW|
D?lyoc

literal 0
HcmV?d00001

diff --git a/src/example/randomants/ressources/ant_dead.png b/src/example/randomants/ressources/ant_dead.png
new file mode 100644
index 0000000000000000000000000000000000000000..cf9a4b9b12215335b24d56daf459f3822db61b40
GIT binary patch
literal 214
zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBq0kV_;y&es0^yz`($g?&#~tz_78O`%fY(
z0|NtFlDE4H!+#K5uy^@n1_lPs0*}aI1_r((Aj~*bn@^g7fq}im)7O>#5vvdnpZLZ{
zfe8!@48fi*jv*T7w+1=#9Z=vols5kvtIh4XX+DeHZl9be62zep`OslgRb2@?Lz_y@
zQ@dYhic`byI0s#B<*Bj>T)5<ucjrqEvD*LL2C`=_PMCFjEywD4asHe17R}z}vYvr~
Ofx*+&&t;ucLK6T*%tk^0

literal 0
HcmV?d00001

diff --git a/src/mas/core/Agent.java b/src/mas/core/Agent.java
index d4b955b..eb85fde 100644
--- a/src/mas/core/Agent.java
+++ b/src/mas/core/Agent.java
@@ -2,7 +2,7 @@ package mas.core;
 
 public class Agent implements ThreeStepCyclable{
 
-    private Schedulable scheduleur;
+    protected Schedulable scheduler;
 
     @Override
     public void perceive() {
@@ -25,7 +25,7 @@ public class Agent implements ThreeStepCyclable{
     }
 
     @Override
-    public void setScheduleur(Schedulable _scheduleur) {
-        scheduleur = _scheduleur;
+    public void setScheduler(Schedulable _scheduler) {
+        scheduler = _scheduler;
     }
 }
diff --git a/src/mas/core/Cyclable.java b/src/mas/core/Cyclable.java
index c272b06..05a7fde 100644
--- a/src/mas/core/Cyclable.java
+++ b/src/mas/core/Cyclable.java
@@ -19,5 +19,5 @@ public interface Cyclable {
     /**
      * TODO
      */
-    void setScheduleur(Schedulable _scheduleur);
+    void setScheduler(Schedulable _scheduler);
 }
diff --git a/src/mas/environment/TwoDContinuosGrid.java b/src/mas/environment/TwoDContinuosGrid.java
index 4ae7f99..5cc7896 100644
--- a/src/mas/environment/TwoDContinuosGrid.java
+++ b/src/mas/environment/TwoDContinuosGrid.java
@@ -2,4 +2,20 @@ package mas.environment;
 
 public class TwoDContinuosGrid {
 
+    private int width;
+    private int height;
+
+    public TwoDContinuosGrid(int _width, int _height){
+        height = _height;
+        width = _width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
 }
diff --git a/src/mas/implementation/base/schedulers/AsyncCycling.java b/src/mas/implementation/base/schedulers/AsyncCycling.java
index 99c821b..9d13109 100644
--- a/src/mas/implementation/base/schedulers/AsyncCycling.java
+++ b/src/mas/implementation/base/schedulers/AsyncCycling.java
@@ -23,7 +23,7 @@ public class AsyncCycling implements Schedulable {
 
         for(Cyclable cyclable : _cyclables){
             cyclables.add(cyclable);
-            cyclable.setScheduleur(this);
+            cyclable.setScheduler(this);
         }
     }
 
@@ -64,7 +64,7 @@ public class AsyncCycling implements Schedulable {
     @Override
     public void addCyclable(Cyclable cyclable) {
         cyclables.add(cyclable);
-        cyclable.setScheduleur(this);
+        cyclable.setScheduler(this);
 
         if(!mustStop){
             executor.execute(() -> {
diff --git a/src/mas/implementation/base/schedulers/FairCycling.java b/src/mas/implementation/base/schedulers/FairCycling.java
index aeb42f0..6d283eb 100644
--- a/src/mas/implementation/base/schedulers/FairCycling.java
+++ b/src/mas/implementation/base/schedulers/FairCycling.java
@@ -3,10 +3,9 @@ package mas.implementation.base.schedulers;
 import mas.core.Cyclable;
 import mas.core.Schedulable;
 
-import java.util.LinkedHashSet;
-import java.util.Queue;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.*;
+import java.util.function.Consumer;
 
 /**
  * Chaque agent execute exactement 1 cycle pour chaque cycle systeme
@@ -40,28 +39,32 @@ public class FairCycling implements Schedulable {
 
     @Override
     public void start() {
-        System.out.println("Je fait start");
-        new Thread(() -> doCycle()).start();
+        //System.out.println("Je fait start");
+        executor.execute(() -> {
+            doCycle();
+        });
     }
 
     @Override
     public void stop() {
-        System.out.println("Je fait stop");
+        //System.out.println("Je fait stop");
         mustStop = true;
         executor.shutdown();
     }
 
     @Override
     public void pause() {
-        System.out.println("Je fait pause");
+        //System.out.println("Je fait pause");
         pauseLatch = new CountDownLatch(1);
         mustPause = true;
     }
 
     @Override
     public void resume() {
-        System.out.println("Je fait resume");
-        pauseLatch.countDown();
+        //System.out.println("Je fait resume");
+        if(pauseLatch != null){
+            pauseLatch.countDown();
+        }
     }
 
     @Override
@@ -69,10 +72,14 @@ public class FairCycling implements Schedulable {
         return false;
     }
 
+    protected void onCycleEnds() {
+
+    }
+
     @Override
     public void addCyclable(Cyclable cyclable){
         //System.out.println("Je fait addCyclebles : " + cyclable.toString());
-        cyclable.setScheduleur(this);
+        cyclable.setScheduler(this);
         pendingToAddCyclables.add(cyclable);
     }
 
@@ -87,12 +94,10 @@ public class FairCycling implements Schedulable {
     }
 
     protected void step() {
-        System.out.println("Je fait step");
+        //System.out.println("Je fait step");
         nbOfCycles++;
         System.out.println("cycle systeme " + nbOfCycles);
 
-        //System.out.println(pendingToAddCyclables.size() + " : " + pendingToAddCyclables);
-
         treatPendingCyclables();
 
         latch = new CountDownLatch(cyclables.size());
@@ -102,13 +107,10 @@ public class FairCycling implements Schedulable {
             executor.execute(() -> {
                 cyclable.cycle();
                 if(!cyclable.terminate()){
-                    //System.out.println("\t\t" + cyclable.toString() + " je fait pendingToAdd");
                     pendingToAddCyclables.add(cyclable);
                 }
-
                 latch.countDown();
             });
-
         }
 
         if (getSleep() != 0) {
@@ -126,10 +128,12 @@ public class FairCycling implements Schedulable {
         }
 
         cyclables.clear();
+
+        onCycleEnds();
     }
 
     protected void doCycle() {
-        System.out.println("Je fait doCycle");
+        //System.out.println("Je fait doCycle");
         step();
         if(stopCondition()){
             this.stop();
@@ -148,7 +152,8 @@ public class FairCycling implements Schedulable {
     }
 
     private void treatPendingCyclables() {
-        while (!pendingToAddCyclables.isEmpty())
-            cyclables.add(pendingToAddCyclables.poll());
+        Queue<Cyclable> buffer = new ConcurrentLinkedQueue<>(pendingToAddCyclables);
+        cyclables.addAll(buffer);
+        pendingToAddCyclables.clear();
     }
 }
diff --git a/src/mas/implementation/base/schedulers/TwoDCycling.java b/src/mas/implementation/base/schedulers/TwoDCycling.java
index 0c9067e..f3d1478 100644
--- a/src/mas/implementation/base/schedulers/TwoDCycling.java
+++ b/src/mas/implementation/base/schedulers/TwoDCycling.java
@@ -1,6 +1,7 @@
 package mas.implementation.base.schedulers;
 
 import mas.core.Cyclable;
+import mas.ui.VUI;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -12,7 +13,7 @@ public class TwoDCycling extends FairCycling{
     /**
      * The state of the scheduler {@link State}
      */
-    private State state;
+    private State state = State.PENDING_START;
 
     /**
      * Method that is called when the scheduler stops
@@ -25,6 +26,10 @@ public class TwoDCycling extends FairCycling{
      */
 
     public enum State {
+        /**
+         * The scheduler is waiting to start
+         */
+        PENDING_START,
         /**
          * The scheduler is running
          */
@@ -32,11 +37,7 @@ public class TwoDCycling extends FairCycling{
         /**
          * The scheduler is paused
          */
-        IDLE,
-        /**
-         * The scheduler is expected to stop at the end at the current cycle
-         */
-        PENDING_STOP
+        IDLE
 
     }
     private List<Consumer<TwoDCycling>> onChange = new ArrayList<>();
@@ -68,22 +69,30 @@ public class TwoDCycling extends FairCycling{
     }
 
     public void doOneCycle() {
-        System.out.println("Je fait doOneCycle");
-        step();
-        if(stopCondition()){
-            this.stop();
-        }
-
-        if (!mustStop) {
-            this.pause();
-        }
+        executor.execute(() -> {
+            step();
+            if(stopCondition()){
+                this.stop();
+            }
+
+            if (!mustStop) {
+                this.pause();
+            }
+        });
     }
     public void startWithSleep(int _sleep){
-        System.out.println("Je commence startWithSleep(" + _sleep + ")");
+        //System.out.println("Je commence startWithSleep(" + _sleep + ")");
         setSleep(_sleep);
-        state = State.RUNNING;
-        resume();
-        executor.execute(() -> doCycle());
+
+
+        switch (state){
+            case PENDING_START -> {
+                start();
+            }
+            default -> {
+                resume();
+            }
+        }
     }
 
 
@@ -94,21 +103,21 @@ public class TwoDCycling extends FairCycling{
     @Override
     public void start() {
         state = State.RUNNING;
-        new Thread(() -> doCycle()).start();
+        super.start();
     }
 
     @Override
     public void pause() {
         state = State.IDLE;
-        pauseLatch = new CountDownLatch(1);
+        if(pauseLatch == null){
+            pauseLatch = new CountDownLatch(1);
+        }
         mustPause = true;
     }
 
     @Override
     public void resume() {
-        if(pauseLatch != null){
-            pauseLatch.countDown();
-        }
+        super.resume();
         state = State.RUNNING;
     }
 }
diff --git a/src/mas/ui/SchedulerToolbar.java b/src/mas/ui/SchedulerToolbar.java
index 69ea352..5cd2b47 100644
--- a/src/mas/ui/SchedulerToolbar.java
+++ b/src/mas/ui/SchedulerToolbar.java
@@ -3,7 +3,6 @@ package mas.ui;
 import mas.implementation.base.schedulers.TwoDCycling;
 
 import javax.swing.*;
-import javax.swing.event.ChangeListener;
 import java.awt.*;
 import java.util.Hashtable;
 
diff --git a/src/mas/ui/VUI.java b/src/mas/ui/VUI.java
new file mode 100644
index 0000000..ee38e12
--- /dev/null
+++ b/src/mas/ui/VUI.java
@@ -0,0 +1,507 @@
+package mas.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+import javax.swing.border.BevelBorder;
+
+import mas.ui.drawables.*;
+
+/**
+ * 
+ * Vectorial UI: This class allows to create dynamic rendering with zoom and
+ * move capacities
+ * 
+ * @author perles
+ *
+ */
+public class VUI {
+	/**
+	 * List of objects currently being drawn by the VUI
+	 */
+	private List<Drawable> drawables = new ArrayList<>();
+	/**
+	 * Lock to avoid concurrent modification on the list {@link #drawables}
+	 */
+	private ReentrantLock drawablesLock = new ReentrantLock();
+
+	/**
+	 * A static map to facilitate access to different instances of VUI
+	 */
+	private static Map<String, VUI> instances = new HashMap<>();
+
+	/**
+	 * The horizontal offset of the drawing zone. Used to allow the user to move the
+	 * view.
+	 */
+	private double worldOffsetX;
+
+	/**
+	 * The vertical offset of the drawing zone. Used to allow the user to move the
+	 * view.
+	 */
+	private double worldOffsetY;
+
+	/**
+	 * The last horizontal position of the mouse when dragging
+	 */
+	protected Integer lastDragX;
+
+	/**
+	 * The last vertical position of the mouse when dragging
+	 */
+	protected Integer lastDragY;
+
+	/**
+	 * The main panel of the VUI
+	 */
+	private JPanel panel;
+
+	/**
+	 * The canvas on which all is drawn
+	 */
+	private JPanel canvas;
+
+	/**
+	 * Label aiming at showing information about the VUI (zoom and offset)
+	 */
+	private JLabel statusLabel;
+
+	/**
+	 * The default value of the {@link #zoom}
+	 */
+	private double defaultZoom = 100;
+	/**
+	 * The default horizontal position of the view
+	 */
+	private double defaultWorldCenterX = 0;
+	/**
+	 * The default vertical position of the view
+	 */
+	private double defaultWorldCenterY = 0;
+	/**
+	 * The value of the zoom. 100 means 1/1 scale
+	 */
+	protected double zoom = defaultZoom;
+
+	/**
+	 * The horizontal position of the view
+	 */
+	private double worldCenterX = defaultWorldCenterX;
+
+	/**
+	 * The vertical position of the view
+	 */
+	private double worldCenterY = defaultWorldCenterY;
+
+	/**
+	 * Get the default VUI
+	 * 
+	 * @return the default VUI
+	 */
+	public static VUI get() {
+		return get("Default");
+	}
+
+	/**
+	 * Create or get a VUI
+	 * 
+	 * @param id
+	 *            The unique id of the VUI
+	 * @return The VUI with id "id"
+	 */
+	public static VUI get(String id) {
+		if (!instances.containsKey(id)) {
+			VUI value = new VUI(id);
+			instances.put(id, value);
+			return value;
+		}
+		return instances.get(id);
+	}
+
+	/**
+	 * Constructor of the VUI. This one is private as it can only be created through
+	 * static method.
+	 * 
+	 * @param title
+	 *            The title used for the vui
+	 */
+	private VUI(String title) {
+		panel = new JPanel(new BorderLayout());
+
+		JPanel statusPanel = new JPanel();
+		statusPanel.setBorder(new BevelBorder(BevelBorder.LOWERED));
+		statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.X_AXIS));
+		statusLabel = new JLabel("status");
+		statusLabel.setHorizontalAlignment(SwingConstants.LEFT);
+		statusPanel.add(statusLabel);
+		JButton resetButton = new JButton("Reset");
+		resetButton.addActionListener(l -> {
+			zoom = defaultZoom;
+			worldCenterX = defaultWorldCenterX;
+			worldCenterY = defaultWorldCenterY;
+			updateCanvas();
+		});
+		statusPanel.add(resetButton);
+
+		canvas = new JPanel() {
+
+			/**
+			 * 
+			 */
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			protected void paintComponent(Graphics g) {
+
+				final Graphics2D g2 = (Graphics2D) g;
+
+				final int w = getSize().width;
+				final int h = getSize().height;
+
+				setWorldOffsetX(worldCenterX + screenToWorldDistance(w / 2));
+				setWorldOffsetY(worldCenterY + screenToWorldDistance(h / 2));
+
+				g.setColor(new Color(0.96f, 0.96f, 0.96f));
+				g.fillRect(0, 0, w, h);
+				drawablesLock.lock();
+				Collections.sort(drawables, (o1, o2) -> o1.getLayer() - o2.getLayer());
+				for (Drawable d : drawables) {
+					d.onDraw(g2);
+				}
+				drawablesLock.unlock();
+			}
+		};
+		canvas.addMouseListener(new MouseListener() {
+
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				// This method is not meant to be used as everything is handled by other methods
+			}
+
+			@Override
+			public void mousePressed(MouseEvent e) {
+
+				lastDragX = e.getX();
+				lastDragY = e.getY();
+			}
+
+			@Override
+			public void mouseExited(MouseEvent e) {
+				lastDragX = null;
+				lastDragY = null;
+			}
+
+			@Override
+			public void mouseEntered(MouseEvent e) {
+				// This method is not meant to be used as everything is handled by other methods
+			}
+
+			@Override
+			public void mouseClicked(MouseEvent e) {
+				// This method is not meant to be used yet
+			}
+		});
+		canvas.addMouseMotionListener(new MouseMotionListener() {
+			@Override
+			public void mouseMoved(MouseEvent e) {
+				// This method is not meant to be used as everything is handled by other methods
+			}
+
+			@Override
+			public void mouseDragged(MouseEvent e) {
+				try {
+					worldCenterX += screenToWorldDistance(e.getX() - lastDragX);
+					worldCenterY += screenToWorldDistance(e.getY() - lastDragY);
+					lastDragX = e.getX();
+					lastDragY = e.getY();
+					updateCanvas();
+				} catch (Exception ez) {
+					// Catch exception occuring when mouse is out of the canvas
+				}
+			}
+		});
+		canvas.addMouseWheelListener(e -> {
+			double wdx = screenToWorldDistance((int) (canvas.getSize().getWidth() / 2 - e.getX()));
+			double wdy = screenToWorldDistance((int) (canvas.getSize().getHeight() / 2 - e.getY()));
+
+			zoom += e.getWheelRotation() * 10;
+			if (zoom < 10)
+				zoom = 10;
+
+			double wdx2 = screenToWorldDistance((int) (canvas.getSize().getWidth() / 2 - e.getX()));
+			double wdy2 = screenToWorldDistance((int) (canvas.getSize().getHeight() / 2 - e.getY()));
+
+			worldCenterX -= wdx2 - wdx;
+			worldCenterY -= wdy2 - wdy;
+			updateCanvas();
+		});
+		canvas.setPreferredSize(new Dimension(800, 600));
+		panel.add(canvas, BorderLayout.CENTER);
+		panel.add(statusPanel, BorderLayout.SOUTH);
+		MainWindow.addTabbedPanel("VUI #" + title, panel);
+
+	}
+
+	/**
+	 * Convert a distance in the world to its equivalent on the screen
+	 * 
+	 * @param d
+	 *            the in world distance
+	 * @return the on screen distance
+	 */
+	public int worldToScreenDistance(double d) {
+		return (int) (d * getZoomFactor());
+	}
+
+	/**
+	 * Convert a distance on the screen to its equivalent in the world
+	 * 
+	 * @param d
+	 *            the on screen distance
+	 * @return the in world distance
+	 */
+	public double screenToWorldDistance(int d) {
+		return ((double) d / getZoomFactor());
+	}
+
+	/**
+	 * Convert a X in the world to its equivalent on the screen
+	 * 
+	 * @param x
+	 *            the X in world
+	 *
+	 * @return the X on screen distance
+	 */
+	public int worldToScreenX(double x) {
+		return (int) ((x + getWorldOffsetX()) * getZoomFactor());
+	}
+
+	/**
+	 * A value that must be multiplied to scale objects
+	 * 
+	 * @return the zoom factor
+	 */
+	public double getZoomFactor() {
+		return zoom / 100;
+	}
+
+	/**
+	 * Convert a Y in the world to its equivalent on the screen
+	 * 
+	 * @param y
+	 *            the Y in world
+	 *
+	 * @return the Y on screen distance
+	 */
+	public int worldToScreenY(double y) {
+		return (int) ((y + getWorldOffsetY()) * getZoomFactor());
+	}
+
+	/**
+	 * Convert a X on the screen to its equivalent in the world
+	 * 
+	 * @param x
+	 *            the X on screen
+	 *
+	 * @return the X in the world distance
+	 */
+	public double screenToWorldX(double x) {
+		return (x) / getZoomFactor() - getWorldOffsetX();
+	}
+
+	/**
+	 * Convert a Y on the screen to its equivalent in the world
+	 * 
+	 * @param y
+	 *            the Y on screen
+	 *
+	 * @return the Y in the world distance
+	 */
+	public double screenToWorldY(double y) {
+		return (y) / getZoomFactor() - getWorldOffsetY();
+	}
+
+	/**
+	 * Add an object to the VUI and repaint it
+	 * 
+	 * @param d
+	 *            the new object
+	 */
+	public void add(Drawable d) {
+		d.setPanel(this);
+		drawablesLock.lock();
+		drawables.add(d);
+		drawablesLock.unlock();
+		updateCanvas();
+	}
+
+	/**
+	 * Refresh the canvas
+	 */
+	public void updateCanvas() {
+		canvas.repaint();
+
+		statusLabel.setText(String.format("Zoom: %.2f Center: (%.2f,%.2f)", zoom, worldCenterX, worldCenterY));
+	}
+
+	/**
+	 * Get the width of the canvas
+	 * 
+	 * @return the canvas width
+	 */
+	public double getCanvasWidth() {
+		return canvas.getSize().getWidth();
+	}
+
+	/**
+	 * Get the height of the canvas
+	 * 
+	 * @return the canvas height
+	 */
+	public double getCanvasHeight() {
+		return canvas.getSize().getHeight();
+	}
+
+	/**
+	 * Get the value that must be added to the X coordinate of in world object
+	 * 
+	 * @return the X offset
+	 */
+	public double getWorldOffsetX() {
+		return worldOffsetX;
+	}
+
+	/**
+	 * Set the value that must be added to the X coordinate of in world object
+	 * 
+	 * @param offsetX
+	 *            the X offset
+	 */
+	public void setWorldOffsetX(double offsetX) {
+		this.worldOffsetX = offsetX;
+	}
+
+	/**
+	 * Get the value that must be added to the Y coordinate of in world object
+	 * 
+	 * @return the Y offset
+	 */
+	public double getWorldOffsetY() {
+		return worldOffsetY;
+	}
+
+	/**
+	 * Set the value that must be added to the Y coordinate of in world object
+	 * 
+	 * @param offsetY
+	 *            the Y offset
+	 */
+	public void setWorldOffsetY(double offsetY) {
+		this.worldOffsetY = offsetY;
+	}
+
+	/**
+	 * Create a point and start rendering it
+	 * 
+	 * @param dx
+	 *            the x coordinate
+	 * @param dy
+	 *            the y coordinate
+	 * @return the point object
+	 */
+	public DrawablePoint createPoint(double dx, double dy) {
+		DrawablePoint drawablePoint = new DrawablePoint(this, dx, dy);
+		add(drawablePoint);
+		return drawablePoint;
+	}
+
+	/**
+	 * Create a rectangle and start rendering it
+	 * 
+	 * @param x
+	 *            the x coordinate
+	 * @param y
+	 *            the y coordinate
+	 * @param w
+	 *            the width
+	 * @param h
+	 *            the height
+	 * @return the rectangle object
+	 */
+	public DrawableRectangle createRectangle(double x, double y, double w, double h) {
+		DrawableRectangle d = new DrawableRectangle(this, x, y, w, h);
+		add(d);
+		return d;
+	}
+
+	/**
+	 * Set the default configuration of the view
+	 * 
+	 * @param zoom
+	 *            the initial zoom value
+	 * @param worldCenterX
+	 *            the initial X center value
+	 * @param worldCenterY
+	 *            the initial Y center value
+	 */
+	public void setDefaultView(double zoom, double worldCenterX, double worldCenterY) {
+		this.zoom = zoom;
+		this.worldCenterX = worldCenterX;
+		this.worldCenterY = worldCenterY;
+		this.defaultZoom = zoom;
+		this.defaultWorldCenterX = worldCenterX;
+		this.defaultWorldCenterY = worldCenterY;
+	}
+
+	/**
+	 * Create an image and start rendering it
+	 * 
+	 * @param dx
+	 *            the x coordinate
+	 * @param dy
+	 *            the y coordinate
+	 * @param filename
+	 *            the filename of the image
+	 * @return the created image
+	 */
+	public DrawableImage createImage(double dx, double dy, String filename) {
+		DrawableImage image = new DrawableImage(this, dx, dy, filename);
+		add(image);
+		return image;
+	}
+
+	/**
+	 * Create a string and start rendering it
+	 * 
+	 * @param dx
+	 *            the x coordinate
+	 * @param dy
+	 *            the y coordinate
+	 * @param text
+	 *            the text to display
+	 * @return the created string
+	 */
+	public DrawableString createString(int dx, int dy, String text) {
+		DrawableString ds = new DrawableString(this, dx, dy, text);
+		add(ds);
+		return ds;
+	}
+}
diff --git a/src/mas/ui/drawables/Drawable.java b/src/mas/ui/drawables/Drawable.java
new file mode 100644
index 0000000..251c8c1
--- /dev/null
+++ b/src/mas/ui/drawables/Drawable.java
@@ -0,0 +1,396 @@
+package mas.ui.drawables;
+
+import mas.ui.VUI;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+
+/**
+ * A drawable is an object that can be drawn by the {@link VUI} system
+ * 
+ * @author Alexandre Perles
+ *
+ */
+public abstract class Drawable {
+
+	/**
+	 * The horizontal position of the object
+	 */
+	private double x;
+	/**
+	 * The vertical position of the object
+	 */
+	private double y;
+	/**
+	 * The width of the object
+	 */
+	private double width;
+
+	/**
+	 * Compute the width as it must be displayed on screen. Given the zoom factor,
+	 * the width displayed can be different than the real width.
+	 * 
+	 * @return the width
+	 */
+	public double getRenderedWidth() {
+		if (isFixed())
+			return width;
+		else
+			return vui.worldToScreenDistance(width);
+	}
+
+	/**
+	 * Set the real width of the object
+	 *
+	 * @param width
+	 *            The new width
+	 */
+	public void setWidth(double width) {
+		this.width = width;
+		update();
+	}
+
+	/**
+	 * Compute the height as it must be displayed on screen. Given the zoom factor,
+	 * the height displayed can be different than the real height.
+	 * 
+	 * @return the width
+	 */
+	public double getRenderedHeight() {
+		if (isFixed())
+			return height;
+		else
+			return vui.worldToScreenDistance(height);
+	}
+
+	/**
+	 * Set the real height of the object
+	 * 
+	 * @param height
+	 *            The new height
+	 */
+	public void setHeight(double height) {
+		this.height = height;
+		update();
+	}
+
+	/**
+	 * Get the real width
+	 * 
+	 * @return the real width
+	 */
+	public double getWidth() {
+		return width;
+	}
+
+	/**
+	 * Get the real height
+	 * 
+	 * @return the real height
+	 */
+	public double getHeight() {
+		return height;
+	}
+
+	/**
+	 * The real height
+	 */
+	protected double height;
+
+	/**
+	 * Does only the border must be displayed ?
+	 */
+	protected boolean strokeMode = false;
+
+	/**
+	 * The color of the object
+	 */
+	protected Color color = Color.black;
+	/**
+	 * The VUI on which the object is drawn
+	 */
+	protected VUI vui;
+	/**
+	 * The order of drawing. An higher layer is drawn on top of the other.
+	 */
+	protected int layer = 0;
+	/**
+	 * The angle of rotation of the object
+	 */
+	private double angle;
+	/**
+	 * A fixed object doesn't move with the view. It can be used for HUD
+	 */
+	private boolean fixed = false;
+	/**
+	 * Must the object be drawn ?
+	 */
+	private boolean visible = true;
+
+	/**
+	 * Getter for the fixed attribute
+	 * 
+	 * @return if the obejct is fixed
+	 */
+	public boolean isFixed() {
+		return fixed;
+	}
+
+	/**
+	 * Getter for the angle attribute
+	 * 
+	 * @return the angle
+	 */
+	public double getAngle() {
+		return angle;
+	}
+
+	/**
+	 * Getter for the layer attribute
+	 * 
+	 * @return the layer
+	 */
+	public int getLayer() {
+		return layer;
+	}
+
+	/**
+	 * Set the layer and update
+	 * 
+	 * @param layer
+	 *            the new layer
+	 * @return the object for chained methods
+	 */
+	public Drawable setLayer(int layer) {
+		this.layer = layer;
+		update();
+		return this;
+	}
+
+	/**
+	 * Set the new angle
+	 * 
+	 * @param angle2
+	 *            the new angle
+	 * @return the object for chained methods
+	 */
+	public Drawable setAngle(double angle2) {
+		this.angle = angle2;
+		update();
+		return this;
+	}
+
+	/**
+	 * Constructor of the obejct
+	 * 
+	 * @param vui
+	 *            the VUI on which the object must be drawn
+	 * @param dx
+	 *            the x real position
+	 * @param dy
+	 *            the y real position
+	 * @param width
+	 *            the real width
+	 * @param height
+	 *            the real height
+	 */
+	protected Drawable(VUI vui, double dx, double dy, double width, double height) {
+		this.vui = vui;
+		x = dx;
+		y = dy;
+		this.width = width;
+		this.height = height;
+	}
+
+	/**
+	 * Draw the object if visible and if on screen
+	 * 
+	 * @param graphics
+	 *            The graphics object that must be used to draw
+	 */
+	public void onDraw(Graphics2D graphics) {
+		if (isVisible() && isOnScreen()) {
+			_onDraw(graphics);
+		}
+	}
+
+	/**
+	 * Is the object on screen ?
+	 * 
+	 * @return true if object is on the screen
+	 */
+	private boolean isOnScreen() {
+		return (isPointOnScreen(left(), top()) || isPointOnScreen(left(), bottom())
+				|| isPointOnScreen(right(), bottom()) || isPointOnScreen(right(), top()));
+	}
+
+	/**
+	 * Is a given coordinate on screen
+	 * 
+	 * @param x
+	 *            the horitontal position
+	 * @param y
+	 *            the vertical position
+	 * @return true if the point is on the screen
+	 */
+	private boolean isPointOnScreen(double x, double y) {
+		return x >= 0 && x <= vui.getCanvasWidth() && y >= 0 && y <= vui.getCanvasHeight();
+	}
+
+	/**
+	 * Method that must be overrided to draw
+	 * 
+	 * @param graphics
+	 *            the Graphics2D object
+	 */
+	public abstract void _onDraw(Graphics2D graphics);
+
+	/**
+	 * Method called when the VUI must be refreshed
+	 */
+	public void update() {
+		if (vui != null)
+			vui.updateCanvas();
+	}
+
+	/**
+	 * Set the associated VUI
+	 * 
+	 * @param vectorialUI
+	 */
+	public void setPanel(VUI vectorialUI) {
+		vui = vectorialUI;
+	}
+
+	/**
+	 * Get the top y coordinate
+	 * 
+	 * @return the top y coordinate
+	 */
+	public double top() {
+		if (isFixed())
+			return y - height / 2;
+		else
+			return vui.worldToScreenY(y - height / 2);
+	}
+
+	/**
+	 * Get the left x coordinate
+	 * 
+	 * @return the left x coordinate
+	 */
+	public double left() {
+		if (isFixed())
+			return x - width / 2;
+		else
+			return vui.worldToScreenX(x - width / 2);
+	}
+
+	/**
+	 * Get the bottom y coordinate
+	 * 
+	 * @return the bottom y coordinate
+	 */
+	public double bottom() {
+		if (isFixed())
+			return y + height / 2;
+		else
+			return vui.worldToScreenY(y + height / 2);
+	}
+
+	/**
+	 * Get the right x coordinate
+	 * 
+	 * @return the right x coordinate
+	 */
+	public double right() {
+		if (isFixed())
+			return x + width / 2;
+		else
+			return vui.worldToScreenX(x + width / 2);
+	}
+
+	/**
+	 * Only draw the border of the object
+	 * 
+	 * @return the object for chained methods
+	 */
+	public Drawable setStrokeOnly() {
+		strokeMode = true;
+		update();
+		return this;
+	}
+
+	/**
+	 * 
+	 * @param color
+	 * @return the object for chained methods
+	 */
+	public Drawable setColor(Color color) {
+		if (color == this.color)
+			return this;
+		this.color = color;
+		update();
+		return this;
+	}
+
+	/**
+	 * 
+	 * @param dx
+	 * @param dy
+	 * @return the object for chained methods
+	 */
+	public Drawable move(double dx, double dy) {
+		if (x == dx && y == dy)
+			return this;
+		this.x = dx;
+		this.y = dy;
+		update();
+		return this;
+	}
+
+	/**
+	 * 
+	 * @return the object for chained methods
+	 */
+	public Drawable setFixed() {
+		this.fixed = true;
+		update();
+		return this;
+	}
+
+	/**
+	 * 
+	 * @return the object for chained methods
+	 */
+	public Drawable show() {
+		return this.setVisible(true);
+	}
+
+	/**
+	 * 
+	 * @return
+	 */
+	public Drawable hide() {
+		return this.setVisible(false);
+	}
+
+	/**
+	 * 
+	 * @return
+	 */
+	public boolean isVisible() {
+		return visible;
+	}
+
+	/**
+	 * 
+	 * @param visible
+	 * @return the object for chained methods
+	 */
+	public Drawable setVisible(boolean visible) {
+		this.visible = visible;
+		update();
+		return this;
+	}
+}
diff --git a/src/mas/ui/drawables/DrawableCircle.java b/src/mas/ui/drawables/DrawableCircle.java
new file mode 100644
index 0000000..2ba660f
--- /dev/null
+++ b/src/mas/ui/drawables/DrawableCircle.java
@@ -0,0 +1,22 @@
+package mas.ui.drawables;
+
+import java.awt.Graphics2D;
+
+import mas.ui.VUI;
+
+public class DrawableCircle extends Drawable {
+	public DrawableCircle(VUI vui, double dx, double dy, double size) {
+		super(vui, dx, dy, size, size);
+	}
+
+	@Override
+	public void _onDraw(Graphics2D graphics) {
+		graphics.setColor(color);
+		if (strokeMode)
+			graphics.drawOval((int)left(), (int)top(), (int) getRenderedWidth(), (int) getRenderedHeight());
+		else
+			graphics.fillOval((int)left(), (int)top(), (int) getRenderedWidth(), (int) getRenderedHeight());
+	}
+
+
+}
diff --git a/src/mas/ui/drawables/DrawableImage.java b/src/mas/ui/drawables/DrawableImage.java
new file mode 100644
index 0000000..aa38592
--- /dev/null
+++ b/src/mas/ui/drawables/DrawableImage.java
@@ -0,0 +1,66 @@
+package mas.ui.drawables;
+
+import mas.ui.VUI;
+
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.imageio.ImageIO;
+
+public class DrawableImage extends Drawable {
+
+	private String filename;
+	private BufferedImage image;
+	private static Map<String, BufferedImage> loadedImages = new HashMap<>();
+
+	public DrawableImage(VUI vui, double dx, double dy, String filename) {
+		super(vui, dx, dy, 0, 0);
+		this.setFilename(filename);
+
+	}
+
+	private BufferedImage loadByFilename(String filename) throws IOException {
+		if (!loadedImages.containsKey(filename)) {
+			loadedImages.put(filename, ImageIO.read(new File(filename)));
+		}
+		return loadedImages.get(filename);
+	}
+
+	public void setFilename(String filename) {
+		this.filename = filename;
+		try {
+			this.image = loadByFilename(this.filename);
+		} catch (IOException e) {
+			//Log.error("AMAK", "Can't find/load the file %s", this.filename);
+			e.printStackTrace();
+			try {
+				this.image = loadByFilename("Resources/unavailable.png");
+			} catch (IOException e1) {
+				e1.printStackTrace();
+			}
+		}
+		setWidth(this.image.getWidth());
+		setHeight(this.image.getHeight());
+
+	}
+
+	@Override
+	public void _onDraw(Graphics2D graphics) {
+		AffineTransform identity = new AffineTransform();
+		AffineTransform trans = new AffineTransform();
+		trans.setTransform(identity);
+		trans.translate(left(), top());
+		trans.rotate(getAngle(), getRenderedWidth() / 2, getRenderedHeight() / 2);
+		if (!isFixed())
+			trans.scale(vui.getZoomFactor()*getWidth()/this.image.getWidth(), vui.getZoomFactor()*getHeight()/this.image.getHeight());
+		graphics.drawImage(image, trans, null);
+		
+	}
+
+
+}
diff --git a/src/mas/ui/drawables/DrawableLine.java b/src/mas/ui/drawables/DrawableLine.java
new file mode 100644
index 0000000..0b7db86
--- /dev/null
+++ b/src/mas/ui/drawables/DrawableLine.java
@@ -0,0 +1,38 @@
+package mas.ui.drawables;
+
+import mas.ui.VUI;
+
+import java.awt.Graphics2D;
+
+public class DrawableLine extends Drawable {
+
+	private double x2, x1;
+	private double y2, y1;
+
+	public DrawableLine(VUI vui, double dx, double dy, double tx, double ty) {
+		super(vui, 0, 0, 0, 0);
+
+		x1 = dx;
+		y1 = dy;
+		x2 = tx;
+		y2 = ty;
+	}
+
+	@Override
+	public void _onDraw(Graphics2D graphics) {
+		graphics.setColor(color);
+		if (isFixed())
+			graphics.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
+		else
+			graphics.drawLine(vui.worldToScreenX(x1), vui.worldToScreenY(y1), vui.worldToScreenX(x2),
+					vui.worldToScreenY(y2));
+	}
+
+	public void move(double dx, double dy, double tx, double ty) {
+		x1 = dx;
+		y1 = dy;
+		x2 = tx;
+		y2 = ty;
+		update();
+	}
+}
diff --git a/src/mas/ui/drawables/DrawableOval.java b/src/mas/ui/drawables/DrawableOval.java
new file mode 100644
index 0000000..8562346
--- /dev/null
+++ b/src/mas/ui/drawables/DrawableOval.java
@@ -0,0 +1,22 @@
+package mas.ui.drawables;
+
+import java.awt.Graphics2D;
+
+import mas.ui.VUI;
+
+public class DrawableOval extends Drawable {
+	public DrawableOval(VUI vui, double dx, double dy, double width, double height) {
+		super(vui, dx, dy, width, height);
+	}
+
+	@Override
+	public void _onDraw(Graphics2D graphics) {
+		graphics.setColor(color);
+		if (strokeMode)
+			graphics.drawOval((int)left(), (int)top(), (int) getRenderedWidth(), (int) getRenderedHeight());
+		else
+			graphics.fillOval((int)left(), (int)top(), (int) getRenderedWidth(), (int) getRenderedHeight());
+	}
+
+
+}
diff --git a/src/mas/ui/drawables/DrawablePoint.java b/src/mas/ui/drawables/DrawablePoint.java
new file mode 100644
index 0000000..55fefe6
--- /dev/null
+++ b/src/mas/ui/drawables/DrawablePoint.java
@@ -0,0 +1,12 @@
+package mas.ui.drawables;
+
+
+import mas.ui.VUI;
+
+public class DrawablePoint extends DrawableRectangle {
+
+	public DrawablePoint(VUI vui, double dx, double dy) {
+		super(vui, dx, dy, 10, 10);
+	}
+
+}
diff --git a/src/mas/ui/drawables/DrawableRectangle.java b/src/mas/ui/drawables/DrawableRectangle.java
new file mode 100644
index 0000000..ff4143e
--- /dev/null
+++ b/src/mas/ui/drawables/DrawableRectangle.java
@@ -0,0 +1,21 @@
+package mas.ui.drawables;
+
+import mas.ui.VUI;
+
+import java.awt.Graphics2D;
+
+public class DrawableRectangle extends Drawable {
+	public DrawableRectangle(VUI vui, double dx, double dy, double width, double height) {
+		super(vui, dx, dy, width, height);
+	}
+
+	@Override
+	public void _onDraw(Graphics2D graphics) {
+		graphics.setColor(color);
+		if (strokeMode)
+			graphics.drawRect((int)left(), (int)top(), (int)getRenderedWidth(), (int)getRenderedHeight());
+		else
+			graphics.fillRect((int)left(), (int)top(), (int)getRenderedWidth(), (int)getRenderedHeight());
+	}
+
+}
diff --git a/src/mas/ui/drawables/DrawableString.java b/src/mas/ui/drawables/DrawableString.java
new file mode 100644
index 0000000..2a3eb38
--- /dev/null
+++ b/src/mas/ui/drawables/DrawableString.java
@@ -0,0 +1,26 @@
+package mas.ui.drawables;
+
+import mas.ui.VUI;
+
+import java.awt.Graphics2D;
+
+public class DrawableString extends Drawable {
+	private String text;
+
+	public DrawableString(VUI vui, double dx, double dy, String text) {
+		super(vui, dx, dy, 1, 1);
+		this.text = text;
+	}
+
+	@Override
+	public void _onDraw(Graphics2D graphics) {
+		graphics.setColor(color);
+		graphics.drawString(text, (int)left(), (int)top());
+	}
+
+	public void setText(String text) {
+		this.text = text;
+	}
+
+
+}
-- 
GitLab