Skip to content

Commit 35c31aa

Browse files
committed
New OSM agent application added.
1 parent a5d8d30 commit 35c31aa

File tree

6 files changed

+295
-243
lines changed

6 files changed

+295
-243
lines changed

aima-gui/src/main/java/aima/gui/fx/framework/SimulationPaneBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Arrays;
55
import java.util.List;
66
import java.util.Optional;
7+
import java.util.function.BooleanSupplier;
78

89
import javafx.geometry.Pos;
910
import javafx.scene.Node;
@@ -28,6 +29,7 @@ public class SimulationPaneBuilder {
2829

2930
protected List<Parameter> parameters = new ArrayList<Parameter>();
3031
protected Optional<Node> stateView = Optional.empty();
32+
/** Should return true if initialization was successful. */
3133
protected Optional<Runnable> initMethod = Optional.empty();
3234
protected Optional<Runnable> simMethod = Optional.empty();
3335

aima-gui/src/main/java/aima/gui/fx/framework/SimulationPaneCtrl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.List;
44
import java.util.Optional;
5+
import java.util.function.BooleanSupplier;
56

67
import aima.core.util.CancelableThread;
78
import javafx.application.Platform;
@@ -94,6 +95,12 @@ public boolean isParamVisible(String paramName) {
9495
return paramCombos.get(paramIdx).isVisible();
9596
}
9697

98+
/** Call this only for parameters which do not depend on other parameters! */
99+
public void setParamDisable(String paramName, boolean value) {
100+
int paramIdx = Parameter.indexOf(params, paramName);
101+
paramCombos.get(paramIdx).setDisable(value);
102+
}
103+
97104
public void setParam(String paramName, int valueIdx) {
98105
int idx = Parameter.indexOf(params, paramName);
99106
if (idx != -1)

aima-gui/src/main/java/aima/gui/fx/views/SimpleEnvironmentViewCtrl.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
import javafx.application.Platform;
88
import javafx.scene.control.SplitPane;
99
import javafx.scene.control.TextArea;
10+
import javafx.scene.layout.Pane;
1011
import javafx.scene.layout.StackPane;
1112

13+
import java.util.Observable;
14+
1215
/**
1316
* Controller class for a simple environment view. It logs informations about
1417
* environment changes on a text area and can be used for any kind of
@@ -18,7 +21,7 @@
1821
* @author Ruediger Lunde
1922
*
2023
*/
21-
public class SimpleEnvironmentViewCtrl implements EnvironmentView {
24+
public class SimpleEnvironmentViewCtrl extends Observable implements EnvironmentView {
2225

2326
protected SplitPane splitPane;
2427
protected TextArea textArea;
@@ -36,18 +39,27 @@ public SimpleEnvironmentViewCtrl(StackPane viewRoot) {
3639
viewRoot.getChildren().add(splitPane);
3740
}
3841

42+
public SimpleEnvironmentViewCtrl(StackPane viewRoot, Pane envStateView, double dividerPos) {
43+
this(viewRoot);
44+
splitPane.getItems().add(0, envStateView);
45+
splitPane.setDividerPosition(0, dividerPos);
46+
}
47+
3948
public void initialize(Environment env) {
4049
if (!textArea.getText().isEmpty())
4150
textArea.appendText("\n");
4251
updateEnvStateView(env);
4352
}
4453

4554
/**
46-
* Should not be called from an FX application thread.
55+
* Can be called from every thread.
4756
*/
4857
@Override
4958
public void notify(String msg) {
50-
Platform.runLater(() -> textArea.appendText("\n" + msg));
59+
if (Platform.isFxApplicationThread())
60+
textArea.appendText("\n" + msg);
61+
else
62+
Platform.runLater(() -> textArea.appendText("\n" + msg));
5163
}
5264

5365
/**
@@ -74,9 +86,9 @@ public void agentActed(Agent agent, Action action, Environment source) {
7486
}
7587

7688
/**
77-
* Is called after agent actions. This implementation does nothing.
89+
* Is called after agent actions. This implementation just notifies all observers.
7890
*/
7991
protected void updateEnvStateView(Environment env) {
80-
92+
this.notifyObservers();
8193
}
8294
}

aimax-osm/src/main/java/aimax/osm/gui/fx/IntegratedOsmAimaFxApp.java renamed to aimax-osm/src/main/java/aimax/osm/gui/fx/IntegratedAimaOsmFxApp.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import aima.gui.fx.demo.IntegratedAimaFxApp;
44
import aima.gui.fx.framework.IntegratedAppPaneBuilder;
5+
import aimax.osm.gui.fx.applications.OsmRouteFindingAgentApp;
56
import aimax.osm.gui.fx.applications.OsmRoutePlannerApp;
67
import javafx.application.Application;
78
import javafx.scene.Scene;
@@ -14,7 +15,7 @@
1415
*
1516
* @author Ruediger Lunde
1617
*/
17-
public class IntegratedOsmAimaFxApp extends Application {
18+
public class IntegratedAimaOsmFxApp extends Application {
1819

1920
public static void main(String[] args) {
2021
launch(args);
@@ -23,7 +24,7 @@ public static void main(String[] args) {
2324
@Override
2425
public void start(Stage primaryStage) throws Exception {
2526
IntegratedAppPaneBuilder builder = new IntegratedAppPaneBuilder();
26-
builder.defineTitle("Integrated OSM AIMA FX App");
27+
builder.defineTitle("Integrated AIMA OSM FX App");
2728
defineContent(builder);
2829
BorderPane root = new BorderPane();
2930
builder.getResultFor(root, primaryStage);
@@ -35,6 +36,7 @@ public static void defineContent(IntegratedAppPaneBuilder builder) {
3536
IntegratedAimaFxApp.defineContent(builder);
3637

3738
builder.registerApp(OsmRoutePlannerApp.class);
39+
builder.registerApp(OsmRouteFindingAgentApp.class);
3840
}
3941

4042
}
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
package aimax.osm.gui.fx.applications;
2+
3+
import aima.core.agent.Action;
4+
import aima.core.agent.Agent;
5+
import aima.core.agent.Environment;
6+
import aima.core.agent.EnvironmentView;
7+
import aima.core.environment.map.*;
8+
import aima.core.search.framework.SearchForActions;
9+
import aima.core.search.framework.problem.Problem;
10+
import aima.core.search.online.LRTAStarAgent;
11+
import aima.core.search.online.OnlineSearchProblem;
12+
import aima.core.util.CancelableThread;
13+
import aima.core.util.math.geom.shapes.Point2D;
14+
import aima.gui.fx.framework.IntegrableApplication;
15+
import aima.gui.fx.framework.Parameter;
16+
import aima.gui.fx.framework.SimulationPaneBuilder;
17+
import aima.gui.fx.framework.SimulationPaneCtrl;
18+
import aima.gui.fx.views.SimpleEnvironmentViewCtrl;
19+
import aima.gui.util.SearchFactory;
20+
import aimax.osm.data.DataResource;
21+
import aimax.osm.data.MapWayAttFilter;
22+
import aimax.osm.data.Position;
23+
import aimax.osm.data.entities.MapNode;
24+
import aimax.osm.gui.fx.viewer.MapPaneCtrl;
25+
import aimax.osm.routing.MapAdapter;
26+
import javafx.application.Platform;
27+
import javafx.scene.layout.BorderPane;
28+
import javafx.scene.layout.Pane;
29+
import javafx.scene.layout.StackPane;
30+
31+
import java.util.ArrayList;
32+
import java.util.List;
33+
34+
/**
35+
* Integrable application which demonstrates how different kinds of search
36+
* algorithms perform an a route finding scenario based on a real OSM map.
37+
*
38+
* @author Ruediger Lunde
39+
*
40+
*/
41+
public class OsmRouteFindingAgentApp extends IntegrableApplication {
42+
43+
public static void main(String[] args) {
44+
launch(args);
45+
}
46+
47+
public static String PARAM_WAY_SELECTION = "WaySelection";
48+
public static String PARAM_SEARCH = "Search";
49+
public static String PARAM_Q_SEARCH_IMPL = "QSearch";
50+
public static String PARAM_HEURISTIC = "Heuristic";
51+
52+
private MapPaneCtrl mapPaneCtrl;
53+
private SimpleEnvironmentViewCtrl envViewCtrl;
54+
private SimulationPaneCtrl simPaneCtrl;
55+
56+
protected MapAdapter map;
57+
protected MapEnvironment env;
58+
/** Search method to be used. */
59+
protected SearchForActions search;
60+
/** Heuristic function to be used when performing informed search. */
61+
protected AdaptableHeuristicFunction heuristic;
62+
63+
protected List<String> markedLocations;
64+
65+
66+
67+
// protected MapEnvironment env = null;
68+
// protected Agent agent = null;
69+
70+
71+
public OsmRouteFindingAgentApp() {
72+
markedLocations = new ArrayList<String>();
73+
}
74+
75+
@Override
76+
public String getTitle() { return "OSM Route Finding Agent App"; }
77+
78+
/**
79+
* Defines state view, parameters, and call-back functions and calls the
80+
* simulation pane builder to create layout and controller objects.
81+
*/
82+
@Override
83+
public Pane createRootPane() {
84+
BorderPane root = new BorderPane();
85+
86+
Parameter[] params = createParameters();
87+
88+
StackPane mapPane = new StackPane();
89+
mapPaneCtrl = new MapPaneCtrl(mapPane);
90+
mapPaneCtrl.loadMap(DataResource.getULMFileResource());
91+
StackPane envView = new StackPane();
92+
envViewCtrl = new SimpleEnvironmentViewCtrl(envView, mapPane, 0.75);
93+
94+
SimulationPaneBuilder builder = new SimulationPaneBuilder();
95+
builder.defineParameters(params);
96+
builder.defineStateView(envView);
97+
builder.defineInitMethod(this::initialize);
98+
builder.defineSimMethod(this::simulate);
99+
simPaneCtrl = builder.getResultFor(root);
100+
simPaneCtrl.setParam(SimulationPaneCtrl.PARAM_SIM_SPEED, 0);
101+
102+
return root;
103+
}
104+
105+
protected Parameter[] createParameters() {
106+
Parameter p1 = new Parameter(PARAM_WAY_SELECTION, "Use any way", "Travel by car", "Travel by bicycle");
107+
Parameter p2 = new Parameter(PARAM_SEARCH, (Object[]) SearchFactory.getInstance().getSearchStrategyNames());
108+
p2.setDefaultValueIndex(5);
109+
Parameter p3 = new Parameter(PARAM_Q_SEARCH_IMPL, (Object[]) SearchFactory.getInstance().getQSearchImplNames());
110+
p3.setDefaultValueIndex(1);
111+
p3.setDependency(PARAM_SEARCH, "Depth First", "Breadth First", "Uniform Cost", "Greedy Best First", "A*");
112+
Parameter p4 = new Parameter(PARAM_HEURISTIC, "0", "SLD");
113+
p4.setDependency(PARAM_SEARCH, "Greedy Best First", "A*", "Recursive Best First",
114+
"Recursive Best First No Loops", "Hill Climbing");
115+
p4.setDefaultValueIndex(1);
116+
return new Parameter[] { p1, p2, p3, p4 };
117+
}
118+
119+
/** Is called after each parameter selection change. */
120+
@Override
121+
public void initialize() {
122+
map = new MapAdapter(mapPaneCtrl.getMap());
123+
map.getOsmMap().getTracks().clear();
124+
switch (simPaneCtrl.getParamValueIndex(PARAM_WAY_SELECTION)) {
125+
case 0:
126+
map.setMapWayFilter(MapWayAttFilter.createAnyWayFilter());
127+
map.ignoreOneways(true);
128+
break;
129+
case 1:
130+
map.setMapWayFilter(MapWayAttFilter.createCarWayFilter());
131+
map.ignoreOneways(false);
132+
break;
133+
case 2:
134+
map.setMapWayFilter(MapWayAttFilter.createBicycleWayFilter());
135+
map.ignoreOneways(false);
136+
break;
137+
}
138+
139+
140+
switch (simPaneCtrl.getParamValueIndex(PARAM_HEURISTIC)) {
141+
case 0:
142+
heuristic = new H1();
143+
break;
144+
default:
145+
heuristic = new H2();
146+
}
147+
search = SearchFactory.getInstance().createSearch(simPaneCtrl.getParamValueIndex(PARAM_SEARCH),
148+
simPaneCtrl.getParamValueIndex(PARAM_Q_SEARCH_IMPL), heuristic);
149+
}
150+
151+
/** Creates new agents and adds them to the current environment. */
152+
protected boolean initAgents() {
153+
List<MapNode> markers = map.getOsmMap().getMarkers();
154+
if (markers.size() < 2) {
155+
this.simPaneCtrl.setStatus("Error: Please set two markers with mouse-left.");
156+
return false;
157+
}
158+
String[] locs = new String[markers.size()];
159+
for (int i = 0; i < markers.size(); i++) {
160+
MapNode node = markers.get(i);
161+
Point2D pt = new Point2D(node.getLon(), node.getLat());
162+
locs[i] = map.getNearestLocation(pt);
163+
}
164+
heuristic.adaptToGoal(locs[1], map);
165+
env = new MapEnvironment(map);
166+
Agent agent = null;
167+
int idx = 0;
168+
switch (idx) {
169+
case 0:
170+
agent = new MapAgent(map, env, search, new String[] { locs[1] });
171+
break;
172+
case 1:
173+
Problem p = new BidirectionalMapProblem(map, null, locs[1]);
174+
OnlineSearchProblem osp = new OnlineSearchProblem(
175+
p.getActionsFunction(), p.getGoalTest(),
176+
p.getStepCostFunction());
177+
agent = new LRTAStarAgent(osp,
178+
MapFunctionFactory.getPerceptToStateFunction(), heuristic);
179+
break;
180+
}
181+
//env.addEnvironmentView(envViewCtrl);
182+
env.addEnvironmentView(new TrackUpdater());
183+
env.addAgent(agent, locs[0]);
184+
return true;
185+
}
186+
187+
188+
/** Starts the experiment. */
189+
public void simulate() {
190+
if (initAgents()) {
191+
while (!env.isDone() && !CancelableThread.currIsCanceled()) {
192+
env.step();
193+
simPaneCtrl.waitAfterStep();
194+
}
195+
envViewCtrl.notify("");
196+
simPaneCtrl.setStatus("Search metrics: " + search.getMetrics());
197+
}
198+
}
199+
200+
@Override
201+
public void finalize() {
202+
simPaneCtrl.cancelSimulation();
203+
}
204+
205+
206+
207+
208+
// helper classes...
209+
210+
/**
211+
* Returns always the heuristic value 0.
212+
*/
213+
static class H1 extends AdaptableHeuristicFunction {
214+
215+
public double h(Object state) {
216+
return 0.0;
217+
}
218+
}
219+
220+
/**
221+
* A simple heuristic which interprets <code>state</code> and {@link #goal}
222+
* as location names and uses the straight-line distance between them as
223+
* heuristic value.
224+
*/
225+
static class H2 extends AdaptableHeuristicFunction {
226+
227+
public double h(Object state) {
228+
double result = 0.0;
229+
Point2D pt1 = map.getPosition((String) state);
230+
Point2D pt2 = map.getPosition((String) goal);
231+
if (pt1 != null && pt2 != null)
232+
result = pt1.distance(pt2);
233+
return result;
234+
}
235+
}
236+
237+
class TrackUpdater implements EnvironmentView {
238+
239+
@Override
240+
public void notify(String msg) { envViewCtrl.notify(msg); }
241+
242+
@Override
243+
public void agentAdded(Agent agent, Environment source) {}
244+
245+
/**
246+
* Reacts on environment changes and updates the tracks.
247+
*/
248+
@Override
249+
public void agentActed(Agent agent, Action command, Environment source) {
250+
if (command instanceof MoveToAction) {
251+
Platform.runLater(() -> updateTrack(agent, env.getAgentLocation(agent)));
252+
}
253+
}
254+
255+
private void updateTrack(Agent agent, String location) {
256+
MapAdapter map = (MapAdapter) env.getMap();
257+
MapNode node = map.getWayNode(location);
258+
if (node != null) {
259+
int aIdx = env.getAgents().indexOf(agent);
260+
map.getOsmMap().addToTrack("Track" + aIdx,
261+
new Position(node.getLat(), node.getLon()));
262+
}
263+
}
264+
}
265+
}

0 commit comments

Comments
 (0)