#include <config.h>
#include <string>
#include <sstream>
#include <limits>
#include <utils/importio/LineHandler.h>
#include <utils/common/StringTokenizer.h>
#include <utils/common/MsgHandler.h>
#include <utils/common/UtilExceptions.h>
#include <utils/common/StringUtils.h>
#include <utils/common/ToString.h>
#include <utils/common/StringUtils.h>
#include <utils/options/OptionsCont.h>
#include <utils/importio/LineReader.h>
#include <utils/geom/GeoConvHelper.h>
#include <netbuild/NBNetBuilder.h>
#include <netbuild/NBNode.h>
#include <netbuild/NBNodeCont.h>
#include <netbuild/NBEdge.h>
#include <netbuild/NBEdgeCont.h>
#include <netbuild/NBTypeCont.h>
#include <netbuild/NBOwnTLDef.h>
#include <netimport/NINavTeqHelper.h>
#include "NILoader.h"
#include "NIImporter_DlrNavteq.h"
const std::string NIImporter_DlrNavteq::GEO_SCALE("1e-5");
const int NIImporter_DlrNavteq::EdgesHandler::MISSING_COLUMN = std::numeric_limits<int>::max();
const std::string NIImporter_DlrNavteq::UNDEFINED("-1");
bool NIImporter_DlrNavteq::keepLength = false;
void
NIImporter_DlrNavteq::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
if (!oc.isSet("dlr-navteq-prefix")) {
return;
}
time_t csTime;
time(&csTime);
keepLength = oc.getBool("dlr-navteq.keep-length");
LineReader lr;
std::map<std::string, PositionVector> myGeoms;
PROGRESS_BEGIN_MESSAGE(TL("Loading nodes"));
std::string file = oc.getString("dlr-navteq-prefix") + "_nodes_unsplitted.txt";
NodesHandler handler1(nb.getNodeCont(), file, myGeoms);
if (!lr.setFile(file)) {
throw ProcessError(TLF("The file '%' could not be opened.", file));
}
lr.readAll(handler1);
PROGRESS_DONE_MESSAGE();
std::map<std::string, std::string> streetNames;
if (oc.getBool("output.street-names")) {
file = oc.getString("dlr-navteq-prefix") + "_names.txt";
if (lr.setFile(file)) {
PROGRESS_BEGIN_MESSAGE(TL("Loading street names"));
NamesHandler handler4(file, streetNames);
lr.readAll(handler4);
PROGRESS_DONE_MESSAGE();
} else {
WRITE_WARNINGF(TL("Output will not contain street names because the file '%' was not found"), file);
}
}
PROGRESS_BEGIN_MESSAGE(TL("Loading edges"));
file = oc.getString("dlr-navteq-prefix") + "_links_unsplitted.txt";
EdgesHandler handler2(nb.getNodeCont(), nb.getEdgeCont(), nb.getTypeCont(), file, myGeoms, streetNames);
if (!lr.setFile(file)) {
throw ProcessError(TLF("The file '%' could not be opened.", file));
}
lr.readAll(handler2);
nb.getEdgeCont().recheckLaneSpread();
PROGRESS_DONE_MESSAGE();
file = oc.getString("dlr-navteq-prefix") + "_traffic_signals.txt";
if (lr.setFile(file)) {
PROGRESS_BEGIN_MESSAGE(TL("Loading traffic lights"));
TrafficlightsHandler handler3(nb.getNodeCont(), nb.getTLLogicCont(), nb.getEdgeCont(), file);
lr.readAll(handler3);
PROGRESS_DONE_MESSAGE();
}
file = oc.getString("dlr-navteq-prefix") + "_prohibited_manoeuvres.txt";
if (lr.setFile(file)) {
PROGRESS_BEGIN_MESSAGE(TL("Loading prohibited manoeuvres"));
ProhibitionHandler handler6(nb.getEdgeCont(), file, csTime);
lr.readAll(handler6);
PROGRESS_DONE_MESSAGE();
}
file = oc.getString("dlr-navteq-prefix") + "_connected_lanes.txt";
if (lr.setFile(file)) {
PROGRESS_BEGIN_MESSAGE(TL("Loading connected lanes"));
ConnectedLanesHandler handler7(nb.getEdgeCont());
lr.readAll(handler7);
PROGRESS_DONE_MESSAGE();
}
file = oc.getString("dlr-navteq-prefix") + "_links_timerestrictions.txt";
if (lr.setFile(file)) {
PROGRESS_BEGIN_MESSAGE(TL("Loading time restrictions"));
if (!oc.isDefault("construction-date")) {
csTime = readDate(oc.getString("construction-date"));
}
TimeRestrictionsHandler handler5(nb.getEdgeCont(), nb.getDistrictCont(), csTime);
lr.readAll(handler5);
handler5.printSummary();
PROGRESS_DONE_MESSAGE();
}
}
double
NIImporter_DlrNavteq::readVersion(const std::string& line, const std::string& file) {
assert(line[0] == '#');
const std::string marker = "extraction version: v";
const std::string lowerCase = StringUtils::to_lower_case(line);
if (lowerCase.find(marker) == std::string::npos) {
return -1;
}
const int vStart = (int)(lowerCase.find(marker) + marker.size());
const int vEnd = (int)line.find(" ", vStart);
try {
const double version = StringUtils::toDouble(line.substr(vStart, vEnd - vStart));
if (version < 0) {
throw ProcessError("Invalid version number '" + toString(version) + "' in file '" + file + "'.");
}
return version;
} catch (NumberFormatException&) {
throw ProcessError("Non-numerical value '" + line.substr(vStart, vEnd - vStart) + "' for version string in file '" + file + "'.");
}
}
NIImporter_DlrNavteq::NodesHandler::NodesHandler(NBNodeCont& nc,
const std::string& file,
std::map<std::string, PositionVector>& geoms)
: myNodeCont(nc), myGeoms(geoms) {
UNUSED_PARAMETER(file);
}
NIImporter_DlrNavteq::NodesHandler::~NodesHandler() {}
bool
NIImporter_DlrNavteq::NodesHandler::report(const std::string& result) {
if (result[0] == '#') {
return true;
}
std::string id;
double x, y;
int no_geoms, intermediate;
std::istringstream stream(result);
stream >> id;
if (stream.fail()) {
throw ProcessError("Something is wrong with the following data line\n" + result);
}
stream >> intermediate;
if (stream.fail()) {
if (myNodeCont.size() == 0) {
return true;
}
throw ProcessError(TLF("Non-numerical value for intermediate status in node %.", id));
}
stream >> no_geoms;
if (stream.fail()) {
throw ProcessError(TLF("Non-numerical value for number of geometries in node %.", id));
}
PositionVector geoms;
for (int i = 0; i < no_geoms; i++) {
stream >> x;
if (stream.fail()) {
throw ProcessError(TLF("Non-numerical value for x-position in node %.", id));
}
stream >> y;
if (stream.fail()) {
throw ProcessError(TLF("Non-numerical value for y-position in node %.", id));
}
Position pos(x, y);
if (!NBNetBuilder::transformCoordinate(pos, true)) {
throw ProcessError(TLF("Unable to project coordinates for node %.", id));
}
geoms.push_back(pos);
}
if (intermediate == 0) {
NBNode* n = new NBNode(id, geoms[0]);
if (!myNodeCont.insert(n)) {
delete n;
if (OptionsCont::getOptions().getBool("ignore-errors")) {
WRITE_WARNINGF(TL("Could not add node '%'."), id);
} else {
throw ProcessError(TLF("Could not add node '%'.", id));
}
}
} else {
myGeoms[id] = geoms;
}
return true;
}
NIImporter_DlrNavteq::EdgesHandler::EdgesHandler(NBNodeCont& nc, NBEdgeCont& ec,
NBTypeCont& tc, const std::string& file,
std::map<std::string, PositionVector>& geoms,
std::map<std::string, std::string>& streetNames):
myNodeCont(nc),
myEdgeCont(ec),
myTypeCont(tc),
myGeoms(geoms),
myStreetNames(streetNames),
myVersion(0),
myFile(file) {
}
NIImporter_DlrNavteq::EdgesHandler::~EdgesHandler() {}
bool
NIImporter_DlrNavteq::EdgesHandler::report(const std::string& result) {
if (result[0] == '#') {
if (!myColumns.empty()) {
return true;
}
const double version = readVersion(result, myFile);
if (version > 0) {
myVersion = version;
const int NUM_COLUMNS = 25;
const int MC = MISSING_COLUMN;
if (myVersion < 3) {
const int columns[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, MC, 12, 13, 14, 15, 16, 17, 18, 19, 20, MC, MC, -21};
myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
} else if (myVersion < 6) {
const int columns[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, MC, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, -23};
myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
} else {
const int columns[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
}
}
return true;
}
if (myColumns.empty()) {
throw ProcessError(TLF("Missing version string in file '%'.", myFile));
}
StringTokenizer st(result, StringTokenizer::WHITECHARS);
const std::string id = getColumn(st, LINK_ID);
int form_of_way;
try {
form_of_way = StringUtils::toInt(getColumn(st, FORM_OF_WAY));
} catch (NumberFormatException&) {
throw ProcessError(TLF("Non-numerical value for form_of_way of link '%'.", id));
}
int brunnel_type;
try {
brunnel_type = StringUtils::toInt(getColumn(st, BRUNNEL_TYPE));
} catch (NumberFormatException&) {
throw ProcessError(TLF("Non-numerical value for brunnel_type of link '%'.", id));
}
int priority;
try {
priority = -StringUtils::toInt(getColumn(st, FUNCTIONAL_ROAD_CLASS));
if (form_of_way == 11) {
priority -= 1;
} else if (form_of_way > 11) {
priority -= 2;
}
} catch (NumberFormatException&) {
throw ProcessError(TLF("Non-numerical value for street_type of link '%'.", id));
}
std::string streetName = getStreetNameFromIDs(
getColumn(st, NAME_ID1_REGIONAL),
getColumn(st, NAME_ID2_LOCAL));
const std::string fromID = getColumn(st, NODE_ID_FROM);
const std::string toID = getColumn(st, NODE_ID_TO);
NBNode* from = myNodeCont.retrieve(fromID);
NBNode* to = myNodeCont.retrieve(toID);
if (from == nullptr) {
throw ProcessError("The from-node '" + fromID + "' of link '" + id + "' could not be found");
}
if (to == nullptr) {
throw ProcessError("The to-node '" + toID + "' of link '" + id + "' could not be found");
}
double speed;
try {
speed = StringUtils::toInt(getColumn(st, SPEED_RESTRICTION, "-1")) / 3.6;
} catch (NumberFormatException&) {
throw ProcessError(TLF("Non-numerical value for the SPEED_RESTRICTION of link '%'.", id));
}
if (speed < 0) {
speed = NINavTeqHelper::getSpeed(id, getColumn(st, SPEED_CATEGORY));
}
int numLanes;
try {
numLanes = StringUtils::toInt(getColumn(st, EXTENDED_NUMBER_OF_LANES, "-1"));
if (numLanes == -1) {
numLanes = NINavTeqHelper::getLaneNumber(id, getColumn(st, NUMBER_OF_LANES), speed);
}
} catch (NumberFormatException&) {
throw ProcessError(TLF("Non-numerical value for the number of lanes of link '%'.", id));
}
const std::string navTeqTypeId = getColumn(st, VEHICLE_TYPE) + "_" + getColumn(st, FORM_OF_WAY);
NBEdge* e = nullptr;
const std::string interID = getColumn(st, BETWEEN_NODE_ID);
if (interID == "-1") {
e = new NBEdge(id, from, to, myTypeCont.knows(navTeqTypeId) ? navTeqTypeId : "", speed, NBEdge::UNSPECIFIED_FRICTION, numLanes, priority,
NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, LaneSpreadFunction::RIGHT, streetName);
} else {
PositionVector geoms = myGeoms[interID];
if (getColumn(st, CONNECTION, "0") == "1") {
geoms = geoms.reverse();
}
geoms.insert(geoms.begin(), from->getPosition());
geoms.push_back(to->getPosition());
const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? id : "";
e = new NBEdge(id, from, to, myTypeCont.knows(navTeqTypeId) ? navTeqTypeId : "", speed, NBEdge::UNSPECIFIED_FRICTION, numLanes, priority,
NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, geoms, LaneSpreadFunction::CENTER, streetName, origID);
}
if (keepLength) {
const double length = StringUtils::toDouble(getColumn(st, LENGTH));
e->setLoadedLength(length);
}
if (myTypeCont.knows(navTeqTypeId)) {
e->setPermissions(myTypeCont.getEdgeTypePermissions(navTeqTypeId));
} else {
const SVCPermissions allPermissions = myTypeCont.getEdgeTypePermissions("");
const SVCPermissions defaultPermissions = OptionsCont::getOptions().getBool("dlr-navteq.tolerant-permissions") ? allPermissions : 0;
if (myVersion < 6.0) {
NINavTeqHelper::addVehicleClasses(*e, getColumn(st, VEHICLE_TYPE), allPermissions, defaultPermissions);
} else {
NINavTeqHelper::addVehicleClassesV6(*e, getColumn(st, VEHICLE_TYPE), allPermissions, defaultPermissions);
}
if (form_of_way == 14) {
e->disallowVehicleClass(-1, SVC_PASSENGER);
}
if (brunnel_type == 10) {
e->setPermissions(SVC_SHIP, -1);
}
}
if (!myEdgeCont.insert(e)) {
delete e;
throw ProcessError(TLF("Could not add edge '%'.", id));
}
return true;
}
std::string
NIImporter_DlrNavteq::EdgesHandler::getColumn(const StringTokenizer& st, ColumnName name, const std::string fallback) {
assert(!myColumns.empty());
if (myColumns[name] == MISSING_COLUMN) {
if (fallback == "") {
throw ProcessError(TLF("Missing column %.", toString(name)));
} else {
return fallback;
}
} else if (myColumns[name] >= 0) {
return st.get((int)(myColumns[name]));
} else {
if ((int) st.size() <= -myColumns[name]) {
if (fallback == "") {
throw ProcessError(TLF("Missing optional column % without default value.", toString(name)));
} else {
return fallback;
}
} else {
return st.get((int)(-myColumns[name]));
}
}
}
std::string
NIImporter_DlrNavteq::EdgesHandler::getStreetNameFromIDs(
const std::string& regionalID, const std::string& localID) const {
std::string result = "";
bool hadRegional = false;
if (myStreetNames.count(regionalID) > 0) {
hadRegional = true;
result += myStreetNames[regionalID];
}
if (myStreetNames.count(localID) > 0) {
if (hadRegional) {
result += " / ";
}
result += myStreetNames[localID];
}
return result;
}
NIImporter_DlrNavteq::TrafficlightsHandler::TrafficlightsHandler(NBNodeCont& nc,
NBTrafficLightLogicCont& tlc,
NBEdgeCont& ne,
const std::string& file) :
myNodeCont(nc),
myTLLogicCont(tlc),
myEdgeCont(ne) {
UNUSED_PARAMETER(file);
}
NIImporter_DlrNavteq::TrafficlightsHandler::~TrafficlightsHandler() {}
bool
NIImporter_DlrNavteq::TrafficlightsHandler::report(const std::string& result) {
if (result[0] == '#') {
return true;
}
StringTokenizer st(result, StringTokenizer::WHITECHARS);
const std::string edgeID = st.get(5);
NBEdge* edge = myEdgeCont.retrieve(edgeID);
if (edge == nullptr) {
WRITE_WARNINGF(TL("The traffic light edge '%' could not be found."), edgeID);
} else {
NBNode* node = edge->getToNode();
if (node->getType() != SumoXMLNodeType::TRAFFIC_LIGHT) {
node->reinit(node->getPosition(), SumoXMLNodeType::TRAFFIC_LIGHT);
TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type"));
NBTrafficLightDefinition* tlDef = new NBOwnTLDef(node->getID(), node, 0, type);
if (!myTLLogicCont.insert(tlDef)) {
delete tlDef;
throw ProcessError(TLF("Could not allocate tls for '%'.", node->getID()));
}
}
}
return true;
}
NIImporter_DlrNavteq::NamesHandler::NamesHandler(
const std::string& file, std::map<std::string, std::string>& streetNames) :
myStreetNames(streetNames) {
UNUSED_PARAMETER(file);
}
NIImporter_DlrNavteq::NamesHandler::~NamesHandler() {}
bool
NIImporter_DlrNavteq::NamesHandler::report(const std::string& result) {
if (result[0] == '#') {
return true;
}
StringTokenizer st(result, StringTokenizer::TAB);
if (st.size() == 1) {
return true;
}
assert(st.size() >= 2);
const std::string id = st.next();
if (st.size() > 2) {
const std::string permanent_id_info = st.next();
}
myStreetNames[id] = st.next();
return true;
}
NIImporter_DlrNavteq::TimeRestrictionsHandler::TimeRestrictionsHandler(NBEdgeCont& ec, NBDistrictCont& dc, time_t constructionTime):
myEdgeCont(ec),
myDistrictCont(dc),
myConstructionTime(constructionTime),
myCS_min(std::numeric_limits<time_t>::max()),
myCS_max(std::numeric_limits<time_t>::min()),
myConstructionEntries(0),
myNotStarted(0),
myUnderConstruction(0),
myFinished(0),
myRemovedEdges(0) {
}
NIImporter_DlrNavteq::TimeRestrictionsHandler::~TimeRestrictionsHandler() {}
bool
NIImporter_DlrNavteq::TimeRestrictionsHandler::report(const std::string& result) {
if (result[0] == '#') {
return true;
}
StringTokenizer st(result, StringTokenizer::WHITECHARS);
const std::string id = st.next();
const std::string type = st.next();
const std::string directionOfFlow = st.next();
const std::string throughTraffic = st.next();
const std::string vehicleType = st.next();
const std::string validityPeriod = st.next();
const std::string warning = "Unrecognized TIME_REC '" + validityPeriod + "'";
if (type == "CS") {
myConstructionEntries++;
if (validityPeriod.size() > 1024) {
WRITE_WARNING(warning);
}
char start[1024];
char duration[1024];
int matched;
matched = sscanf(validityPeriod.c_str(), "[(%[^)]){%[^}]}]", start, duration);
if (matched == 2) {
time_t tStart = readTimeRec(start, "");
time_t tEnd = readTimeRec(start, duration);
myCS_min = MIN2(myCS_min, tStart);
myCS_max = MAX2(myCS_max, tEnd);
if (myConstructionTime < tEnd) {
NBEdge* edge = myEdgeCont.retrieve(id);
if (edge != nullptr) {
myRemovedEdges++;
myEdgeCont.extract(myDistrictCont, edge, true);
}
if (myConstructionTime < tStart) {
myNotStarted++;
} else {
myUnderConstruction++;
}
} else {
myFinished++;
}
} else {
WRITE_WARNING(warning);
};
}
return true;
}
void
NIImporter_DlrNavteq::TimeRestrictionsHandler::printSummary() {
if (myConstructionEntries > 0) {
char buff[1024];
std::ostringstream msg;
strftime(buff, 1024, "%Y-%m-%d", localtime(&myCS_min));
msg << "Parsed " << myConstructionEntries << " construction entries between " << buff;
strftime(buff, 1024, "%Y-%m-%d", localtime(&myCS_max));
msg << " and " << buff << ".\n";
strftime(buff, 1024, "%Y-%m-%d", localtime(&myConstructionTime));
msg << "Removed " << myRemovedEdges << " edges not yet constructed at " << buff << ".\n";
msg << " not yet started: " << myNotStarted << "\n";
msg << " under construction: " << myUnderConstruction << "\n";
msg << " finished: " << myFinished << "\n";
WRITE_MESSAGE(msg.str());
}
}
int
NIImporter_DlrNavteq::readPrefixedInt(const std::string& s, const std::string& prefix, int fallBack) {
int result = fallBack;
const size_t pos = s.find(prefix);
if (pos != std::string::npos) {
sscanf(s.substr(pos + prefix.size()).c_str(), "%i", &result);
}
return result;
}
time_t
NIImporter_DlrNavteq::readTimeRec(const std::string& start, const std::string& duration) {
struct tm timeinfo;
timeinfo.tm_hour = 0;
timeinfo.tm_min = 0;
timeinfo.tm_sec = 0;
timeinfo.tm_year = 0;
timeinfo.tm_mon = 0;
timeinfo.tm_mday = 1;
timeinfo.tm_wday = 0;
timeinfo.tm_yday = 0;
timeinfo.tm_isdst = 0;
timeinfo.tm_year = readPrefixedInt(start, "y") + readPrefixedInt(duration, "y") - 1900;
timeinfo.tm_mon = readPrefixedInt(start, "M") + readPrefixedInt(duration, "M") - 1;
timeinfo.tm_mday = 7 * (readPrefixedInt(start, "w") + readPrefixedInt(duration, "w"));
timeinfo.tm_mday += readPrefixedInt(start, "d") + readPrefixedInt(duration, "d");
time_t result = mktime(&timeinfo);
return result;
}
time_t
NIImporter_DlrNavteq::readDate(const std::string& yyyymmdd) {
struct tm timeinfo;
timeinfo.tm_hour = 0;
timeinfo.tm_min = 0;
timeinfo.tm_sec = 0;
timeinfo.tm_wday = 0;
timeinfo.tm_yday = 0;
timeinfo.tm_isdst = 0;
if (yyyymmdd.size() == 10
&& yyyymmdd[4] == '-'
&& yyyymmdd[7] == '-') {
try {
timeinfo.tm_year = StringUtils::toInt(yyyymmdd.substr(0, 4)) - 1900;
timeinfo.tm_mon = StringUtils::toInt(yyyymmdd.substr(5, 2)) - 1;
timeinfo.tm_mday = StringUtils::toInt(yyyymmdd.substr(8, 2));
return mktime(&timeinfo);
} catch (...) {
}
}
WRITE_ERRORF(TL("Could not parse YYYY-MM-DD date '%'"), yyyymmdd);
time_t now;
time(&now);
return now;
}
NIImporter_DlrNavteq::ProhibitionHandler::ProhibitionHandler(
NBEdgeCont& ec, const std::string& file, time_t constructionTime) :
myEdgeCont(ec),
myFile(file),
myVersion(0),
myConstructionTime(constructionTime) {
}
NIImporter_DlrNavteq::ProhibitionHandler::~ProhibitionHandler() {}
bool
NIImporter_DlrNavteq::ProhibitionHandler::report(const std::string& result) {
if (result[0] == '#') {
if (myVersion == 0) {
const double version = readVersion(result, myFile);
if (version > 0) {
myVersion = version;
}
}
return true;
}
StringTokenizer st(result, StringTokenizer::TAB);
if (st.size() == 1) {
return true;
}
if (myVersion >= 6) {
assert(st.size() >= 7);
const std::string id = st.next();
const std::string permanent = st.next();
const std::string validityPeriod = st.next();
const std::string throughTraffic = st.next();
const std::string vehicleType = st.next();
if (validityPeriod != UNDEFINED) {
WRITE_WARNINGF(TL("Ignoring temporary prohibited manoeuvre (%)."), validityPeriod);
return true;
}
}
const std::string startEdge = st.next();
const std::string endEdge = st.get(st.size() - 1);
NBEdge* from = myEdgeCont.retrieve(startEdge);
if (from == nullptr) {
WRITE_WARNINGF(TL("Ignoring prohibition from unknown start edge '%'."), startEdge);
return true;
}
NBEdge* to = myEdgeCont.retrieve(endEdge);
if (to == nullptr) {
WRITE_WARNINGF(TL("Ignoring prohibition from unknown end edge '%'."), endEdge);
return true;
}
from->removeFromConnections(to, -1, -1, true);
return true;
}
NIImporter_DlrNavteq::ConnectedLanesHandler::ConnectedLanesHandler(
NBEdgeCont& ec) :
myEdgeCont(ec) {
}
NIImporter_DlrNavteq::ConnectedLanesHandler::~ConnectedLanesHandler() {}
bool
NIImporter_DlrNavteq::ConnectedLanesHandler::report(const std::string& result) {
if (result[0] == '#') {
return true;
}
StringTokenizer st(result, StringTokenizer::TAB);
if (st.size() == 1) {
return true;
}
assert(st.size() >= 7);
const std::string nodeID = st.next();
const std::string vehicleType = st.next();
const std::string fromLaneS = st.next();
const std::string toLaneS = st.next();
const std::string throughTraffic = st.next();
const std::string startEdge = st.next();
const std::string endEdge = st.get(st.size() - 1);
NBEdge* from = myEdgeCont.retrieve(startEdge);
if (from == nullptr) {
WRITE_WARNINGF(TL("Ignoring prohibition from unknown start edge '%'."), startEdge);
return true;
}
NBEdge* to = myEdgeCont.retrieve(endEdge);
if (to == nullptr) {
WRITE_WARNINGF(TL("Ignoring prohibition from unknown end edge '%'."), endEdge);
return true;
}
int fromLane = StringUtils::toInt(fromLaneS) - 1;
if (fromLane < 0 || fromLane >= from->getNumLanes()) {
WRITE_WARNINGF(TL("Ignoring invalid lane index '%' in connection from edge '%' with % lanes."), fromLaneS, startEdge, from->getNumLanes());
return true;
}
int toLane = StringUtils::toInt(toLaneS) - 1;
if (toLane < 0 || toLane >= to->getNumLanes()) {
WRITE_WARNINGF(TL("Ignoring invalid lane index '%' in connection to edge '%' with % lanes"), toLaneS, endEdge, to->getNumLanes());
return true;
}
if (!from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::Lane2LaneInfoType::USER, true)) {
if (OptionsCont::getOptions().getBool("show-errors.connections-first-try")) {
WRITE_WARNINGF(TL("Could not set loaded connection from '%' to '%'."), from->getLaneID(fromLane), to->getLaneID(toLane));
}
const bool warnOnly = st.size() > 7;
myEdgeCont.addPostProcessConnection(from->getID(), fromLane, to->getID(), toLane, false, KEEPCLEAR_UNSPECIFIED,
NBEdge::UNSPECIFIED_CONTPOS, NBEdge::UNSPECIFIED_VISIBILITY_DISTANCE,
NBEdge::UNSPECIFIED_SPEED, NBEdge::UNSPECIFIED_FRICTION, NBEdge::UNSPECIFIED_LOADED_LENGTH, PositionVector::EMPTY, false, warnOnly);
}
from->declareConnectionsAsLoaded(NBEdge::EdgeBuildingStep::INIT);
from->getLaneStruct(fromLane).connectionsDone = true;
return true;
}