1 package org.opentrafficsim.aimsun;
2
3 import java.awt.Dimension;
4 import java.awt.Frame;
5 import java.awt.event.ActionEvent;
6 import java.io.ByteArrayInputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.OutputStream;
10 import java.io.PrintWriter;
11 import java.net.ServerSocket;
12 import java.net.Socket;
13 import java.net.URISyntaxException;
14 import java.nio.charset.StandardCharsets;
15 import java.rmi.RemoteException;
16 import java.util.LinkedHashMap;
17 import java.util.Map;
18
19 import javax.naming.NamingException;
20 import javax.swing.JFrame;
21 import javax.xml.bind.JAXBException;
22 import javax.xml.parsers.ParserConfigurationException;
23
24 import org.djunits.unit.DurationUnit;
25 import org.djunits.unit.TimeUnit;
26 import org.djunits.value.ValueRuntimeException;
27 import org.djunits.value.vdouble.scalar.Duration;
28 import org.djunits.value.vdouble.scalar.Length;
29 import org.djunits.value.vdouble.scalar.Time;
30 import org.djutils.logger.LogCategory;
31 import org.opentrafficsim.aimsun.proto.AimsunControlProtoBuf;
32 import org.opentrafficsim.aimsun.proto.AimsunControlProtoBuf.GTUPositions;
33 import org.opentrafficsim.base.parameters.ParameterException;
34 import org.opentrafficsim.core.animation.gtu.colorer.DefaultSwitchableGTUColorer;
35 import org.opentrafficsim.core.dsol.AbstractOTSModel;
36 import org.opentrafficsim.core.dsol.OTSAnimator;
37 import org.opentrafficsim.core.dsol.OTSLoggingAnimator;
38 import org.opentrafficsim.core.dsol.OTSModelInterface;
39 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
40 import org.opentrafficsim.core.geometry.OTSGeometryException;
41 import org.opentrafficsim.core.gtu.GTU;
42 import org.opentrafficsim.core.gtu.GTUDumper;
43 import org.opentrafficsim.core.gtu.GTUException;
44 import org.opentrafficsim.core.gtu.GTUType;
45 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
46 import org.opentrafficsim.core.network.NetworkException;
47 import org.opentrafficsim.core.network.OTSNetwork;
48 import org.opentrafficsim.draw.core.OTSDrawingException;
49 import org.opentrafficsim.draw.factory.DefaultAnimationFactory;
50 import org.opentrafficsim.road.network.OTSRoadNetwork;
51 import org.opentrafficsim.road.network.factory.xml.XmlParserException;
52 import org.opentrafficsim.road.network.factory.xml.parser.XmlNetworkLaneParser;
53 import org.opentrafficsim.road.network.lane.CrossSectionLink;
54 import org.opentrafficsim.road.network.lane.conflict.ConflictBuilder;
55 import org.opentrafficsim.road.network.lane.conflict.LaneCombinationList;
56 import org.opentrafficsim.swing.gui.OTSAnimationPanel;
57 import org.opentrafficsim.swing.gui.OTSSimulationApplication;
58 import org.opentrafficsim.swing.gui.OTSSwingApplication;
59 import org.pmw.tinylog.Level;
60 import org.xml.sax.SAXException;
61
62 import nl.tudelft.simulation.dsol.SimRuntimeException;
63 import nl.tudelft.simulation.dsol.logger.SimLogger;
64 import nl.tudelft.simulation.dsol.simulators.DEVSRealTimeClock;
65 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
66 import nl.tudelft.simulation.event.EventInterface;
67 import nl.tudelft.simulation.event.EventListenerInterface;
68 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
69 import nl.tudelft.simulation.jstats.streams.StreamInterface;
70 import nl.tudelft.simulation.language.d3.DirectedPoint;
71
72
73
74
75
76
77
78
79
80
81
82 public class AimsunControl
83 {
84
85 private AimsunModel model = null;
86
87
88
89
90
91
92
93
94
95
96
97 public static void main(final String[] args) throws NetworkException, OTSGeometryException, NamingException,
98 ValueRuntimeException, ParameterException, SimRuntimeException
99 {
100
101 SimLogger.setAllLogLevel(Level.WARNING);
102 SimLogger.setLogCategories(LogCategory.ALL);
103
104 String ip = null;
105 Integer port = null;
106
107 for (String arg : args)
108 {
109 int equalsPos = arg.indexOf("=");
110 if (equalsPos < 0)
111 {
112 System.err.println("Unhandled argument \"" + arg + "\"");
113 }
114 String key = arg.substring(0, equalsPos);
115 String value = arg.substring(equalsPos + 1);
116 switch (key.toUpperCase())
117 {
118 case "IP":
119 ip = value;
120 break;
121 case "PORT":
122 try
123 {
124 port = Integer.parseInt(value);
125 }
126 catch (NumberFormatException exception)
127 {
128 System.err.println("Bad port number \"" + value + "\"");
129 System.exit(1);
130 }
131 break;
132 default:
133 System.err.println("Unhandled argument \"" + arg + "\"");
134 }
135 }
136 if (null == ip || null == port)
137 {
138 System.err.println("Missing required argument(s) ip=<ip-number_or_hostname> port=<port-number>");
139 System.exit(1);
140 }
141 try
142 {
143 System.out.println("Creating server socket for port " + port);
144 ServerSocket serverSocket = new ServerSocket(port);
145 serverSocket.setReuseAddress(true);
146 System.out.println("Waiting for client to connect");
147 Socket clientSocket = serverSocket.accept();
148 System.out.println("Client connected; closing server socket");
149 serverSocket.close();
150 System.out.println("Socket time out is " + clientSocket.getSoTimeout());
151 clientSocket.setSoTimeout(0);
152 System.out.println("Constructing animation/simulation");
153 AimsunControlAimsunControl">AimsunControl aimsunControl = new AimsunControl();
154 aimsunControl.commandLoop(clientSocket);
155 }
156 catch (IOException exception)
157 {
158 exception.printStackTrace();
159 }
160 System.exit(0);
161 }
162
163
164 private Time simulateUntil = null;
165
166
167 private Boolean waitingForSimulator = false;
168
169
170
171
172
173
174 protected void sendGTUPositionsToAimsun(final OutputStream outputStream)
175 {
176 OTSSimulatorInterface simulator = this.model.getSimulator();
177 Time stopTime = simulator.getSimulatorTime();
178
179 AimsunControlProtoBuf.GTUPositions.Builder builder = AimsunControlProtoBuf.GTUPositions.newBuilder();
180 for (GTU gtu : this.model.getNetwork().getGTUs())
181 {
182 AimsunControlProtoBuf.GTUPositions.GTUPosition.Builder gpb =
183 AimsunControlProtoBuf.GTUPositions.GTUPosition.newBuilder();
184 gpb.setGtuId(gtu.getId());
185 DirectedPoint dp;
186 try
187 {
188 dp = gtu.getOperationalPlan().getLocation(stopTime);
189 gpb.setX(dp.x);
190 gpb.setY(dp.y);
191 gpb.setZ(dp.z);
192 gpb.setAngle(dp.getRotZ());
193 gpb.setLength(gtu.getLength().si);
194 gpb.setWidth(gtu.getWidth().si);
195 gpb.setGtuTypeId(Integer.parseInt(gtu.getGTUType().getId().split("\\.")[1]));
196 gpb.setSpeed(gtu.getSpeed().si);
197 builder.addGtuPos(gpb.build());
198 }
199 catch (OperationalPlanException exception)
200 {
201 exception.printStackTrace();
202 }
203 }
204 builder.setStatus("OK");
205 GTUPositions gtuPositions = builder.build();
206 AimsunControlProtoBuf.OTSMessage.Builder resultBuilder = AimsunControlProtoBuf.OTSMessage.newBuilder();
207 resultBuilder.setGtuPositions(gtuPositions);
208 AimsunControlProtoBuf.OTSMessage result = resultBuilder.build();
209 this.simulateUntil = null;
210 try
211 {
212 transmitMessage(result, outputStream);
213 }
214 catch (IOException exception)
215 {
216 exception.printStackTrace();
217 }
218
219 waitingForSimulator = false;
220
221 while (this.simulateUntil == null)
222 {
223 try
224 {
225 Thread.sleep(1);
226 }
227 catch (InterruptedException exception)
228 {
229 System.err.println("Interrupted exception (sendGTUPositionsToAimsun)");
230
231 }
232 }
233 try
234 {
235 simulator.scheduleEventAbs(this.simulateUntil, this, this, "sendGTUPositionsToAimsun", new Object[] {outputStream});
236 }
237 catch (SimRuntimeException exception)
238 {
239 exception.printStackTrace();
240 }
241
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255 private void commandLoop(final Socket socket) throws IOException, NetworkException, OTSGeometryException, NamingException,
256 ValueRuntimeException, ParameterException, SimRuntimeException
257 {
258 System.out.println("Entering command loop");
259 InputStream inputStream = socket.getInputStream();
260 OutputStream outputStream = socket.getOutputStream();
261 String error = null;
262 boolean simulatorStarted = false;
263 while (null == error)
264 {
265 try
266 {
267 if (waitingForSimulator)
268 {
269
270
271 while (waitingForSimulator)
272 {
273 if (!this.model.getSimulator().isRunning())
274 {
275 System.out.println("Simulator has stopped; constructing GTUPositions message with error status");
276 Time stopTime = this.model.getSimulator().getSimulatorTime();
277 AimsunControlProtoBuf.GTUPositions.Builder builder =
278 AimsunControlProtoBuf.GTUPositions.newBuilder();
279 for (GTU gtu : this.model.getNetwork().getGTUs())
280 {
281 AimsunControlProtoBuf.GTUPositions.GTUPosition.Builder gpb =
282 AimsunControlProtoBuf.GTUPositions.GTUPosition.newBuilder();
283 gpb.setGtuId(gtu.getId());
284 DirectedPoint dp;
285 try
286 {
287 dp = gtu.getOperationalPlan().getLocation(stopTime);
288 gpb.setX(dp.x);
289 gpb.setY(dp.y);
290 gpb.setZ(dp.z);
291 gpb.setAngle(dp.getRotZ());
292 gpb.setLength(gtu.getLength().si);
293 gpb.setWidth(gtu.getWidth().si);
294 gpb.setGtuTypeId(Integer.parseInt(gtu.getGTUType().getId().split("\\.")[1]));
295 gpb.setSpeed(gtu.getSpeed().si);
296 builder.addGtuPos(gpb.build());
297 }
298 catch (OperationalPlanException exception)
299 {
300 exception.printStackTrace();
301 }
302 }
303 builder.setStatus("ERROR");
304 GTUPositions gtuPositions = builder.build();
305 AimsunControlProtoBuf.OTSMessage.Builder resultBuilder =
306 AimsunControlProtoBuf.OTSMessage.newBuilder();
307 resultBuilder.setGtuPositions(gtuPositions);
308 AimsunControlProtoBuf.OTSMessage result = resultBuilder.build();
309 this.simulateUntil = null;
310 try
311 {
312 transmitMessage(result, outputStream);
313 }
314 catch (IOException exception)
315 {
316 exception.printStackTrace();
317 }
318 System.out.println("Error message sent");
319
320 waitingForSimulator = false;
321 break;
322 }
323 try
324 {
325 Thread.sleep(1);
326 }
327 catch (InterruptedException exception)
328 {
329 System.err.println("Interrupted exception (command loop)");
330
331 }
332 }
333
334
335 }
336 byte[] sizeBytes = new byte[4];
337
338 fillBuffer(inputStream, sizeBytes);
339 int size = ((sizeBytes[0] & 0xff) << 24) + ((sizeBytes[1] & 0xff) << 16) + ((sizeBytes[2] & 0xff) << 8)
340 + (sizeBytes[3] & 0xff);
341
342 byte[] buffer = new byte[size];
343 fillBuffer(inputStream, buffer);
344 AimsunControlProtoBuf.OTSMessage message = AimsunControlProtoBuf.OTSMessage.parseFrom(buffer);
345
346 if (null == message)
347 {
348 System.out.println("Connection terminated; exiting");
349 break;
350 }
351 switch (message.getMsgCase())
352 {
353 case CREATESIMULATION:
354 System.out.println("Received CREATESIMULATION message");
355 AimsunControlProtoBuf.CreateSimulation createSimulation = message.getCreateSimulation();
356 String networkXML = createSimulation.getNetworkXML();
357 try (PrintWriter pw = new PrintWriter("c:/Temp/AimsunOtsNetwork.xml"))
358 {
359 pw.print(networkXML);
360 }
361 Duration runDuration = new Duration(3600, DurationUnit.SECOND);
362 System.out.println("runDuration " + runDuration);
363 Duration warmupDuration = new Duration(0, DurationUnit.SECOND);
364 try
365 {
366 OTSAnimator animator = new OTSLoggingAnimator("C:/Temp/AimsunEventlog.txt");
367 this.model = new AimsunModel(animator, "Aimsun generated model", "Aimsun model", networkXML);
368 Map<String, StreamInterface> map = new LinkedHashMap<>();
369
370 map.put("generation", new MersenneTwister(6L));
371 animator.initialize(Time.ZERO, warmupDuration, runDuration, this.model, map);
372 OTSAnimationPanel animationPanel =
373 new OTSAnimationPanel(this.model.getNetwork().getExtent(), new Dimension(1100, 1000),
374 animator, this.model, OTSSwingApplication.DEFAULT_COLORER, this.model.getNetwork());
375 DefaultAnimationFactory.animateXmlNetwork(this.model.getNetwork(), animator,
376 new DefaultSwitchableGTUColorer());
377 new AimsunSwingApplication(this.model, animationPanel);
378 JFrame frame = (JFrame) animationPanel.getParent().getParent().getParent();
379 frame.setExtendedState(Frame.NORMAL);
380 frame.setSize(new Dimension(1100, 1000));
381 frame.setBounds(0, 25, 1100, 1000);
382 animator.setSpeedFactor(Double.MAX_VALUE, true);
383 animator.setSpeedFactor(1000.0, true);
384 try
385 {
386 Thread.sleep(300);
387 }
388 catch (InterruptedException e)
389 {
390 e.printStackTrace();
391 }
392 animationPanel.actionPerformed(new ActionEvent(this, 0, "ZoomAll"));
393 }
394 catch (SimRuntimeException | NamingException | OTSDrawingException exception1)
395 {
396 exception1.printStackTrace();
397
398 error = "XML ERROR";
399 }
400 break;
401
402 case SIMULATEUNTIL:
403 {
404 AimsunControlProtoBuf.SimulateUntil simulateUntilThing = message.getSimulateUntil();
405 Time stopTime = new Time(simulateUntilThing.getTime(), TimeUnit.BASE_SECOND);
406 System.out.println("Received SIMULATEUNTIL " + stopTime + " message");
407 OTSSimulatorInterface simulator = this.model.getSimulator();
408 if (!simulatorStarted)
409 {
410 simulatorStarted = true;
411 simulator.scheduleEventAbs(stopTime, this, this, "sendGTUPositionsToAimsun",
412 new Object[] {outputStream});
413 System.out.println("Starting simulator");
414 this.simulateUntil = stopTime;
415 simulator.start();
416 }
417 else if (!simulator.isRunning())
418 {
419
420 error = "HMM Simulator stopped";
421 }
422 else
423 {
424
425 waitingForSimulator = true;
426 this.simulateUntil = stopTime;
427 }
428 break;
429 }
430
431 case GTUPOSITIONS:
432 System.out.println("Received GTUPOSITIONS message SHOULD NOT HAPPEN");
433 socket.close();
434 return;
435
436 case MSG_NOT_SET:
437 System.out.println("Received MSG_NOT_SET message SHOULD NOT HAPPEN");
438 socket.close();
439 return;
440
441 default:
442 System.out.println("Received unknown message SHOULD NOT HAPPEN");
443 socket.close();
444 break;
445 }
446 }
447 catch (IOException exception)
448 {
449 exception.printStackTrace();
450 break;
451 }
452 }
453 }
454
455
456
457
458
459
460
461 private void transmitMessage(final AimsunControlProtoBuf.OTSMessage message, final OutputStream outputStream)
462 throws IOException
463 {
464 int size = message.getSerializedSize();
465
466
467 byte[] sizeBytes = new byte[4];
468 sizeBytes[0] = (byte) ((size >> 24) & 0xff);
469 sizeBytes[1] = (byte) ((size >> 16) & 0xff);
470 sizeBytes[2] = (byte) ((size >> 8) & 0xff);
471 sizeBytes[3] = (byte) (size & 0xff);
472 outputStream.write(sizeBytes);
473 byte[] buffer = new byte[size];
474 buffer = message.toByteArray();
475 outputStream.write(buffer);
476
477 }
478
479
480
481
482
483
484
485 static void fillBuffer(final InputStream in, final byte[] buffer) throws IOException
486 {
487
488 int offset = 0;
489 while (true)
490 {
491 int bytesRead = in.read(buffer, offset, buffer.length - offset);
492 if (-1 == bytesRead)
493 {
494 break;
495 }
496 offset += bytesRead;
497 if (buffer.length == offset)
498 {
499
500 break;
501 }
502 if (buffer.length < offset)
503 {
504 System.err.println("fillBuffer: Oops: Got more than " + buffer.length + " requested bytes");
505 break;
506 }
507
508
509 }
510 if (offset != buffer.length)
511 {
512 throw new IOException("Got only " + offset + " of expected " + buffer.length + " bytes");
513 }
514 }
515
516
517
518
519 class AimsunSwingApplication extends OTSSimulationApplication<OTSModelInterface>
520 {
521
522 private static final long serialVersionUID = 1L;
523
524
525
526
527
528
529 AimsunSwingApplication(final OTSModelInterface model, final OTSAnimationPanel panel) throws OTSDrawingException
530 {
531 super(model, panel);
532 }
533 }
534
535
536
537
538 class AimsunModel extends AbstractOTSModel implements EventListenerInterface
539 {
540
541 private static final long serialVersionUID = 20170419L;
542
543
544 private OTSRoadNetwork network;
545
546
547 private final String xml;
548
549
550
551
552
553
554
555 AimsunModel(final OTSSimulatorInterface simulator, final String shortName, final String description, final String xml)
556 {
557 super(simulator, shortName, description);
558 this.xml = xml;
559 }
560
561
562 @Override
563 public void notify(final EventInterface event) throws RemoteException
564 {
565 System.err.println("Received event " + event);
566 }
567
568
569 @Override
570 public void constructModel() throws SimRuntimeException
571 {
572 try
573 {
574 this.simulator.addListener(this, DEVSRealTimeClock.CHANGE_SPEED_FACTOR_EVENT);
575 this.simulator.addListener(this, SimulatorInterface.TIME_CHANGED_EVENT);
576 }
577 catch (RemoteException exception1)
578 {
579 exception1.printStackTrace();
580 }
581 this.network = new OTSRoadNetwork(getShortName(), true);
582 try
583 {
584 XmlNetworkLaneParser.build(new ByteArrayInputStream(this.xml.getBytes(StandardCharsets.UTF_8)), this.network,
585 getSimulator(), false);
586 LaneCombinationList ignoreList = new LaneCombinationList();
587 try
588 {
589
590 ignoreList.addLinkCombination((CrossSectionLink) this.network.getLink("928_J5"),
591 (CrossSectionLink) this.network.getLink("928_J6"));
592 ignoreList.addLinkCombination((CrossSectionLink) this.network.getLink("925_J1"),
593 (CrossSectionLink) this.network.getLink("925_J2"));
594 }
595 catch (NullPointerException npe)
596 {
597
598 }
599 LaneCombinationList permittedList = new LaneCombinationList();
600 ConflictBuilder.buildConflictsParallel(this.network, this.network.getGtuType(GTUType.DEFAULTS.VEHICLE),
601 getSimulator(), new ConflictBuilder.FixedWidthGenerator(Length.instantiateSI(2.0)), ignoreList,
602 permittedList);
603 new GTUDumper(simulator, Time.ZERO, Duration.instantiateSI(60), network, "C:/Temp/aimsun");
604 }
605 catch (NetworkException | OTSGeometryException | JAXBException | URISyntaxException | XmlParserException
606 | SAXException | ParserConfigurationException | GTUException exception)
607 {
608 exception.printStackTrace();
609
610
611 throw new SimRuntimeException(exception);
612 }
613 }
614
615
616 @Override
617 public OTSNetwork getNetwork()
618 {
619 return this.network;
620 }
621
622 }
623
624 }