diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..a818314fefa41afad001f9d5e79d4d28946a98f7 --- /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 0000000000000000000000000000000000000000..2bc891e500f57d724fd01116ec29becdcf1c026d --- /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 0000000000000000000000000000000000000000..35eb1ddfbbc029bcab630581847471d7f238ec53 --- /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 0000000000000000000000000000000000000000..8d61c8e3e5b28ba2c6e6c4c1fdd8999e67946c27 --- /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 465901d39d1ff2230c736c945573842291613ec9..9a6028d3382fcba772704add9dae66a24f189a03 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 c1b976fda9ae4396f2dc692eb0f6ccdfd1f19360..83acbcb244e4adaea6edc4b64fff998d421c0ff9 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 761f71765995663e71cf643f878c40179f35b9c3..8e69a2f883dfa593621e42f48b0c0d2b2c82aeef 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 0000000000000000000000000000000000000000..5f64c9961e5fa31dc4080e2764d4cef8a6952433 --- /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 0000000000000000000000000000000000000000..771a2134d1f2a63a092be2ce6ac50759c3e37ff9 --- /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 0000000000000000000000000000000000000000..9afcb72c75ab6641cae77b8985243cdf9cb5bd82 --- /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 Binary files /dev/null and b/src/example/randomants/ressources/ant.png differ 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 Binary files /dev/null and b/src/example/randomants/ressources/ant_dead.png differ diff --git a/src/mas/core/Agent.java b/src/mas/core/Agent.java index d4b955b3308628c5c1625b3674b8eb2ef433c10e..eb85fde476e067e1f15ee042bafd3500a3efaaa9 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 c272b066b98e525ab4f2190f4720eb4ea3896fe6..05a7fde131c41402cd9f5e804ebadbca4863f54d 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 4ae7f991c0e1ea0a73e91d8bcc034ceafde4815d..5cc7896232d1b82233c79930fd9f49c1bf6bb431 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 99c821b41f5e0bc580e8715d4fc3feafbf412b46..9d131094c09d0b295fb00282cdbcd2574775777e 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 aeb42f01d4ddecc62f7d69740c01c5cdf944bd41..6d283eb96e462665e53b10b674baaf9a383c8cf2 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 0c9067e8653e0506601e9af239ae533373d0f1f6..f3d1478cb1e33eb51310059e5fc1a425e3d4c1a4 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 69ea3523befc110b5b2376beff25302dbce83116..5cd2b47d432c59e356f78e7c988ac880579f99b0 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 0000000000000000000000000000000000000000..ee38e122d5dc92716391b71d44bf6bfd612bd889 --- /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 0000000000000000000000000000000000000000..251c8c10ed2d8ccc3622c955db6be50790108b5c --- /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 0000000000000000000000000000000000000000..2ba660f3a39bff3e2b40c28bdaa7e4242473b90a --- /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 0000000000000000000000000000000000000000..aa385926e53d15aec69d45c84b57bee8f0ca24c4 --- /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 0000000000000000000000000000000000000000..0b7db864b66bfd2222b0b9dc1afcc3f8bfc6ec35 --- /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 0000000000000000000000000000000000000000..856234610492a7001668cf82f7e01420090cdb5a --- /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 0000000000000000000000000000000000000000..55fefe64df0f593426d625c1a86a84e096e91dba --- /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 0000000000000000000000000000000000000000..ff4143e277ba4788fda4cdc564260b0ea917e0a9 --- /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 0000000000000000000000000000000000000000..2a3eb3842dc61da3e75acab676996fa23276b1c1 --- /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; + } + + +}