19 package org.matsim.core.network;
21 import org.apache.logging.log4j.LogManager;
22 import org.apache.logging.log4j.Logger;
48 final class NetworkImpl
implements Network, Lockable, TimeDependentNetwork, SearchableNetwork {
50 private final static Logger log = LogManager.getLogger(NetworkImpl.class);
52 private double capacityPeriod = 3600.0 ;
54 private final IdMap<Node, Node> nodes =
new IdMap<>(Node.class);
56 private final IdMap<Link, Link> links =
new IdMap<>(Link.class);
58 private QuadTree<Node> nodeQuadTree = null;
60 private LinkQuadTree linkQuadTree = null;
62 private static final double DEFAULT_EFFECTIVE_CELL_SIZE = 7.5;
64 private double effectiveCellSize = DEFAULT_EFFECTIVE_CELL_SIZE;
66 private double effectiveLaneWidth = 3.75;
68 private NetworkFactory factory;
72 private final Queue<NetworkChangeEvent> networkChangeEvents
79 =
new PriorityQueue<>(11,
new NetworkChangeEvent.StartTimeComparator() ) ;
81 private String name = null;
83 private int counter=0;
85 private int nextMsg=1;
87 private int counter2=0;
89 private int nextMsg2=1;
91 private boolean locked = false ;
92 private final Attributes attributes =
new AttributesImpl();
94 NetworkImpl(LinkFactory linkFactory) {
95 this.factory =
new NetworkFactoryImpl(
this, linkFactory);
99 public void addLink(
final Link link) {
100 Link testLink = links.get(link.getId());
101 if (testLink != null) {
102 if (testLink == link) {
103 log.warn(
"Trying to add a link a second time to the network. link id = " + link.getId().toString());
106 throw new IllegalArgumentException(
"There exists already a link with id = " + link.getId().toString() +
107 ".\nExisting link: " + testLink +
"\nLink to be added: " + link +
108 ".\nLink is not added to the network.");
112 Node fromNode = nodes.get(link.getFromNode().getId());
113 if (fromNode == null) {
114 throw new IllegalArgumentException(
"Trying to add link = " + link.getId() +
", but its fromNode = " + link.getFromNode().getId() +
" has not been added to the network.");
116 Node toNode = nodes.get(link.getToNode().getId());
117 if (toNode == null) {
118 throw new IllegalArgumentException(
"Trying to add link = " + link.getId() +
", but its toNode = " + link.getToNode().getId() +
" has not been added to the network.");
121 if (!fromNode.getOutLinks().containsKey(link.getId()))
122 fromNode.addOutLink(link);
123 if (!toNode.getInLinks().containsKey(link.getId()))
124 toNode.addInLink(link);
126 link.setFromNode(fromNode);
127 link.setToNode(toNode);
129 links.put(link.getId(), link);
131 if (this.linkQuadTree != null) {
132 double linkMinX = Math.min(link.getFromNode().getCoord().getX(), link.getToNode().getCoord().getX());
133 double linkMaxX = Math.max(link.getFromNode().getCoord().getX(), link.getToNode().getCoord().getX());
134 double linkMinY = Math.min(link.getFromNode().getCoord().getY(), link.getToNode().getCoord().getY());
135 double linkMaxY = Math.max(link.getFromNode().getCoord().getY(), link.getToNode().getCoord().getY());
136 if (Double.isInfinite(
this.linkQuadTree.getMinEasting())) {
138 this.linkQuadTree = null;
139 }
else if (this.linkQuadTree.getMinEasting() <= linkMinX && this.linkQuadTree.getMaxEasting() > linkMaxX
140 && this.linkQuadTree.getMinNorthing() <= linkMinY && this.linkQuadTree.getMaxNorthing() > linkMaxY) {
141 this.linkQuadTree.put(link);
144 this.linkQuadTree = null;
151 if (this.counter % this.nextMsg == 0) {
155 if ( this.locked && link instanceof Lockable ) {
156 ((Lockable)link).setLocked() ;
160 private void printLinksCount() {
161 log.info(
" link # " + this.counter);
164 private void printNodesCount() {
165 log.info(
" node # " + this.counter2);
169 public void addNode(
final Node nn) {
170 Id<Node>
id = nn.getId() ;
171 Node node = this.nodes.get(
id);
174 log.warn(
"Trying to add a node a second time to the network. node id = " +
id.toString());
177 throw new IllegalArgumentException(
"There exists already a node with id = " +
id.toString() +
178 ".\nExisting node: " + node +
"\nNode to be added: " + nn +
179 ".\nNode is not added to the network.");
181 this.nodes.put(
id, nn);
182 if (this.nodeQuadTree != null) {
183 if (Double.isInfinite(
this.nodeQuadTree.getMinEasting())) {
185 this.nodeQuadTree.clear();
186 this.nodeQuadTree = null;
187 }
else if (this.nodeQuadTree.getMinEasting() <= nn.getCoord().getX() && this.nodeQuadTree.getMaxEasting() > nn.getCoord().getX()
188 && this.nodeQuadTree.getMinNorthing() <= nn.getCoord().getY() && this.nodeQuadTree.getMaxNorthing() > nn.getCoord().getY()) {
189 this.nodeQuadTree.put(nn.getCoord().getX(), nn.getCoord().getY(), nn);
192 this.nodeQuadTree.clear();
193 this.nodeQuadTree = null;
199 if (this.counter2 % this.nextMsg2 == 0) {
204 if ( this.locked && nn instanceof Lockable ) {
205 ((Lockable)nn).setLocked() ;
213 public Node removeNode(
final Id<Node> nodeId) {
214 Node n = this.nodes.remove(nodeId);
218 HashSet<Link> links1 =
new HashSet<>();
219 links1.addAll(n.getInLinks().values());
220 links1.addAll(n.getOutLinks().values());
221 for (Link l : links1) {
222 removeLink(l.getId());
224 if (this.nodeQuadTree != null) {
225 this.nodeQuadTree.remove(n.getCoord().getX(),n.getCoord().getY(),n);
231 public Link removeLink(
final Id<Link> linkId) {
232 Link l = this.links.remove(linkId);
236 l.getFromNode().removeOutLink(l.getId()) ;
237 l.getToNode().removeInLink(l.getId()) ;
239 if (this.linkQuadTree != null) {
240 this.linkQuadTree.remove(l);
254 public void setCapacityPeriod(
final double capPeriod) {
256 this.capacityPeriod = (int) capPeriod;
259 public void setEffectiveCellSize(
final double effectiveCellSize) {
261 if (this.effectiveCellSize != effectiveCellSize) {
262 if (effectiveCellSize != DEFAULT_EFFECTIVE_CELL_SIZE) {
263 log.warn(
"Setting effectiveCellSize to a non-default value of " + effectiveCellSize);
265 log.info(
"Setting effectiveCellSize to " + effectiveCellSize);
267 this.effectiveCellSize = effectiveCellSize;
271 public void setEffectiveLaneWidth(
final double effectiveLaneWidth) {
273 if (!Double.isNaN(
this.effectiveLaneWidth) && this.effectiveLaneWidth != effectiveLaneWidth) {
274 log.warn(
this +
"[effectiveLaneWidth=" + this.effectiveLaneWidth +
" already set. Will be overwritten with " + effectiveLaneWidth +
"]");
276 this.effectiveLaneWidth = effectiveLaneWidth;
286 @Override
public void setNetworkChangeEvents(
final List<NetworkChangeEvent> events) {
287 this.networkChangeEvents.clear();
288 for(Link link : getLinks().values()) {
289 if (link instanceof TimeVariantLinkImpl) {
290 ((TimeVariantLinkImpl)link).clearEvents();
296 for (NetworkChangeEvent event : events) {
297 this.addNetworkChangeEvent(event);
309 public void addNetworkChangeEvent(
final NetworkChangeEvent event) {
310 this.networkChangeEvents.add(event);
311 for (Link link : event.getLinks()) {
312 if (link instanceof TimeVariantLinkImpl) {
313 ((TimeVariantLinkImpl)link).applyEvent(event);
315 throw new IllegalArgumentException(
"Link " + link.getId().toString() +
" is not timeVariant. " 316 +
"Did you make the network factory time variant? The easiest way to achieve this is " 317 +
"either in the config file, or syntax of the type\n" 318 +
"config.network().setTimeVariantNetwork(true);\n" 319 +
"Scenario scenario = ScenarioUtils.load/createScenario(config);\n" 320 +
"Note that the scenario needs to be created _after_ the config option is set, otherwise" 321 +
"the factory will already be there.");
327 public double getCapacityPeriod() {
328 return this.capacityPeriod;
331 public double getEffectiveCellSize() {
332 return this.effectiveCellSize;
336 public double getEffectiveLaneWidth() {
337 return this.effectiveLaneWidth;
341 public Map<Id<Node>, Node> getNodes() {
342 return Collections.unmodifiableMap(this.nodes);
345 @Override
public Link getNearestLinkExactly(
final Coord coord) {
346 return this.getLinkQuadTree().getNearest(coord.getX(), coord.getY());
355 @Override
public Node getNearestNode(
final Coord coord) {
356 return this.getNodeQuadTree().getClosest(coord.getX(), coord.getY());
366 @Override
public Collection<Node> getNearestNodes(
final Coord coord,
final double distance) {
367 return this.getNodeQuadTree().getDisk(coord.getX(), coord.getY(), distance);
371 public Queue<NetworkChangeEvent> getNetworkChangeEvents() {
372 return this.networkChangeEvents;
375 public NetworkFactory getFactory() {
384 public String toString() {
385 return super.toString() +
386 "[capperiod=" + this.capacityPeriod +
"]" +
387 "[nof_nodes=" + this.nodes.size() +
"]";
395 synchronized private void buildQuadTree() {
399 if (this.nodeQuadTree != null) {
402 double startTime = System.currentTimeMillis();
403 double minx = Double.POSITIVE_INFINITY;
404 double miny = Double.POSITIVE_INFINITY;
405 double maxx = Double.NEGATIVE_INFINITY;
406 double maxy = Double.NEGATIVE_INFINITY;
407 for (Node n : this.nodes.values()) {
408 if (n.getCoord().getX() < minx) { minx = n.getCoord().getX(); }
409 if (n.getCoord().getY() < miny) { miny = n.getCoord().getY(); }
410 if (n.getCoord().getX() > maxx) { maxx = n.getCoord().getX(); }
411 if (n.getCoord().getY() > maxy) { maxy = n.getCoord().getY(); }
419 log.info(
"building QuadTree for nodes: xrange(" + minx +
"," + maxx +
"); yrange(" + miny +
"," + maxy +
")");
420 QuadTree<Node> quadTree =
new QuadTree<>(minx, miny, maxx, maxy);
421 for (Node n : this.nodes.values()) {
422 quadTree.put(n.getCoord().getX(), n.getCoord().getY(), n);
427 this.nodeQuadTree = quadTree;
428 log.info(
"Building QuadTree took " + ((System.currentTimeMillis() - startTime) / 1000.0) +
" seconds.");
431 synchronized private void buildLinkQuadTree() {
432 if (this.linkQuadTree != null) {
435 double startTime = System.currentTimeMillis();
436 double minx = Double.POSITIVE_INFINITY;
437 double miny = Double.POSITIVE_INFINITY;
438 double maxx = Double.NEGATIVE_INFINITY;
439 double maxy = Double.NEGATIVE_INFINITY;
440 for (Node n : this.nodes.values()) {
441 if (n.getCoord().getX() < minx) { minx = n.getCoord().getX(); }
442 if (n.getCoord().getY() < miny) { miny = n.getCoord().getY(); }
443 if (n.getCoord().getX() > maxx) { maxx = n.getCoord().getX(); }
444 if (n.getCoord().getY() > maxy) { maxy = n.getCoord().getY(); }
452 log.info(
"building LinkQuadTree for nodes: xrange(" + minx +
"," + maxx +
"); yrange(" + miny +
"," + maxy +
")");
453 LinkQuadTree qt =
new LinkQuadTree(minx, miny, maxx, maxy);
454 for (Link l : this.links.values()) {
457 this.linkQuadTree = qt;
458 log.info(
"Building LinkQuadTree took " + ((System.currentTimeMillis() - startTime) / 1000.0) +
" seconds.");
462 public Map<Id<Link>, Link> getLinks() {
463 return Collections.unmodifiableMap(links);
466 void setFactory(
final NetworkFactory networkFactory) {
467 this.factory = networkFactory;
471 public String getName() {
475 public void setName(String name) {
480 public void setLocked() {
482 for ( Link link : this.links.values() ) {
483 if ( link instanceof Lockable ) {
484 ((Lockable) link).setLocked();
487 for ( Node node : this.nodes.values() ) {
488 if ( node instanceof Lockable ) {
489 ((Lockable) node).setLocked();
493 private void testForLocked() {
495 throw new RuntimeException(
"Network is locked; too late to do this. See comments in code.") ;
498 @Override
public Attributes getAttributes() {
501 @Override
public LinkQuadTree getLinkQuadTree() {
502 if (this.linkQuadTree == null) buildLinkQuadTree();
503 return this.linkQuadTree ;
505 @Override
public QuadTree<Node> getNodeQuadTree() {
506 if (this.nodeQuadTree == null) buildQuadTree();
507 return this.nodeQuadTree ;