Initial commit.

This commit is contained in:
Mikael Capelle 2018-01-29 12:35:24 +01:00
commit 65c81b9921
34 changed files with 2193 additions and 0 deletions

23
.classpath Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main"/>
<classpathentry kind="src" path="src/test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry kind="lib" path="libs/piccolo2d-core-3.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/piccolo2d-core-3.0-javadoc.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="libs/piccolo2d-extras-3.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/piccolo2d-extras-3.0-javadoc.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="libs/piccolo2d-swt-3.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/piccolo2d-swt-3.0-javadoc.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>be-graphes-base</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

61
FORMAT Normal file
View File

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

21
FORMAT_PATH Normal file
View File

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

View File

@ -0,0 +1,59 @@
package org.insa.algo ;
import java.io.* ;
public abstract class AbstractAlgorithm {
protected PrintStream output;
protected AbstractInstance instance;
protected AbstractSolution solution;
/**
*
* @param instance
* @param logOutput
*/
protected AbstractAlgorithm(AbstractInstance instance, PrintStream logOutput) {
this.instance = instance;
this.output = logOutput;
this.solution = null;
}
/**
* Update the current solution.
*
* @param solution New solution, or null to unset the current solution.
*
*/
protected void updateLastSolution(AbstractSolution solution) {
this.solution = solution;
}
/**
* @return Instance corresponding to this algorithm.
*/
public AbstractInstance getInstance() { return instance; }
/**
* @return Last solution, or null if no solution was stored.
*/
public AbstractSolution getLastSolution() { return solution; }
/**
* Run the algorithm and update the current solution.
*
* @return true if a feasible solution was found (even non-optimal).
*/
public boolean run() {
this.solution = this.doRun();
return this.solution != null && this.solution.isFeasible();
}
/**
* Abstract method that should be implemented by child class.
*
* @return A solution, if one was found, or null.
*/
protected abstract AbstractSolution doRun();
}

View File

@ -0,0 +1,20 @@
package org.insa.algo;
import org.insa.graph.Graph;
public abstract class AbstractInstance {
protected Graph graph;
/**
* Create a new abstract instance with the given graph.
*
* @param graph
*/
protected AbstractInstance(Graph graph) {
this.graph = graph;
}
public Graph getGraph() { return graph; }
}

View File

@ -0,0 +1,67 @@
package org.insa.algo;
import java.time.Duration;
public abstract class AbstractSolution {
/**
* Possible status for a solution.
*
*/
public enum Status {
UNKNOWN,
INFEASIBLE,
FEASIBLE,
OPTIMAL,
};
// Status of the solution.
Status status;
// Solving time for the solution
Duration solvingTime;
// Original instance of the solution
AbstractInstance instance;
/**
* Create a new abstract solution with unknown status.
*
* @param instance
*/
protected AbstractSolution(AbstractInstance instance) {
this.instance = instance;
this.solvingTime = Duration.ZERO;
this.status = Status.UNKNOWN;
}
protected AbstractSolution(AbstractInstance instance,
Duration solvingTime, Status status) {
this.instance = instance;
this.solvingTime = solvingTime;
this.status = status;
}
/**
* @return Original instance for this solution.
*/
public AbstractInstance getInstance() { return instance; }
/**
* @return Status of this solution.
*/
public Status getStatus() { return status; }
/**
* @return Solving time of this solution.
*/
public Duration getSolvingTime() { return solvingTime; }
/**
* @return true if the solution is feasible or optimal.
*/
public boolean isFeasible() {
return status == Status.FEASIBLE || status == Status.OPTIMAL;
}
}

View File

@ -0,0 +1,30 @@
package org.insa.algo.connectivity ;
import java.io.* ;
import org.insa.algo.AbstractAlgorithm;
import org.insa.algo.AbstractSolution;
public class ConnectivityAlgorithm extends AbstractAlgorithm {
/**
*
* @param instance
* @param logOutput
*/
public ConnectivityAlgorithm(ConnectivityInstance instance, PrintStream logOutput) {
super(instance, logOutput);
}
/**
* {@inheritDoc}
*/
@Override
protected AbstractSolution doRun() {
ConnectivityInstance instance = (ConnectivityInstance)getInstance();
ConnectivitySolution solution = null;
// TODO:
return solution;
}
}

View File

@ -0,0 +1,16 @@
package org.insa.algo.connectivity;
import org.insa.algo.AbstractInstance;
import org.insa.graph.Graph;
public class ConnectivityInstance extends AbstractInstance {
/**
*
* @param graph
*/
public ConnectivityInstance(Graph graph) {
super(graph);
}
}

View File

@ -0,0 +1,20 @@
package org.insa.algo.connectivity;
import java.time.Duration;
import org.insa.algo.AbstractSolution;
public class ConnectivitySolution extends AbstractSolution {
protected ConnectivitySolution(ConnectivityInstance instance) {
super(instance);
}
protected ConnectivitySolution(ConnectivityInstance instance,
Duration solvingTime, Status status) {
super(instance, solvingTime, status);
// TODO:
}
}

View File

@ -0,0 +1,58 @@
package org.insa.base ;
/**
* Choix des couleurs pour l'affichage.
*/
import java.awt.* ;
import org.insa.drawing.Drawing;
public class Couleur {
static final Color autoroute = Color.red ;
static final Color bigroute = new Color(255, 105, 0) ;
static final Color tiroute = new Color(255, 234, 0) ;
static final Color cote = Color.blue ;
public static void set(Drawing d, char type) {
// Voir le fichier Descripteur.java pour le type des routes.
switch (type) {
case 'a':
d.setWidth(2) ;
d.setColor(Color.red) ;
break ;
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
d.setWidth(1) ;
d.setColor(bigroute) ;
break ;
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
d.setWidth(1) ;
d.setColor(tiroute) ;
break ;
case 'z':
d.setWidth(4) ;
d.setColor(cote) ;
break ;
default:
d.setWidth(1) ;
d.setColor(Color.black) ;
}
}
}

View File

@ -0,0 +1,115 @@
package org.insa.base ;
import java.io.* ;
import java.util.zip.* ;
/* Ne lisez pas cette classe. Lancez javadoc et lisez la doc generee plutot. */
/**
* La classe Openfile permet de lire les fichiers contenant les cartes :
* <ul>
* <li> en trouvant le bon dossier parmi les dossiers pre-configures </li>
* <li> en dezippant automatiquement si besoin </li>
* </ul>
*
*/
public class Openfile {
// Le programme examine chaque dossier dans l'ordre jusqu'a trouver celui qui contient la carte voulue
private static final String[] datadirs =
{ // NE MODIFIEZ PAS CELUI-CI
// car il permet de tester en etant a l'INSA.
"/home/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps",
// Celui-ci pour les chemins
"/home/commetud/3eme Annee MIC/Graphes-et-Algorithmes/",
// On cherche aussi dans le sous-repertoire local "Maps" (s'il existe)
"Maps",
// et dans le repertoire courant (Unix uniquement)
".",
// Si vous utilisez votre propre dossier pour les donnees, mettez-le ici.
"/home/votrepropredossier/a/vous",
} ;
// Extension testees. Garder l'extension vide dans la liste.
private static final String[] extensions = { ".map", ".gz", ".map.gz", ".path", ".path.gz", "" } ;
/**
* Ouvre le fichier indiqué et renvoie un DataInputStream sur ce fichier.
* Le fichier ne sera pas ferme avant la fin de l'application.
* @param filename Nom du fichier a ouvrir (sans chemin)
*/
public static DataInputStream open (String filename) {
if (!filename.equals (new File(filename).getName())) {
System.out.println("Le nom du fichier ne doit pas contenir un chemin (ni absolu, ni relatif).") ;
System.out.println("Il doit juste contenir le nom du fichier contenant la carte.") ;
System.out.println("Si vous voulez utiliser un dossier specifique, configurez base/Openfile.java") ;
System.exit(1) ;
}
boolean trouve = false ;
InputStream fileinput = null ;
String fname = null ;
String fullpath = null ;
for (int extn = 0 ; !trouve && extn < extensions.length ; extn++) {
fname = filename + extensions[extn] ;
for (int index = 0 ; !trouve && index < datadirs.length ; index++) {
fullpath = datadirs[index] + File.separator + fname ;
File file = new File(fullpath) ;
if (file.canRead()) {
trouve = true ;
try {
fileinput = new FileInputStream(file) ;
} catch (IOException e) {
e.printStackTrace() ;
System.exit(1) ;
}
}
}
}
if (!trouve) {
// Pas trouve
System.out.println("Impossible de trouver le fichier " + filename) ;
System.out.println(" pourtant j'ai cherche dans les dossiers : ") ;
int existepas = 0 ;
for (int i = 0 ; i < datadirs.length ; i++) {
System.out.println(" - " + datadirs[i]) ;
if (!new File(datadirs[i]).isDirectory()) {
switch (existepas) {
case 0: System.out.println(" (Ce dossier n'existe pas d'ailleurs)") ; break;
case 1: System.out.println(" (Ce dossier n'existe pas non plus)") ; break;
default: System.out.println(" (Celui-la non plus)") ; break;
}
existepas++ ;
}
System.out.println() ;
}
System.exit(1) ;
}
System.out.println("Fichier utilisee : " + fullpath) ;
System.out.println() ;
if (fname.endsWith(".gz")) {
// The file is gzipped.
try {
fileinput = new GZIPInputStream(fileinput) ;
} catch (IOException e) {
e.printStackTrace() ;
System.exit(1) ;
}
}
else {
fileinput = new BufferedInputStream(fileinput) ;
}
return new DataInputStream(fileinput) ;
}
}

View File

@ -0,0 +1,86 @@
package org.insa.base ;
import java.io.* ;
/* Ne lisez pas cette classe. Lancez javadoc et lisez la doc generee plutot. */
/**
* La classe Readarg facilite la lecture de donnees depuis le clavier ou depuis la ligne de commande.
*
*/
public class Readarg {
private final String[] args ;
private int next ;
// Le Java est le langage prefere des Shadoks.
private final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public Readarg(String[] argz) {
this.args = argz ;
this.next = 0 ;
}
/**
* Obtient une chaine, ou bien depuis la ligne de commande, ou depuis l'entree standard.
* @param msg Message affiche avant de demander la chaine
*/
public String lireString (String msg) {
String resultat = "" ;
System.out.print(msg) ;
if (this.next >= this.args.length) {
try {
resultat = br.readLine () ;
} catch (Exception e) {
System.err.println ("Erreur de lecture de l'entree standard.") ;
System.exit(1) ;
}
}
else {
resultat = this.args[this.next] ;
this.next++ ;
System.out.println (resultat) ;
}
return resultat ;
}
/**
* Obtient un entier, ou bien depuis la ligne de commande, ou depuis l'entree standard.
* @param msg Message affiche avant de demander l'entier
*/
public int lireInt (String msg) {
String lu = lireString (msg) ;
int result = 0 ;
try {
result = Integer.parseInt(lu) ;
}
catch (Exception e) {
System.err.println ("Un entier est attendu mais je lis " + lu) ;
System.exit(1) ;
}
return result ;
}
/**
* Obtient un float, ou bien depuis la ligne de commande, ou depuis l'entree standard.
* @param msg Message affiche avant de demander le float.
*/
public float lireFloat (String msg) {
String lu = lireString (msg) ;
float result = 0 ;
try {
result = Float.parseFloat(lu) ;
}
catch (Exception e) {
System.err.println ("Un reel est attendu mais je lis " + lu) ;
System.exit(1) ;
}
return result ;
}
}

View File

@ -0,0 +1,57 @@
package org.insa.base ;
import java.io.* ;
import org.insa.drawing.Drawing;
/**
* Fonctions accessoires dont vous n'avez pas a vous servir directement.
*/
public class Utils {
// Calibrer la sortie graphique en fonction de la carte
// Vous pouvez modifier les coordonnees pour ameliorer le rendu.
public static void calibrer(String nomCarte, Drawing dessin) {
if (nomCarte.startsWith("insa")) {
// L'INSA
dessin.setBB (1.462, 1.473, 43.567, 43.5744) ;
}
else if (nomCarte.startsWith("paris")) {
// Ile de la Cité, Paris
dessin.setBB (2.329, 2.372, 48.839, 48.867) ;
}
else if (nomCarte.startsWith("mayot")) {
// Mayotte
dessin.setBB (44.5, 45.5, -13.25, -12.25) ;
}
else if (nomCarte.startsWith("reuni")) {
// La Réunion
dessin.setBB (55.0, 56.0, -21.5, -20.5) ;
}
else if (nomCarte.startsWith("midip")) {
dessin.setBB (-0.6, 3.8, 42.2, 45.3) ;
}
else if (nomCarte.startsWith("franc")) {
dessin.setBB (-5.2, 10.0, 41.0, 51.5) ;
}
else if (nomCarte.startsWith("pfranc")) {
dessin.setBB (-5.2, 10.0, 41.0, 51.5) ;
}
else if (nomCarte.startsWith("morbihan")) {
dessin.setBB (-3.53, -2.452, 47.27, 47.665) ;
}
else if (nomCarte.startsWith("newzealand")) {
dessin.setBB (153.415, 179.912, -47.931, -33.980) ;
}
else if (nomCarte.startsWith("fract") || nomCarte.startsWith("carr")) {
dessin.setBB (-0.05, 1.05, -0.05, 1.05) ;
}
else {
dessin.setBB (-20.0, 50.0, 20.0, 70.0) ;
}
}
}

View File

@ -0,0 +1,83 @@
package org.insa.drawing ;
/**
* Classe abstraite pour dessiner a l'ecran.
* Deux implementations : une sous-classe DessinVisible qui dessine vraiment a l'ecran
* et une sous-classe DessinInvisible qui ne dessine rien (pour ne pas ralentir les tests avec l'affichage).
*/
import java.awt.* ;
public interface Drawing {
/**
* Enable auto-repaint mode - When this mode is enable, call to
* drawing function will automatically repaint the drawing, which
* may be very slow in some case.
*
* @param autoRepaint Use true to enable auto-repaint, false to disable.
*
*/
public void setAutoRepaint(boolean autoRepaint);
/**
* Repaint the drawing.
*
*/
public void repaint();
/**
* Set the pencil width.
*
* @param width Width for the pencil.
*
*/
public void setWidth(int width);
/**
* Set the pencil color.
*
* param color Color for the pencil.
*
*/
public void setColor(Color col);
/**
* Indique les bornes de la fenetre graphique.
* Le calcul des coordonnees en pixel se fera automatiquement
* a l'appel des methodes drawLine et autres.
*
* @param long1 longitude du bord gauche
* @param long2 longitude du bord droit
* @param lat1 latitude du bord bas
* @param lat2 latitude du bord haut
*
*/
public void setBB(double long1, double long2, double lat1, double lat2);
/**
* Trace un segment.
* @param long1 longitude du premier point
* @param lat1 latitude du premier point
* @param long2 longitude du second point
* @param lat2 latitude du second point
*/
public void drawLine(float long1, float lat1, float long2, float lat2);
/**
* Trace un point.
* @param lon longitude du point
* @param lat latitude du point
* @param width grosseur du point
*/
public void drawPoint(float lon, float lat, int width);
/**
* Ecrit du texte a la position indiquee.
* @param lon longitude du point ou positionner le texte.
* @param lat latitude du point ou positionner le texte.
* @param txt le texte a ecrire.
*/
public void putText(float lon, float lat, String txt);
}

View File

@ -0,0 +1,38 @@
package org.insa.drawing;
import java.awt.Color;
/**
* Cette implementation de la classe Dessin ne produit pas d'affichage,
* ce qui accelere l'execution (utile pour ne pas ralentir les tests).
*/
public class DrawingInvisible implements Drawing {
public DrawingInvisible () { }
@Override
public void setWidth(int width) { }
@Override
public void setColor(Color col) { }
@Override
public void setBB(double long1, double long2, double lat1, double lat2) { }
@Override
public void drawLine(float long1, float lat1, float long2, float lat2) { }
@Override
public void drawPoint(float lon, float lat, int width) { }
@Override
public void putText(float lon, float lat, String txt) { }
@Override
public void setAutoRepaint(boolean autoRepaint) { }
@Override
public void repaint() { }
}

View File

@ -0,0 +1,184 @@
package org.insa.drawing;
import java.awt.*;
import java.awt.image.*;
/**
* Cette implementation de la classe Dessin produit vraiment un affichage
* (au contraire de la classe DessinInvisible).
*/
public class DrawingVisible extends Canvas implements Drawing {
/**
*
*/
private static final long serialVersionUID = 96779785877771827L;
private final Graphics2D gr;
private float long1;
private float long2;
private float lat1;
private float lat2;
private final float width;
private final float height;
private boolean bb_is_set ;
private Image image;
private ZoomAndPanListener zoomAndPanListener;
public boolean autoRepaint = true;
/**
* Cree et affiche une nouvelle fenetre de dessin.
*/
public DrawingVisible (int largeur, int hauteur) {
super();
this.zoomAndPanListener = new ZoomAndPanListener(this, 0, ZoomAndPanListener.DEFAULT_MAX_ZOOM_LEVEL, 1.2);
this.addMouseListener(zoomAndPanListener);
this.addMouseMotionListener(zoomAndPanListener);
this.addMouseWheelListener(zoomAndPanListener);
BufferedImage img = new BufferedImage (largeur, hauteur, BufferedImage.TYPE_3BYTE_BGR);
this.image = img;
this.gr = img.createGraphics();
this.zoomAndPanListener.setCoordTransform(this.gr.getTransform());
this.bb_is_set = false;
this.width = largeur;
this.height = hauteur;
this.long1 = (float)0.0;
this.long2 = (float)largeur;
this.lat1 = (float)0.0;
this.lat2 = (float)hauteur;
this.setColor(Color.white);
gr.fillRect(0,0, largeur, hauteur);
this.repaint();
}
@Override
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D)g1;
g.setTransform(zoomAndPanListener.getCoordTransform());
g.drawImage(image, 0, 0, this);
}
@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(0, 0);
if (image != null) {
int w = image.getWidth(null);
int h = image.getHeight(null);
size = new Dimension(w > 0 ? w : 0, h > 0 ? h : 0);
}
return size;
}
@Override
public void setAutoRepaint(boolean autoRepaint) {
this.autoRepaint = autoRepaint;
}
protected void doAutoPaint() {
if (autoRepaint) {
this.repaint();
}
}
public void setWidth (int width) {
this.gr.setStroke(new BasicStroke(width));
}
public void setColor (Color col) {
this.gr.setColor (col);
}
public void setBB (double long1, double long2, double lat1, double lat2) {
if (long1 > long2 || lat1 > lat2) {
throw new Error("DessinVisible.setBB : mauvaises coordonnees.");
}
/* Adapte la BB en fonction de la taille du dessin, pour préserver le ratio largeur/hauteur */
double deltalong = long2 - long1 ;
double deltalat = lat2 - lat1 ;
double ratiobb = deltalong / deltalat ;
double ratiogr = width / height ;
/* On ne peut qu'agrandir la BB, pour ne rien perdre.
* Si le ratiobb est trop petit, il faut agrandir deltalong
* s'il est trop grand, il faut agrandir deltalat. */
if (ratiobb < ratiogr) {
/* De combien faut-il agrandir ? */
double delta = (ratiogr - ratiobb) * deltalat ;
this.long1 = (float)(long1 - 0.5*delta) ;
this.long2 = (float)(long2 + 0.5*delta) ;
this.lat1 = (float)lat1 ;
this.lat2 = (float)lat2 ;
}
else {
double delta = (deltalong / ratiogr) - deltalat ;
this.long1 = (float)long1 ;
this.long2 = (float)long2 ;
this.lat1 = (float)(lat1 - 0.5*delta);
this.lat2 = (float)(lat2 + 0.5*delta);
}
this.bb_is_set = true ;
}
private int projx(float lon) {
return (int)(width * (lon - this.long1) / (this.long2 - this.long1)) ;
}
private int projy(float lat) {
return (int)(height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1))) ;
}
private void checkBB() {
if (!this.bb_is_set) {
throw new Error("Classe DessinVisible : vous devez invoquer la methode setBB avant de dessiner.") ;
}
}
public void drawLine (float long1, float lat1, float long2, float lat2) {
this.checkBB() ;
int x1 = this.projx(long1) ;
int x2 = this.projx(long2) ;
int y1 = this.projy(lat1) ;
int y2 = this.projy(lat2) ;
gr.drawLine(x1, y1, x2, y2) ;
this.doAutoPaint();
}
public void drawPoint (float lon, float lat, int width) {
this.checkBB() ;
int x = this.projx(lon) - width / 2 ;
int y = this.projy(lat) - width / 2 ;
gr.fillOval (x, y, width, width) ;
this.doAutoPaint();
}
public void putText (float lon, float lat, String txt) {
this.checkBB() ;
int x = this.projx(lon) ;
int y = this.projy(lat) ;
gr.drawString (txt, x, y) ;
this.doAutoPaint();
}
}

View File

@ -0,0 +1,135 @@
package org.insa.drawing;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
public class ZoomAndPanListener implements MouseListener, MouseMotionListener, MouseWheelListener {
public static final int DEFAULT_MIN_ZOOM_LEVEL = -20;
public static final int DEFAULT_MAX_ZOOM_LEVEL = 10;
public static final double DEFAULT_ZOOM_MULTIPLICATION_FACTOR = 1.2;
private Component targetComponent;
private int zoomLevel = 0;
private int minZoomLevel = DEFAULT_MIN_ZOOM_LEVEL;
private int maxZoomLevel = DEFAULT_MAX_ZOOM_LEVEL;
private double zoomMultiplicationFactor = DEFAULT_ZOOM_MULTIPLICATION_FACTOR;
private Point dragStartScreen;
private Point dragEndScreen;
private AffineTransform coordTransform = new AffineTransform();
public ZoomAndPanListener(Component targetComponent) {
this.targetComponent = targetComponent;
}
public ZoomAndPanListener(Component targetComponent, int minZoomLevel, int maxZoomLevel, double zoomMultiplicationFactor) {
this.targetComponent = targetComponent;
this.minZoomLevel = minZoomLevel;
this.maxZoomLevel = maxZoomLevel;
this.zoomMultiplicationFactor = zoomMultiplicationFactor;
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
dragStartScreen = e.getPoint();
dragEndScreen = null;
}
public void mouseReleased(MouseEvent e) {
// moveCamera(e);
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
moveCamera(e);
}
public void mouseWheelMoved(MouseWheelEvent e) {
zoomCamera(e);
}
private void moveCamera(MouseEvent e) {
try {
dragEndScreen = e.getPoint();
Point2D.Float dragStart = transformPoint(dragStartScreen);
Point2D.Float dragEnd = transformPoint(dragEndScreen);
double dx = dragEnd.getX() - dragStart.getX();
double dy = dragEnd.getY() - dragStart.getY();
coordTransform.translate(dx, dy);
dragStartScreen = dragEndScreen;
dragEndScreen = null;
targetComponent.repaint();
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
}
}
private void zoomCamera(MouseWheelEvent e) {
try {
int wheelRotation = e.getWheelRotation();
Point p = e.getPoint();
if (wheelRotation > 0) {
if (zoomLevel < maxZoomLevel) {
zoomLevel++;
Point2D p1 = transformPoint(p);
coordTransform.scale(1 / zoomMultiplicationFactor, 1 / zoomMultiplicationFactor);
Point2D p2 = transformPoint(p);
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
targetComponent.repaint();
}
} else {
if (zoomLevel > minZoomLevel) {
zoomLevel--;
Point2D p1 = transformPoint(p);
coordTransform.scale(zoomMultiplicationFactor, zoomMultiplicationFactor);
Point2D p2 = transformPoint(p);
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
targetComponent.repaint();
}
}
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
}
}
private Point2D.Float transformPoint(Point p1) throws NoninvertibleTransformException {
AffineTransform inverse = coordTransform.createInverse();
Point2D.Float p2 = new Point2D.Float();
inverse.transform(p1, p2);
return p2;
}
public int getZoomLevel() {
return zoomLevel;
}
public void setZoomLevel(int zoomLevel) {
this.zoomLevel = zoomLevel;
}
public AffineTransform getCoordTransform() {
return coordTransform;
}
public void setCoordTransform(AffineTransform coordTransform) {
this.coordTransform = coordTransform;
}
}

View File

@ -0,0 +1,81 @@
package org.insa.graph;
import java.util.ArrayList;
public class Arc {
// Destination node.
private Node dest;
// Length of the road (in meters).
private int length;
// Road information.
RoadInformation info;
// Segments.
ArrayList<Point> points;
/**
* @param dest
* @param length
* @param roadInformation
* @param points
*/
public Arc(Node dest, int length, RoadInformation roadInformation) {
this.dest = dest;
this.length = length;
this.info = roadInformation;
this.points = new ArrayList<Point>();
}
/**
* @param dest
* @param length
* @param roadInformation
* @param points
*/
public Arc(Node dest, int length, RoadInformation roadInformation, ArrayList<Point> points) {
this.dest = dest;
this.length = length;
this.info = roadInformation;
this.points = points;
}
/**
* @return Destination node of this arc.
*/
public Node getDest() {
return dest;
}
/**
* @return Length of this arc, in meters.
*/
public int getLength() {
return length;
}
/**
* @return Minimum time required to travel this arc, in seconds.
*/
public float getMinimumTravelTime() {
return getLength() * 3600f / (info.getMaximumSpeed() * 1000f);
}
/**
* @return Road information for this arc.
*/
public RoadInformation getInfo() {
return info;
}
/**
* @return Points representing segments of this arc. This function may return an empty
* ArrayList if the segments are stored in the reversed arc (for two-ways road).
*/
public ArrayList<Point> getPoints() {
return points;
}
}

View File

@ -0,0 +1,28 @@
package org.insa.graph ;
import java.util.ArrayList;
public class Graph {
// Map identifier.
private int mapId;
// Nodes of the graph.
private ArrayList<Node> nodes;
public Graph(int mapId, ArrayList<Node> nodes) {
this.mapId = mapId;
this.nodes = nodes;
}
/**
* @return Nodes of this graph.
*/
public ArrayList<Node> getNodes() { return nodes; }
/**
* @return Map ID of this graph.
*/
public int getMapId() { return mapId; }
}

View File

@ -0,0 +1,52 @@
package org.insa.graph;
import java.util.ArrayList;
public class Node {
// ID of the node.
private int id;
// Point of this graph.
private Point point;
// Successors.
private ArrayList<Arc> successors;
/**
* Create a new Node corresponding to the given Point with
* an empty list of successors.
*
* @param point
*/
public Node(int id, Point point) {
this.id = id;
this.point = point;
this.successors = new ArrayList<Arc>();
}
/**
* Add a successor to this node.
*
* @param arc Arc to the successor.
*/
public void addSuccessor(Arc arc) {
successors.add(arc);
}
/**
* @return ID of this node.
*/
public int getId() { return id; }
/**
* @return List of successors of this node.
*/
public ArrayList<Arc> getSuccessors() { return successors; }
/**
* @return Point of this node.
*/
public Point getPoint() { return point; }
}

View File

@ -0,0 +1,62 @@
package org.insa.graph;
/**
* Class representing a point on Earth.
*
*/
public class Point {
// Earth radius, in meters;
private static final double EARTH_RADIUS = 6378137.0 ;
/**
* Compute the distance between the two given points.
*
* @param long1
* @param lat1
* @param long2
* @param lat2
* @return
*/
public static double distance(Point p1, Point p2) {
double sinLat = Math.sin(Math.toRadians(p1.getLatitude()))*Math.sin(Math.toRadians(p2.getLatitude()));
double cosLat = Math.cos(Math.toRadians(p1.getLatitude()))*Math.cos(Math.toRadians(p2.getLatitude()));
double cosLong = Math.cos(Math.toRadians(p2.getLongitude() - p1.getLongitude()));
return EARTH_RADIUS * Math.acos(sinLat+cosLat*cosLong);
}
// Longitude and latitude of the point.
private float longitude, latitude;
/**
*
* @param longitude Longitude of the point, in degrees.
* @param latitude Latitude of the point, in degrees.
*/
public Point(float longitude, float latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
/**
* @return Longitude of this point (in degrees).
*/
public float getLongitude() { return longitude; }
/**
* @return Latitude of this point (in degrees).
*/
public float getLatitude() { return latitude; }
/**
* Compute the distance from this point to the given point
*
* @param target Target point.
*
* @return Distane between this point and the target point, in meters.
*/
public double distanceTo(Point target) {
return distance(this, target);
}
}

View File

@ -0,0 +1,85 @@
package org.insa.graph ;
/**
* Class containing information for road that may be shared
* by multiple arcs.
*
*/
public class RoadInformation {
/**
* Road type.
*/
public enum RoadType {
MOTORWAY,
TRUNK,
PRIMARY,
SECONDARY,
MOTORWAY_LINK,
TRUNK_LINK,
PRIMARY_LINK,
SECONDARY_LINK,
TERTIARY,
RESIDENTIAL,
UNCLASSIFIED,
ROAD,
LIVING_STREET,
SERVICE,
ROUNDABOUT,
COASTLINE
}
// Type of the road (see above).
private RoadType type;
// One way road?
private boolean oneway;
// Max speed in kilometers per hour.
private int maxSpeed;
// Name of the road.
private String name;
public RoadInformation(RoadType roadType, boolean isOneWay, int maxSpeed, String name) {
this.type = roadType;
this.oneway = isOneWay;
this.maxSpeed = maxSpeed;
this.name = name;
}
/**
* @return Type of the road.
*/
public RoadType getType() { return type; }
/**
* @return true if this is a one-way road.
*/
public boolean isOneWay() { return oneway; }
/**
* @return Maximum speed for this road (in km/h).
*/
public int getMaximumSpeed() { return maxSpeed; }
/**
* @return Name of the road.
*/
public String getName() { return name; }
@Override
public String toString() {
String typeAsString = "road";
if (getType() == RoadType.COASTLINE) {
typeAsString = "coast";
}
if (getType() == RoadType.MOTORWAY) {
typeAsString = "highway";
}
return typeAsString + " : " + getName()
+ " " + (isOneWay() ? " (oneway) " : "")
+ maxSpeed + " km/h (max.)";
}
}

View File

@ -0,0 +1,16 @@
package org.insa.graph.io;
import org.insa.graph.Graph;
public interface AbstractGraphReader {
/**
* Read a graph an returns it.
*
* @return Graph.
* @throws Exception
*
*/
public Graph read() throws Exception;
}

View File

@ -0,0 +1,18 @@
package org.insa.graph.io;
import org.insa.graph.Graph;
import org.insa.graph.Path;
public interface AbstractPathReader {
/**
* Read a path of the given graph and returns it.
*
* @param graph Graph of the path.
*
* @return A new path.
* @throws Exception
*/
public Path readPath(Graph graph) throws Exception;
}

View File

@ -0,0 +1,21 @@
package org.insa.graph.io;
import java.io.IOException;
public class BadFormatException extends IOException {
/**
*
*/
private static final long serialVersionUID = -5455552814725826052L;
/**
*
* @param actualVersion
* @param expectedVersion
*/
public BadFormatException() {
super();
}
}

View File

@ -0,0 +1,36 @@
package org.insa.graph.io;
import java.io.IOException;
public class BadMagicNumberException extends IOException {
/**
*
*/
private static final long serialVersionUID = -2176603967548838864L;
// Actual and expected magic numbers.
private int actualNumber, expectedNumber;
/**
*
* @param actualVersion
* @param expectedVersion
*/
public BadMagicNumberException(int actualNumber, int expectedNumber) {
super();
this.actualNumber = actualNumber;
this.expectedNumber = expectedNumber;
}
/**
*
*/
public int getActualMagicNumber() { return actualNumber; }
/**
*
*/
public int getExpectedMagicNumber() { return expectedNumber; }
}

View File

@ -0,0 +1,35 @@
package org.insa.graph.io;
import java.io.IOException;
public class BadVersionException extends IOException {
/**
*
*/
private static final long serialVersionUID = 7776317018302386042L;
// Actual and expected version..
private int actualVersion, expectedVersion;
/**
*
* @param actualVersion
* @param expectedVersion
*/
public BadVersionException(int actualVersion, int expectedVersion) {
super();
this.actualVersion = actualVersion;
this.expectedVersion = expectedVersion;
}
/**
*
*/
public int getActualVersion() { return actualVersion; }
/**
*
*/
public int getExpectedVersion() { return expectedVersion; }
}

View File

@ -0,0 +1,176 @@
package org.insa.graph.io;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import org.insa.graph.Arc;
import org.insa.graph.Graph;
import org.insa.graph.Node;
import org.insa.graph.Point;
import org.insa.graph.RoadInformation;
import org.insa.graph.RoadInformation.RoadType;
public class BinaryGraphReader extends BinaryReader implements AbstractGraphReader {
// Map version and magic number targeted for this reader.
private static final int VERSION = 4;
private static final int MAGIC_NUMBER = 0xbacaff;
/**
* Convert a character to its corresponding road type.
*
* @param ch Character to convert.
*
* @return Road type corresponding to ch.
*
* @see http://wiki.openstreetmap.org/wiki/Highway_tag_usage.
*/
public static RoadType toRoadType(char ch) {
switch (ch) {
case 'a': return RoadType.MOTORWAY;
case 'b': return RoadType.TRUNK;
case 'c': return RoadType.PRIMARY;
case 'd': return RoadType.SECONDARY;
case 'e': return RoadType.MOTORWAY_LINK;
case 'f': return RoadType.TRUNK_LINK;
case 'g': return RoadType.PRIMARY_LINK;
case 'h': return RoadType.SECONDARY_LINK;
case 'i': return RoadType.TERTIARY;
case 'j': return RoadType.RESIDENTIAL;
case 'k': return RoadType.UNCLASSIFIED;
case 'l': return RoadType.ROAD;
case 'm': return RoadType.LIVING_STREET;
case 'n': return RoadType.SERVICE;
case 'o': return RoadType.ROUNDABOUT;
case 'z': return RoadType.COASTLINE;
}
return RoadType.UNCLASSIFIED;
}
/**
* Create a new BinaryGraphReader using the given DataInputStream.
*
* @param dis
*/
public BinaryGraphReader(DataInputStream dis) {
super(MAGIC_NUMBER, VERSION, dis);
}
@Override
public Graph read() throws IOException {
// Read and check magic number and file version.
checkMagicNumberOrThrow(dis.readInt());
checkVersionOrThrow(dis.readInt());
// Read map id.
int mapId = dis.readInt();
// Read zone.
int graphZone = dis.readInt();
// Number of descriptors and nodes.
int nbDesc = dis.readInt();
int nbNodes = dis.readInt();
// Number of successors for each nodes.
int[] nbSuccessors = new int[nbNodes];
// Construct an array list with initial capacity of nbNodes.
ArrayList<Node> nodes = new ArrayList<Node>(nbNodes);
// Read nodes.
for (int node = 0; node < nbNodes; ++node) {
float longitude = ((float)dis.readInt ()) / 1E6f;
float latitude = ((float)dis.readInt ()) / 1E6f;
nbSuccessors[node] = dis.readUnsignedByte();
nodes.add(new Node(node, new Point(longitude, latitude)));
}
// Check format.
checkByteOrThrow(255);
// Read descriptors.
RoadInformation[] descs = new RoadInformation[nbDesc];
// Read
for (int descr = 0; descr < nbDesc; ++descr) {
descs[descr] = readRoadInformation();
}
// Check format.
checkByteOrThrow(254);
// Read successors and convert to arcs.
for (int node = 0; node < nbNodes; ++node) {
for (int succ = 0; succ < nbSuccessors[node]; ++succ) {
// Read destination zone.
int destZone = dis.readUnsignedByte();
// Read target node number.
int destNode = this.read24bits();
// Read information number.
int descrNum = this.read24bits();
// Length of the arc.
int length = dis.readUnsignedShort();
// Number of segments.
int nbSegments = dis.readUnsignedShort();
// Chain of points corresponding to the segments.
ArrayList<Point> points = new ArrayList<Point>(nbSegments + 2);
points.add(nodes.get(node).getPoint());
for (int seg = 0; seg < nbSegments; ++seg) {
Point lastPoint = points.get(points.size() - 1);
float dlon = (dis.readShort()) / 2.0e5f;
float dlat = (dis.readShort()) / 2.0e5f;
points.add(new Point(lastPoint.getLongitude() + dlon,
lastPoint.getLatitude() + dlat));
}
points.add(nodes.get(destNode).getPoint());
if (graphZone == destZone) {
RoadInformation info = descs[descrNum];
Node orig = nodes.get(node);
Node dest = nodes.get(destNode);
// Add successor to initial arc.
orig.addSuccessor(new Arc(dest, length, info, points));
// And reverse arc if its a two-way road.
if (!info.isOneWay()) {
// Add without segments.
dest.addSuccessor(new Arc(orig, length, info));
}
}
}
}
// Check format.
checkByteOrThrow(253);
return new Graph(mapId, nodes);
}
/**
* Read the next road information from the stream.
*
* @throws IOException
*/
private RoadInformation readRoadInformation() throws IOException {
char type = (char)dis.readUnsignedByte();
int x = dis.readUnsignedByte() ;
return new RoadInformation(toRoadType(type), (x & 0x80) > 0, (x & 0x7F) * 5, dis.readUTF());
}
}

View File

@ -0,0 +1,70 @@
package org.insa.graph.io;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import org.insa.graph.Graph;
import org.insa.graph.Node;
import org.insa.graph.Path;
public class BinaryPathReader extends BinaryReader implements AbstractPathReader {
// Map version and magic number targeted for this reader.
private static final int VERSION = 1;
private static final int MAGIC_NUMBER = 0xdecafe;
public BinaryPathReader(DataInputStream dis) {
super(MAGIC_NUMBER, VERSION, dis);
}
@Override
public Path readPath(Graph graph) throws Exception {
// Read and check magic number and version.
checkMagicNumberOrThrow(dis.readInt());
checkVersionOrThrow(dis.readInt());
// Read map ID and check against graph.
int mapId = dis.readInt();
if (mapId != graph.getMapId()) {
throw new MapMismatchException(mapId, graph.getMapId());
}
// Number of nodes in the path (without first and last).
int nbNodes = dis.readInt();
ArrayList<Node> nodes = new ArrayList<Node>(nbNodes + 2);
// Read first node
nodes.add(readNode(graph));
// Read last node
Node lastNode = readNode(graph);
// Read intermediate nodes:
for (int node = 0; node < nbNodes; ++node) {
nodes.add(readNode(graph));
}
// Add last node
nodes.add(lastNode);
return new Path(graph, nodes);
}
/**
* Read a node from the stream and returns id.
*
* @return
* @throws IOException
*/
protected Node readNode(Graph graph) throws IOException {
// Discard zone.
dis.readUnsignedByte();
return graph.getNodes().get(read24bits());
}
}

View File

@ -0,0 +1,67 @@
package org.insa.graph.io;
import java.io.DataInputStream;
import java.io.IOException;
public abstract class BinaryReader {
// Map version and magic number targeted for this reader.
private int version;
private int magicNumber;
// InputStream
protected DataInputStream dis;
protected BinaryReader(int magicNumber, int version, DataInputStream dis) {
this.magicNumber = magicNumber;
this.version = version;
this.dis = dis;
}
/**
* @param version
* @throws BadVersionException
*/
public void checkVersionOrThrow(int version) throws BadVersionException {
if (this.version != version) {
throw new BadVersionException(version, this.version);
}
}
/**
* @param magicNumber
* @throws BadMagicNumberException
*/
public void checkMagicNumberOrThrow(int magicNumber) throws BadMagicNumberException {
if (this.magicNumber != magicNumber) {
throw new BadMagicNumberException(magicNumber, this.magicNumber);
}
}
/**
* Check if the next byte in the input stream correspond to the
* given byte. This function consumes the next byte in the input
* stream.
*
* @param i Byte to check against.
*
* @throws IOException
*/
public void checkByteOrThrow(int i) throws IOException {
if (dis.readUnsignedByte() != i) {
throw new BadFormatException();
}
}
/**
* Read 24 bits from the stream and return the corresponding integer value.
*
* @return Integer value read from the next 24 bits of the stream.
*
* @throws IOException
*/
protected int read24bits() throws IOException {
int x = dis.readUnsignedShort() ;
return (x << 8) | dis.readUnsignedByte() ;
}
}

View File

@ -0,0 +1,36 @@
package org.insa.graph.io;
public class MapMismatchException extends Exception {
/**
*
*/
private static final long serialVersionUID = 3076730078387819138L;
// Actual and expected magic numbers.
private int actualMapId, expectedMapId;
/**
*
* @param actualVersion
* @param expectedVersion
*/
public MapMismatchException(int actualMapId, int expectedMapId) {
super();
this.actualMapId = actualMapId;
this.expectedMapId = expectedMapId;
}
/**
* @return
*/
public int getActualMapId() {
return actualMapId;
}
/**
* @return
*/
public int getExpectedMapId() {
return expectedMapId;
}
}

View File

@ -0,0 +1,252 @@
//
// ******************PUBLIC OPERATIONS*********************
// void insert( x ) --> Insert x
// Comparable deleteMin( )--> Return and remove smallest item
// Comparable findMin( ) --> Return smallest item
// boolean isEmpty( ) --> Return true if empty; else false
// ******************ERRORS********************************
// Throws RuntimeException for findMin and deleteMin when empty
package org.insa.utility;
import java.util.* ;
/**
* Implements a binary heap.
* Note that all "matching" is based on the compareTo method.
* @author Mark Allen Weiss
* @author DLB
*/
public class BinaryHeap<E extends Comparable<E>> {
private int currentSize; // Number of elements in heap
// Java genericity does not work with arrays.
// We have to use an ArrayList
private ArrayList<E> array; // The heap array
/**
* Construct the binary heap.
*/
public BinaryHeap() {
this.currentSize = 0;
this.array = new ArrayList<E>() ;
}
// Constructor used for debug.
public BinaryHeap(BinaryHeap<E> heap) {
this.currentSize = heap.currentSize ;
this.array = new ArrayList<E>(heap.array) ;
}
// Sets an element in the array
private void arraySet(int index, E value) {
if (index == this.array.size()) {
this.array.add(value) ;
}
else {
this.array.set(index, value) ;
}
}
/**
* Test if the heap is logically empty.
* @return true if empty, false otherwise.
*/
public boolean isEmpty() { return this.currentSize == 0; }
/**
* Returns size.
* @return current size.
*/
public int size() { return this.currentSize; }
/**
* Returns index of parent.
*/
private int index_parent(int index) {
return (index - 1) / 2 ;
}
/**
* Returns index of left child.
*/
private int index_left(int index) {
return index * 2 + 1 ;
}
/**
* Insert into the heap.
* @param x the item to insert.
*/
public void insert(E x) {
int index = this.currentSize++ ;
this.arraySet(index, x) ;
this.percolateUp(index) ;
}
/**
* Internal method to percolate up in the heap.
* @param index the index at which the percolate begins.
*/
private void percolateUp(int index) {
E x = this.array.get(index) ;
for( ; index > 0 && x.compareTo(this.array.get(index_parent(index)) ) < 0; index = index_parent(index) ) {
E moving_val = this.array.get(index_parent(index)) ;
this.arraySet(index, moving_val) ;
}
this.arraySet(index, x) ;
}
/**
* Internal method to percolate down in the heap.
* @param index the index at which the percolate begins.
*/
private void percolateDown(int index) {
int ileft = index_left(index) ;
int iright = ileft + 1 ;
if (ileft < this.currentSize) {
E current = this.array.get(index) ;
E left = this.array.get(ileft) ;
boolean hasRight = iright < this.currentSize ;
E right = (hasRight)?this.array.get(iright):null ;
if (!hasRight || left.compareTo(right) < 0) {
// Left is smaller
if (left.compareTo(current) < 0) {
this.arraySet(index, left) ;
this.arraySet(ileft, current) ;
this.percolateDown( ileft ) ;
}
}
else {
// Right is smaller
if (right.compareTo(current) < 0) {
this.arraySet(index, right) ;
this.arraySet(iright, current) ;
this.percolateDown( iright ) ;
}
}
}
}
/**
* Find the smallest item in the heap.
* @return the smallest item.
* @throws Exception if empty.
*/
public E findMin( ) {
if( isEmpty() )
throw new RuntimeException( "Empty binary heap" );
return this.array.get(0);
}
/**
* Remove the smallest item from the heap.
* @return the smallest item.
* @throws Exception if empty.
*/
public E deleteMin( ) {
E minItem = findMin( );
E lastItem = this.array.get(--this.currentSize) ;
this.arraySet(0, lastItem) ;
this.percolateDown( 0 );
return minItem;
}
/**
* Prints the heap
*/
public void print() {
System.out.println() ;
System.out.println("======== HEAP (size = " + this.currentSize + ") ========") ;
System.out.println() ;
for (int i = 0 ; i < this.currentSize ; i++) {
System.out.println(this.array.get(i).toString()) ;
}
System.out.println() ;
System.out.println("-------- End of heap --------") ;
System.out.println() ;
}
/**
* Prints the elements of the heap according to their respective order.
*/
public void printSorted() {
BinaryHeap<E> copy = new BinaryHeap<E>(this) ;
System.out.println() ;
System.out.println("======== Sorted HEAP (size = " + this.currentSize + ") ========") ;
System.out.println() ;
while (!copy.isEmpty()) {
System.out.println(copy.deleteMin()) ;
}
System.out.println() ;
System.out.println("-------- End of heap --------") ;
System.out.println() ;
}
// Test program : compare with the reference implementation PriorityQueue.
public static void main(String [] args) {
BinaryHeap<Integer> heap = new BinaryHeap<Integer>() ;
PriorityQueue<Integer> queue = new PriorityQueue<Integer>() ;
int count = 0 ;
int blocksize = 10000 ;
System.out.println("Interrupt to stop the test.") ;
while (true) {
// Insert up to blocksize elements
int nb_insert = (int)(Math.random() * (blocksize + 1)) ;
for (int i = 0 ; i < nb_insert ; i++) {
Integer obj = new Integer(i) ;
heap.insert(obj) ;
queue.add(obj) ;
}
// Remove up to blocksize elements
int nb_remove = (int)(Math.random() * blocksize * 1.1) ;
if (nb_remove > queue.size()) {
nb_remove = queue.size() ;
}
for (int i = 0 ; i < nb_remove ; i++) {
int removed1 = queue.poll().intValue() ;
int removed2 = heap.deleteMin().intValue() ;
if (removed1 != removed2) {
System.out.println("Ouch : expected " + removed1 + " .. but got " + removed2) ;
System.exit(1) ;
}
}
if (heap.size() != queue.size()) {
System.out.println("Ouch : heap size = " + heap.size() + " queue size = " + queue.size() ) ;
System.exit(1) ;
}
count += nb_remove ;
if (count > 1000000) {
System.out.println("" + count + " items successfully compared. Heap size : " + heap.size()) ;
count = 0 ;
}
}
}
}

View File

@ -0,0 +1,68 @@
package org.insa.utility;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.stream.IntStream;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class BinaryHeapTest {
private BinaryHeap<Integer> rangeHeap1;
static IntStream dataRange1() {
return IntStream.range(0, 20);
}
@BeforeAll
static void initAll() {
}
@BeforeEach
void init() {
// Create the range heap
this.rangeHeap1 = new BinaryHeap<Integer>();
dataRange1().forEach((int x) -> rangeHeap1.insert(x));
}
@Test
void testInsert() {
BinaryHeap<Integer> heap = new BinaryHeap<Integer>();
int size = 0;
for (int x: dataRange1().toArray()) {
heap.insert(x);
size += 1;
assertEquals(heap.size(), size);
}
}
@Test
void testDeleteMin() {
int[] range1 = dataRange1().toArray();
int size = range1.length;
assertEquals(rangeHeap1.size(), size);
for (int x: range1) {
assertEquals(rangeHeap1.deleteMin().intValue(), x);
size -= 1;
assertEquals(rangeHeap1.size(), size);
}
}
@AfterEach
void tearDown() {
}
@AfterAll
static void tearDownAll() {
}
}