Browse Source

Initial commit.

Mikael Capelle 6 years ago
commit
65c81b9921
34 changed files with 2193 additions and 0 deletions
  1. 23
    0
      .classpath
  2. 17
    0
      .project
  3. 61
    0
      FORMAT
  4. 21
    0
      FORMAT_PATH
  5. 59
    0
      src/main/org/insa/algo/AbstractAlgorithm.java
  6. 20
    0
      src/main/org/insa/algo/AbstractInstance.java
  7. 67
    0
      src/main/org/insa/algo/AbstractSolution.java
  8. 30
    0
      src/main/org/insa/algo/connectivity/ConnectivityAlgorithm.java
  9. 16
    0
      src/main/org/insa/algo/connectivity/ConnectivityInstance.java
  10. 20
    0
      src/main/org/insa/algo/connectivity/ConnectivitySolution.java
  11. 58
    0
      src/main/org/insa/base/Couleur.java
  12. 115
    0
      src/main/org/insa/base/Openfile.java
  13. 86
    0
      src/main/org/insa/base/Readarg.java
  14. 57
    0
      src/main/org/insa/base/Utils.java
  15. 83
    0
      src/main/org/insa/drawing/Drawing.java
  16. 38
    0
      src/main/org/insa/drawing/DrawingInvisible.java
  17. 184
    0
      src/main/org/insa/drawing/DrawingVisible.java
  18. 135
    0
      src/main/org/insa/drawing/ZoomAndPanListener.java
  19. 81
    0
      src/main/org/insa/graph/Arc.java
  20. 28
    0
      src/main/org/insa/graph/Graph.java
  21. 52
    0
      src/main/org/insa/graph/Node.java
  22. 62
    0
      src/main/org/insa/graph/Point.java
  23. 85
    0
      src/main/org/insa/graph/RoadInformation.java
  24. 16
    0
      src/main/org/insa/graph/io/AbstractGraphReader.java
  25. 18
    0
      src/main/org/insa/graph/io/AbstractPathReader.java
  26. 21
    0
      src/main/org/insa/graph/io/BadFormatException.java
  27. 36
    0
      src/main/org/insa/graph/io/BadMagicNumberException.java
  28. 35
    0
      src/main/org/insa/graph/io/BadVersionException.java
  29. 176
    0
      src/main/org/insa/graph/io/BinaryGraphReader.java
  30. 70
    0
      src/main/org/insa/graph/io/BinaryPathReader.java
  31. 67
    0
      src/main/org/insa/graph/io/BinaryReader.java
  32. 36
    0
      src/main/org/insa/graph/io/MapMismatchException.java
  33. 252
    0
      src/main/org/insa/utility/BinaryHeap.java
  34. 68
    0
      src/test/org/insa/utility/BinaryHeapTest.java

+ 23
- 0
.classpath View File

@@ -0,0 +1,23 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<classpath>
3
+	<classpathentry kind="src" path="src/main"/>
4
+	<classpathentry kind="src" path="src/test"/>
5
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
6
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
7
+	<classpathentry kind="lib" path="libs/piccolo2d-core-3.0.jar">
8
+		<attributes>
9
+			<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/piccolo2d-core-3.0-javadoc.jar!/"/>
10
+		</attributes>
11
+	</classpathentry>
12
+	<classpathentry kind="lib" path="libs/piccolo2d-extras-3.0.jar">
13
+		<attributes>
14
+			<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/piccolo2d-extras-3.0-javadoc.jar!/"/>
15
+		</attributes>
16
+	</classpathentry>
17
+	<classpathentry kind="lib" path="libs/piccolo2d-swt-3.0.jar">
18
+		<attributes>
19
+			<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/piccolo2d-swt-3.0-javadoc.jar!/"/>
20
+		</attributes>
21
+	</classpathentry>
22
+	<classpathentry kind="output" path="bin"/>
23
+</classpath>

+ 17
- 0
.project View File

@@ -0,0 +1,17 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<projectDescription>
3
+	<name>be-graphes-base</name>
4
+	<comment></comment>
5
+	<projects>
6
+	</projects>
7
+	<buildSpec>
8
+		<buildCommand>
9
+			<name>org.eclipse.jdt.core.javabuilder</name>
10
+			<arguments>
11
+			</arguments>
12
+		</buildCommand>
13
+	</buildSpec>
14
+	<natures>
15
+		<nature>org.eclipse.jdt.core.javanature</nature>
16
+	</natures>
17
+</projectDescription>

+ 61
- 0
FORMAT View File

@@ -0,0 +1,61 @@
1
+===  Format des fichiers .map  ===
2
+
3
+ - Version du document (= version du format) : 4
4
+
5
+ - Sauf mention contraire, les entiers sont codés en big endian (compatible DataOutputStream).
6
+
7
+ [No d'octets] = signification
8
+
9
+ [0-3]   = Magic number 0xbacaff (doit se trouver au début du fichier)
10
+ [4-7]   = Version du format
11
+ [8-11]  = Identifiant de carte
12
+ [12-15] = Numéro de zone
13
+ [16-19] = Nombre de descripteurs dans ce fichier
14
+ [20-23] = Nombre de noeuds dans ce fichier
15
+
16
+ [24-..] = 
17
+    * Tous les noeuds, les uns après les autres, en commençant par le numéro 0. Voir le format d'un noeud.
18
+    * Puis un octet à 255.
19
+
20
+    * Puis, tous les descripteurs, les uns après les autres, en commençant par le numéro 0. 
21
+      Voir le format des descripteurs.
22
+    * Puis un octet à 254.
23
+
24
+    * Puis, toutes les routes sortantes (routes sortantes du premier noeud, puis celles du deuxième noeud, etc. )
25
+    * Puis un octet à 253.
26
+
27
+    (fin du fichier)
28
+
29
+
30
+===  Format des noeuds ===
31
+
32
+ [0-3]  = longitude sur 32 bits (à diviser par 1E6)
33
+ [4-7]  = latitude  sur 32 bits (à diviser par 1E6)
34
+ [8]    = Nombre de routes sortantes sur 8 bits
35
+
36
+
37
+===  Format des routes sortantes (taille variable car dépend du nombre de segments) ===
38
+
39
+ [0]      = Numéro de zone du noeud destination (8 bits)
40
+ [1-3]    = Numéro du noeud destination, dans la zone donnée (24 bits, big endian)
41
+ [4-6]    = Numéro de descripteur (24 bits)
42
+ [7-8]    = Longueur de l'arête (16 bits), en mètres, prenant en compte tous les segments.
43
+ [9-10]   = Nombre de segments (16 bits), éventuellement 0.
44
+ [11-...] = Segments
45
+
46
+
47
+=== Format des segments ===
48
+
49
+ [0-1] = Delta de longitude, sur 16 bits signés (à diviser par 2.0E5)
50
+ [2-3] = Delta de latitude, sur 16 bits signés (à diviser par 2.0E5)
51
+
52
+===  Format des descripteurs  (la taille est variable, car elle dépend du nom du chemin) ===
53
+
54
+ [0]   = Un caractère indiquant le type de chemin (voir dans Descripteur.java)
55
+ [1]
56
+  .bit 7 = sens unique
57
+  .bits 0-6 = vitesse max en km/h à multiplier par 5.
58
+
59
+ [2-]  = Nom du chemin, de type String-UTF8 (les deux premiers octets donnent la longueur de la chaîne)
60
+
61
+

+ 21
- 0
FORMAT_PATH View File

@@ -0,0 +1,21 @@
1
+===  Format des fichiers .path  ===
2
+
3
+ - Version du document (= version du format) : 1
4
+
5
+ - Sauf mention contraire, les entiers sont codés en big endian (compatible DataOutputStream).
6
+
7
+ [No d'octets] = signification
8
+
9
+ [0-3]   = Magic number 0xdecafe (doit se trouver au début du fichier)
10
+ [4-7]   = Version du format
11
+ [8-11]  = Identifiant de carte
12
+ [12-15] = Nombre de noeuds dans le chemin
13
+ [16-19] = Identifiant du premier noeud (8 bits zone + 24 bits numéro noeud)
14
+ [20-23] = Identifiant du dernier noeud (8 bits zone + 24 bits numéro noeud)
15
+
16
+ [24-27] = Identifiant du premier noeud (encore)
17
+ [28-31] = Identifiant du deuxième noeud
18
+ [32-35] = Identifiant du troisième noeud
19
+ etc.
20
+ [derniers octets] = Identifiant du dernier noeud
21
+

+ 59
- 0
src/main/org/insa/algo/AbstractAlgorithm.java View File

@@ -0,0 +1,59 @@
1
+package org.insa.algo ;
2
+
3
+import java.io.* ;
4
+
5
+public abstract class AbstractAlgorithm {
6
+
7
+    protected PrintStream output;
8
+    protected AbstractInstance instance;
9
+    protected AbstractSolution solution;
10
+    
11
+    /**
12
+     * 
13
+     * @param instance
14
+     * @param logOutput
15
+     */
16
+    protected AbstractAlgorithm(AbstractInstance instance, PrintStream logOutput) {
17
+    		this.instance = instance;
18
+    		this.output = logOutput;	
19
+    		this.solution = null;
20
+    }
21
+    
22
+    /**
23
+     * Update the current solution.
24
+     * 
25
+     * @param solution New solution, or null to unset the current solution.
26
+     * 
27
+     */
28
+    protected void updateLastSolution(AbstractSolution solution) {
29
+    		this.solution = solution;
30
+    }
31
+    
32
+    /**
33
+     * @return Instance corresponding to this algorithm.
34
+     */
35
+    public AbstractInstance getInstance() { return instance; }
36
+    
37
+    /**
38
+     * @return Last solution, or null if no solution was stored.
39
+     */
40
+    public AbstractSolution getLastSolution() { return solution; }
41
+        
42
+    /**
43
+     * Run the algorithm and update the current solution.
44
+     * 
45
+     * @return true if a feasible solution was found (even non-optimal).
46
+     */
47
+    public boolean run() {
48
+    		this.solution = this.doRun();
49
+    		return this.solution != null && this.solution.isFeasible();
50
+    }
51
+    
52
+    /**
53
+     * Abstract method that should be implemented by child class.
54
+     * 
55
+     * @return A solution, if one was found, or null.
56
+     */
57
+    protected abstract AbstractSolution doRun();
58
+
59
+}

+ 20
- 0
src/main/org/insa/algo/AbstractInstance.java View File

@@ -0,0 +1,20 @@
1
+package org.insa.algo;
2
+
3
+import org.insa.graph.Graph;
4
+
5
+public abstract class AbstractInstance {
6
+
7
+	protected Graph graph;
8
+	
9
+	/**
10
+	 * Create a new abstract instance with the given graph.
11
+	 * 
12
+	 * @param graph
13
+	 */
14
+	protected AbstractInstance(Graph graph) {
15
+		this.graph = graph;
16
+	}
17
+	
18
+	public Graph getGraph() { return graph; }
19
+	
20
+}

+ 67
- 0
src/main/org/insa/algo/AbstractSolution.java View File

@@ -0,0 +1,67 @@
1
+package org.insa.algo;
2
+
3
+import java.time.Duration;
4
+
5
+public abstract class AbstractSolution {
6
+
7
+	/**
8
+	 * Possible status for a solution.
9
+	 *
10
+	 */
11
+	public enum Status {
12
+		UNKNOWN,
13
+		INFEASIBLE,
14
+		FEASIBLE,
15
+		OPTIMAL,
16
+	};
17
+	
18
+	// Status of the solution.
19
+	Status status;
20
+	
21
+	// Solving time for the solution
22
+	Duration solvingTime;
23
+	
24
+	// Original instance of the solution
25
+	AbstractInstance instance;
26
+
27
+	/**
28
+	 * Create a new abstract solution with unknown status.
29
+	 * 
30
+	 * @param instance
31
+	 */
32
+	protected AbstractSolution(AbstractInstance instance) {
33
+		this.instance = instance;
34
+		this.solvingTime = Duration.ZERO;
35
+		this.status = Status.UNKNOWN;
36
+	}
37
+	
38
+	protected AbstractSolution(AbstractInstance instance, 
39
+							  Duration solvingTime, Status status) {
40
+		this.instance = instance;
41
+		this.solvingTime = solvingTime;
42
+		this.status = status;
43
+	}
44
+	
45
+	/**
46
+	 * @return Original instance for this solution.
47
+	 */
48
+	public AbstractInstance getInstance() { return instance; }
49
+	
50
+	/**
51
+	 * @return Status of this solution.
52
+	 */
53
+	public Status getStatus() { return status; }
54
+	
55
+	/**
56
+	 * @return Solving time of this solution.
57
+	 */
58
+	public Duration getSolvingTime() { return solvingTime; }
59
+	
60
+	/**
61
+	 * @return true if the solution is feasible or optimal.
62
+	 */
63
+	public boolean isFeasible() {
64
+		return status == Status.FEASIBLE || status == Status.OPTIMAL;
65
+	}
66
+	
67
+}

+ 30
- 0
src/main/org/insa/algo/connectivity/ConnectivityAlgorithm.java View File

@@ -0,0 +1,30 @@
1
+package org.insa.algo.connectivity ;
2
+
3
+import java.io.* ;
4
+
5
+import org.insa.algo.AbstractAlgorithm;
6
+import org.insa.algo.AbstractSolution;
7
+
8
+public class ConnectivityAlgorithm extends AbstractAlgorithm {
9
+
10
+	/**
11
+	 * 
12
+	 * @param instance
13
+	 * @param logOutput
14
+	 */
15
+	public ConnectivityAlgorithm(ConnectivityInstance instance, PrintStream logOutput) {
16
+		super(instance, logOutput);
17
+	}
18
+
19
+	/**
20
+	 * {@inheritDoc}
21
+	 */
22
+	@Override
23
+	protected AbstractSolution doRun() {
24
+		ConnectivityInstance instance = (ConnectivityInstance)getInstance();
25
+		ConnectivitySolution solution = null;
26
+		// TODO: 
27
+		return solution;
28
+	}
29
+
30
+}

+ 16
- 0
src/main/org/insa/algo/connectivity/ConnectivityInstance.java View File

@@ -0,0 +1,16 @@
1
+package org.insa.algo.connectivity;
2
+
3
+import org.insa.algo.AbstractInstance;
4
+import org.insa.graph.Graph;
5
+
6
+public class ConnectivityInstance extends AbstractInstance {
7
+
8
+	/**
9
+	 * 
10
+	 * @param graph
11
+	 */
12
+	public ConnectivityInstance(Graph graph) {
13
+		super(graph);
14
+	}
15
+
16
+}

+ 20
- 0
src/main/org/insa/algo/connectivity/ConnectivitySolution.java View File

@@ -0,0 +1,20 @@
1
+package org.insa.algo.connectivity;
2
+
3
+import java.time.Duration;
4
+
5
+import org.insa.algo.AbstractSolution;
6
+
7
+public class ConnectivitySolution extends AbstractSolution {
8
+
9
+	protected ConnectivitySolution(ConnectivityInstance instance) {
10
+		super(instance);
11
+	}
12
+	
13
+	protected ConnectivitySolution(ConnectivityInstance instance, 
14
+					   Duration solvingTime, Status status) {
15
+		super(instance, solvingTime, status);
16
+		
17
+		// TODO:
18
+	}
19
+
20
+}

+ 58
- 0
src/main/org/insa/base/Couleur.java View File

@@ -0,0 +1,58 @@
1
+package org.insa.base ;
2
+
3
+/**
4
+ *   Choix des couleurs pour l'affichage.
5
+ */
6
+
7
+import java.awt.* ;
8
+
9
+import org.insa.drawing.Drawing;
10
+
11
+public class Couleur {
12
+
13
+    static final Color autoroute = Color.red ;
14
+    static final Color bigroute = new Color(255, 105, 0) ;
15
+    static final Color tiroute = new Color(255, 234, 0) ;
16
+    static final Color cote = Color.blue ;
17
+
18
+    public static void set(Drawing d, char type) {
19
+
20
+	// Voir le fichier Descripteur.java pour le type des routes.
21
+	switch (type) {
22
+	case 'a':
23
+	    d.setWidth(2) ;
24
+	    d.setColor(Color.red) ;
25
+	    break ;
26
+
27
+	case 'b':
28
+	case 'c':
29
+	case 'd':
30
+	case 'e':
31
+	case 'f':
32
+	case 'g':
33
+	    d.setWidth(1) ;
34
+	    d.setColor(bigroute) ;
35
+	    break ;
36
+	case 'h':
37
+	case 'i':
38
+	case 'j':
39
+	case 'k':
40
+	case 'l':
41
+	case 'm':
42
+	case 'n':
43
+	case 'o':
44
+	    d.setWidth(1) ;
45
+	    d.setColor(tiroute) ;
46
+	    break ;
47
+	    
48
+	case 'z':
49
+	    d.setWidth(4) ;
50
+	    d.setColor(cote) ;
51
+	    break ;
52
+	    
53
+	default:
54
+	    d.setWidth(1) ;
55
+	    d.setColor(Color.black) ;
56
+	}
57
+    }
58
+}

+ 115
- 0
src/main/org/insa/base/Openfile.java View File

@@ -0,0 +1,115 @@
1
+package org.insa.base ;
2
+
3
+import java.io.* ;
4
+import java.util.zip.* ;
5
+
6
+/* Ne lisez pas cette classe. Lancez javadoc et lisez la doc generee plutot. */
7
+
8
+/**
9
+ *  La classe Openfile permet de lire les fichiers contenant les cartes :
10
+ *   <ul>
11
+ *    <li> en trouvant le bon dossier parmi les dossiers pre-configures </li>
12
+ *    <li> en dezippant automatiquement si besoin </li>
13
+ *   </ul>
14
+ *
15
+ */
16
+public class Openfile {
17
+
18
+    // Le programme examine chaque dossier dans l'ordre jusqu'a trouver celui qui contient la carte voulue
19
+    private static final String[] datadirs = 
20
+    {  	// NE MODIFIEZ PAS CELUI-CI
21
+	// car il permet de tester en etant a l'INSA.
22
+	"/home/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps",
23
+
24
+	// Celui-ci pour les chemins
25
+	"/home/commetud/3eme Annee MIC/Graphes-et-Algorithmes/",
26
+
27
+        // On cherche aussi dans le sous-repertoire local "Maps" (s'il existe)
28
+	"Maps", 
29
+
30
+	// et dans le repertoire courant (Unix uniquement)
31
+	".",
32
+
33
+	// Si vous utilisez votre propre dossier pour les donnees, mettez-le ici.
34
+	"/home/votrepropredossier/a/vous",
35
+    } ;
36
+
37
+    // Extension testees. Garder l'extension vide dans la liste.
38
+    private static final String[] extensions = { ".map", ".gz", ".map.gz", ".path", ".path.gz", "" } ;
39
+
40
+    /** 
41
+     * Ouvre le fichier indiqué et renvoie un DataInputStream sur ce fichier.
42
+     * Le fichier ne sera pas ferme avant la fin de l'application.
43
+     * @param filename  Nom du fichier a ouvrir (sans chemin)
44
+     */
45
+    public static DataInputStream open (String filename) {
46
+
47
+	if (!filename.equals (new File(filename).getName())) {
48
+	    System.out.println("Le nom du fichier ne doit pas contenir un chemin (ni absolu, ni relatif).") ;
49
+	    System.out.println("Il doit juste contenir le nom du fichier contenant la carte.") ;
50
+	    System.out.println("Si vous voulez utiliser un dossier specifique, configurez base/Openfile.java") ;
51
+	    System.exit(1) ;
52
+	}
53
+
54
+	boolean trouve = false ;
55
+	InputStream fileinput = null ;
56
+	String fname = null ;
57
+	String fullpath = null ;
58
+
59
+	for (int extn = 0 ; !trouve && extn < extensions.length ; extn++) {
60
+	    fname = filename + extensions[extn] ;
61
+	    for (int index = 0 ; !trouve && index < datadirs.length ; index++) {
62
+		fullpath = datadirs[index] + File.separator + fname ;
63
+		File file = new File(fullpath) ;
64
+		if (file.canRead()) {
65
+		    trouve = true ;
66
+		    try {
67
+			fileinput = new FileInputStream(file) ;
68
+		    } catch (IOException e) {
69
+			e.printStackTrace() ;
70
+			System.exit(1) ;
71
+		    }
72
+		}
73
+	    }
74
+	}
75
+
76
+	if (!trouve) {
77
+	    // Pas trouve
78
+	    System.out.println("Impossible de trouver le fichier " + filename) ;
79
+	    System.out.println("  pourtant j'ai cherche dans les dossiers : ") ;
80
+	    int existepas = 0 ;
81
+	    for (int i = 0 ; i < datadirs.length ; i++) {
82
+		System.out.println("     - " + datadirs[i]) ;
83
+		if (!new File(datadirs[i]).isDirectory()) {
84
+		    switch (existepas) {
85
+		    case 0:  System.out.println("       (Ce dossier n'existe pas d'ailleurs)") ; break;
86
+		    case 1:  System.out.println("       (Ce dossier n'existe pas non plus)") ; break;
87
+		    default: System.out.println("       (Celui-la non plus)") ; break;
88
+		    }
89
+		    existepas++ ;
90
+		}
91
+		System.out.println() ;
92
+	    }
93
+	    System.exit(1) ;
94
+	}
95
+
96
+	System.out.println("Fichier utilisee : " + fullpath) ;
97
+	System.out.println() ;
98
+
99
+	if (fname.endsWith(".gz")) {
100
+	    // The file is gzipped.
101
+	    try {
102
+		fileinput = new GZIPInputStream(fileinput) ;
103
+	    } catch (IOException e) {
104
+		e.printStackTrace() ;
105
+		System.exit(1) ;		
106
+	    }
107
+	}
108
+	else {
109
+	    fileinput = new BufferedInputStream(fileinput) ;
110
+	}
111
+
112
+	return new DataInputStream(fileinput) ;
113
+    }
114
+
115
+}

+ 86
- 0
src/main/org/insa/base/Readarg.java View File

@@ -0,0 +1,86 @@
1
+package org.insa.base ;
2
+
3
+import java.io.* ;
4
+
5
+/* Ne lisez pas cette classe. Lancez javadoc et lisez la doc generee plutot. */
6
+
7
+/**
8
+ *  La classe Readarg facilite la lecture de donnees depuis le clavier ou depuis la ligne de commande.
9
+ *
10
+ */
11
+public class Readarg {
12
+
13
+    private final String[] args ;
14
+    private int next ;
15
+
16
+    // Le Java est le langage prefere des Shadoks.
17
+    private final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
18
+
19
+    public Readarg(String[] argz) {
20
+	this.args = argz ;
21
+	this.next = 0 ;
22
+    }
23
+
24
+    /** 
25
+     * Obtient une chaine, ou bien depuis la ligne de commande, ou depuis l'entree standard.
26
+     * @param msg  Message affiche avant de demander la chaine
27
+     */
28
+    public String lireString (String msg) {
29
+	
30
+	String resultat = "" ;
31
+
32
+	System.out.print(msg) ;
33
+	
34
+	if (this.next >= this.args.length) {
35
+	    try {
36
+		resultat = br.readLine () ;
37
+	    } catch (Exception e) {
38
+		System.err.println ("Erreur de lecture de l'entree standard.") ;
39
+		System.exit(1) ;
40
+	    }
41
+	}
42
+	else {
43
+	    resultat = this.args[this.next] ;
44
+	    this.next++ ;
45
+	    System.out.println (resultat) ;
46
+	}
47
+
48
+	return resultat ;
49
+    }
50
+
51
+
52
+    /** 
53
+     * Obtient un entier, ou bien depuis la ligne de commande, ou depuis l'entree standard.
54
+     * @param msg  Message affiche avant de demander l'entier
55
+     */
56
+    public int lireInt (String msg) {
57
+	String lu = lireString (msg) ;
58
+	int result = 0 ;
59
+	try {
60
+	    result = Integer.parseInt(lu) ;
61
+	}
62
+	catch (Exception e) {
63
+	    System.err.println ("Un entier est attendu mais je lis " + lu) ;
64
+	    System.exit(1) ;
65
+	}
66
+	return result ;
67
+    }
68
+
69
+    /** 
70
+     * Obtient un float, ou bien depuis la ligne de commande, ou depuis l'entree standard.
71
+     * @param msg  Message affiche avant de demander le float.
72
+     */
73
+    public float lireFloat (String msg) {
74
+	String lu = lireString (msg) ;
75
+	float result = 0 ;
76
+	try {
77
+	    result = Float.parseFloat(lu) ;
78
+	}
79
+	catch (Exception e) {
80
+	    System.err.println ("Un reel est attendu mais je lis " + lu) ;
81
+	    System.exit(1) ;
82
+	}
83
+	
84
+	return result ;
85
+    }
86
+}

+ 57
- 0
src/main/org/insa/base/Utils.java View File

@@ -0,0 +1,57 @@
1
+package org.insa.base ;
2
+
3
+import java.io.* ;
4
+
5
+import org.insa.drawing.Drawing;
6
+
7
+/**
8
+ *   Fonctions accessoires dont vous n'avez pas a vous servir directement.
9
+ */
10
+public class Utils {
11
+
12
+
13
+	// Calibrer la sortie graphique en fonction de la carte
14
+	// Vous pouvez modifier les coordonnees pour ameliorer le rendu.
15
+	public static void calibrer(String nomCarte, Drawing dessin) {
16
+
17
+		if (nomCarte.startsWith("insa")) {
18
+			// L'INSA
19
+			dessin.setBB (1.462, 1.473, 43.567, 43.5744) ;
20
+		}
21
+		else if (nomCarte.startsWith("paris")) {
22
+			// Ile de la Cité, Paris
23
+			dessin.setBB (2.329, 2.372, 48.839, 48.867) ;
24
+		}
25
+		else if (nomCarte.startsWith("mayot")) {
26
+			// Mayotte
27
+			dessin.setBB (44.5, 45.5, -13.25, -12.25) ;
28
+		}
29
+		else if (nomCarte.startsWith("reuni")) {
30
+			// La Réunion
31
+			dessin.setBB (55.0, 56.0, -21.5, -20.5) ;
32
+		}
33
+		else if (nomCarte.startsWith("midip")) {
34
+			dessin.setBB (-0.6, 3.8, 42.2, 45.3) ;
35
+		}
36
+		else if (nomCarte.startsWith("franc")) {
37
+			dessin.setBB (-5.2, 10.0, 41.0, 51.5) ;
38
+		}
39
+		else if (nomCarte.startsWith("pfranc")) {
40
+			dessin.setBB (-5.2, 10.0, 41.0, 51.5) ;
41
+		}
42
+		else if (nomCarte.startsWith("morbihan")) {
43
+			dessin.setBB (-3.53, -2.452, 47.27, 47.665) ;
44
+		}
45
+		else if (nomCarte.startsWith("newzealand")) {
46
+			dessin.setBB (153.415, 179.912, -47.931, -33.980) ;
47
+		}
48
+		else if (nomCarte.startsWith("fract") || nomCarte.startsWith("carr")) {
49
+			dessin.setBB (-0.05, 1.05, -0.05, 1.05) ;
50
+		}
51
+		else {
52
+			dessin.setBB (-20.0, 50.0, 20.0, 70.0) ;
53
+		}
54
+	}
55
+
56
+
57
+}

+ 83
- 0
src/main/org/insa/drawing/Drawing.java View File

@@ -0,0 +1,83 @@
1
+package org.insa.drawing ;
2
+
3
+/**
4
+ *   Classe abstraite pour dessiner a l'ecran.
5
+ *   Deux implementations : une sous-classe DessinVisible qui dessine vraiment a l'ecran
6
+ *   et une sous-classe DessinInvisible qui ne dessine rien (pour ne pas ralentir les tests avec l'affichage).
7
+ */
8
+
9
+import java.awt.* ;
10
+
11
+public interface Drawing {
12
+	
13
+	/**
14
+	 * Enable auto-repaint mode - When this mode is enable, call to 
15
+	 * drawing function will automatically repaint the drawing, which
16
+	 * may be very slow in some case.
17
+	 * 
18
+	 * @param autoRepaint Use true to enable auto-repaint, false to disable.
19
+	 * 
20
+	 */
21
+	public void setAutoRepaint(boolean autoRepaint);
22
+	
23
+	/**
24
+	 * Repaint the drawing.
25
+	 * 
26
+	 */
27
+	public void repaint();
28
+	
29
+    /**
30
+     * Set the pencil width.
31
+     * 
32
+     * @param width Width for the pencil.
33
+     * 
34
+     */
35
+    public void setWidth(int width);
36
+    
37
+    /**
38
+     * Set the pencil color.
39
+     * 
40
+     * param color Color for the pencil.
41
+     * 
42
+     */
43
+    public void setColor(Color col);
44
+
45
+    /**
46
+     *  Indique les bornes de la fenetre graphique.
47
+     *  Le calcul des coordonnees en pixel se fera automatiquement
48
+     *  a l'appel des methodes drawLine et autres.
49
+     *
50
+     *  @param long1 longitude du bord gauche
51
+     *  @param long2 longitude du bord droit
52
+     *  @param lat1 latitude du bord bas
53
+     *  @param lat2 latitude du bord haut
54
+     *  
55
+     */
56
+    public void setBB(double long1, double long2, double lat1, double lat2);
57
+
58
+    /**
59
+     *  Trace un segment.
60
+     *  @param long1 longitude du premier point
61
+     *  @param lat1 latitude du premier point
62
+     *  @param long2 longitude du second point
63
+     *  @param lat2 latitude du second point
64
+     */
65
+    public void drawLine(float long1, float lat1, float long2, float lat2);
66
+
67
+    /**
68
+     *  Trace un point.
69
+     *  @param lon longitude du point
70
+     *  @param lat latitude du point
71
+     *  @param width grosseur du point
72
+     */
73
+    public void drawPoint(float lon, float lat, int width);
74
+
75
+    /**
76
+     *  Ecrit du texte a la position indiquee.
77
+     *  @param lon longitude du point ou positionner le texte.
78
+     *  @param lat latitude du point ou positionner le texte.
79
+     *  @param txt le texte a ecrire.
80
+     */
81
+    public void putText(float lon, float lat, String txt);
82
+
83
+}

+ 38
- 0
src/main/org/insa/drawing/DrawingInvisible.java View File

@@ -0,0 +1,38 @@
1
+package org.insa.drawing;
2
+
3
+import java.awt.Color;
4
+
5
+/**
6
+ *   Cette implementation de la classe Dessin ne produit pas d'affichage,
7
+ *   ce qui accelere l'execution (utile pour ne pas ralentir les tests).
8
+ */
9
+
10
+public class DrawingInvisible implements Drawing {
11
+    
12
+    public DrawingInvisible () { }
13
+
14
+	@Override
15
+	public void setWidth(int width) { }
16
+
17
+	@Override
18
+	public void setColor(Color col) { }
19
+
20
+	@Override
21
+	public void setBB(double long1, double long2, double lat1, double lat2) { }
22
+
23
+	@Override
24
+	public void drawLine(float long1, float lat1, float long2, float lat2) { }
25
+
26
+	@Override
27
+	public void drawPoint(float lon, float lat, int width) { }
28
+
29
+	@Override
30
+	public void putText(float lon, float lat, String txt) { }
31
+
32
+	@Override
33
+	public void setAutoRepaint(boolean autoRepaint) {	 }
34
+
35
+	@Override
36
+	public void repaint() { }
37
+    
38
+}

+ 184
- 0
src/main/org/insa/drawing/DrawingVisible.java View File

@@ -0,0 +1,184 @@
1
+package org.insa.drawing;
2
+
3
+import java.awt.*;
4
+import java.awt.image.*;
5
+
6
+/**
7
+ *   Cette implementation de la classe Dessin produit vraiment un affichage
8
+ *   (au contraire de la classe DessinInvisible).
9
+ */
10
+
11
+public class DrawingVisible extends Canvas implements Drawing {
12
+
13
+	/**
14
+	 * 
15
+	 */
16
+	private static final long serialVersionUID = 96779785877771827L;
17
+
18
+	private final Graphics2D gr;
19
+
20
+	private float long1;
21
+	private float long2;
22
+	private float lat1;
23
+	private float lat2;
24
+	private final float width;
25
+	private final float height;
26
+
27
+	private boolean bb_is_set ;
28
+	
29
+	private Image image;
30
+	private ZoomAndPanListener zoomAndPanListener;
31
+	
32
+	public boolean autoRepaint = true;
33
+
34
+	/**
35
+	 *  Cree et affiche une nouvelle fenetre de dessin.
36
+	 */
37
+	public DrawingVisible (int largeur, int hauteur) {
38
+		super();
39
+		
40
+		this.zoomAndPanListener = new ZoomAndPanListener(this, 0, ZoomAndPanListener.DEFAULT_MAX_ZOOM_LEVEL, 1.2);
41
+		this.addMouseListener(zoomAndPanListener);
42
+		this.addMouseMotionListener(zoomAndPanListener);
43
+		this.addMouseWheelListener(zoomAndPanListener);
44
+		
45
+		BufferedImage img = new BufferedImage (largeur, hauteur, BufferedImage.TYPE_3BYTE_BGR);
46
+		
47
+		this.image = img;
48
+		this.gr = img.createGraphics();
49
+		
50
+		this.zoomAndPanListener.setCoordTransform(this.gr.getTransform());
51
+		
52
+		this.bb_is_set = false;
53
+
54
+		this.width = largeur;
55
+		this.height = hauteur;
56
+
57
+		this.long1 = (float)0.0;
58
+		this.long2 = (float)largeur;
59
+		this.lat1  = (float)0.0;
60
+		this.lat2  = (float)hauteur;
61
+
62
+		this.setColor(Color.white);
63
+		gr.fillRect(0,0, largeur, hauteur);
64
+		this.repaint();
65
+
66
+	}
67
+
68
+	@Override
69
+	public void paint(Graphics g1) {
70
+		Graphics2D g = (Graphics2D)g1;
71
+		g.setTransform(zoomAndPanListener.getCoordTransform());
72
+		g.drawImage(image, 0, 0, this);
73
+	}
74
+	
75
+
76
+	@Override
77
+	public Dimension getPreferredSize() {
78
+		Dimension size = new Dimension(0, 0);
79
+
80
+		if (image != null) {
81
+			int w = image.getWidth(null);
82
+			int h = image.getHeight(null);
83
+			size = new Dimension(w > 0 ? w : 0, h > 0 ? h : 0);
84
+		}
85
+		return size;
86
+	}
87
+	
88
+	@Override
89
+	public void setAutoRepaint(boolean autoRepaint) {
90
+		this.autoRepaint = autoRepaint;
91
+	}
92
+	
93
+	protected void doAutoPaint() {
94
+		if (autoRepaint) {
95
+			this.repaint();
96
+		}
97
+	}
98
+	
99
+	public void setWidth (int width) {
100
+		this.gr.setStroke(new BasicStroke(width));
101
+	}
102
+
103
+	public void setColor (Color col) {
104
+		this.gr.setColor (col);
105
+	}
106
+
107
+	public void setBB (double long1, double long2, double lat1, double lat2) {	
108
+
109
+		if (long1 > long2 || lat1 > lat2) {
110
+			throw new Error("DessinVisible.setBB : mauvaises coordonnees.");
111
+		}
112
+
113
+		/* Adapte la BB en fonction de la taille du dessin, pour préserver le ratio largeur/hauteur */
114
+		double deltalong = long2 - long1 ;
115
+		double deltalat = lat2 - lat1 ;
116
+		double ratiobb = deltalong / deltalat ;
117
+		double ratiogr = width / height ;
118
+
119
+		/* On ne peut qu'agrandir la BB, pour ne rien perdre. 
120
+		 * Si le ratiobb est trop petit, il faut agrandir deltalong 
121
+		 * s'il est trop grand, il faut agrandir deltalat. */
122
+		if (ratiobb < ratiogr) {
123
+			/* De combien faut-il agrandir ? */
124
+			double delta = (ratiogr - ratiobb) * deltalat ;
125
+
126
+			this.long1 = (float)(long1 - 0.5*delta) ;
127
+			this.long2 = (float)(long2 + 0.5*delta) ;
128
+			this.lat1 = (float)lat1 ;
129
+			this.lat2 = (float)lat2 ;
130
+		}
131
+		else {
132
+			double delta = (deltalong / ratiogr) - deltalat ;
133
+
134
+			this.long1 = (float)long1 ;
135
+			this.long2 = (float)long2 ;
136
+			this.lat1 = (float)(lat1 - 0.5*delta);
137
+			this.lat2 = (float)(lat2 + 0.5*delta);
138
+		}
139
+
140
+		this.bb_is_set = true ;
141
+	}
142
+
143
+	private int projx(float lon) {
144
+		return (int)(width * (lon - this.long1) / (this.long2 - this.long1)) ;
145
+	}
146
+
147
+	private int projy(float lat) {
148
+		return (int)(height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1))) ;
149
+	}
150
+
151
+	private void checkBB() {
152
+		if (!this.bb_is_set) {
153
+			throw new Error("Classe DessinVisible : vous devez invoquer la methode setBB avant de dessiner.") ;
154
+		}
155
+	}
156
+
157
+	public void drawLine (float long1, float lat1, float long2, float lat2) {
158
+		this.checkBB() ;
159
+		int x1 = this.projx(long1) ;
160
+		int x2 = this.projx(long2) ;
161
+		int y1 = this.projy(lat1) ;
162
+		int y2 = this.projy(lat2) ;
163
+
164
+		gr.drawLine(x1, y1, x2, y2) ;
165
+		this.doAutoPaint();
166
+	}
167
+
168
+	public void drawPoint (float lon, float lat, int width) {
169
+		this.checkBB() ;
170
+		int x = this.projx(lon) - width / 2 ;
171
+		int y = this.projy(lat) - width / 2 ;
172
+		gr.fillOval (x, y, width, width) ;
173
+		this.doAutoPaint();
174
+	}
175
+
176
+	public void putText (float lon, float lat, String txt) {
177
+		this.checkBB() ;
178
+		int x = this.projx(lon) ;
179
+		int y = this.projy(lat) ;
180
+		gr.drawString (txt, x, y) ;
181
+		this.doAutoPaint();	
182
+	}
183
+
184
+}

+ 135
- 0
src/main/org/insa/drawing/ZoomAndPanListener.java View File

@@ -0,0 +1,135 @@
1
+package org.insa.drawing;
2
+import java.awt.*;
3
+import java.awt.event.*;
4
+import java.awt.geom.AffineTransform;
5
+import java.awt.geom.NoninvertibleTransformException;
6
+import java.awt.geom.Point2D;
7
+
8
+public class ZoomAndPanListener implements MouseListener, MouseMotionListener, MouseWheelListener {
9
+	public static final int DEFAULT_MIN_ZOOM_LEVEL = -20;
10
+	public static final int DEFAULT_MAX_ZOOM_LEVEL = 10;
11
+	public static final double DEFAULT_ZOOM_MULTIPLICATION_FACTOR = 1.2;
12
+
13
+	private Component targetComponent;
14
+
15
+	private int zoomLevel = 0;
16
+	private int minZoomLevel = DEFAULT_MIN_ZOOM_LEVEL;
17
+	private int maxZoomLevel = DEFAULT_MAX_ZOOM_LEVEL;
18
+	private double zoomMultiplicationFactor = DEFAULT_ZOOM_MULTIPLICATION_FACTOR;
19
+
20
+	private Point dragStartScreen;
21
+	private Point dragEndScreen;
22
+	private AffineTransform coordTransform = new AffineTransform();
23
+
24
+	public ZoomAndPanListener(Component targetComponent) {
25
+		this.targetComponent = targetComponent;
26
+	}
27
+
28
+	public ZoomAndPanListener(Component targetComponent, int minZoomLevel, int maxZoomLevel, double zoomMultiplicationFactor) {
29
+		this.targetComponent = targetComponent;
30
+		this.minZoomLevel = minZoomLevel;
31
+		this.maxZoomLevel = maxZoomLevel;
32
+		this.zoomMultiplicationFactor = zoomMultiplicationFactor;
33
+	}
34
+
35
+
36
+	public void mouseClicked(MouseEvent e) {
37
+	}
38
+
39
+	public void mousePressed(MouseEvent e) {
40
+		dragStartScreen = e.getPoint();
41
+		dragEndScreen = null;
42
+	}
43
+
44
+	public void mouseReleased(MouseEvent e) {
45
+//        moveCamera(e);
46
+	}
47
+
48
+	public void mouseEntered(MouseEvent e) {
49
+	}
50
+
51
+	public void mouseExited(MouseEvent e) {
52
+	}
53
+
54
+	public void mouseMoved(MouseEvent e) {
55
+	}
56
+
57
+	public void mouseDragged(MouseEvent e) {
58
+		moveCamera(e);
59
+	}
60
+
61
+	public void mouseWheelMoved(MouseWheelEvent e) {
62
+		zoomCamera(e);
63
+	}
64
+
65
+	private void moveCamera(MouseEvent e) {
66
+		try {
67
+			dragEndScreen = e.getPoint();
68
+			Point2D.Float dragStart = transformPoint(dragStartScreen);
69
+			Point2D.Float dragEnd = transformPoint(dragEndScreen);
70
+			double dx = dragEnd.getX() - dragStart.getX();
71
+			double dy = dragEnd.getY() - dragStart.getY();
72
+			coordTransform.translate(dx, dy);
73
+			dragStartScreen = dragEndScreen;
74
+			dragEndScreen = null;
75
+			targetComponent.repaint();
76
+		} catch (NoninvertibleTransformException ex) {
77
+			ex.printStackTrace();
78
+		}
79
+	}
80
+
81
+	private void zoomCamera(MouseWheelEvent e) {
82
+		try {
83
+			int wheelRotation = e.getWheelRotation();
84
+			Point p = e.getPoint();
85
+			if (wheelRotation > 0) {
86
+				if (zoomLevel < maxZoomLevel) {
87
+					zoomLevel++;
88
+					Point2D p1 = transformPoint(p);
89
+					coordTransform.scale(1 / zoomMultiplicationFactor, 1 / zoomMultiplicationFactor);
90
+					Point2D p2 = transformPoint(p);
91
+					coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
92
+					targetComponent.repaint();
93
+				}
94
+			} else {
95
+				if (zoomLevel > minZoomLevel) {
96
+					zoomLevel--;
97
+					Point2D p1 = transformPoint(p);
98
+					coordTransform.scale(zoomMultiplicationFactor, zoomMultiplicationFactor);
99
+					Point2D p2 = transformPoint(p);
100
+					coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
101
+					targetComponent.repaint();
102
+				}
103
+			}
104
+		} catch (NoninvertibleTransformException ex) {
105
+			ex.printStackTrace();
106
+		}
107
+	}
108
+
109
+	private Point2D.Float transformPoint(Point p1) throws NoninvertibleTransformException {
110
+
111
+		AffineTransform inverse = coordTransform.createInverse();
112
+
113
+		Point2D.Float p2 = new Point2D.Float();
114
+		inverse.transform(p1, p2);
115
+		return p2;
116
+	}
117
+
118
+	public int getZoomLevel() {
119
+		return zoomLevel;
120
+	}
121
+
122
+
123
+	public void setZoomLevel(int zoomLevel) {
124
+		this.zoomLevel = zoomLevel;
125
+	}
126
+
127
+
128
+	public AffineTransform getCoordTransform() {
129
+		return coordTransform;
130
+	}
131
+
132
+	public void setCoordTransform(AffineTransform coordTransform) {
133
+		this.coordTransform = coordTransform;
134
+	}
135
+}

+ 81
- 0
src/main/org/insa/graph/Arc.java View File

@@ -0,0 +1,81 @@
1
+package org.insa.graph;
2
+
3
+import java.util.ArrayList;
4
+
5
+public class Arc {
6
+	
7
+	// Destination node.
8
+	private Node dest;
9
+
10
+	// Length of the road (in meters).
11
+	private int length;
12
+	
13
+	// Road information.
14
+	RoadInformation info;
15
+	
16
+	// Segments.
17
+	ArrayList<Point> points;
18
+	
19
+	/**
20
+	 * @param dest
21
+	 * @param length
22
+	 * @param roadInformation
23
+	 * @param points
24
+	 */
25
+	public Arc(Node dest, int length, RoadInformation roadInformation) {
26
+		this.dest = dest;
27
+		this.length = length;
28
+		this.info = roadInformation;
29
+		this.points = new ArrayList<Point>();
30
+	}
31
+
32
+	/**
33
+	 * @param dest
34
+	 * @param length
35
+	 * @param roadInformation
36
+	 * @param points
37
+	 */
38
+	public Arc(Node dest, int length, RoadInformation roadInformation, ArrayList<Point> points) {
39
+		this.dest = dest;
40
+		this.length = length;
41
+		this.info = roadInformation;
42
+		this.points = points;
43
+	}
44
+	
45
+	/**
46
+	 * @return Destination node of this arc.
47
+	 */
48
+	public Node getDest() {
49
+		return dest;
50
+	}
51
+
52
+	/**
53
+	 * @return Length of this arc, in meters.
54
+	 */
55
+	public int getLength() {
56
+		return length;
57
+	}
58
+	
59
+	/**
60
+	 * @return Minimum time required to travel this arc, in seconds.
61
+	 */
62
+	public float getMinimumTravelTime() {
63
+		return getLength() * 3600f / (info.getMaximumSpeed() * 1000f);
64
+	}
65
+
66
+	/**
67
+	 * @return Road information for this arc.
68
+	 */
69
+	public RoadInformation getInfo() {
70
+		return info;
71
+	}
72
+
73
+	/**
74
+	 * @return Points representing segments of this arc. This function may return an empty
75
+	 * ArrayList if the segments are stored in the reversed arc (for two-ways road).
76
+	 */
77
+	public ArrayList<Point> getPoints() {
78
+		return points;
79
+	}
80
+
81
+}

+ 28
- 0
src/main/org/insa/graph/Graph.java View File

@@ -0,0 +1,28 @@
1
+package org.insa.graph ;
2
+
3
+import java.util.ArrayList;
4
+
5
+public class Graph {
6
+
7
+	// Map identifier.
8
+	private int mapId;
9
+	
10
+	// Nodes of the graph.
11
+	private ArrayList<Node> nodes;
12
+
13
+	public Graph(int mapId, ArrayList<Node> nodes) {
14
+		this.mapId = mapId;
15
+		this.nodes = nodes;
16
+	}
17
+	
18
+	/**
19
+	 * @return Nodes of this graph.
20
+	 */
21
+	public ArrayList<Node> getNodes() { return nodes; }
22
+	
23
+	/**
24
+	 * @return Map ID of this graph.
25
+	 */
26
+	public int getMapId() { return mapId; }
27
+
28
+}

+ 52
- 0
src/main/org/insa/graph/Node.java View File

@@ -0,0 +1,52 @@
1
+package org.insa.graph;
2
+
3
+import java.util.ArrayList;
4
+
5
+public class Node {
6
+
7
+	// ID of the node.
8
+	private int id;
9
+	
10
+	// Point of this graph.
11
+	private Point point;
12
+	
13
+	// Successors.
14
+	private ArrayList<Arc> successors;
15
+	
16
+	/**
17
+	 * Create a new Node corresponding to the given Point with
18
+	 * an empty list of successors.
19
+	 * 
20
+	 * @param point
21
+	 */
22
+	public Node(int id, Point point) {
23
+		this.id = id;
24
+		this.point = point;
25
+		this.successors = new ArrayList<Arc>();
26
+	}
27
+
28
+	/**
29
+	 * Add a successor to this node.
30
+	 * 
31
+	 * @param arc Arc to the successor.
32
+	 */
33
+	public void addSuccessor(Arc arc) {
34
+		successors.add(arc);
35
+	}
36
+	
37
+	/**
38
+	 * @return ID of this node.
39
+	 */
40
+	public int getId() { return id; }
41
+	
42
+	/**
43
+	 * @return List of successors of this node.
44
+	 */
45
+	public ArrayList<Arc> getSuccessors() { return successors; }
46
+	
47
+	/**
48
+	 * @return Point of this node.
49
+	 */
50
+	public Point getPoint() { return point; }
51
+	
52
+}

+ 62
- 0
src/main/org/insa/graph/Point.java View File

@@ -0,0 +1,62 @@
1
+package org.insa.graph;
2
+
3
+/**
4
+ * Class representing a point on Earth.
5
+ *
6
+ */
7
+public class Point {
8
+	
9
+	// Earth radius, in meters;
10
+	private static final double EARTH_RADIUS = 6378137.0 ;
11
+	
12
+	/**
13
+	 * Compute the distance between the two given points.
14
+	 * 
15
+	 * @param long1
16
+	 * @param lat1
17
+	 * @param long2
18
+	 * @param lat2
19
+	 * @return
20
+	 */
21
+	public static double distance(Point p1, Point p2) {
22
+		double sinLat = Math.sin(Math.toRadians(p1.getLatitude()))*Math.sin(Math.toRadians(p2.getLatitude()));
23
+		double cosLat = Math.cos(Math.toRadians(p1.getLatitude()))*Math.cos(Math.toRadians(p2.getLatitude()));
24
+		double cosLong = Math.cos(Math.toRadians(p2.getLongitude() - p1.getLongitude()));
25
+		return EARTH_RADIUS * Math.acos(sinLat+cosLat*cosLong);
26
+	}
27
+
28
+	// Longitude and latitude of the point.
29
+	private float longitude, latitude;
30
+	
31
+	/**
32
+	 * 
33
+	 * @param longitude Longitude of the point, in degrees.
34
+	 * @param latitude Latitude of the point, in degrees.
35
+	 */
36
+	public Point(float longitude, float latitude) {
37
+		this.longitude = longitude;
38
+		this.latitude = latitude;
39
+	}
40
+	
41
+	/**
42
+	 * @return Longitude of this point (in degrees).
43
+	 */
44
+	public float getLongitude() { return longitude; }
45
+	
46
+	/**
47
+	 * @return Latitude of this point (in degrees).
48
+	 */
49
+	public float getLatitude() { return latitude; }
50
+
51
+	/**
52
+	 * Compute the distance from this point to the given point
53
+	 * 
54
+	 * @param target Target point.
55
+	 * 
56
+	 * @return Distane between this point and the target point, in meters.
57
+	 */
58
+	public double distanceTo(Point target) {
59
+		return distance(this, target);
60
+	}
61
+	
62
+}

+ 85
- 0
src/main/org/insa/graph/RoadInformation.java View File

@@ -0,0 +1,85 @@
1
+package org.insa.graph ;
2
+
3
+/**
4
+ * Class containing information for road that may be shared
5
+ * by multiple arcs.
6
+ * 
7
+ */
8
+public class RoadInformation {
9
+	
10
+	/**
11
+	 * Road type.
12
+	 */
13
+	public enum RoadType {
14
+		MOTORWAY,
15
+		TRUNK,
16
+		PRIMARY,
17
+		SECONDARY,
18
+		MOTORWAY_LINK,
19
+		TRUNK_LINK,
20
+		PRIMARY_LINK,
21
+		SECONDARY_LINK,
22
+		TERTIARY,
23
+		RESIDENTIAL,
24
+		UNCLASSIFIED,
25
+		ROAD,
26
+		LIVING_STREET,
27
+		SERVICE,
28
+		ROUNDABOUT,
29
+		COASTLINE
30
+	}
31
+
32
+	// Type of the road (see above).
33
+	private RoadType type;
34
+
35
+	// One way road?
36
+	private boolean oneway;
37
+
38
+	// Max speed in kilometers per hour.
39
+	private int maxSpeed;
40
+
41
+	// Name of the road.
42
+	private String name;
43
+
44
+	public RoadInformation(RoadType roadType, boolean isOneWay, int maxSpeed, String name) {
45
+		this.type = roadType;
46
+		this.oneway = isOneWay;
47
+		this.maxSpeed = maxSpeed;
48
+		this.name = name;
49
+	}
50
+	
51
+	/**
52
+	 * @return Type of the road.
53
+	 */
54
+	public RoadType getType() { return type; }
55
+	
56
+	/**
57
+	 * @return true if this is a one-way road.
58
+	 */
59
+	public boolean isOneWay() { return oneway; }
60
+	
61
+	/**
62
+	 * @return Maximum speed for this road (in km/h).
63
+	 */
64
+	public int getMaximumSpeed() { return maxSpeed; }
65
+	
66
+	/**
67
+	 * @return Name of the road.
68
+	 */
69
+	public String getName() { return name; }
70
+
71
+	@Override
72
+	public String toString() {
73
+		String typeAsString = "road";
74
+		if (getType() == RoadType.COASTLINE) {
75
+			typeAsString = "coast";
76
+		}
77
+		if (getType() == RoadType.MOTORWAY) {
78
+			typeAsString = "highway";
79
+		}
80
+		return typeAsString + " : " + getName() 
81
+				+ " " + (isOneWay() ? " (oneway) " : "") 
82
+				+ maxSpeed + " km/h (max.)";
83
+	}
84
+
85
+}

+ 16
- 0
src/main/org/insa/graph/io/AbstractGraphReader.java View File

@@ -0,0 +1,16 @@
1
+package org.insa.graph.io;
2
+
3
+import org.insa.graph.Graph;
4
+
5
+public interface AbstractGraphReader {
6
+	
7
+	/**
8
+	 * Read a graph an returns it.
9
+	 * 
10
+	 * @return Graph.
11
+	 * @throws Exception 
12
+	 * 
13
+	 */
14
+	public Graph read() throws Exception;
15
+
16
+}

+ 18
- 0
src/main/org/insa/graph/io/AbstractPathReader.java View File

@@ -0,0 +1,18 @@
1
+package org.insa.graph.io;
2
+
3
+import org.insa.graph.Graph;
4
+import org.insa.graph.Path;
5
+
6
+public interface AbstractPathReader {
7
+
8
+	/**
9
+	 * Read a path of the given graph and returns it.
10
+	 * 
11
+	 * @param graph Graph of the path.
12
+	 * 
13
+	 * @return A new path.
14
+	 * @throws Exception 
15
+	 */
16
+	public Path readPath(Graph graph) throws Exception;
17
+	
18
+}

+ 21
- 0
src/main/org/insa/graph/io/BadFormatException.java View File

@@ -0,0 +1,21 @@
1
+package org.insa.graph.io;
2
+
3
+import java.io.IOException;
4
+
5
+public class BadFormatException extends IOException {
6
+
7
+	/**
8
+	 * 
9
+	 */
10
+	private static final long serialVersionUID = -5455552814725826052L;
11
+
12
+	/**
13
+	 * 
14
+	 * @param actualVersion
15
+	 * @param expectedVersion
16
+	 */
17
+	public BadFormatException() {
18
+		super();
19
+	}
20
+
21
+}

+ 36
- 0
src/main/org/insa/graph/io/BadMagicNumberException.java View File

@@ -0,0 +1,36 @@
1
+package org.insa.graph.io;
2
+
3
+import java.io.IOException;
4
+
5
+public class BadMagicNumberException extends IOException {
6
+
7
+	/**
8
+	 * 
9
+	 */
10
+	private static final long serialVersionUID = -2176603967548838864L;
11
+	
12
+	// Actual and expected magic numbers.
13
+	private int actualNumber, expectedNumber;
14
+	
15
+	/**
16
+	 * 
17
+	 * @param actualVersion
18
+	 * @param expectedVersion
19
+	 */
20
+	public BadMagicNumberException(int actualNumber, int expectedNumber) {
21
+		super();
22
+		this.actualNumber = actualNumber;
23
+		this.expectedNumber = expectedNumber;
24
+	}
25
+	
26
+	/**
27
+	 * 
28
+	 */
29
+	public int getActualMagicNumber() { return actualNumber; }
30
+	
31
+	/**
32
+	 * 
33
+	 */
34
+	public int getExpectedMagicNumber() { return expectedNumber; }
35
+
36
+}

+ 35
- 0
src/main/org/insa/graph/io/BadVersionException.java View File

@@ -0,0 +1,35 @@
1
+package org.insa.graph.io;
2
+
3
+import java.io.IOException;
4
+
5
+public class BadVersionException extends IOException {
6
+
7
+	/**
8
+	 * 
9
+	 */
10
+	private static final long serialVersionUID = 7776317018302386042L;
11
+	
12
+	// Actual and expected version..
13
+	private int actualVersion, expectedVersion;
14
+	
15
+	/**
16
+	 * 
17
+	 * @param actualVersion
18
+	 * @param expectedVersion
19
+	 */
20
+	public BadVersionException(int actualVersion, int expectedVersion) {
21
+		super();
22
+		this.actualVersion = actualVersion;
23
+		this.expectedVersion = expectedVersion;
24
+	}
25
+	
26
+	/**
27
+	 * 
28
+	 */
29
+	public int getActualVersion() { return actualVersion; }
30
+	
31
+	/**
32
+	 * 
33
+	 */
34
+	public int getExpectedVersion() { return expectedVersion; }
35
+}

+ 176
- 0
src/main/org/insa/graph/io/BinaryGraphReader.java View File

@@ -0,0 +1,176 @@
1
+package org.insa.graph.io;
2
+
3
+import java.io.DataInputStream;
4
+import java.io.IOException;
5
+import java.util.ArrayList;
6
+
7
+import org.insa.graph.Arc;
8
+import org.insa.graph.Graph;
9
+import org.insa.graph.Node;
10
+import org.insa.graph.Point;
11
+import org.insa.graph.RoadInformation;
12
+import org.insa.graph.RoadInformation.RoadType;
13
+
14
+public class BinaryGraphReader extends BinaryReader implements AbstractGraphReader {
15
+	
16
+	// Map version and magic number targeted for this reader.
17
+	private static final int VERSION = 4;
18
+	private static final int MAGIC_NUMBER = 0xbacaff;
19
+
20
+	/**
21
+	 * Convert a character to its corresponding road type.
22
+	 * 
23
+	 * @param ch Character to convert.
24
+	 * 
25
+	 * @return Road type corresponding to ch.
26
+	 * 
27
+	 * @see http://wiki.openstreetmap.org/wiki/Highway_tag_usage.
28
+	 */
29
+	public static RoadType toRoadType(char ch) {
30
+		switch (ch) {
31
+			case 'a': return RoadType.MOTORWAY;
32
+			case 'b': return RoadType.TRUNK;
33
+			case 'c': return RoadType.PRIMARY;
34
+			case 'd': return RoadType.SECONDARY;
35
+			case 'e': return RoadType.MOTORWAY_LINK;
36
+			case 'f': return RoadType.TRUNK_LINK;
37
+			case 'g': return RoadType.PRIMARY_LINK;
38
+			case 'h': return RoadType.SECONDARY_LINK;
39
+			case 'i': return RoadType.TERTIARY;
40
+			case 'j': return RoadType.RESIDENTIAL;
41
+			case 'k': return RoadType.UNCLASSIFIED;
42
+			case 'l': return RoadType.ROAD;
43
+			case 'm': return RoadType.LIVING_STREET;
44
+			case 'n': return RoadType.SERVICE;
45
+			case 'o': return RoadType.ROUNDABOUT;
46
+			case 'z': return RoadType.COASTLINE;
47
+		}
48
+		return RoadType.UNCLASSIFIED;
49
+	}
50
+
51
+	/**
52
+	 * Create a new BinaryGraphReader using the given DataInputStream.
53
+	 * 
54
+	 * @param dis
55
+	 */
56
+	public BinaryGraphReader(DataInputStream dis) {
57
+		super(MAGIC_NUMBER, VERSION, dis);
58
+	}
59
+
60
+	@Override
61
+	public Graph read() throws IOException {
62
+		
63
+		// Read and check magic number and file version.
64
+		checkMagicNumberOrThrow(dis.readInt());
65
+		checkVersionOrThrow(dis.readInt());
66
+		
67
+		// Read map id.
68
+		int mapId = dis.readInt();
69
+		
70
+		// Read zone.
71
+		int graphZone = dis.readInt();
72
+
73
+		// Number of descriptors and nodes.
74
+		int nbDesc = dis.readInt();
75
+		int nbNodes = dis.readInt();
76
+		
77
+		// Number of successors for each nodes.
78
+		int[] nbSuccessors = new int[nbNodes];
79
+
80
+		// Construct an array list with initial capacity of nbNodes.
81
+		ArrayList<Node> nodes = new ArrayList<Node>(nbNodes);
82
+		
83
+		// Read nodes.
84
+		for (int node = 0; node < nbNodes; ++node) {
85
+			float longitude = ((float)dis.readInt ()) / 1E6f;
86
+			float latitude = ((float)dis.readInt ()) / 1E6f;
87
+			nbSuccessors[node] = dis.readUnsignedByte();
88
+			nodes.add(new Node(node, new Point(longitude, latitude)));
89
+		}
90
+		
91
+		// Check format.
92
+		checkByteOrThrow(255);
93
+		
94
+		// Read descriptors.
95
+		RoadInformation[] descs = new RoadInformation[nbDesc];
96
+		
97
+		// Read
98
+		for (int descr = 0; descr < nbDesc; ++descr) {
99
+			descs[descr] = readRoadInformation();
100
+		}
101
+		
102
+		// Check format.
103
+		checkByteOrThrow(254);
104
+		
105
+		// Read successors and convert to arcs.
106
+		for (int node = 0; node < nbNodes; ++node) {
107
+			for (int succ = 0; succ < nbSuccessors[node]; ++succ) {
108
+				
109
+				// Read destination zone.
110
+				int destZone = dis.readUnsignedByte();
111
+				
112
+				// Read target node number.
113
+				int destNode = this.read24bits();
114
+				
115
+				// Read information number.
116
+				int descrNum = this.read24bits();
117
+				
118
+				// Length of the arc.
119
+				int length = dis.readUnsignedShort();
120
+				
121
+				// Number of segments.
122
+				int nbSegments = dis.readUnsignedShort();
123
+
124
+				// Chain of points corresponding to the segments.
125
+				ArrayList<Point> points = new ArrayList<Point>(nbSegments + 2);
126
+				points.add(nodes.get(node).getPoint());
127
+				
128
+				for (int seg = 0; seg < nbSegments; ++seg) {
129
+					Point lastPoint = points.get(points.size() - 1);
130
+							
131
+					float dlon = (dis.readShort()) / 2.0e5f;
132
+					float dlat = (dis.readShort()) / 2.0e5f;
133
+					
134
+					points.add(new Point(lastPoint.getLongitude() + dlon,
135
+										lastPoint.getLatitude() + dlat));
136
+				}
137
+				
138
+				points.add(nodes.get(destNode).getPoint());
139
+				
140
+				if (graphZone == destZone) {
141
+					
142
+					RoadInformation info = descs[descrNum];
143
+					Node orig = nodes.get(node);
144
+					Node dest = nodes.get(destNode);
145
+	
146
+					// Add successor to initial arc.
147
+					orig.addSuccessor(new Arc(dest, length, info, points));
148
+					
149
+					// And reverse arc if its a two-way road.
150
+					if (!info.isOneWay()) {
151
+						// Add without segments.
152
+						dest.addSuccessor(new Arc(orig, length, info));
153
+					}
154
+					
155
+				}
156
+			}
157
+		}
158
+		
159
+		// Check format.
160
+		checkByteOrThrow(253);
161
+		
162
+		return new Graph(mapId, nodes);
163
+	}
164
+		
165
+	/**
166
+	 * Read the next road information from the stream.
167
+	 * 
168
+	 * @throws IOException
169
+	 */
170
+	private RoadInformation readRoadInformation() throws IOException {
171
+		char type = (char)dis.readUnsignedByte();
172
+		int x = dis.readUnsignedByte() ;
173
+		return new RoadInformation(toRoadType(type), (x & 0x80) > 0, (x & 0x7F) * 5, dis.readUTF());
174
+	}
175
+	
176
+}

+ 70
- 0
src/main/org/insa/graph/io/BinaryPathReader.java View File

@@ -0,0 +1,70 @@
1
+package org.insa.graph.io;
2
+
3
+import java.io.DataInputStream;
4
+import java.io.IOException;
5
+import java.util.ArrayList;
6
+
7
+import org.insa.graph.Graph;
8
+import org.insa.graph.Node;
9
+import org.insa.graph.Path;
10
+
11
+public class BinaryPathReader extends BinaryReader implements AbstractPathReader {
12
+
13
+	// Map version and magic number targeted for this reader.
14
+	private static final int VERSION = 1;
15
+	private static final int MAGIC_NUMBER = 0xdecafe;
16
+
17
+	public BinaryPathReader(DataInputStream dis) {
18
+		super(MAGIC_NUMBER, VERSION, dis);
19
+	}
20
+
21
+	@Override
22
+	public Path readPath(Graph graph) throws Exception {
23
+		
24
+		// Read and check magic number and version.
25
+		checkMagicNumberOrThrow(dis.readInt());
26
+		checkVersionOrThrow(dis.readInt());
27
+		
28
+		// Read map ID and check against graph.
29
+		int mapId = dis.readInt();
30
+		
31
+		if (mapId != graph.getMapId()) {
32
+			throw new MapMismatchException(mapId, graph.getMapId());
33
+		}
34
+		
35
+		// Number of nodes in the path (without first and last).
36
+		int nbNodes = dis.readInt();
37
+		
38
+		ArrayList<Node> nodes = new ArrayList<Node>(nbNodes + 2);
39
+		
40
+		// Read first node
41
+		nodes.add(readNode(graph));
42
+		
43
+		// Read last node
44
+		Node lastNode = readNode(graph);
45
+		
46
+		// Read intermediate nodes:
47
+		for (int node = 0; node < nbNodes; ++node) {
48
+			nodes.add(readNode(graph));
49
+		}
50
+		
51
+		// Add last node
52
+		nodes.add(lastNode);
53
+		
54
+		return new Path(graph, nodes);
55
+	}
56
+
57
+	/**
58
+	 * Read a node from the stream and returns id.
59
+	 * 
60
+	 * @return
61
+	 * @throws IOException 
62
+	 */
63
+	protected Node readNode(Graph graph) throws IOException {
64
+		// Discard zone.
65
+		dis.readUnsignedByte();
66
+		
67
+		return graph.getNodes().get(read24bits());
68
+	}
69
+
70
+}

+ 67
- 0
src/main/org/insa/graph/io/BinaryReader.java View File

@@ -0,0 +1,67 @@
1
+package org.insa.graph.io;
2
+
3
+import java.io.DataInputStream;
4
+import java.io.IOException;
5
+
6
+public abstract class BinaryReader {
7
+	
8
+	// Map version and magic number targeted for this reader.
9
+	private int version;
10
+	private int magicNumber;
11
+	
12
+	// InputStream
13
+	protected DataInputStream dis;
14
+	
15
+	protected BinaryReader(int magicNumber, int version, DataInputStream dis) {
16
+		this.magicNumber = magicNumber;
17
+		this.version = version;
18
+		this.dis = dis;
19
+	}
20
+	
21
+	/**
22
+	 * @param version
23
+	 * @throws BadVersionException 
24
+	 */
25
+	public void checkVersionOrThrow(int version) throws BadVersionException {
26
+		if (this.version != version) {
27
+			throw new BadVersionException(version, this.version);
28
+		}
29
+	}
30
+	
31
+	/**
32
+	 * @param magicNumber
33
+	 * @throws BadMagicNumberException 
34
+	 */
35
+	public void checkMagicNumberOrThrow(int magicNumber) throws BadMagicNumberException {
36
+		if (this.magicNumber != magicNumber) {
37
+			throw new BadMagicNumberException(magicNumber, this.magicNumber);
38
+		}
39
+	}
40
+	
41
+	/**
42
+	 * Check if the next byte in the input stream correspond to the
43
+	 * given byte. This function consumes the next byte in the input
44
+	 * stream.
45
+	 * 
46
+	 * @param i Byte to check against.
47
+	 * 
48
+	 * @throws IOException 
49
+	 */
50
+	public void checkByteOrThrow(int i) throws IOException {
51
+		if (dis.readUnsignedByte() != i) {
52
+			throw new BadFormatException();
53
+		}
54
+	}
55
+	
56
+	/**
57
+	 * Read 24 bits from the stream and return the corresponding integer value.
58
+	 * 
59
+	 * @return Integer value read from the next 24 bits of the stream.
60
+	 * 
61
+	 * @throws IOException
62
+	 */
63
+	protected int read24bits() throws IOException {
64
+		int x = dis.readUnsignedShort() ;
65
+		return (x << 8) | dis.readUnsignedByte() ;
66
+	}
67
+}

+ 36
- 0
src/main/org/insa/graph/io/MapMismatchException.java View File

@@ -0,0 +1,36 @@
1
+package org.insa.graph.io;
2
+
3
+public class MapMismatchException extends Exception {
4
+
5
+	/**
6
+	 * 
7
+	 */
8
+	private static final long serialVersionUID = 3076730078387819138L;
9
+	// Actual and expected magic numbers.
10
+	private int actualMapId, expectedMapId;
11
+	
12
+	/**
13
+	 * 
14
+	 * @param actualVersion
15
+	 * @param expectedVersion
16
+	 */
17
+	public MapMismatchException(int actualMapId, int expectedMapId) {
18
+		super();
19
+		this.actualMapId = actualMapId;
20
+		this.expectedMapId = expectedMapId;
21
+	}
22
+
23
+	/**
24
+	 * @return
25
+	 */
26
+	public int getActualMapId() {
27
+		return actualMapId;
28
+	}
29
+
30
+	/**
31
+	 * @return
32
+	 */
33
+	public int getExpectedMapId() {
34
+		return expectedMapId;
35
+	}
36
+}

+ 252
- 0
src/main/org/insa/utility/BinaryHeap.java View File

@@ -0,0 +1,252 @@
1
+//
2
+// ******************PUBLIC OPERATIONS*********************
3
+// void insert( x )       --> Insert x
4
+// Comparable deleteMin( )--> Return and remove smallest item
5
+// Comparable findMin( )  --> Return smallest item
6
+// boolean isEmpty( )     --> Return true if empty; else false
7
+// ******************ERRORS********************************
8
+// Throws RuntimeException for findMin and deleteMin when empty
9
+
10
+package org.insa.utility;
11
+
12
+import java.util.* ;
13
+
14
+/**
15
+ * Implements a binary heap.
16
+ * Note that all "matching" is based on the compareTo method.
17
+ * @author Mark Allen Weiss
18
+ * @author DLB
19
+ */
20
+public class BinaryHeap<E extends Comparable<E>> {
21
+
22
+	private int currentSize; // Number of elements in heap
23
+
24
+	// Java genericity does not work with arrays.
25
+	// We have to use an ArrayList
26
+	private ArrayList<E> array; // The heap array
27
+
28
+	/**
29
+	 * Construct the binary heap.
30
+	 */
31
+	public BinaryHeap() {
32
+		this.currentSize = 0;
33
+		this.array = new ArrayList<E>() ;
34
+	}
35
+
36
+	// Constructor used for debug.
37
+	public BinaryHeap(BinaryHeap<E> heap) {
38
+		this.currentSize = heap.currentSize ;
39
+		this.array = new ArrayList<E>(heap.array) ;
40
+	}
41
+
42
+	// Sets an element in the array
43
+	private void arraySet(int index, E value) {
44
+		if (index == this.array.size()) {
45
+			this.array.add(value) ;
46
+		}
47
+		else {
48
+			this.array.set(index, value) ;
49
+		}
50
+	}
51
+
52
+	/**
53
+	 * Test if the heap is logically empty.
54
+	 * @return true if empty, false otherwise.
55
+	 */
56
+	public boolean isEmpty() { return this.currentSize == 0; }
57
+
58
+	/**
59
+	 * Returns size.
60
+	 * @return current size.
61
+	 */
62
+	public int size() { return this.currentSize; }
63
+
64
+
65
+	/**
66
+	 * Returns index of parent.
67
+	 */
68
+	private int index_parent(int index) {
69
+		return (index - 1) / 2 ;
70
+	}
71
+
72
+	/**
73
+	 * Returns index of left child.
74
+	 */
75
+	private int index_left(int index) {
76
+		return index * 2 + 1 ;
77
+	}
78
+
79
+	/**
80
+	 * Insert into the heap.
81
+	 * @param x the item to insert.
82
+	 */
83
+	public void insert(E x) {
84
+		int index = this.currentSize++ ;
85
+		this.arraySet(index, x) ;
86
+		this.percolateUp(index) ;
87
+	}
88
+
89
+	/**
90
+	 * Internal method to percolate up in the heap.
91
+	 * @param index the index at which the percolate begins.
92
+	 */
93
+	private void percolateUp(int index) {
94
+		E x = this.array.get(index) ;
95
+
96
+		for( ; index > 0 && x.compareTo(this.array.get(index_parent(index)) ) < 0; index = index_parent(index) ) {
97
+			E moving_val = this.array.get(index_parent(index)) ;
98
+			this.arraySet(index, moving_val) ;
99
+		}
100
+
101
+		this.arraySet(index, x) ;
102
+	}
103
+
104
+	/**
105
+	 * Internal method to percolate down in the heap.
106
+	 * @param index the index at which the percolate begins.
107
+	 */
108
+	private void percolateDown(int index) {
109
+		int ileft = index_left(index) ;
110
+		int iright = ileft + 1 ;
111
+
112
+		if (ileft < this.currentSize) {
113
+			E current = this.array.get(index) ;
114
+			E left = this.array.get(ileft) ;
115
+			boolean hasRight = iright < this.currentSize ;
116
+			E right = (hasRight)?this.array.get(iright):null ;
117
+
118
+			if (!hasRight || left.compareTo(right) < 0) {
119
+				// Left is smaller
120
+				if (left.compareTo(current) < 0) {
121
+					this.arraySet(index, left) ;
122
+					this.arraySet(ileft, current) ;
123
+					this.percolateDown( ileft ) ;
124
+				}
125
+			}
126
+			else {
127
+				// Right is smaller
128
+				if (right.compareTo(current) < 0) {
129
+					this.arraySet(index, right) ;
130
+					this.arraySet(iright, current) ;
131
+					this.percolateDown( iright ) ;
132
+				}		
133
+			}
134
+		}
135
+	}
136
+
137
+	/**
138
+	 * Find the smallest item in the heap.
139
+	 * @return the smallest item.
140
+	 * @throws Exception if empty.
141
+	 */
142
+	public E findMin( ) {
143
+		if( isEmpty() )
144
+			throw new RuntimeException( "Empty binary heap" );
145
+		return this.array.get(0);
146
+	}
147
+
148
+	/**
149
+	 * Remove the smallest item from the heap.
150
+	 * @return the smallest item.
151
+	 * @throws Exception if empty.
152
+	 */
153
+	public E deleteMin( ) {
154
+		E minItem = findMin( );
155
+		E lastItem = this.array.get(--this.currentSize) ;
156
+		this.arraySet(0, lastItem) ;
157
+		this.percolateDown( 0 );
158
+		return minItem;
159
+	}
160
+
161
+	/**
162
+	 * Prints the heap
163
+	 */
164
+	public void print() {
165
+		System.out.println() ;
166
+		System.out.println("========  HEAP  (size = " + this.currentSize + ")  ========") ;
167
+		System.out.println() ;
168
+
169
+		for (int i = 0 ; i < this.currentSize ; i++) {
170
+			System.out.println(this.array.get(i).toString()) ;
171
+		}
172
+
173
+		System.out.println() ;
174
+		System.out.println("--------  End of heap  --------") ;
175
+		System.out.println() ;
176
+	}
177
+
178
+	/**
179
+	 * Prints the elements of the heap according to their respective order.
180
+	 */
181
+	public void printSorted() {
182
+
183
+		BinaryHeap<E> copy = new BinaryHeap<E>(this) ;
184
+
185
+		System.out.println() ;
186
+		System.out.println("========  Sorted HEAP  (size = " + this.currentSize + ")  ========") ;
187
+		System.out.println() ;
188
+
189
+		while (!copy.isEmpty()) {
190
+			System.out.println(copy.deleteMin()) ;
191
+		}
192
+
193
+		System.out.println() ;
194
+		System.out.println("--------  End of heap  --------") ;
195
+		System.out.println() ;
196
+	}
197
+
198
+
199
+
200
+	// Test program : compare with the reference implementation PriorityQueue.
201
+	public static void main(String [] args) {
202
+		BinaryHeap<Integer> heap = new BinaryHeap<Integer>() ;
203
+		PriorityQueue<Integer> queue = new PriorityQueue<Integer>() ;
204
+
205
+		int count = 0 ;
206
+		int blocksize = 10000 ;
207
+
208
+		System.out.println("Interrupt to stop the test.") ;
209
+
210
+		while (true) {
211
+
212
+			// Insert up to blocksize elements
213
+			int nb_insert = (int)(Math.random() * (blocksize + 1)) ;
214
+
215
+			for (int i = 0 ; i < nb_insert ; i++) {
216
+				Integer obj = new Integer(i) ;
217
+				heap.insert(obj) ;
218
+				queue.add(obj) ;
219
+			}
220
+
221
+			// Remove up to blocksize elements
222
+			int nb_remove = (int)(Math.random() * blocksize * 1.1) ;
223
+
224
+			if (nb_remove > queue.size()) {
225
+				nb_remove = queue.size() ;
226
+			}
227
+
228
+			for (int i = 0 ; i < nb_remove ; i++) {
229
+
230
+				int removed1 = queue.poll().intValue() ;
231
+				int removed2 = heap.deleteMin().intValue() ;
232
+
233
+				if (removed1 != removed2) {
234
+					System.out.println("Ouch : expected " + removed1 + "  .. but got " + removed2) ;
235
+					System.exit(1) ;
236
+				}
237
+			}
238
+
239
+			if (heap.size() != queue.size()) {
240
+				System.out.println("Ouch : heap size = " + heap.size() + "  queue size = " + queue.size() ) ;
241
+				System.exit(1) ;
242
+			}
243
+
244
+			count += nb_remove ;
245
+
246
+			if (count > 1000000) {
247
+				System.out.println("" + count + " items successfully compared. Heap size : " + heap.size()) ;
248
+				count = 0 ;
249
+			}
250
+		}
251
+	}
252
+}

+ 68
- 0
src/test/org/insa/utility/BinaryHeapTest.java View File

@@ -0,0 +1,68 @@
1
+package org.insa.utility;
2
+
3
+import static org.junit.jupiter.api.Assertions.assertEquals;
4
+import static org.junit.jupiter.api.Assertions.fail;
5
+
6
+import java.util.stream.IntStream;
7
+
8
+import org.junit.jupiter.api.AfterAll;
9
+import org.junit.jupiter.api.AfterEach;
10
+import org.junit.jupiter.api.BeforeAll;
11
+import org.junit.jupiter.api.BeforeEach;
12
+import org.junit.jupiter.api.Disabled;
13
+import org.junit.jupiter.api.Test;
14
+import org.junit.jupiter.params.ParameterizedTest;
15
+import org.junit.jupiter.params.provider.MethodSource;
16
+
17
+public class BinaryHeapTest {
18
+	
19
+	private BinaryHeap<Integer> rangeHeap1;
20
+	
21
+	static IntStream dataRange1() {
22
+		return IntStream.range(0, 20);
23
+	}
24
+	
25
+	@BeforeAll
26
+    static void initAll() {
27
+		
28
+    }
29
+
30
+    @BeforeEach
31
+    void init() {
32
+    		// Create the range heap
33
+    		this.rangeHeap1 = new BinaryHeap<Integer>();
34
+    		dataRange1().forEach((int x) -> rangeHeap1.insert(x));
35
+    }
36
+
37
+    @Test
38
+    void testInsert() {
39
+    		BinaryHeap<Integer> heap = new BinaryHeap<Integer>();
40
+    		int size = 0;
41
+    		for (int x: dataRange1().toArray()) {
42
+    			heap.insert(x);
43
+    			size += 1;
44
+    			assertEquals(heap.size(), size);
45
+    		}
46
+    }
47
+    
48
+    @Test
49
+    void testDeleteMin() {
50
+		int[] range1 = dataRange1().toArray();
51
+		int size = range1.length;
52
+		assertEquals(rangeHeap1.size(), size);
53
+		for (int x: range1) {
54
+			assertEquals(rangeHeap1.deleteMin().intValue(), x);
55
+			size -= 1;
56
+			assertEquals(rangeHeap1.size(), size);
57
+		}
58
+    }
59
+
60
+    @AfterEach
61
+    void tearDown() {
62
+    }
63
+
64
+    @AfterAll
65
+    static void tearDownAll() {
66
+    }
67
+    
68
+}

Loading…
Cancel
Save