001/* *********************************************************************** *
002 * project: org.matsim.*
003 * LanesConsistencyChecker
004 *                                                                         *
005 * *********************************************************************** *
006 *                                                                         *
007 * copyright       : (C) 2009 by the members listed in the COPYING,        *
008 *                   LICENSE and WARRANTY file.                            *
009 * email           : info at matsim dot org                                *
010 *                                                                         *
011 * *********************************************************************** *
012 *                                                                         *
013 *   This program is free software; you can redistribute it and/or modify  *
014 *   it under the terms of the GNU General Public License as published by  *
015 *   the Free Software Foundation; either version 2 of the License, or     *
016 *   (at your option) any later version.                                   *
017 *   See also COPYING, LICENSE and WARRANTY file                           *
018 *                                                                         *
019 * *********************************************************************** */
020package org.matsim.lanes;
021
022import java.util.LinkedList;
023import java.util.List;
024
025import org.apache.log4j.Logger;
026import org.matsim.api.core.v01.Id;
027import org.matsim.api.core.v01.network.Link;
028import org.matsim.api.core.v01.network.Network;
029
030
031/**
032 * 
033 * @author dgrether, tthunig
034 */
035public final class LanesConsistencyChecker {
036  
037        private static final Logger log = Logger.getLogger(LanesConsistencyChecker.class);
038        private Network network;
039        private Lanes lanes;
040        private boolean removeMalformed = false;
041        
042        public LanesConsistencyChecker(Network net, Lanes laneDefs) {
043                this.network = net;
044                this.lanes = laneDefs;
045        }
046        
047        public void checkConsistency() {
048                log.info("checking consistency...");
049                List<Id<Link>> linksWithMalformedLanes = new LinkedList<>();
050                for (LanesToLinkAssignment l2l : this.lanes.getLanesToLinkAssignments().values()){
051                        if (!isLaneOnLinkConsistent(l2l)){
052                                linksWithMalformedLanes.add(l2l.getLinkId());
053                        }
054                }               
055                
056                if (this.removeMalformed){
057                        for (Id<Link> linkId : linksWithMalformedLanes) {
058                                this.lanes.getLanesToLinkAssignments().remove(linkId);
059                                log.info("remove lanes on link " + linkId);
060                        }
061                }
062                log.info("checked consistency. Lanes on " + linksWithMalformedLanes.size() + " links have been removed.");
063        }
064        
065        private boolean isLaneOnLinkConsistent(LanesToLinkAssignment l2l) {
066                //check if link exists for each assignment of one or more lanes to a link
067                if (!this.network.getLinks().containsKey(l2l.getLinkId())) {
068                        log.error("No link found for lanesToLinkAssignment on link Id(linkIdRef): "  + l2l.getLinkId());
069                        return false;
070                }
071                //check length
072                else {
073                        Link link = this.network.getLinks().get(l2l.getLinkId());
074                        for (Lane l : l2l.getLanes().values()){
075                                if (link.getLength() < l.getStartsAtMeterFromLinkEnd()) {
076                                        log.error("Link Id " + link.getId() + " is shorter than an assigned lane with id " + l.getId());
077                                        return false;
078                                }
079                        }
080                }
081                
082                //check toLinks or toLanes specified in the lanes 
083                for (Lane lane : l2l.getLanes().values()) {
084                        if (lane.getToLaneIds() != null) {
085                                for (Id<Lane> toLaneId : lane.getToLaneIds()){
086                                        if (! l2l.getLanes().containsKey(toLaneId)){
087                                                log.error("Error: toLane not existing:");
088                                                log.error("  Lane Id: " + lane.getId() + " on Link Id: " + l2l.getLinkId() + 
089                                                                " leads to Lane Id: " + toLaneId + " that is not existing!");
090                                                return false;
091                                                // TODO just delete this toLane?
092                                        }
093                                }
094                        }
095                        //check availability of toLink in network
096                        else if (lane.getToLinkIds() != null){
097                                for (Id<Link> toLinkId : lane.getToLinkIds()) {
098                                        if (! this.network.getLinks().containsKey(toLinkId)){
099                                                log.error("No link found in network for toLinkId " + toLinkId + " of laneId " + lane.getId() + " of link id " + l2l.getLinkId());
100                                                return false;
101                                                // TODO just delete this toLink?
102                                        } else {
103                                                Link link = this.network.getLinks().get(l2l.getLinkId());
104                                                if (! link.getToNode().getOutLinks().containsKey(toLinkId)){
105                                                        log.error("The given toLink " + toLinkId + " is not reachable from lane " + lane.getId() + " on link " + link.getId());
106                                                        return false;
107                                                        // TODO just delete this toLink?
108                                                }
109                                        }
110                                }
111                        }
112                }
113                
114                // comment this out, because not every out-link of a node has to be reached by every in-link. theresa, aug'17
115//              //second check matching of link's outlinks and lane's toLinks
116//              Link link = this.network.getLinks().get(l2l.getLinkId());
117//              log.info("Link id: " + l2l.getLinkId());
118//              Set<Id<Link>> toLinksFromLanes = new HashSet<>();
119//              for (Lane lane : l2l.getLanes().values()){
120//                      if (lane.getToLinkIds() != null){
121//                              toLinksFromLanes.addAll(lane.getToLinkIds());
122//                      }
123//              }
124//              
125//              for (Link nodeOutLink : link.getToNode().getOutLinks().values()){
126//                      log.info("\t\thas outlink: " + nodeOutLink.getId());
127//                      if (!toLinksFromLanes.contains(nodeOutLink.getId())){
128//                              log.error("Error: Lane Outlink: ");
129//                              log.error("\t\tThe lanes of link " + link.getId() + " do not lead to all of the outlinks of the links toNode " + link.getToNode().getId() + " . The outlink " + nodeOutLink.getId()
130//                              + " is not reachable from the lanes of this link. ");
131//                              for (Lane lane : l2l.getLanes().values()){
132//                                      log.error("\t\tLane id: " + lane.getId());
133//                                      if (lane.getToLinkIds() != null){
134//                                              for (Id<Link> id : lane.getToLinkIds()){
135//                                                      log.error("\t\t\t\thas toLinkId: " + id);
136//                                              }
137//                                      }
138//                                      log.error("End: Lane Outlink Error Message");
139//                              }
140//                              return false;
141//                      }
142//              }
143                return true;
144        }
145
146        public boolean isRemoveMalformed() {
147                return removeMalformed;
148        }
149        
150        public void setRemoveMalformed(boolean removeMalformed) {
151                this.removeMalformed = removeMalformed;
152        }
153
154}