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