Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file PCLoaderVisum.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Christoph Sommer
18 : /// @author Michael Behrisch
19 : /// @date Thu, 02.11.2006
20 : ///
21 : // A reader of pois and polygons stored in VISUM-format
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <string>
26 : #include <map>
27 : #include <fstream>
28 : #include <utils/common/StringTokenizer.h>
29 : #include <utils/common/UtilExceptions.h>
30 : #include <utils/common/MsgHandler.h>
31 : #include <utils/common/StringUtils.h>
32 : #include <utils/common/StringUtils.h>
33 : #include <utils/common/ToString.h>
34 : #include <utils/common/FileHelpers.h>
35 : #include <utils/options/OptionsCont.h>
36 : #include <utils/options/Option.h>
37 : #include <utils/importio/LineReader.h>
38 : #include <utils/common/StdDefs.h>
39 : #include <polyconvert/PCPolyContainer.h>
40 : #include "PCLoaderVisum.h"
41 : #include <utils/common/RGBColor.h>
42 : #include <utils/geom/GeomHelper.h>
43 : #include <utils/geom/Boundary.h>
44 : #include <utils/geom/Position.h>
45 : #include <utils/geom/GeoConvHelper.h>
46 : #include <utils/importio/NamedColumnsParser.h>
47 :
48 : StringBijection<PCLoaderVisum::VISUM_KEY>::Entry PCLoaderVisum::KEYS_DE[] = {
49 : // duplicates NIImporter_VISUM::KEYS_DE due to lack of suitable common location
50 : { "VSYS", VISUM_SYS },
51 : { "STRECKENTYP", VISUM_LINKTYPE },
52 : { "KNOTEN", VISUM_NODE },
53 : { "BEZIRK", VISUM_DISTRICT },
54 : { "PUNKT", VISUM_POINT },
55 : { "STRECKE", VISUM_LINK },
56 : { "V0IV", VISUM_V0 },
57 : { "VSYSSET", VISUM_TYPES },
58 : { "RANG", VISUM_RANK },
59 : { "KAPIV", VISUM_CAPACITY },
60 : { "XKOORD", VISUM_XCOORD },
61 : { "YKOORD", VISUM_YCOORD },
62 : { "ID", VISUM_ID },
63 : { "CODE", VISUM_CODE },
64 : { "VONKNOTNR", VISUM_FROMNODE },
65 : { "NACHKNOTNR", VISUM_TONODE },
66 : { "TYPNR", VISUM_TYPE },
67 : { "TYP", VISUM_TYP },
68 : { "ANBINDUNG", VISUM_DISTRICT_CONNECTION },
69 : { "BEZNR", VISUM_SOURCE_DISTRICT },
70 : { "KNOTNR", VISUM_FROMNODENO },
71 : { "RICHTUNG", VISUM_DIRECTION },
72 : { "FLAECHEID", VISUM_SURFACEID },
73 : { "TFLAECHEID", VISUM_FACEID },
74 : { "VONPUNKTID", VISUM_FROMPOINTID },
75 : { "NACHPUNKTID", VISUM_TOPOINTID },
76 : { "KANTE", VISUM_EDGE },
77 : { "ABBIEGER", VISUM_TURN },
78 : { "UEBERKNOTNR", VISUM_VIANODENO },
79 : { "ANZFAHRSTREIFEN", VISUM_NUMLANES },
80 : { "INDEX", VISUM_INDEX },
81 : { "STRECKENPOLY", VISUM_LINKPOLY },
82 : { "FLAECHENELEMENT", VISUM_SURFACEITEM },
83 : { "TEILFLAECHENELEMENT", VISUM_FACEITEM },
84 : { "KANTEID", VISUM_EDGEID },
85 : { "Q", VISUM_ORIGIN },
86 : { "Z", VISUM_DESTINATION },
87 : { "KATNR", VISUM_CATID },
88 : { "ZWISCHENPUNKT", VISUM_EDGEITEM },
89 : { "POIKATEGORIE", VISUM_POICATEGORY },
90 : { "NR", VISUM_NO } // must be the last one
91 : };
92 :
93 :
94 : StringBijection<PCLoaderVisum::VISUM_KEY> PCLoaderVisum::KEYS(PCLoaderVisum::KEYS_DE, VISUM_NO);
95 :
96 :
97 : // ===========================================================================
98 : // method definitions
99 : // ===========================================================================
100 : void
101 41 : PCLoaderVisum::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill,
102 : PCTypeMap& tm) {
103 82 : if (!oc.isSet("visum-files")) {
104 41 : return;
105 : }
106 0 : const std::string languageFile = oc.getString("visum.language-file");
107 0 : if (languageFile != "") {
108 0 : loadLanguage(languageFile);
109 : }
110 : // parse file(s)
111 0 : std::vector<std::string> files = oc.getStringVector("visum-files");
112 0 : for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
113 0 : if (!FileHelpers::isReadable(*file)) {
114 0 : throw ProcessError(TLF("Could not open visum-file '%'.", *file));
115 : }
116 0 : PROGRESS_BEGIN_MESSAGE("Parsing from visum-file '" + *file + "'");
117 0 : load(*file, oc, toFill, tm);
118 0 : PROGRESS_DONE_MESSAGE();
119 : }
120 0 : }
121 :
122 :
123 :
124 : void
125 0 : PCLoaderVisum::load(const std::string& file, OptionsCont& oc, PCPolyContainer& toFill,
126 : PCTypeMap& tm) {
127 : GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
128 : std::string what;
129 : std::map<long long int, Position> punkte;
130 : std::map<long long int, PositionVector> kanten;
131 : std::map<long long int, PositionVector> teilflaechen;
132 : std::map<long long int, long long int> flaechenelemente;
133 0 : NamedColumnsParser lineParser;
134 0 : LineReader lr(file);
135 0 : while (lr.hasMore()) {
136 0 : std::string line = lr.readLine();
137 : // reset if current is over
138 0 : if (line.length() == 0 || line[0] == '*' || line[0] == '$') {
139 : what = "";
140 : }
141 : // read items
142 0 : if (what == "$" + KEYS.getString(VISUM_POINT)) {
143 0 : lineParser.parseLine(line);
144 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_ID)));
145 0 : double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
146 0 : double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
147 : Position pos(x, y);
148 0 : if (!geoConvHelper.x2cartesian(pos)) {
149 0 : WRITE_WARNINGF(TL("Unable to project coordinates for point '%'."), toString(id));
150 : }
151 0 : punkte[id] = pos;
152 : continue;
153 0 : } else if (what == "$" + KEYS.getString(VISUM_EDGE)) {
154 0 : lineParser.parseLine(line);
155 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_ID)));
156 0 : long long int fromID = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FROMPOINTID)));
157 0 : long long int toID = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_TOPOINTID)));
158 0 : PositionVector vec;
159 0 : vec.push_back(punkte[fromID]);
160 0 : vec.push_back(punkte[toID]);
161 0 : kanten[id] = vec;
162 : continue;
163 0 : } else if (what == "$" + KEYS.getString(VISUM_EDGEITEM)) {
164 0 : lineParser.parseLine(line);
165 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_EDGEID)));
166 0 : int index = StringUtils::toInt(lineParser.get(KEYS.getString(VISUM_INDEX)));
167 0 : double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
168 0 : double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
169 : Position pos(x, y);
170 0 : if (!geoConvHelper.x2cartesian(pos)) {
171 0 : WRITE_WARNINGF(TL("Unable to project coordinates for edge '%'."), toString(id));
172 : }
173 0 : kanten[id].insert(kanten[id].begin() + index, pos);
174 : continue;
175 0 : } else if (what == "$" + KEYS.getString(VISUM_FACEITEM)) {
176 0 : lineParser.parseLine(line);
177 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FACEID)));
178 : //int index = StringUtils::toInt(lineParser.get("INDEX"));
179 : //index = 0; /// hmmmm - assume it's sorted...
180 0 : long long int kid = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_EDGEID)));
181 0 : int dir = StringUtils::toInt(lineParser.get(KEYS.getString(VISUM_DIRECTION)));
182 0 : if (teilflaechen.find(id) == teilflaechen.end()) {
183 0 : teilflaechen[id] = PositionVector();
184 : }
185 0 : if (dir == 0) {
186 0 : for (int i = 0; i < (int) kanten[kid].size(); ++i) {
187 0 : teilflaechen[id].push_back_noDoublePos(kanten[kid][i]);
188 : }
189 : } else {
190 0 : for (int i = (int) kanten[kid].size() - 1; i >= 0; --i) {
191 0 : teilflaechen[id].push_back_noDoublePos(kanten[kid][i]);
192 : }
193 : }
194 : continue;
195 0 : } else if (what == "$" + KEYS.getString(VISUM_SURFACEITEM)) {
196 0 : lineParser.parseLine(line);
197 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
198 0 : long long int tid = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FACEID)));
199 0 : flaechenelemente[id] = tid;
200 : continue;
201 0 : }
202 : // set if read
203 0 : if (line[0] == '$') {
204 : what = "";
205 0 : if (line.find("$" + KEYS.getString(VISUM_POINT) + ":") == 0) {
206 0 : what = "$" + KEYS.getString(VISUM_POINT);
207 0 : } else if (line.find("$" + KEYS.getString(VISUM_EDGE) + ":") == 0) {
208 0 : what = "$" + KEYS.getString(VISUM_EDGE);
209 0 : } else if (line.find("$" + KEYS.getString(VISUM_EDGEITEM) + ":") == 0) {
210 0 : what = "$" + KEYS.getString(VISUM_EDGEITEM);
211 0 : } else if (line.find("$" + KEYS.getString(VISUM_FACEITEM) + ":") == 0) {
212 0 : what = "$" + KEYS.getString(VISUM_FACEITEM);
213 0 : } else if (line.find("$" + KEYS.getString(VISUM_SURFACEITEM) + ":") == 0) {
214 0 : what = "$" + KEYS.getString(VISUM_SURFACEITEM);
215 : }
216 0 : if (what != "") {
217 0 : lineParser.reinit(line.substr(what.length() + 1));
218 : }
219 : }
220 : }
221 :
222 : // do some more sane job...
223 0 : RGBColor c = RGBColor::parseColor(oc.getString("color"));
224 : std::map<std::string, std::string> typemap;
225 : // load the pois/polys
226 0 : lr.reinit();
227 : bool parsingCategories = false;
228 : bool parsingPOIs = false;
229 : bool parsingDistrictsDirectly = false;
230 0 : PositionVector vec;
231 : std::string polyType, lastID;
232 : bool first = true;
233 0 : while (lr.hasMore()) {
234 0 : std::string line = lr.readLine();
235 : // do not parse empty lines
236 0 : if (line.length() == 0) {
237 0 : continue;
238 : }
239 : // do not parse comment lines
240 0 : if (line[0] == '*') {
241 0 : continue;
242 : }
243 :
244 0 : if (line[0] == '$') {
245 : // reset parsing on new entry type
246 : parsingCategories = false;
247 : parsingPOIs = false;
248 : parsingDistrictsDirectly = false;
249 : polyType = "";
250 : }
251 :
252 0 : if (parsingCategories) {
253 : // parse the category
254 0 : StringTokenizer st(line, ";");
255 0 : std::string catid = st.next();
256 0 : std::string catname = st.next();
257 0 : typemap[catid] = catname;
258 0 : }
259 0 : if (parsingPOIs) {
260 : // parse the poi
261 : // $POI:Nr;CATID;CODE;NAME;Kommentar;XKoord;YKoord;
262 0 : lineParser.parseLine(line);
263 0 : long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
264 0 : std::string id = toString(idL);
265 0 : std::string catid = lineParser.get(KEYS.getString(VISUM_CATID));
266 : // process read values
267 0 : double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
268 0 : double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
269 : Position pos(x, y);
270 0 : if (!geoConvHelper.x2cartesian(pos)) {
271 0 : WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), id);
272 : }
273 0 : std::string type = typemap[catid];
274 : // patch the values
275 0 : bool discard = oc.getBool("discard");
276 0 : std::string icon = oc.getString("icon");
277 0 : double layer = oc.getFloat("layer");
278 0 : RGBColor color;
279 0 : if (tm.has(type)) {
280 0 : const PCTypeMap::TypeDef& def = tm.get(type);
281 0 : id = def.prefix + id;
282 0 : type = def.id;
283 0 : color = def.color;
284 0 : discard = def.discard;
285 0 : icon = def.icon;
286 0 : layer = def.layer;
287 : } else {
288 0 : id = oc.getString("prefix") + id;
289 0 : color = c;
290 : }
291 0 : if (!discard) {
292 : const std::string origId = id;
293 : int index = 1;
294 0 : while (toFill.getPOIs().get(id) != nullptr) {
295 0 : id = origId + "#" + toString(index++);
296 : }
297 0 : PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer);
298 0 : toFill.add(poi);
299 : }
300 : }
301 :
302 : // poly
303 0 : if (polyType != "") {
304 0 : StringTokenizer st(line, ";");
305 0 : std::string id = st.next();
306 : std::string type;
307 0 : if (!first && lastID != id) {
308 : // we have parsed a polygon completely
309 0 : RGBColor color;
310 0 : double layer = oc.getFloat("layer");
311 0 : bool discard = oc.getBool("discard");
312 0 : if (tm.has(polyType)) {
313 0 : const PCTypeMap::TypeDef& def = tm.get(polyType);
314 0 : id = def.prefix + id;
315 0 : type = def.id;
316 0 : color = def.color;
317 0 : discard = def.discard;
318 0 : layer = def.layer;
319 : } else {
320 0 : id = oc.getString("prefix") + id;
321 0 : type = oc.getString("type");
322 0 : color = c;
323 : }
324 0 : if (!discard) {
325 : const std::string origId = id;
326 : int index = 1;
327 0 : while (toFill.getPolygons().get(id) != nullptr) {
328 0 : id = origId + "#" + toString(index++);
329 : }
330 0 : SUMOPolygon* poly = new SUMOPolygon(id, type, color, vec, false, false, 1, layer);
331 0 : toFill.add(poly);
332 : }
333 : vec.clear();
334 : }
335 : lastID = id;
336 : first = false;
337 : // parse current poly
338 0 : std::string index = st.next();
339 0 : std::string xpos = st.next();
340 0 : std::string ypos = st.next();
341 : Position pos2D((double) atof(xpos.c_str()), (double) atof(ypos.c_str()));
342 0 : if (!geoConvHelper.x2cartesian(pos2D)) {
343 0 : WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), id);
344 : }
345 0 : vec.push_back(pos2D);
346 0 : }
347 :
348 : // district refering a shape
349 0 : if (parsingDistrictsDirectly) {
350 : //$BEZIRK:NR CODE NAME TYPNR XKOORD YKOORD FLAECHEID BEZART IVANTEIL_Q IVANTEIL_Z OEVANTEIL METHODEANBANTEILE ZWERT1 ZWERT2 ZWERT3 ISTINAUSWAHL OBEZNR NOM_COM COD_COM
351 0 : lineParser.parseLine(line);
352 0 : long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
353 0 : std::string id = toString(idL);
354 0 : long long int area = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
355 0 : double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
356 0 : double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
357 : // patch the values
358 0 : std::string type = "district";
359 0 : bool discard = oc.getBool("discard");
360 0 : std::string icon = oc.getString("icon");
361 0 : double layer = oc.getFloat("layer");
362 0 : RGBColor color;
363 0 : if (tm.has(type)) {
364 0 : const PCTypeMap::TypeDef& def = tm.get(type);
365 0 : id = def.prefix + id;
366 0 : type = def.id;
367 0 : color = def.color;
368 0 : discard = def.discard;
369 0 : icon = def.icon;
370 0 : layer = def.layer;
371 : } else {
372 0 : id = oc.getString("prefix") + id;
373 0 : type = oc.getString("type");
374 0 : color = c;
375 : }
376 0 : if (!discard) {
377 0 : if (teilflaechen[flaechenelemente[area]].size() > 0) {
378 : const std::string origId = id;
379 : int index = 1;
380 0 : while (toFill.getPolygons().get(id) != nullptr) {
381 0 : id = origId + "#" + toString(index++);
382 : }
383 0 : const auto shape = teilflaechen[flaechenelemente[area]];
384 0 : SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, false, 1, layer);
385 0 : toFill.add(poly);
386 0 : } else {
387 : Position pos(x, y);
388 0 : if (!geoConvHelper.x2cartesian(pos)) {
389 0 : WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), id);
390 : }
391 : const std::string origId = id;
392 : int index = 1;
393 0 : while (toFill.getPOIs().get(id) != nullptr) {
394 0 : id = origId + "#" + toString(index++);
395 : }
396 0 : PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer);
397 0 : toFill.add(poi);
398 : }
399 : }
400 : }
401 :
402 :
403 0 : if (line.find("$POIKATEGORIEDEF:") == 0 || line.find("$" + KEYS.getString(VISUM_POICATEGORY) + ":") == 0) {
404 : // ok, got categories, begin parsing from next line
405 : parsingCategories = true;
406 0 : lineParser.reinit(line.substr(line.find(":") + 1));
407 : }
408 0 : if ((line.find("$POI:") == 0) || line.find("$POIOFCAT") != std::string::npos) {
409 : // ok, got pois, begin parsing from next line
410 : parsingPOIs = true;
411 0 : lineParser.reinit(line.substr(line.find(":") + 1));
412 : }
413 0 : if (line.find("$" + KEYS.getString(VISUM_DISTRICT)) == 0 && line.find(KEYS.getString(VISUM_SURFACEID)) != std::string::npos) {
414 : // ok, have a district header, and it seems like districts would reference shapes...
415 : parsingDistrictsDirectly = true;
416 0 : lineParser.reinit(line.substr(line.find(":") + 1));
417 : }
418 :
419 :
420 0 : if (line.find("$BEZIRKPOLY") != std::string::npos) {
421 : polyType = "district";
422 : }
423 0 : if (line.find("$GEBIETPOLY") != std::string::npos) {
424 : polyType = "area";
425 : }
426 :
427 : }
428 0 : }
429 :
430 :
431 : void
432 0 : PCLoaderVisum::loadLanguage(const std::string& file) {
433 0 : std::ifstream strm(file.c_str());
434 0 : if (!strm.good()) {
435 0 : throw ProcessError(TLF("Could not load VISUM language map from '%'.", file));
436 : }
437 0 : while (strm.good()) {
438 : std::string keyDE;
439 : std::string keyNew;
440 0 : strm >> keyDE;
441 0 : strm >> keyNew;
442 : if (KEYS.hasString(keyDE)) {
443 0 : VISUM_KEY key = KEYS.get(keyDE);
444 0 : KEYS.remove(keyDE, key);
445 0 : KEYS.insert(keyNew, key);
446 : } else if (keyDE != "") {
447 : // do not warn about network-related keys (NIImporter_VISUM)
448 : //WRITE_WARNINGF(TL("Unknown entry '%' in VISUM language map"), keyDE);
449 : }
450 : }
451 :
452 0 : }
453 :
454 : /****************************************************************************/
|