Update code.
This commit is contained in:
		
							parent
							
								
									a6e8a22081
								
							
						
					
					
						commit
						71accfe13b
					
				
					 18 changed files with 436 additions and 266 deletions
				
			
		
							
								
								
									
										15
									
								
								.classpath
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								.classpath
									
									
									
									
									
								
							|  | @ -18,21 +18,6 @@ | ||||||
| 		</attributes> | 		</attributes> | ||||||
| 	</classpathentry> | 	</classpathentry> | ||||||
| 	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/> | 	<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="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> | 	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> | ||||||
| 		<attributes> | 		<attributes> | ||||||
| 			<attribute name="maven.pomderived" value="true"/> | 			<attribute name="maven.pomderived" value="true"/> | ||||||
|  |  | ||||||
|  | @ -1,24 +1,22 @@ | ||||||
| package org.insa.algo ; | package org.insa.algo ; | ||||||
| 
 | 
 | ||||||
|  | import java.time.Duration; | ||||||
|  | import java.time.Instant; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| 
 | 
 | ||||||
| public abstract class AbstractAlgorithm implements Runnable { | public abstract class AbstractAlgorithm<Observer> { | ||||||
| 
 | 
 | ||||||
|     protected AbstractInstance instance; |     protected AbstractInstance instance; | ||||||
|     protected AbstractSolution solution; |     protected ArrayList<Observer> observers; | ||||||
| 
 |  | ||||||
|     protected ArrayList<AbstractObserver> observers; |  | ||||||
|      |      | ||||||
|     protected AbstractAlgorithm(AbstractInstance instance) { |     protected AbstractAlgorithm(AbstractInstance instance) { | ||||||
| 		this.instance = instance; | 		this.instance = instance; | ||||||
| 		this.observers = new ArrayList<AbstractObserver>();	 | 		this.observers = new ArrayList<Observer>();	 | ||||||
| 		this.solution = null; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected AbstractAlgorithm(AbstractInstance instance, ArrayList<AbstractObserver> observers) { |     protected AbstractAlgorithm(AbstractInstance instance, ArrayList<Observer> observers) { | ||||||
|     		this.instance = instance; |     		this.instance = instance; | ||||||
|     		this.observers = observers;;	 |     		this.observers = observers;;	 | ||||||
|     		this.solution = null; |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|  | @ -26,44 +24,32 @@ public abstract class AbstractAlgorithm implements Runnable { | ||||||
|      *  |      *  | ||||||
|      * @param observer |      * @param observer | ||||||
|      */ |      */ | ||||||
|     public void addObserver(AbstractObserver observer) { |     public void addObserver(Observer observer) { | ||||||
|     		observers.add(observer); |     		observers.add(observer); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * @return The list of observers for this algorithm. |      * @return The list of observers for this algorithm. | ||||||
|      */ |      */ | ||||||
|     public ArrayList<AbstractObserver> getObservers() { |     public ArrayList<Observer> getObservers() { | ||||||
|     		return observers; |     		return observers; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |  | ||||||
|      * 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. |      * @return Instance corresponding to this algorithm. | ||||||
|      */ |      */ | ||||||
|     public AbstractInstance getInstance() { return instance; } |     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. |      * Run the algorithm and update the current solution. | ||||||
|      *  |      *  | ||||||
|      * @return true if a feasible solution was found (even non-optimal). |      * @return true if a feasible solution was found (even non-optimal). | ||||||
|      */ |      */ | ||||||
|     public void run() { |     public AbstractSolution run() { | ||||||
|     		this.solution = this.doRun(); |     		Instant start = Instant.now(); | ||||||
|  |     		AbstractSolution solution = this.doRun(); | ||||||
|  |     		solution.setSolvingTime(Duration.between(start, Instant.now())); | ||||||
|  |     		return solution; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|  |  | ||||||
|  | @ -1,20 +0,0 @@ | ||||||
| package org.insa.algo; |  | ||||||
| 
 |  | ||||||
| public abstract class AbstractObserver { |  | ||||||
| 	 |  | ||||||
| 	// Specify if the observer is graphic or not. |  | ||||||
| 	private final boolean isgraphic; |  | ||||||
| 	 |  | ||||||
| 	protected AbstractObserver(boolean isGraphic) { |  | ||||||
| 		this.isgraphic = isGraphic; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/** |  | ||||||
| 	 * @return true if this observer is graphic (use drawing to display |  | ||||||
| 	 * information). |  | ||||||
| 	 */ |  | ||||||
| 	public boolean isGraphic() { |  | ||||||
| 		return isgraphic; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| } |  | ||||||
|  | @ -35,10 +35,8 @@ public abstract class AbstractSolution { | ||||||
| 		this.status = Status.UNKNOWN; | 		this.status = Status.UNKNOWN; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	protected AbstractSolution(AbstractInstance instance,  | 	protected AbstractSolution(AbstractInstance instance, Status status) { | ||||||
| 							  Duration solvingTime, Status status) { |  | ||||||
| 		this.instance = instance; | 		this.instance = instance; | ||||||
| 		this.solvingTime = solvingTime; |  | ||||||
| 		this.status = status; | 		this.status = status; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | @ -57,6 +55,15 @@ public abstract class AbstractSolution { | ||||||
| 	 */ | 	 */ | ||||||
| 	public Duration getSolvingTime() { return solvingTime; } | 	public Duration getSolvingTime() { return solvingTime; } | ||||||
| 	 | 	 | ||||||
|  | 	/** | ||||||
|  | 	 * Set the solving time of this solution. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param solvingTime Solving time for the solution. | ||||||
|  | 	 */ | ||||||
|  | 	protected void setSolvingTime(Duration solvingTime) { | ||||||
|  | 		this.solvingTime = solvingTime; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 * @return true if the solution is feasible or optimal. | 	 * @return true if the solution is feasible or optimal. | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
|  | @ -0,0 +1,30 @@ | ||||||
|  | package org.insa.algo.strongconnectivity; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | 
 | ||||||
|  | import org.insa.graph.Node; | ||||||
|  | 
 | ||||||
|  | public interface StronglyConnectedComponentObserver { | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Notify that the algorithm is entering a new component. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param curNode Starting node for the component. | ||||||
|  | 	 */ | ||||||
|  | 	public void notifyStartComponent(Node curNode); | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  | 	 * Notify that a new node has been found for the current component. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param node New node found for the current component. | ||||||
|  | 	 */ | ||||||
|  | 	public void notifyNewNodeInComponent(Node node); | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  | 	 * Notify that the algorithm has computed a new component. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param nodes List of nodes in the component. | ||||||
|  | 	 */ | ||||||
|  | 	public void notifyEndComponent(ArrayList<Node> nodes); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -2,7 +2,7 @@ package org.insa.algo.strongconnectivity ; | ||||||
| 
 | 
 | ||||||
| import org.insa.algo.AbstractAlgorithm; | import org.insa.algo.AbstractAlgorithm; | ||||||
| 
 | 
 | ||||||
| public abstract class StronglyConnectedComponentsAlgorithm extends AbstractAlgorithm { | public abstract class StronglyConnectedComponentsAlgorithm extends AbstractAlgorithm<StronglyConnectedComponentObserver> { | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 *  | 	 *  | ||||||
|  | @ -13,4 +13,14 @@ public abstract class StronglyConnectedComponentsAlgorithm extends AbstractAlgor | ||||||
| 		super(instance); | 		super(instance); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	@Override | ||||||
|  | 	public StronglyConnectedComponentsSolution run() { | ||||||
|  | 		return (StronglyConnectedComponentsSolution)super.run(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	@Override | ||||||
|  | 	public StronglyConnectedComponentsInstance getInstance() { | ||||||
|  | 		return (StronglyConnectedComponentsInstance)super.getInstance(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| package org.insa.algo.strongconnectivity; | package org.insa.algo.strongconnectivity; | ||||||
| 
 | 
 | ||||||
| import java.time.Duration; |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| 
 | 
 | ||||||
| import org.insa.algo.AbstractSolution; | import org.insa.algo.AbstractSolution; | ||||||
|  | @ -16,8 +15,8 @@ public class StronglyConnectedComponentsSolution extends AbstractSolution { | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	protected StronglyConnectedComponentsSolution(StronglyConnectedComponentsInstance instance,  | 	protected StronglyConnectedComponentsSolution(StronglyConnectedComponentsInstance instance,  | ||||||
| 					   Duration solvingTime, Status status, ArrayList<ArrayList<Node>> components) { | 					   Status status, ArrayList<ArrayList<Node>> components) { | ||||||
| 		super(instance, solvingTime, status); | 		super(instance, status); | ||||||
| 		this.components = components; | 		this.components = components; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  |  | ||||||
|  | @ -1,12 +1,9 @@ | ||||||
| package org.insa.algo.strongconnectivity; | package org.insa.algo.strongconnectivity; | ||||||
| 
 | 
 | ||||||
| import java.time.Duration; |  | ||||||
| import java.time.Instant; |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Stack; | import java.util.Stack; | ||||||
| 
 | 
 | ||||||
| import org.insa.algo.AbstractSolution; |  | ||||||
| import org.insa.algo.AbstractSolution.Status; | import org.insa.algo.AbstractSolution.Status; | ||||||
| import org.insa.graph.Arc; | import org.insa.graph.Arc; | ||||||
| import org.insa.graph.Graph; | import org.insa.graph.Graph; | ||||||
|  | @ -74,7 +71,6 @@ public class TarjanAlgorithm extends StronglyConnectedComponentsAlgorithm { | ||||||
| 	 * @return The strong component containing the given node. | 	 * @return The strong component containing the given node. | ||||||
| 	 */ | 	 */ | ||||||
| 	protected void findAndAddStrongComponent(Node v) { | 	protected void findAndAddStrongComponent(Node v) { | ||||||
| 		Graph graph = getInstance().getGraph(); |  | ||||||
| 		 | 		 | ||||||
| 		// Update node info, index and push the node. | 		// Update node info, index and push the node. | ||||||
| 		indexes[v.getId()] = index; | 		indexes[v.getId()] = index; | ||||||
|  | @ -117,14 +113,11 @@ public class TarjanAlgorithm extends StronglyConnectedComponentsAlgorithm { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	protected AbstractSolution doRun() { | 	protected StronglyConnectedComponentsSolution doRun() { | ||||||
| 		Graph graph = getInstance().getGraph(); | 		Graph graph = getInstance().getGraph(); | ||||||
| 		 | 		 | ||||||
| 		components = new ArrayList<ArrayList<Node>>(); | 		components = new ArrayList<ArrayList<Node>>(); | ||||||
| 		 | 		 | ||||||
| 		// Starting time... |  | ||||||
| 		Instant start = Instant.now(); |  | ||||||
| 		 |  | ||||||
| 		// Initialize everything | 		// Initialize everything | ||||||
| 		final int nbNodes = graph.getNodes().size(); | 		final int nbNodes = graph.getNodes().size(); | ||||||
| 		stack = new Stack<Node>(); | 		stack = new Stack<Node>(); | ||||||
|  | @ -145,11 +138,7 @@ public class TarjanAlgorithm extends StronglyConnectedComponentsAlgorithm { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		// Duration... | 		return new StronglyConnectedComponentsSolution(getInstance(), Status.OPTIMAL, components); | ||||||
| 		Duration solvingTime = Duration.between(start, Instant.now()); |  | ||||||
| 		 |  | ||||||
| 		return new StronglyConnectedComponentsSolution((StronglyConnectedComponentsInstance)getInstance(), |  | ||||||
| 					   solvingTime, Status.OPTIMAL, components); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ import org.insa.drawing.Drawing; | ||||||
| import org.insa.drawing.graph.GraphDrawing; | import org.insa.drawing.graph.GraphDrawing; | ||||||
| import org.insa.graph.Node; | import org.insa.graph.Node; | ||||||
| 
 | 
 | ||||||
| public class WeaklyConnectedComponentGraphicObserver extends WeaklyConnectedComponentObserver { | public class WeaklyConnectedComponentGraphicObserver implements WeaklyConnectedComponentObserver { | ||||||
| 	 | 	 | ||||||
| 	private static final Color[] COLORS = { | 	private static final Color[] COLORS = { | ||||||
| 		Color.BLUE, Color.ORANGE, Color.GREEN, Color.YELLOW, Color.RED | 		Color.BLUE, Color.ORANGE, Color.GREEN, Color.YELLOW, Color.RED | ||||||
|  | @ -21,7 +21,6 @@ public class WeaklyConnectedComponentGraphicObserver extends WeaklyConnectedComp | ||||||
| 	private int cindex = 0; | 	private int cindex = 0; | ||||||
| 	 | 	 | ||||||
| 	public WeaklyConnectedComponentGraphicObserver(Drawing drawing) { | 	public WeaklyConnectedComponentGraphicObserver(Drawing drawing) { | ||||||
| 		super(true); |  | ||||||
| 		this.drawing = drawing; | 		this.drawing = drawing; | ||||||
| 		this.gdrawing = new GraphDrawing(drawing); | 		this.gdrawing = new GraphDrawing(drawing); | ||||||
| 		this.drawing.setAutoRepaint(true); | 		this.drawing.setAutoRepaint(true); | ||||||
|  |  | ||||||
|  | @ -2,37 +2,29 @@ package org.insa.algo.weakconnectivity; | ||||||
| 
 | 
 | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| 
 | 
 | ||||||
| import org.insa.algo.AbstractObserver; |  | ||||||
| import org.insa.graph.Node; | import org.insa.graph.Node; | ||||||
| 
 | 
 | ||||||
| public abstract class WeaklyConnectedComponentObserver extends AbstractObserver { | public interface WeaklyConnectedComponentObserver { | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * {@inheritDoc} |  | ||||||
| 	 */ |  | ||||||
| 	protected WeaklyConnectedComponentObserver(boolean isGraphic) { |  | ||||||
| 		super(isGraphic); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Notify that the algorithm is entering a new component. | 	 * Notify that the algorithm is entering a new component. | ||||||
| 	 *  | 	 *  | ||||||
| 	 * @param curNode Starting node for the component. | 	 * @param curNode Starting node for the component. | ||||||
| 	 */ | 	 */ | ||||||
| 	public abstract void notifyStartComponent(Node curNode); | 	public void notifyStartComponent(Node curNode); | ||||||
| 	 | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 * Notify that a new node has been found for the current component. | 	 * Notify that a new node has been found for the current component. | ||||||
| 	 *  | 	 *  | ||||||
| 	 * @param node New node found for the current component. | 	 * @param node New node found for the current component. | ||||||
| 	 */ | 	 */ | ||||||
| 	public abstract void notifyNewNodeInComponent(Node node); | 	public void notifyNewNodeInComponent(Node node); | ||||||
| 	 | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 * Notify that the algorithm has computed a new component. | 	 * Notify that the algorithm has computed a new component. | ||||||
| 	 *  | 	 *  | ||||||
| 	 * @param nodes List of nodes in the component. | 	 * @param nodes List of nodes in the component. | ||||||
| 	 */ | 	 */ | ||||||
| 	public abstract void notifyEndComponent(ArrayList<Node> nodes); | 	public void notifyEndComponent(ArrayList<Node> nodes); | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ import java.util.ArrayList; | ||||||
| 
 | 
 | ||||||
| import org.insa.graph.Node; | import org.insa.graph.Node; | ||||||
| 
 | 
 | ||||||
| public class WeaklyConnectedComponentTextObserver extends WeaklyConnectedComponentObserver { | public class WeaklyConnectedComponentTextObserver implements WeaklyConnectedComponentObserver { | ||||||
| 	 | 	 | ||||||
| 	// Number of the current component. | 	// Number of the current component. | ||||||
| 	private int numComponent = 1; | 	private int numComponent = 1; | ||||||
|  | @ -14,7 +14,6 @@ public class WeaklyConnectedComponentTextObserver extends WeaklyConnectedCompone | ||||||
| 	PrintStream stream; | 	PrintStream stream; | ||||||
| 
 | 
 | ||||||
| 	public WeaklyConnectedComponentTextObserver(PrintStream stream) { | 	public WeaklyConnectedComponentTextObserver(PrintStream stream) { | ||||||
| 		super(false); |  | ||||||
| 		this.stream = stream; | 		this.stream = stream; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,23 +1,18 @@ | ||||||
| package org.insa.algo.weakconnectivity; | package org.insa.algo.weakconnectivity; | ||||||
| 
 | 
 | ||||||
| import java.time.Duration; |  | ||||||
| import java.time.Instant; |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.LinkedList; | import java.util.LinkedList; | ||||||
| import java.util.Queue; | import java.util.Queue; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| 
 | 
 | ||||||
| import org.insa.algo.AbstractAlgorithm; | import org.insa.algo.AbstractAlgorithm; | ||||||
| import org.insa.algo.AbstractObserver; |  | ||||||
| import org.insa.algo.AbstractSolution; |  | ||||||
| import org.insa.algo.AbstractSolution.Status; | import org.insa.algo.AbstractSolution.Status; | ||||||
| import org.insa.graph.Arc; | import org.insa.graph.Arc; | ||||||
| import org.insa.graph.Graph; | import org.insa.graph.Graph; | ||||||
| import org.insa.graph.Node; | import org.insa.graph.Node; | ||||||
| 
 | 
 | ||||||
| public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm { | public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm<WeaklyConnectedComponentObserver>{ | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 *  | 	 *  | ||||||
|  | @ -28,6 +23,49 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm { | ||||||
| 		super(instance); | 		super(instance); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	@Override | ||||||
|  | 	public WeaklyConnectedComponentsSolution run() { | ||||||
|  | 		return (WeaklyConnectedComponentsSolution)super.run(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	@Override | ||||||
|  | 	public WeaklyConnectedComponentsInstance getInstance() { | ||||||
|  | 		return (WeaklyConnectedComponentsInstance)super.getInstance(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  | 	 * Notify all observers that the algorithm is entering a new component. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param curNode Starting node for the component. | ||||||
|  | 	 */ | ||||||
|  | 	protected void notifyStartComponent(Node curNode) { | ||||||
|  | 		for (WeaklyConnectedComponentObserver obs: getObservers()) { | ||||||
|  | 			obs.notifyStartComponent(curNode); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  | 	 * Notify all observers that a new node has been found for the current component. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param node New node found for the current component. | ||||||
|  | 	 */ | ||||||
|  | 	protected void notifyNewNodeInComponent(Node node) { | ||||||
|  | 		for (WeaklyConnectedComponentObserver obs: getObservers()) { | ||||||
|  | 			obs.notifyNewNodeInComponent(node); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  | 	 * Notify all observers that the algorithm has computed a new component. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param nodes List of nodes in the component. | ||||||
|  | 	 */ | ||||||
|  | 	protected void notifyEndComponent(ArrayList<Node> nodes) { | ||||||
|  | 		for (WeaklyConnectedComponentObserver obs: getObservers()) { | ||||||
|  | 			obs.notifyEndComponent(nodes); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 * @return An adjacency list for the undirected graph equivalent to the stored graph. | 	 * @return An adjacency list for the undirected graph equivalent to the stored graph. | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -66,9 +104,8 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm { | ||||||
| 		// Using a queue because we are doing a BFS | 		// Using a queue because we are doing a BFS | ||||||
| 		Queue<Integer> queue = new LinkedList<Integer>(); | 		Queue<Integer> queue = new LinkedList<Integer>(); | ||||||
| 
 | 
 | ||||||
| 		for (AbstractObserver obs: getObservers()) { | 		// Notify observers about the current component. | ||||||
| 			((WeaklyConnectedComponentObserver)obs).notifyStartComponent(nodes.get(cur)); | 		notifyStartComponent(nodes.get(cur)); | ||||||
| 		} |  | ||||||
| 		 | 		 | ||||||
| 		// Add original node and loop until the queue is empty. | 		// Add original node and loop until the queue is empty. | ||||||
| 		queue.add(cur); | 		queue.add(cur); | ||||||
|  | @ -77,8 +114,8 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm { | ||||||
| 			Node node = nodes.get(queue.remove()); | 			Node node = nodes.get(queue.remove()); | ||||||
| 			component.add(node); | 			component.add(node); | ||||||
| 			 | 			 | ||||||
| 			// notify observers | 			// Notify observers | ||||||
| 			for (AbstractObserver obs: getObservers()) ((WeaklyConnectedComponentObserver)obs).notifyNewNodeInComponent(node); | 			notifyNewNodeInComponent(node); | ||||||
| 			 | 			 | ||||||
| 			for (Integer destId: ugraph.get(node.getId())) { | 			for (Integer destId: ugraph.get(node.getId())) { | ||||||
| 				Node dest = nodes.get(destId); | 				Node dest = nodes.get(destId); | ||||||
|  | @ -89,17 +126,13 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		for (AbstractObserver obs: getObservers()) { | 		notifyEndComponent(component); | ||||||
| 			((WeaklyConnectedComponentObserver)obs).notifyEndComponent(component); |  | ||||||
| 		} |  | ||||||
| 		 | 		 | ||||||
| 		return component; | 		return component; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	protected AbstractSolution doRun() { | 	protected WeaklyConnectedComponentsSolution doRun() { | ||||||
| 		 |  | ||||||
| 		Instant start = Instant.now(); |  | ||||||
| 		 | 		 | ||||||
| 		Graph graph = getInstance().getGraph(); | 		Graph graph = getInstance().getGraph(); | ||||||
| 		ArrayList<HashSet<Integer>> ugraph = createUndirectedGraph(); | 		ArrayList<HashSet<Integer>> ugraph = createUndirectedGraph(); | ||||||
|  | @ -118,10 +151,7 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm { | ||||||
| 			for (; cur < marked.length && marked[cur]; ++cur); | 			for (; cur < marked.length && marked[cur]; ++cur); | ||||||
| 		} | 		} | ||||||
| 				 | 				 | ||||||
| 		Duration solvingTime = Duration.between(start, Instant.now()); | 		return new WeaklyConnectedComponentsSolution(getInstance(), Status.OPTIMAL, components); | ||||||
| 		 |  | ||||||
| 		return new WeaklyConnectedComponentsSolution((WeaklyConnectedComponentsInstance)getInstance(),  |  | ||||||
| 				solvingTime, Status.OPTIMAL, components); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| package org.insa.algo.weakconnectivity; | package org.insa.algo.weakconnectivity; | ||||||
| 
 | 
 | ||||||
| import java.time.Duration; |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| 
 | 
 | ||||||
| import org.insa.algo.AbstractSolution; | import org.insa.algo.AbstractSolution; | ||||||
|  | @ -16,8 +15,8 @@ public class WeaklyConnectedComponentsSolution extends AbstractSolution { | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	protected WeaklyConnectedComponentsSolution(WeaklyConnectedComponentsInstance instance,  | 	protected WeaklyConnectedComponentsSolution(WeaklyConnectedComponentsInstance instance,  | ||||||
| 					   Duration solvingTime, Status status, ArrayList<ArrayList<Node>> components) { | 					   Status status, ArrayList<ArrayList<Node>> components) { | ||||||
| 		super(instance, solvingTime, status); | 		super(instance, status); | ||||||
| 		this.components = components; | 		this.components = components; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  |  | ||||||
|  | @ -5,17 +5,23 @@ import java.awt.Color; | ||||||
| import java.awt.Dimension; | import java.awt.Dimension; | ||||||
| import java.awt.event.ActionEvent; | import java.awt.event.ActionEvent; | ||||||
| import java.awt.event.ActionListener; | import java.awt.event.ActionListener; | ||||||
|  | import java.awt.event.KeyEvent; | ||||||
|  | import java.awt.event.MouseAdapter; | ||||||
|  | import java.awt.event.MouseEvent; | ||||||
|  | import java.awt.event.MouseListener; | ||||||
| import java.awt.event.WindowAdapter; | import java.awt.event.WindowAdapter; | ||||||
| import java.awt.event.WindowEvent; | import java.awt.event.WindowEvent; | ||||||
|  | import java.awt.geom.NoninvertibleTransformException; | ||||||
|  | import java.awt.geom.Point2D; | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||||
| import java.io.PrintStream; | import java.io.PrintStream; | ||||||
| import java.lang.reflect.Constructor; | import java.time.Duration; | ||||||
|  | import java.time.Instant; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| 
 | 
 | ||||||
| import javax.swing.BorderFactory; | import javax.swing.BorderFactory; | ||||||
| import javax.swing.BoxLayout; |  | ||||||
| import javax.swing.JButton; | import javax.swing.JButton; | ||||||
| import javax.swing.JFileChooser; | import javax.swing.JFileChooser; | ||||||
| import javax.swing.JFrame; | import javax.swing.JFrame; | ||||||
|  | @ -30,10 +36,10 @@ import javax.swing.JSplitPane; | ||||||
| import javax.swing.JTextArea; | import javax.swing.JTextArea; | ||||||
| import javax.swing.KeyStroke; | import javax.swing.KeyStroke; | ||||||
| import javax.swing.SwingConstants; | import javax.swing.SwingConstants; | ||||||
|  | import javax.swing.Timer; | ||||||
| import javax.swing.UIManager; | import javax.swing.UIManager; | ||||||
| import javax.swing.filechooser.FileNameExtensionFilter; | import javax.swing.filechooser.FileNameExtensionFilter; | ||||||
| 
 | 
 | ||||||
| import org.insa.algo.AbstractSolution; |  | ||||||
| import org.insa.algo.shortestpath.BellmanFordAlgorithm; | import org.insa.algo.shortestpath.BellmanFordAlgorithm; | ||||||
| import org.insa.algo.shortestpath.ShortestPathAlgorithm; | import org.insa.algo.shortestpath.ShortestPathAlgorithm; | ||||||
| import org.insa.algo.shortestpath.ShortestPathGraphicObserver; | import org.insa.algo.shortestpath.ShortestPathGraphicObserver; | ||||||
|  | @ -41,7 +47,6 @@ import org.insa.algo.shortestpath.ShortestPathInstance; | ||||||
| import org.insa.algo.shortestpath.ShortestPathInstance.Mode; | import org.insa.algo.shortestpath.ShortestPathInstance.Mode; | ||||||
| import org.insa.algo.shortestpath.ShortestPathSolution; | import org.insa.algo.shortestpath.ShortestPathSolution; | ||||||
| import org.insa.algo.weakconnectivity.WeaklyConnectedComponentGraphicObserver; | import org.insa.algo.weakconnectivity.WeaklyConnectedComponentGraphicObserver; | ||||||
| import org.insa.algo.weakconnectivity.WeaklyConnectedComponentTextObserver; |  | ||||||
| import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm; | import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm; | ||||||
| import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsInstance; | import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsInstance; | ||||||
| import org.insa.drawing.Drawing; | import org.insa.drawing.Drawing; | ||||||
|  | @ -49,17 +54,17 @@ import org.insa.drawing.graph.BlackAndWhiteGraphPalette; | ||||||
| import org.insa.drawing.graph.GraphDrawing; | import org.insa.drawing.graph.GraphDrawing; | ||||||
| import org.insa.drawing.graph.PathDrawing; | import org.insa.drawing.graph.PathDrawing; | ||||||
| import org.insa.graph.Graph; | import org.insa.graph.Graph; | ||||||
|  | import org.insa.graph.Node; | ||||||
| import org.insa.graph.Path; | import org.insa.graph.Path; | ||||||
|  | import org.insa.graph.Point; | ||||||
| import org.insa.graph.io.BinaryGraphReader; | import org.insa.graph.io.BinaryGraphReader; | ||||||
| import org.insa.graph.io.BinaryPathReader; | import org.insa.graph.io.BinaryPathReader; | ||||||
| import org.insa.graph.io.MapMismatchException; | import org.insa.graph.io.MapMismatchException; | ||||||
| import org.insa.graph.io.Openfile; | import org.insa.graph.io.Openfile; | ||||||
| 
 | 
 | ||||||
| import com.sun.glass.events.KeyEvent; |  | ||||||
| 
 |  | ||||||
| public class MainWindow extends JFrame { | public class MainWindow extends JFrame { | ||||||
| 
 | 
 | ||||||
| 	public class JOutputStream extends OutputStream { | 	protected class JOutputStream extends OutputStream { | ||||||
| 		private JTextArea textArea; | 		private JTextArea textArea; | ||||||
| 
 | 
 | ||||||
| 		public JOutputStream(JTextArea textArea) { | 		public JOutputStream(JTextArea textArea) { | ||||||
|  | @ -77,6 +82,90 @@ public class MainWindow extends JFrame { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	protected interface CallableWithNodes { | ||||||
|  | 		 | ||||||
|  | 		void call(ArrayList<Node> nodes); | ||||||
|  | 		 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	protected class DrawingClickListener extends MouseAdapter { | ||||||
|  | 	 | ||||||
|  | 		// Enable/Disable. | ||||||
|  | 		private boolean enabled = false; | ||||||
|  | 
 | ||||||
|  | 		// List of points. | ||||||
|  | 		private ArrayList<Node> points = new ArrayList<Node>(); | ||||||
|  | 		 | ||||||
|  | 		// Number of points to find before running. | ||||||
|  | 		private int nTargetPoints = 0; | ||||||
|  | 		 | ||||||
|  | 		// Callable to call when points are reached. | ||||||
|  | 		CallableWithNodes callable = null; | ||||||
|  | 		 | ||||||
|  | 		/** | ||||||
|  | 		 * @return true if this listener is enabled. | ||||||
|  | 		 */ | ||||||
|  | 		public boolean isEnabled() { | ||||||
|  | 			return enabled; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		/** | ||||||
|  | 		 * Enable this listener. | ||||||
|  | 		 *  | ||||||
|  | 		 * @param nTargetPoints Number of point to found before calling the callable. | ||||||
|  | 		 */ | ||||||
|  | 		public void enable(int nTargetPoints, CallableWithNodes callable) { | ||||||
|  | 			this.enabled = true; | ||||||
|  | 			MainWindow.this.getJMenuBar().setEnabled(false); | ||||||
|  | 			this.nTargetPoints = nTargetPoints; | ||||||
|  | 			this.points.clear(); | ||||||
|  | 			this.callable = callable; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		/** | ||||||
|  | 		 * Disable this listener. | ||||||
|  | 		 */ | ||||||
|  | 		public void disable() { | ||||||
|  | 			this.enabled = false; | ||||||
|  | 			MainWindow.this.getJMenuBar().setEnabled(true); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  |         public void mouseClicked(MouseEvent evt) { | ||||||
|  |         		if (!isEnabled()) { | ||||||
|  |         			return; | ||||||
|  |         		} | ||||||
|  |         		Point lonlat; | ||||||
|  | 			try { | ||||||
|  | 				lonlat = drawing.getLongitudeLatitude(evt); | ||||||
|  | 			}  | ||||||
|  | 			catch (NoninvertibleTransformException e) { | ||||||
|  | 				// Should never happens in "normal" circumstances...  | ||||||
|  | 				e.printStackTrace(); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			System.out.println("MOUSE CLICKED: " + evt.getPoint() + " -> " + lonlat); | ||||||
|  | 			 | ||||||
|  | 			ArrayList<Node> nodes = graph.getNodes(); | ||||||
|  | 			Node node = null; | ||||||
|  | 			double minDis = Double.POSITIVE_INFINITY; | ||||||
|  | 			for (int n = 0 ; n < nodes.size(); ++n) { | ||||||
|  | 				double dis = lonlat.distanceTo(nodes.get(n).getPoint()); | ||||||
|  | 				if (dis < minDis) { | ||||||
|  | 					node = nodes.get(n); | ||||||
|  | 					minDis = dis; | ||||||
|  | 				} | ||||||
|  |             } | ||||||
|  | 			new GraphDrawing(drawing).drawPoint(node.getPoint(), 10, Color.BLUE); | ||||||
|  |         		points.add(node); | ||||||
|  |         		if (points.size() == nTargetPoints) { | ||||||
|  |             		System.out.println("CALLABLE!"); | ||||||
|  |         			callable.call(points); | ||||||
|  |         			this.disable(); | ||||||
|  |         		} | ||||||
|  |         } | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 *  | 	 *  | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -90,7 +179,7 @@ public class MainWindow extends JFrame { | ||||||
| 	/** | 	/** | ||||||
| 	 *  | 	 *  | ||||||
| 	 */ | 	 */ | ||||||
| 	private static final Dimension DEFAULT_DIMENSION = new Dimension(800, 600); | 	private static final int THREAD_TIMER_DELAY = 1000; // in milliseconds | ||||||
| 
 | 
 | ||||||
| 	// Current graph. | 	// Current graph. | ||||||
| 	private Graph graph; | 	private Graph graph; | ||||||
|  | @ -98,6 +187,10 @@ public class MainWindow extends JFrame { | ||||||
| 	// Current loaded path. | 	// Current loaded path. | ||||||
| 	private Path currentPath; | 	private Path currentPath; | ||||||
| 
 | 
 | ||||||
|  | 	// Drawing and click adapter. | ||||||
|  | 	private Drawing drawing; | ||||||
|  | 	private DrawingClickListener clickAdapter; | ||||||
|  | 	 | ||||||
| 	// List of item for the top menus. | 	// List of item for the top menus. | ||||||
| 	private JMenuItem openMapItem; | 	private JMenuItem openMapItem; | ||||||
| 
 | 
 | ||||||
|  | @ -107,25 +200,24 @@ public class MainWindow extends JFrame { | ||||||
| 	// Label containing the map ID of the current graph. | 	// Label containing the map ID of the current graph. | ||||||
| 	private JLabel mapIdPanel; | 	private JLabel mapIdPanel; | ||||||
| 	 | 	 | ||||||
|  | 	// Thread information | ||||||
|  | 	private Instant threadStartTime; | ||||||
|  | 	private Timer threadTimer; | ||||||
| 	private JPanel threadPanel; | 	private JPanel threadPanel; | ||||||
| 
 | 
 | ||||||
| 	// Log stream and print stream | 	// Log stream and print stream | ||||||
| 	private JOutputStream logStream; | 	private JOutputStream logStream; | ||||||
|  | 	 | ||||||
|  | 	@SuppressWarnings("unused") | ||||||
| 	private PrintStream printStream; | 	private PrintStream printStream; | ||||||
| 	 | 	 | ||||||
| 	// Current running thread | 	// Current running thread | ||||||
| 	private Thread currentThread; | 	private Thread currentThread; | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 *  |  | ||||||
| 	 */ |  | ||||||
| 	private Drawing drawing; |  | ||||||
| 
 |  | ||||||
| 	public MainWindow() { | 	public MainWindow() { | ||||||
| 		super(WINDOW_TITLE); | 		super(WINDOW_TITLE); | ||||||
| 		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); | 		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); | ||||||
| 		setLayout(new BorderLayout()); | 		setLayout(new BorderLayout()); | ||||||
| 		setSize(DEFAULT_DIMENSION); |  | ||||||
| 		setJMenuBar(createMenuBar()); | 		setJMenuBar(createMenuBar()); | ||||||
| 
 | 
 | ||||||
| 		addWindowListener(new WindowAdapter() { | 		addWindowListener(new WindowAdapter() { | ||||||
|  | @ -145,7 +237,10 @@ public class MainWindow extends JFrame { | ||||||
| 		JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); | 		JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); | ||||||
| 
 | 
 | ||||||
| 		drawing = new Drawing(); | 		drawing = new Drawing(); | ||||||
| 		drawing.setBackground(Color.WHITE); | 		 | ||||||
|  | 		// Click adapter | ||||||
|  | 		this.clickAdapter = new DrawingClickListener(); | ||||||
|  | 		drawing.addMouseListener(this.clickAdapter); | ||||||
| 
 | 
 | ||||||
| 		JTextArea infoPanel = new JTextArea(); | 		JTextArea infoPanel = new JTextArea(); | ||||||
| 		infoPanel.setMinimumSize(new Dimension(200, 50)); | 		infoPanel.setMinimumSize(new Dimension(200, 50)); | ||||||
|  | @ -168,22 +263,45 @@ public class MainWindow extends JFrame { | ||||||
| 		this.add(createStatusBar(), BorderLayout.SOUTH); | 		this.add(createStatusBar(), BorderLayout.SOUTH); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	private void launchThread(Runnable runnable) { | 	private void restartThreadTimer() { | ||||||
|  | 		threadStartTime = Instant.now(); | ||||||
|  | 		threadTimer.restart(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private void stopThreadTimer() { | ||||||
|  | 		threadTimer.stop(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  | 	 * @param runnable | ||||||
|  | 	 * @param canInterrupt | ||||||
|  | 	 */ | ||||||
|  | 	private void launchThread(Runnable runnable, boolean canInterrupt) { | ||||||
|  | 		if (canInterrupt) { | ||||||
| 			currentThread = new Thread(new Runnable() { | 			currentThread = new Thread(new Runnable() { | ||||||
| 				@Override | 				@Override | ||||||
| 				public void run() { | 				public void run() { | ||||||
|  | 					restartThreadTimer(); | ||||||
| 					threadPanel.setVisible(true); | 					threadPanel.setVisible(true); | ||||||
| 					runnable.run(); | 					runnable.run(); | ||||||
| 				threadPanel.setVisible(false); | 					clearCurrentThread(); | ||||||
| 				} | 				} | ||||||
| 			}); | 			}); | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			currentThread = new Thread(runnable); | ||||||
|  | 		} | ||||||
| 		currentThread.start(); | 		currentThread.start(); | ||||||
| 	} | 	} | ||||||
|  | 	private void launchThread(Runnable runnable) { | ||||||
|  | 		launchThread(runnable, true); | ||||||
|  | 	} | ||||||
| 	 | 	 | ||||||
| 	private ShortestPathInstance getShortestPathParameters() { | 	 | ||||||
| 		// TODO: Select origin / end nodes. | 	private void clearCurrentThread() { | ||||||
| 		return new ShortestPathInstance( | 		stopThreadTimer(); | ||||||
| 			graph, graph.getNodes().get(2), graph.getNodes().get(139), Mode.TIME); | 		threadPanel.setVisible(false); | ||||||
|  | 		currentThread = null; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) {	 | 	private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) {	 | ||||||
|  | @ -192,16 +310,14 @@ public class MainWindow extends JFrame { | ||||||
| 		launchThread(new Runnable() { | 		launchThread(new Runnable() { | ||||||
| 			@Override | 			@Override | ||||||
| 			public void run() { | 			public void run() { | ||||||
| 				spAlgorithm.run(); | 				ShortestPathSolution solution = spAlgorithm.run(); | ||||||
| 				AbstractSolution solution = spAlgorithm.getLastSolution(); |  | ||||||
| 				if (solution != null && solution.isFeasible()) { | 				if (solution != null && solution.isFeasible()) { | ||||||
| 					new PathDrawing(drawing).drawPath(((ShortestPathSolution)solution).getPath()); | 					new PathDrawing(drawing).drawPath(solution.getPath()); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	@SuppressWarnings("restriction") |  | ||||||
| 	private JMenuBar createMenuBar() { | 	private JMenuBar createMenuBar() { | ||||||
| 
 | 
 | ||||||
| 		// Open Map item... | 		// Open Map item... | ||||||
|  | @ -218,6 +334,9 @@ public class MainWindow extends JFrame { | ||||||
| 				chooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); | 				chooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); | ||||||
| 				chooser.setFileFilter(filter); | 				chooser.setFileFilter(filter); | ||||||
| 				if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) { | 				if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) { | ||||||
|  | 					launchThread(new Runnable() { | ||||||
|  | 						@Override | ||||||
|  | 						public void run() { | ||||||
| 							BinaryGraphReader reader; | 							BinaryGraphReader reader; | ||||||
| 							try { | 							try { | ||||||
| 								reader = new BinaryGraphReader( | 								reader = new BinaryGraphReader( | ||||||
|  | @ -241,6 +360,8 @@ public class MainWindow extends JFrame { | ||||||
| 							} | 							} | ||||||
| 							mapIdPanel.setText("Map ID: 0x" + Integer.toHexString(graph.getMapId())); | 							mapIdPanel.setText("Map ID: 0x" + Integer.toHexString(graph.getMapId())); | ||||||
| 						} | 						} | ||||||
|  | 					}, false); | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
|  | @ -352,7 +473,12 @@ public class MainWindow extends JFrame { | ||||||
| 				WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(instance); | 				WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(instance); | ||||||
| 				algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing)); | 				algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing)); | ||||||
| 				// algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream)); | 				// algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream)); | ||||||
| 				launchThread(algo); | 				launchThread(new Runnable() { | ||||||
|  | 					@Override | ||||||
|  | 					public void run() { | ||||||
|  | 						algo.run(); | ||||||
|  | 					} | ||||||
|  | 				}); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
|  | @ -361,7 +487,13 @@ public class MainWindow extends JFrame { | ||||||
| 		bellmanItem.addActionListener(new ActionListener() { | 		bellmanItem.addActionListener(new ActionListener() { | ||||||
| 			@Override | 			@Override | ||||||
| 			public void actionPerformed(ActionEvent e) { | 			public void actionPerformed(ActionEvent e) { | ||||||
| 				launchShortestPathThread(new BellmanFordAlgorithm(getShortestPathParameters())); | 				clickAdapter.enable(2, new CallableWithNodes() { | ||||||
|  | 					@Override | ||||||
|  | 					public void call(ArrayList<Node> nodes) { | ||||||
|  | 						launchShortestPathThread(new BellmanFordAlgorithm( | ||||||
|  | 								new ShortestPathInstance(graph, nodes.get(0), nodes.get(1), Mode.TIME))); | ||||||
|  | 					} | ||||||
|  | 				}); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 		graphItems.add(wccItem); | 		graphItems.add(wccItem); | ||||||
|  | @ -387,11 +519,19 @@ public class MainWindow extends JFrame { | ||||||
| 		return menuBar; | 		return menuBar; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	@SuppressWarnings("deprecation") | ||||||
|  | 	private void stopCurrentThread() { | ||||||
|  | 		// Should not be used in production code, but here I have no idea how | ||||||
|  | 		// to do this properly... Cannot use .interrupt() because it would requires | ||||||
|  | 		// the algorithm to watch the ThreadInteruption exception. | ||||||
|  | 		currentThread.stop(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	private JPanel createStatusBar() { | 	private JPanel createStatusBar() { | ||||||
| 		// create the status bar panel and shove it down the bottom of the frame | 		// create the status bar panel and shove it down the bottom of the frame | ||||||
| 		JPanel statusPanel = new JPanel(); | 		JPanel statusPanel = new JPanel(); | ||||||
| 		statusPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY)); | 		statusPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY)); | ||||||
| 		statusPanel.setPreferredSize(new Dimension(getWidth(), 34)); | 		statusPanel.setPreferredSize(new Dimension(getWidth(), 38)); | ||||||
| 		statusPanel.setLayout(new BorderLayout()); | 		statusPanel.setLayout(new BorderLayout()); | ||||||
| 
 | 
 | ||||||
| 		mapIdPanel = new JLabel(); | 		mapIdPanel = new JLabel(); | ||||||
|  | @ -399,9 +539,10 @@ public class MainWindow extends JFrame { | ||||||
| 		statusPanel.add(mapIdPanel, BorderLayout.WEST); | 		statusPanel.add(mapIdPanel, BorderLayout.WEST); | ||||||
| 		 | 		 | ||||||
| 		JLabel threadInfo = new JLabel("Thread running... "); | 		JLabel threadInfo = new JLabel("Thread running... "); | ||||||
|  | 		JLabel threadTimerLabel = new JLabel("00:00:00"); | ||||||
| 		JButton threadButton = new JButton("Stop"); | 		JButton threadButton = new JButton("Stop"); | ||||||
| 		threadButton.addActionListener(new ActionListener() { | 		threadButton.addActionListener(new ActionListener() { | ||||||
| 			@SuppressWarnings("deprecation") | 
 | ||||||
| 			@Override | 			@Override | ||||||
| 			public void actionPerformed(ActionEvent e) { | 			public void actionPerformed(ActionEvent e) { | ||||||
| 				if (currentThread != null && currentThread.isAlive()) { | 				if (currentThread != null && currentThread.isAlive()) { | ||||||
|  | @ -409,17 +550,30 @@ public class MainWindow extends JFrame { | ||||||
| 							"Are you sure you want to kill the running thread?", "Kill Confirmation", | 							"Are you sure you want to kill the running thread?", "Kill Confirmation", | ||||||
| 							JOptionPane.YES_NO_OPTION); | 							JOptionPane.YES_NO_OPTION); | ||||||
| 					if (confirmed == JOptionPane.YES_OPTION) { | 					if (confirmed == JOptionPane.YES_OPTION) { | ||||||
| 						currentThread.stop(); | 						stopCurrentThread(); | ||||||
| 						currentThread = null; | 						clearCurrentThread(); | ||||||
| 						threadPanel.setVisible(false); | 						threadPanel.setVisible(false); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
|  | 		 | ||||||
|  | 		threadTimer = new Timer(THREAD_TIMER_DELAY, new ActionListener() { | ||||||
|  | 			@Override | ||||||
|  | 			public void actionPerformed(ActionEvent e) { | ||||||
|  | 				Duration elapsed = Duration.between(threadStartTime, Instant.now()); | ||||||
|  | 				long seconds = elapsed.getSeconds(); | ||||||
|  | 				threadTimerLabel.setText(String.format( | ||||||
|  | 				    "%02d:%02d:%02d", seconds/3600, seconds/60 % 60, seconds % 60)); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		threadTimer.setInitialDelay(0); | ||||||
|  | 		 | ||||||
| 		threadPanel = new JPanel(); | 		threadPanel = new JPanel(); | ||||||
| 		threadPanel.add(threadInfo); | 		threadPanel.add(threadInfo); | ||||||
|  | 		threadPanel.add(threadTimerLabel); | ||||||
| 		threadPanel.add(threadButton); | 		threadPanel.add(threadButton); | ||||||
| 		// threadPanel.setVisible(false); | 		threadPanel.setVisible(false); | ||||||
| 		statusPanel.add(threadPanel, BorderLayout.EAST); | 		statusPanel.add(threadPanel, BorderLayout.EAST); | ||||||
| 
 | 
 | ||||||
| 		return statusPanel; | 		return statusPanel; | ||||||
|  |  | ||||||
|  | @ -5,10 +5,15 @@ import java.awt.Color; | ||||||
| import java.awt.Graphics; | import java.awt.Graphics; | ||||||
| import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||||
| import java.awt.Image; | import java.awt.Image; | ||||||
|  | import java.awt.event.MouseEvent; | ||||||
|  | import java.awt.geom.NoninvertibleTransformException; | ||||||
|  | import java.awt.geom.Point2D; | ||||||
| import java.awt.image.*; | import java.awt.image.*; | ||||||
| 
 | 
 | ||||||
| import javax.swing.JPanel; | import javax.swing.JPanel; | ||||||
| 
 | 
 | ||||||
|  | import org.insa.graph.Point; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  *   Cette implementation de la classe Dessin produit vraiment un affichage |  *   Cette implementation de la classe Dessin produit vraiment un affichage | ||||||
|  *   (au contraire de la classe DessinInvisible). |  *   (au contraire de la classe DessinInvisible). | ||||||
|  | @ -23,16 +28,11 @@ public class Drawing extends JPanel { | ||||||
| 	 | 	 | ||||||
| 	private final Graphics2D gr; | 	private final Graphics2D gr; | ||||||
| 
 | 
 | ||||||
| 	private float long1; | 	private double long1, long2, lat1, lat2; | ||||||
| 	private float long2; |  | ||||||
| 	private float lat1; |  | ||||||
| 	private float lat2; |  | ||||||
| 	 | 	 | ||||||
| 	// Width and height of the image | 	// Width and height of the image | ||||||
| 	private final int width, height; | 	private final int width, height; | ||||||
| 	 | 	 | ||||||
| 	private boolean bb_is_set ; |  | ||||||
| 	 |  | ||||||
| 	private Image image; | 	private Image image; | ||||||
| 	private ZoomAndPanListener zoomAndPanListener; | 	private ZoomAndPanListener zoomAndPanListener; | ||||||
| 	 | 	 | ||||||
|  | @ -58,13 +58,10 @@ public class Drawing extends JPanel { | ||||||
| 		 | 		 | ||||||
| 		this.zoomAndPanListener.setCoordTransform(this.gr.getTransform()); | 		this.zoomAndPanListener.setCoordTransform(this.gr.getTransform()); | ||||||
| 
 | 
 | ||||||
| 		this.bb_is_set = false; | 		this.long1 = -180; | ||||||
| 
 | 		this.long2 = 180; | ||||||
| 
 | 		this.lat1  = -90; | ||||||
| 		this.long1 = 0.0f; | 		this.lat2  = 90; | ||||||
| 		this.long2 = this.width; |  | ||||||
| 		this.lat1  = 0.0f; |  | ||||||
| 		this.lat2  = this.height; |  | ||||||
| 
 | 
 | ||||||
| 		this.clear(); | 		this.clear(); | ||||||
| 		this.repaint(); | 		this.repaint(); | ||||||
|  | @ -108,12 +105,10 @@ public class Drawing extends JPanel { | ||||||
| 			throw new Error("DessinVisible.setBB : mauvaises coordonnees."); | 			throw new Error("DessinVisible.setBB : mauvaises coordonnees."); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		this.long1 = (float)long1; | 		this.long1 = long1; | ||||||
| 		this.long2 = (float)long2; | 		this.long2 = long2; | ||||||
| 		this.lat1= (float)lat1; | 		this.lat1= lat1; | ||||||
| 		this.lat2 = (float)lat2; | 		this.lat2 = lat2; | ||||||
| 		 |  | ||||||
| 		this.bb_is_set = true; |  | ||||||
| 				 | 				 | ||||||
| 		double scale = 1 / Math.max(this.width / (double)this.getWidth(),  this.height / (double)this.getHeight()); | 		double scale = 1 / Math.max(this.width / (double)this.getWidth(),  this.height / (double)this.getHeight()); | ||||||
| 		 | 		 | ||||||
|  | @ -126,43 +121,57 @@ public class Drawing extends JPanel { | ||||||
| 		 | 		 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private int projx(float lon) { | 	private int projx(double lon) { | ||||||
| 		return (int)(width * (lon - this.long1) / (this.long2 - this.long1)) ; | 		return (int)(width * (lon - this.long1) / (this.long2 - this.long1)) ; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private int projy(float lat) { | 	private int projy(double lat) { | ||||||
| 		return (int)(height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1))) ; | 		return (int)(height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1))) ; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	private void checkBB() { | 	/** | ||||||
| 		if (!this.bb_is_set) { | 	 * Return the longitude and latitude corresponding to the given | ||||||
| 			throw new Error("Classe DessinVisible : vous devez invoquer la methode setBB avant de dessiner.") ; | 	 * position of the MouseEvent. | ||||||
| 		} | 	 *  | ||||||
|  | 	 * @param event | ||||||
|  | 	 *  | ||||||
|  | 	 * @return | ||||||
|  | 	 */ | ||||||
|  | 	public Point getLongitudeLatitude(MouseEvent event) throws NoninvertibleTransformException { | ||||||
|  | 		// Get the point using the inverse transform of the Zoom/Pan object, this gives us | ||||||
|  | 		// a point within the drawing box (between [0, 0] and [width, height]). | ||||||
|  | 		Point2D ptDst = this.zoomAndPanListener.getCoordTransform().inverseTransform(event.getPoint(), null); | ||||||
|  | 		 | ||||||
|  | 		// Inverse the "projection" on x/y to get longitude and latitude. | ||||||
|  | 		double lon = ptDst.getX(); | ||||||
|  | 		double lat = ptDst.getY(); | ||||||
|  | 		lon = (lon / this.width) * (this.long2 - this.long1) + this.long1; | ||||||
|  | 		lat = (1 - lat / this.height) * (this.lat2 - this.lat1) + this.lat1; | ||||||
|  | 		 | ||||||
|  | 		// Return a new point. | ||||||
|  | 		return new Point(lon, lat);			 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public void drawLine(float long1, float lat1, float long2, float lat2) { | 	public void drawLine(Point from, Point to) { | ||||||
| 		this.checkBB() ; | 		int x1 = this.projx(from.getLongitude()) ; | ||||||
| 		int x1 = this.projx(long1) ; | 		int x2 = this.projx(to.getLongitude()) ; | ||||||
| 		int x2 = this.projx(long2) ; | 		int y1 = this.projy(from.getLatitude()) ; | ||||||
| 		int y1 = this.projy(lat1) ; | 		int y2 = this.projy(to.getLatitude()) ; | ||||||
| 		int y2 = this.projy(lat2) ; |  | ||||||
| 
 | 
 | ||||||
| 		gr.drawLine(x1, y1, x2, y2) ; | 		gr.drawLine(x1, y1, x2, y2) ; | ||||||
| 		this.doAutoPaint(); | 		this.doAutoPaint(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public void drawPoint(float lon, float lat, int width) { | 	public void drawPoint(Point point, int width) { | ||||||
| 		this.checkBB() ; | 		int x = this.projx(point.getLongitude()) - width / 2; | ||||||
| 		int x = this.projx(lon) - width / 2 ; | 		int y = this.projy(point.getLatitude()) - width / 2; | ||||||
| 		int y = this.projy(lat) - width / 2 ; |  | ||||||
| 		gr.fillOval(x, y, width, width); | 		gr.fillOval(x, y, width, width); | ||||||
| 		this.doAutoPaint(); | 		this.doAutoPaint(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public void putText(float lon, float lat, String txt) { | 	public void putText(Point point, String txt) { | ||||||
| 		this.checkBB() ; | 		int x = this.projx(point.getLongitude()); | ||||||
| 		int x = this.projx(lon) ; | 		int y = this.projy(point.getLatitude()); | ||||||
| 		int y = this.projy(lat) ; |  | ||||||
| 		gr.drawString(txt, x, y); | 		gr.drawString(txt, x, y); | ||||||
| 		this.doAutoPaint();	 | 		this.doAutoPaint();	 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -9,7 +9,6 @@ import org.insa.graph.Arc; | ||||||
| import org.insa.graph.Graph; | import org.insa.graph.Graph; | ||||||
| import org.insa.graph.Node; | import org.insa.graph.Node; | ||||||
| import org.insa.graph.Point; | import org.insa.graph.Point; | ||||||
| import org.insa.graph.RoadInformation.RoadType; |  | ||||||
| 
 | 
 | ||||||
| public class GraphDrawing { | public class GraphDrawing { | ||||||
| 
 | 
 | ||||||
|  | @ -30,8 +29,7 @@ public class GraphDrawing { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public void drawLine(Point p1, Point p2) { | 	public void drawLine(Point p1, Point p2) { | ||||||
| 		drawing.drawLine(p1.getLongitude(), p1.getLatitude(),  | 		drawing.drawLine(p1, p2); | ||||||
| 				p2.getLongitude(), p2.getLatitude()); |  | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public void drawPoint(Point p) { | 	public void drawPoint(Point p) { | ||||||
|  | @ -39,12 +37,12 @@ public class GraphDrawing { | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public void drawPoint(Point p, int width) { | 	public void drawPoint(Point p, int width) { | ||||||
| 		drawing.drawPoint(p.getLongitude(), p.getLatitude(), width); | 		drawing.drawPoint(p, width); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public void drawPoint(Point p, int width, Color c) { | 	public void drawPoint(Point p, int width, Color c) { | ||||||
| 		drawing.setColor(c); | 		drawing.setColor(c); | ||||||
| 		drawing.drawPoint(p.getLongitude(), p.getLatitude(), width); | 		drawing.drawPoint(p, width); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  |  | ||||||
|  | @ -26,14 +26,14 @@ public class Point { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Longitude and latitude of the point. | 	// Longitude and latitude of the point. | ||||||
| 	private float longitude, latitude; | 	private double longitude, latitude; | ||||||
| 	 | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 *  | 	 *  | ||||||
| 	 * @param longitude Longitude of the point, in degrees. | 	 * @param longitude Longitude of the point, in degrees. | ||||||
| 	 * @param latitude Latitude of the point, in degrees. | 	 * @param latitude Latitude of the point, in degrees. | ||||||
| 	 */ | 	 */ | ||||||
| 	public Point(float longitude, float latitude) { | 	public Point(double longitude, double latitude) { | ||||||
| 		this.longitude = longitude; | 		this.longitude = longitude; | ||||||
| 		this.latitude = latitude; | 		this.latitude = latitude; | ||||||
| 	} | 	} | ||||||
|  | @ -41,12 +41,12 @@ public class Point { | ||||||
| 	/** | 	/** | ||||||
| 	 * @return Longitude of this point (in degrees). | 	 * @return Longitude of this point (in degrees). | ||||||
| 	 */ | 	 */ | ||||||
| 	public float getLongitude() { return longitude; } | 	public double getLongitude() { return longitude; } | ||||||
| 	 | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 * @return Latitude of this point (in degrees). | 	 * @return Latitude of this point (in degrees). | ||||||
| 	 */ | 	 */ | ||||||
| 	public float getLatitude() { return latitude; } | 	public double getLatitude() { return latitude; } | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Compute the distance from this point to the given point | 	 * Compute the distance from this point to the given point | ||||||
|  | @ -59,4 +59,8 @@ public class Point { | ||||||
| 		return distance(this, target); | 		return distance(this, target); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	@Override | ||||||
|  | 	public String toString() { | ||||||
|  | 		return String.format("Point(%f, %f)", getLongitude(), getLatitude()); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -65,7 +65,7 @@ public class BinaryPathReader extends BinaryReader implements AbstractPathReader | ||||||
| 			current = node; | 			current = node; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		return new Path(graph, nodes.get(0), arcs); | 		return new Path(graph, arcs); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue