#include <config.h>
#include <string>
#include <map>
#include <fstream>
#include <utils/common/StringTokenizer.h>
#include <utils/common/UtilExceptions.h>
#include <utils/common/MsgHandler.h>
#include <utils/common/StringUtils.h>
#include <utils/common/StringUtils.h>
#include <utils/common/ToString.h>
#include <utils/common/FileHelpers.h>
#include <utils/options/OptionsCont.h>
#include <utils/options/Option.h>
#include <utils/importio/LineReader.h>
#include <utils/common/StdDefs.h>
#include <polyconvert/PCPolyContainer.h>
#include "PCLoaderVisum.h"
#include <utils/common/RGBColor.h>
#include <utils/geom/GeomHelper.h>
#include <utils/geom/Boundary.h>
#include <utils/geom/Position.h>
#include <utils/geom/GeoConvHelper.h>
#include <utils/importio/NamedColumnsParser.h>
StringBijection<PCLoaderVisum::VISUM_KEY>::Entry PCLoaderVisum::KEYS_DE[] = {
{ "VSYS", VISUM_SYS },
{ "STRECKENTYP", VISUM_LINKTYPE },
{ "KNOTEN", VISUM_NODE },
{ "BEZIRK", VISUM_DISTRICT },
{ "PUNKT", VISUM_POINT },
{ "STRECKE", VISUM_LINK },
{ "V0IV", VISUM_V0 },
{ "VSYSSET", VISUM_TYPES },
{ "RANG", VISUM_RANK },
{ "KAPIV", VISUM_CAPACITY },
{ "XKOORD", VISUM_XCOORD },
{ "YKOORD", VISUM_YCOORD },
{ "ID", VISUM_ID },
{ "CODE", VISUM_CODE },
{ "VONKNOTNR", VISUM_FROMNODE },
{ "NACHKNOTNR", VISUM_TONODE },
{ "TYPNR", VISUM_TYPE },
{ "TYP", VISUM_TYP },
{ "ANBINDUNG", VISUM_DISTRICT_CONNECTION },
{ "BEZNR", VISUM_SOURCE_DISTRICT },
{ "KNOTNR", VISUM_FROMNODENO },
{ "RICHTUNG", VISUM_DIRECTION },
{ "FLAECHEID", VISUM_SURFACEID },
{ "TFLAECHEID", VISUM_FACEID },
{ "VONPUNKTID", VISUM_FROMPOINTID },
{ "NACHPUNKTID", VISUM_TOPOINTID },
{ "KANTE", VISUM_EDGE },
{ "ABBIEGER", VISUM_TURN },
{ "UEBERKNOTNR", VISUM_VIANODENO },
{ "ANZFAHRSTREIFEN", VISUM_NUMLANES },
{ "INDEX", VISUM_INDEX },
{ "STRECKENPOLY", VISUM_LINKPOLY },
{ "FLAECHENELEMENT", VISUM_SURFACEITEM },
{ "TEILFLAECHENELEMENT", VISUM_FACEITEM },
{ "KANTEID", VISUM_EDGEID },
{ "Q", VISUM_ORIGIN },
{ "Z", VISUM_DESTINATION },
{ "KATNR", VISUM_CATID },
{ "ZWISCHENPUNKT", VISUM_EDGEITEM },
{ "POIKATEGORIE", VISUM_POICATEGORY },
{ "NR", VISUM_NO }
};
StringBijection<PCLoaderVisum::VISUM_KEY> PCLoaderVisum::KEYS(PCLoaderVisum::KEYS_DE, VISUM_NO);
void
PCLoaderVisum::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill,
PCTypeMap& tm) {
if (!oc.isSet("visum-files")) {
return;
}
const std::string languageFile = oc.getString("visum.language-file");
if (languageFile != "") {
loadLanguage(languageFile);
}
std::vector<std::string> files = oc.getStringVector("visum-files");
for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
if (!FileHelpers::isReadable(*file)) {
throw ProcessError(TLF("Could not open visum-file '%'.", *file));
}
PROGRESS_BEGIN_MESSAGE("Parsing from visum-file '" + *file + "'");
load(*file, oc, toFill, tm);
PROGRESS_DONE_MESSAGE();
}
}
void
PCLoaderVisum::load(const std::string& file, OptionsCont& oc, PCPolyContainer& toFill,
PCTypeMap& tm) {
GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
std::string what;
std::map<long long int, Position> punkte;
std::map<long long int, PositionVector> kanten;
std::map<long long int, PositionVector> teilflaechen;
std::map<long long int, long long int> flaechenelemente;
NamedColumnsParser lineParser;
LineReader lr(file);
while (lr.hasMore()) {
std::string line = lr.readLine();
if (line.length() == 0 || line[0] == '*' || line[0] == '$') {
what = "";
}
if (what == "$" + KEYS.getString(VISUM_POINT)) {
lineParser.parseLine(line);
long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_ID)));
double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
Position pos(x, y);
if (!geoConvHelper.x2cartesian(pos)) {
WRITE_WARNINGF(TL("Unable to project coordinates for point '%'."), toString(id));
}
punkte[id] = pos;
continue;
} else if (what == "$" + KEYS.getString(VISUM_EDGE)) {
lineParser.parseLine(line);
long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_ID)));
long long int fromID = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FROMPOINTID)));
long long int toID = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_TOPOINTID)));
PositionVector vec;
vec.push_back(punkte[fromID]);
vec.push_back(punkte[toID]);
kanten[id] = vec;
continue;
} else if (what == "$" + KEYS.getString(VISUM_EDGEITEM)) {
lineParser.parseLine(line);
long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_EDGEID)));
int index = StringUtils::toInt(lineParser.get(KEYS.getString(VISUM_INDEX)));
double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
Position pos(x, y);
if (!geoConvHelper.x2cartesian(pos)) {
WRITE_WARNINGF(TL("Unable to project coordinates for edge '%'."), toString(id));
}
kanten[id].insert(kanten[id].begin() + index, pos);
continue;
} else if (what == "$" + KEYS.getString(VISUM_FACEITEM)) {
lineParser.parseLine(line);
long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FACEID)));
long long int kid = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_EDGEID)));
int dir = StringUtils::toInt(lineParser.get(KEYS.getString(VISUM_DIRECTION)));
if (teilflaechen.find(id) == teilflaechen.end()) {
teilflaechen[id] = PositionVector();
}
if (dir == 0) {
for (int i = 0; i < (int) kanten[kid].size(); ++i) {
teilflaechen[id].push_back_noDoublePos(kanten[kid][i]);
}
} else {
for (int i = (int) kanten[kid].size() - 1; i >= 0; --i) {
teilflaechen[id].push_back_noDoublePos(kanten[kid][i]);
}
}
continue;
} else if (what == "$" + KEYS.getString(VISUM_SURFACEITEM)) {
lineParser.parseLine(line);
long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
long long int tid = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FACEID)));
flaechenelemente[id] = tid;
continue;
}
if (line[0] == '$') {
what = "";
if (line.find("$" + KEYS.getString(VISUM_POINT) + ":") == 0) {
what = "$" + KEYS.getString(VISUM_POINT);
} else if (line.find("$" + KEYS.getString(VISUM_EDGE) + ":") == 0) {
what = "$" + KEYS.getString(VISUM_EDGE);
} else if (line.find("$" + KEYS.getString(VISUM_EDGEITEM) + ":") == 0) {
what = "$" + KEYS.getString(VISUM_EDGEITEM);
} else if (line.find("$" + KEYS.getString(VISUM_FACEITEM) + ":") == 0) {
what = "$" + KEYS.getString(VISUM_FACEITEM);
} else if (line.find("$" + KEYS.getString(VISUM_SURFACEITEM) + ":") == 0) {
what = "$" + KEYS.getString(VISUM_SURFACEITEM);
}
if (what != "") {
lineParser.reinit(line.substr(what.length() + 1));
}
}
}
RGBColor c = RGBColor::parseColor(oc.getString("color"));
std::map<std::string, std::string> typemap;
lr.reinit();
bool parsingCategories = false;
bool parsingPOIs = false;
bool parsingDistrictsDirectly = false;
PositionVector vec;
std::string polyType, lastID;
bool first = true;
while (lr.hasMore()) {
std::string line = lr.readLine();
if (line.length() == 0) {
continue;
}
if (line[0] == '*') {
continue;
}
if (line[0] == '$') {
parsingCategories = false;
parsingPOIs = false;
parsingDistrictsDirectly = false;
polyType = "";
}
if (parsingCategories) {
StringTokenizer st(line, ";");
std::string catid = st.next();
std::string catname = st.next();
typemap[catid] = catname;
}
if (parsingPOIs) {
lineParser.parseLine(line);
long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
std::string id = toString(idL);
std::string catid = lineParser.get(KEYS.getString(VISUM_CATID));
double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
Position pos(x, y);
if (!geoConvHelper.x2cartesian(pos)) {
WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), id);
}
std::string type = typemap[catid];
bool discard = oc.getBool("discard");
std::string icon = oc.getString("icon");
double layer = oc.getFloat("layer");
RGBColor color;
if (tm.has(type)) {
const PCTypeMap::TypeDef& def = tm.get(type);
id = def.prefix + id;
type = def.id;
color = def.color;
discard = def.discard;
icon = def.icon;
layer = def.layer;
} else {
id = oc.getString("prefix") + id;
color = c;
}
if (!discard) {
const std::string origId = id;
int index = 1;
while (toFill.getPOIs().get(id) != nullptr) {
id = origId + "#" + toString(index++);
}
PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer);
toFill.add(poi);
}
}
if (polyType != "") {
StringTokenizer st(line, ";");
std::string id = st.next();
std::string type;
if (!first && lastID != id) {
RGBColor color;
double layer = oc.getFloat("layer");
bool discard = oc.getBool("discard");
if (tm.has(polyType)) {
const PCTypeMap::TypeDef& def = tm.get(polyType);
id = def.prefix + id;
type = def.id;
color = def.color;
discard = def.discard;
layer = def.layer;
} else {
id = oc.getString("prefix") + id;
type = oc.getString("type");
color = c;
}
if (!discard) {
const std::string origId = id;
int index = 1;
while (toFill.getPolygons().get(id) != nullptr) {
id = origId + "#" + toString(index++);
}
SUMOPolygon* poly = new SUMOPolygon(id, type, color, vec, false, false, 1, layer);
toFill.add(poly);
}
vec.clear();
}
lastID = id;
first = false;
std::string index = st.next();
std::string xpos = st.next();
std::string ypos = st.next();
Position pos2D((double) atof(xpos.c_str()), (double) atof(ypos.c_str()));
if (!geoConvHelper.x2cartesian(pos2D)) {
WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), id);
}
vec.push_back(pos2D);
}
if (parsingDistrictsDirectly) {
lineParser.parseLine(line);
long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
std::string id = toString(idL);
long long int area = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
std::string type = "district";
bool discard = oc.getBool("discard");
std::string icon = oc.getString("icon");
double layer = oc.getFloat("layer");
RGBColor color;
if (tm.has(type)) {
const PCTypeMap::TypeDef& def = tm.get(type);
id = def.prefix + id;
type = def.id;
color = def.color;
discard = def.discard;
icon = def.icon;
layer = def.layer;
} else {
id = oc.getString("prefix") + id;
type = oc.getString("type");
color = c;
}
if (!discard) {
if (teilflaechen[flaechenelemente[area]].size() > 0) {
const std::string origId = id;
int index = 1;
while (toFill.getPolygons().get(id) != nullptr) {
id = origId + "#" + toString(index++);
}
const auto shape = teilflaechen[flaechenelemente[area]];
SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, false, 1, layer);
toFill.add(poly);
} else {
Position pos(x, y);
if (!geoConvHelper.x2cartesian(pos)) {
WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), id);
}
const std::string origId = id;
int index = 1;
while (toFill.getPOIs().get(id) != nullptr) {
id = origId + "#" + toString(index++);
}
PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer);
toFill.add(poi);
}
}
}
if (line.find("$POIKATEGORIEDEF:") == 0 || line.find("$" + KEYS.getString(VISUM_POICATEGORY) + ":") == 0) {
parsingCategories = true;
lineParser.reinit(line.substr(line.find(":") + 1));
}
if ((line.find("$POI:") == 0) || line.find("$POIOFCAT") != std::string::npos) {
parsingPOIs = true;
lineParser.reinit(line.substr(line.find(":") + 1));
}
if (line.find("$" + KEYS.getString(VISUM_DISTRICT)) == 0 && line.find(KEYS.getString(VISUM_SURFACEID)) != std::string::npos) {
parsingDistrictsDirectly = true;
lineParser.reinit(line.substr(line.find(":") + 1));
}
if (line.find("$BEZIRKPOLY") != std::string::npos) {
polyType = "district";
}
if (line.find("$GEBIETPOLY") != std::string::npos) {
polyType = "area";
}
}
}
void
PCLoaderVisum::loadLanguage(const std::string& file) {
std::ifstream strm(file.c_str());
if (!strm.good()) {
throw ProcessError(TLF("Could not load VISUM language map from '%'.", file));
}
while (strm.good()) {
std::string keyDE;
std::string keyNew;
strm >> keyDE;
strm >> keyNew;
if (KEYS.hasString(keyDE)) {
VISUM_KEY key = KEYS.get(keyDE);
KEYS.remove(keyDE, key);
KEYS.insert(keyNew, key);
} else if (keyDE != "") {
}
}
}