1 package org.opentrafficsim.demo;
2
3 import java.awt.Dimension;
4 import java.net.URL;
5 import java.rmi.RemoteException;
6 import java.util.ArrayList;
7 import java.util.LinkedHashMap;
8 import java.util.LinkedHashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Random;
12 import java.util.Set;
13 import java.util.function.Supplier;
14
15 import javax.naming.NamingException;
16
17 import org.djunits.unit.AccelerationUnit;
18 import org.djunits.unit.DurationUnit;
19 import org.djunits.unit.FrequencyUnit;
20 import org.djunits.unit.LengthUnit;
21 import org.djunits.unit.SpeedUnit;
22 import org.djunits.value.vdouble.scalar.Acceleration;
23 import org.djunits.value.vdouble.scalar.Duration;
24 import org.djunits.value.vdouble.scalar.Frequency;
25 import org.djunits.value.vdouble.scalar.Length;
26 import org.djunits.value.vdouble.scalar.Speed;
27 import org.djunits.value.vdouble.scalar.Time;
28 import org.djutils.io.URLResource;
29 import org.opentrafficsim.animation.GraphLaneUtil;
30 import org.opentrafficsim.base.parameters.ParameterException;
31 import org.opentrafficsim.base.parameters.ParameterSet;
32 import org.opentrafficsim.base.parameters.ParameterTypes;
33 import org.opentrafficsim.core.definitions.DefaultsNl;
34 import org.opentrafficsim.core.distributions.ConstantGenerator;
35 import org.opentrafficsim.core.distributions.Distribution;
36 import org.opentrafficsim.core.distributions.FrequencyAndObject;
37 import org.opentrafficsim.core.distributions.Generator;
38 import org.opentrafficsim.core.dsol.AbstractOtsModel;
39 import org.opentrafficsim.core.dsol.OtsAnimator;
40 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
41 import org.opentrafficsim.core.gtu.GtuException;
42 import org.opentrafficsim.core.gtu.GtuType;
43 import org.opentrafficsim.core.idgenerator.IdGenerator;
44 import org.opentrafficsim.core.network.Link;
45 import org.opentrafficsim.core.network.NetworkException;
46 import org.opentrafficsim.core.network.Node;
47 import org.opentrafficsim.core.network.route.ProbabilisticRouteGenerator;
48 import org.opentrafficsim.core.network.route.Route;
49 import org.opentrafficsim.core.parameters.ParameterFactory;
50 import org.opentrafficsim.core.parameters.ParameterFactoryByType;
51 import org.opentrafficsim.core.perception.HistoryManagerDevs;
52 import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
53 import org.opentrafficsim.demo.ShortMerge.ShortMergeModel;
54 import org.opentrafficsim.draw.graphs.GraphPath;
55 import org.opentrafficsim.draw.graphs.PlotScheduler;
56 import org.opentrafficsim.draw.graphs.TrajectoryPlot;
57 import org.opentrafficsim.draw.gtu.DefaultCarAnimation.GtuData.GtuMarker;
58 import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
59 import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator;
60 import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator.RoomChecker;
61 import org.opentrafficsim.road.gtu.generator.TtcRoomChecker;
62 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuTemplate;
63 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuTemplateDistribution;
64 import org.opentrafficsim.road.gtu.generator.headway.HeadwayGenerator;
65 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
66 import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIdm;
67 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
68 import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlus;
69 import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlusFactory;
70 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationConflicts;
71 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationIncentive;
72 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationSpeedLimitTransition;
73 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationTrafficLights;
74 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLmrsPerceptionFactory;
75 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveCourtesy;
76 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveGetInLane;
77 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep;
78 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute;
79 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSocioSpeed;
80 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeedWithCourtesy;
81 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.Lmrs;
82 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory;
83 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
84 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
85 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
86 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.MandatoryIncentive;
87 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
88 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
89 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
90 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
91 import org.opentrafficsim.road.network.RoadNetwork;
92 import org.opentrafficsim.road.network.factory.xml.parser.XmlParser;
93 import org.opentrafficsim.road.network.lane.CrossSectionLink;
94 import org.opentrafficsim.road.network.lane.Lane;
95 import org.opentrafficsim.road.network.lane.LanePosition;
96 import org.opentrafficsim.road.network.lane.object.SpeedSign;
97 import org.opentrafficsim.road.network.sampling.LaneDataRoad;
98 import org.opentrafficsim.road.network.sampling.RoadSampler;
99 import org.opentrafficsim.swing.graphs.OtsPlotScheduler;
100 import org.opentrafficsim.swing.graphs.SwingPlot;
101 import org.opentrafficsim.swing.graphs.SwingTrajectoryPlot;
102 import org.opentrafficsim.swing.gui.AnimationToggles;
103 import org.opentrafficsim.swing.gui.OtsAnimationPanel;
104 import org.opentrafficsim.swing.gui.OtsSimulationApplication;
105
106 import nl.tudelft.simulation.dsol.SimRuntimeException;
107 import nl.tudelft.simulation.jstats.distributions.DistNormal;
108 import nl.tudelft.simulation.jstats.distributions.DistUniform;
109 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
110 import nl.tudelft.simulation.jstats.streams.StreamInterface;
111 import nl.tudelft.simulation.language.DsolException;
112
113
114
115
116
117
118
119
120
121
122 public class ShortMerge extends OtsSimulationApplication<ShortMergeModel>
123 {
124
125 private static final long serialVersionUID = 20170407L;
126
127
128 static final String NETWORK = "shortMerge";
129
130
131 static final double TRUCK_FRACTION = 0.15;
132
133
134 static final double LEFT_FRACTION = 0.3;
135
136
137 static final Frequency MAIN_DEMAND = new Frequency(1000, FrequencyUnit.PER_HOUR);
138
139
140 static final Frequency RAMP_DEMAND = new Frequency(500, FrequencyUnit.PER_HOUR);
141
142
143 static final Synchronization SYNCHRONIZATION = Synchronization.ALIGN_GAP;
144
145
146 static final Cooperation COOPERATION = Cooperation.PASSIVE_MOVING;
147
148
149 static final boolean ADDITIONAL_INCENTIVES = true;
150
151
152 public static final Time SIMTIME = Time.instantiateSI(3600);
153
154
155
156
157
158
159
160 public ShortMerge(final String title, final OtsAnimationPanel panel, final ShortMergeModel model)
161 {
162 super(model, panel, Map.of(DefaultsNl.TRUCK, GtuMarker.SQUARE));
163 }
164
165 @Override
166 protected void setAnimationToggles()
167 {
168 AnimationToggles.setTextAnimationTogglesFull(getAnimationPanel());
169 getAnimationPanel().getAnimationPanel().toggleClass(Link.class);
170 getAnimationPanel().getAnimationPanel().toggleClass(Node.class);
171 getAnimationPanel().getAnimationPanel().showClass(SpeedSign.class);
172 }
173
174 @Override
175 protected void addTabs()
176 {
177 GraphPath<LaneDataRoad> path;
178 try
179 {
180 Lane start = ((CrossSectionLink) getModel().getNetwork().getLink("AB")).getLanes().get(1);
181 path = GraphLaneUtil.createPath("Right lane", start);
182 }
183 catch (NetworkException exception)
184 {
185 throw new RuntimeException("Could not create a path as a lane has no set speed limit.", exception);
186 }
187 RoadSampler sampler = new RoadSampler(getModel().getNetwork());
188 GraphPath.initRecording(sampler, path);
189 PlotScheduler scheduler = new OtsPlotScheduler(getModel().getSimulator());
190 Duration updateInterval = Duration.instantiateSI(10.0);
191 SwingPlot plot = new SwingTrajectoryPlot(
192 new TrajectoryPlot("Trajectory right lane", updateInterval, scheduler, sampler.getSamplerData(), path));
193 getAnimationPanel().getTabbedPane().addTab(getAnimationPanel().getTabbedPane().getTabCount(), "Trajectories",
194 plot.getContentPane());
195 }
196
197
198
199
200
201 public static void main(final String[] args)
202 {
203 demo(true);
204 }
205
206
207
208
209
210 public static void demo(final boolean exitOnClose)
211 {
212 try
213 {
214 OtsAnimator simulator = new OtsAnimator("ShortMerge");
215 final ShortMergeModel otsModel = new ShortMergeModel(simulator);
216 simulator.initialize(Time.ZERO, Duration.ZERO, Duration.instantiateSI(SIMTIME.si), otsModel,
217 HistoryManagerDevs.noHistory(simulator));
218 OtsAnimationPanel animationPanel = new OtsAnimationPanel(otsModel.getNetwork().getExtent(), new Dimension(800, 600),
219 simulator, otsModel, DEFAULT_GTU_COLORERS, otsModel.getNetwork());
220 ShortMerge app = new ShortMerge("ShortMerge", animationPanel, otsModel);
221 app.setExitOnClose(exitOnClose);
222 animationPanel.enableSimulationControlButtons();
223 }
224 catch (SimRuntimeException | NamingException | RemoteException | IndexOutOfBoundsException | DsolException exception)
225 {
226 exception.printStackTrace();
227 }
228 }
229
230
231
232
233
234
235
236
237
238
239
240 public static class ShortMergeModel extends AbstractOtsModel
241 {
242
243 private static final long serialVersionUID = 20170407L;
244
245
246 private RoadNetwork network;
247
248
249
250
251 public ShortMergeModel(final OtsSimulatorInterface simulator)
252 {
253 super(simulator);
254 }
255
256
257
258
259 public void setNetwork(final RoadNetwork network)
260 {
261 this.network = network;
262 }
263
264 @Override
265 public void constructModel() throws SimRuntimeException
266 {
267 try
268 {
269 URL xmlURL = URLResource.getResource("/resources/lmrs/" + NETWORK + ".xml");
270 this.network = new RoadNetwork("ShortMerge", getSimulator());
271 new XmlParser(this.network).setUrl(xmlURL).build();
272 addGenerator();
273
274 }
275 catch (Exception exception)
276 {
277 exception.printStackTrace();
278 }
279 }
280
281 @Override
282 public RoadNetwork getNetwork()
283 {
284 return this.network;
285 }
286
287
288
289
290
291
292
293
294
295 private void addGenerator()
296 throws ParameterException, GtuException, NetworkException, SimRuntimeException, RemoteException
297 {
298
299 Random seedGenerator = new Random(1L);
300 Map<String, StreamInterface> streams = new LinkedHashMap<>();
301 StreamInterface stream = new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1);
302 streams.put("headwayGeneration", stream);
303 streams.put("gtuClass", new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1));
304 getStreamInformation().addStream("headwayGeneration", stream);
305 getStreamInformation().addStream("gtuClass", streams.get("gtuClass"));
306
307 TtcRoomChecker roomChecker = new TtcRoomChecker(new Duration(10.0, DurationUnit.SI));
308 IdGenerator idGenerator = new IdGenerator("");
309
310 CarFollowingModelFactory<IdmPlus> idmPlusFactory = new IdmPlusFactory(streams.get("gtuClass"));
311 ParameterSet params = new ParameterSet();
312 params.setDefaultParameter(AbstractIdm.DELTA);
313
314 Supplier<Set<MandatoryIncentive>> mandatorySupplier = () ->
315 {
316 Set<MandatoryIncentive> mandatoryIncentives = new LinkedHashSet<>();
317 mandatoryIncentives.add(new IncentiveRoute());
318 if (ADDITIONAL_INCENTIVES)
319 {
320 if ("".equals("We skip this for now"))
321 {
322 mandatoryIncentives.add(new IncentiveGetInLane());
323 }
324 }
325 return mandatoryIncentives;
326 };
327 Supplier<Set<VoluntaryIncentive>> voluntarySupplier = () ->
328 {
329 Set<VoluntaryIncentive> voluntaryIncentives = new LinkedHashSet<>();
330 voluntaryIncentives.add(new IncentiveSpeedWithCourtesy());
331 voluntaryIncentives.add(new IncentiveKeep());
332 if (ADDITIONAL_INCENTIVES)
333 {
334 voluntaryIncentives.add(new IncentiveCourtesy());
335 voluntaryIncentives.add(new IncentiveSocioSpeed());
336 }
337 return voluntaryIncentives;
338 };
339 Supplier<Set<AccelerationIncentive>> accelerationSupplier = () ->
340 {
341 Set<AccelerationIncentive> accelerationIncentives = new LinkedHashSet<>();
342 accelerationIncentives.add(new AccelerationSpeedLimitTransition());
343 accelerationIncentives.add(new AccelerationTrafficLights());
344 accelerationIncentives.add(new AccelerationConflicts());
345 return accelerationIncentives;
346 };
347
348 LaneBasedTacticalPlannerFactory<Lmrs> tacticalFactory = new LmrsFactory(idmPlusFactory,
349 new DefaultLmrsPerceptionFactory(), SYNCHRONIZATION, COOPERATION, GapAcceptance.INFORMED, Tailgating.NONE,
350 mandatorySupplier, voluntarySupplier, accelerationSupplier);
351
352 GtuType car = DefaultsNl.CAR;
353 GtuType truck = DefaultsNl.TRUCK;
354 Route routeAE = this.network.getShortestRouteBetween(car, this.network.getNode("A"), this.network.getNode("E"));
355 Route routeAG = !NETWORK.equals("shortWeave") ? null
356 : this.network.getShortestRouteBetween(car, this.network.getNode("A"), this.network.getNode("G"));
357 Route routeFE = this.network.getShortestRouteBetween(car, this.network.getNode("F"), this.network.getNode("E"));
358 Route routeFG = !NETWORK.equals("shortWeave") ? null
359 : this.network.getShortestRouteBetween(car, this.network.getNode("F"), this.network.getNode("G"));
360
361 double leftFraction = NETWORK.equals("shortWeave") ? LEFT_FRACTION : 0.0;
362 List<FrequencyAndObject<Route>> routesA = new ArrayList<>();
363 routesA.add(new FrequencyAndObject<>(1.0 - leftFraction, routeAE));
364 routesA.add(new FrequencyAndObject<>(leftFraction, routeAG));
365 List<FrequencyAndObject<Route>> routesF = new ArrayList<>();
366 routesF.add(new FrequencyAndObject<>(1.0 - leftFraction, routeFE));
367 routesF.add(new FrequencyAndObject<>(leftFraction, routeFG));
368 Generator<Route> routeGeneratorA = new ProbabilisticRouteGenerator(routesA, stream);
369 Generator<Route> routeGeneratorF = new ProbabilisticRouteGenerator(routesF, stream);
370
371 Speed speedA = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
372 Speed speedF = new Speed(20.0, SpeedUnit.KM_PER_HOUR);
373
374 CrossSectionLink linkA = (CrossSectionLink) this.network.getLink("AB");
375 CrossSectionLink linkF = (CrossSectionLink) this.network.getLink("FF2");
376
377 ParameterFactoryByType bcFactory = new ParameterFactoryByType();
378 bcFactory.addParameter(car, ParameterTypes.FSPEED, new DistNormal(stream, 123.7 / 120, 12.0 / 120));
379 bcFactory.addParameter(car, LmrsParameters.SOCIO, new DistNormal(stream, 0.5, 0.1));
380 bcFactory.addParameter(truck, ParameterTypes.A, new Acceleration(0.8, AccelerationUnit.SI));
381 bcFactory.addParameter(truck, LmrsParameters.SOCIO, new DistNormal(stream, 0.5, 0.1));
382 bcFactory.addParameter(Tailgating.RHO, Tailgating.RHO.getDefaultValue());
383
384 Generator<Duration> headwaysA1 = new HeadwayGenerator(MAIN_DEMAND, stream);
385 Generator<Duration> headwaysA2 = new HeadwayGenerator(MAIN_DEMAND, stream);
386 Generator<Duration> headwaysA3 = new HeadwayGenerator(MAIN_DEMAND, stream);
387 Generator<Duration> headwaysF = new HeadwayGenerator(RAMP_DEMAND, stream);
388
389
390 ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedCar =
391 new ContinuousDistDoubleScalar.Rel<>(new DistUniform(stream, 160, 200), SpeedUnit.KM_PER_HOUR);
392 ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedTruck =
393 new ContinuousDistDoubleScalar.Rel<>(new DistUniform(stream, 80, 95), SpeedUnit.KM_PER_HOUR);
394
395 LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
396 new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory, bcFactory);
397
398 LaneBasedGtuTemplate carA = new LaneBasedGtuTemplate(car, new ConstantGenerator<>(Length.instantiateSI(4.0)),
399 new ConstantGenerator<>(Length.instantiateSI(2.0)), speedCar, strategicalFactory, routeGeneratorA);
400 LaneBasedGtuTemplate carF = new LaneBasedGtuTemplate(car, new ConstantGenerator<>(Length.instantiateSI(4.0)),
401 new ConstantGenerator<>(Length.instantiateSI(2.0)), speedCar, strategicalFactory, routeGeneratorF);
402 LaneBasedGtuTemplate truckA = new LaneBasedGtuTemplate(truck, new ConstantGenerator<>(Length.instantiateSI(15.0)),
403 new ConstantGenerator<>(Length.instantiateSI(2.5)), speedTruck, strategicalFactory, routeGeneratorA);
404 LaneBasedGtuTemplate truckF = new LaneBasedGtuTemplate(truck, new ConstantGenerator<>(Length.instantiateSI(15.0)),
405 new ConstantGenerator<>(Length.instantiateSI(2.5)), speedTruck, strategicalFactory, routeGeneratorF);
406
407 Distribution<LaneBasedGtuTemplate> gtuTypeAllCarA = new Distribution<>(streams.get("gtuClass"));
408 gtuTypeAllCarA.add(new FrequencyAndObject<>(1.0, carA));
409
410 Distribution<LaneBasedGtuTemplate> gtuType1LaneF = new Distribution<>(streams.get("gtuClass"));
411 gtuType1LaneF.add(new FrequencyAndObject<>(1.0 - 2 * TRUCK_FRACTION, carF));
412 gtuType1LaneF.add(new FrequencyAndObject<>(2 * TRUCK_FRACTION, truckF));
413
414 Distribution<LaneBasedGtuTemplate> gtuType2ndLaneA = new Distribution<>(streams.get("gtuClass"));
415 gtuType2ndLaneA.add(new FrequencyAndObject<>(1.0 - 2 * TRUCK_FRACTION, carA));
416 gtuType2ndLaneA.add(new FrequencyAndObject<>(2 * TRUCK_FRACTION, truckA));
417
418 Distribution<LaneBasedGtuTemplate> gtuType3rdLaneA = new Distribution<>(streams.get("gtuClass"));
419 gtuType3rdLaneA.add(new FrequencyAndObject<>(1.0 - 3 * TRUCK_FRACTION, carA));
420 gtuType3rdLaneA.add(new FrequencyAndObject<>(3 * TRUCK_FRACTION, truckA));
421
422 makeGenerator(getLane(linkA, "FORWARD1"), speedA, "gen1", idGenerator, gtuTypeAllCarA, headwaysA1, roomChecker,
423 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
424 if (NETWORK.equals("shortWeave"))
425 {
426 makeGenerator(getLane(linkA, "FORWARD2"), speedA, "gen2", idGenerator, gtuTypeAllCarA, headwaysA2, roomChecker,
427 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
428 makeGenerator(getLane(linkA, "FORWARD3"), speedA, "gen3", idGenerator, gtuType3rdLaneA, headwaysA3, roomChecker,
429 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
430 }
431 else
432 {
433 makeGenerator(getLane(linkA, "FORWARD2"), speedA, "gen2", idGenerator, gtuType2ndLaneA, headwaysA2, roomChecker,
434 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
435 }
436 makeGenerator(getLane(linkF, "FORWARD1"), speedF, "gen4", idGenerator, gtuType1LaneF, headwaysF, roomChecker,
437 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
438
439 new SpeedSign("sign1", getLane(linkA, "FORWARD1"), Length.instantiateSI(10),
440 new Speed(130.0, SpeedUnit.KM_PER_HOUR), DefaultsNl.VEHICLE, Duration.ZERO,
441 new Duration(24, DurationUnit.HOUR));
442
443 }
444
445
446
447
448
449
450
451 private Lane getLane(final CrossSectionLink link, final String id)
452 {
453 return (Lane) link.getCrossSectionElement(id);
454 }
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473 private void makeGenerator(final Lane lane, final Speed generationSpeed, final String id, final IdGenerator idGenerator,
474 final Distribution<LaneBasedGtuTemplate> distribution, final Generator<Duration> headwayGenerator,
475 final RoomChecker roomChecker, final ParameterFactory bcFactory,
476 final LaneBasedTacticalPlannerFactory<?> tacticalFactory, final Time simulationTime,
477 final StreamInterface stream) throws SimRuntimeException, GtuException, ParameterException, NetworkException
478 {
479
480 Set<LanePosition> initialLongitudinalPositions = new LinkedHashSet<>();
481 initialLongitudinalPositions.add(new LanePosition(lane, new Length(5.0, LengthUnit.SI)));
482 LaneBasedGtuTemplateDistribution characteristicsGenerator = new LaneBasedGtuTemplateDistribution(distribution);
483 new LaneBasedGtuGenerator(id, headwayGenerator, characteristicsGenerator,
484 GeneratorPositions.create(initialLongitudinalPositions, stream), this.network, getSimulator(), roomChecker,
485 idGenerator);
486 }
487
488 }
489
490 }