Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 : { "NETZ", VISUM_NETWORK },
91 : { "DEFKOORD", VISUM_PROJECTIONDEFINITION },
92 : { "NR", VISUM_NO } // must be the last one
93 : };
94 :
95 :
96 : StringBijection<PCLoaderVisum::VISUM_KEY> PCLoaderVisum::KEYS(PCLoaderVisum::KEYS_DE, VISUM_NO);
97 :
98 :
99 : // ===========================================================================
100 : // method definitions
101 : // ===========================================================================
102 : void
103 44 : PCLoaderVisum::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill,
104 : PCTypeMap& tm) {
105 88 : if (!oc.isSet("visum-files")) {
106 44 : return;
107 : }
108 0 : const std::string languageFile = oc.getString("visum.language-file");
109 0 : if (languageFile != "") {
110 0 : loadLanguage(languageFile);
111 : }
112 : // parse file(s)
113 0 : std::vector<std::string> files = oc.getStringVector("visum-files");
114 0 : for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
115 0 : if (!FileHelpers::isReadable(*file)) {
116 0 : throw ProcessError(TLF("Could not open visum-file '%'.", *file));
117 : }
118 0 : PROGRESS_BEGIN_MESSAGE("Parsing from visum-file '" + *file + "'");
119 0 : load(*file, oc, toFill, tm);
120 0 : PROGRESS_DONE_MESSAGE();
121 : }
122 0 : }
123 :
124 :
125 :
126 : void
127 0 : PCLoaderVisum::load(const std::string& file, OptionsCont& oc, PCPolyContainer& toFill,
128 : PCTypeMap& tm) {
129 : GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
130 : std::string what;
131 : std::map<long long int, Position> punkte;
132 : std::map<long long int, PositionVector> kanten;
133 : std::map<long long int, PositionVector> teilflaechen;
134 : std::map<long long int, long long int> flaechenelemente;
135 0 : NamedColumnsParser lineParser;
136 0 : LineReader lr(file);
137 0 : while (lr.hasMore()) {
138 0 : std::string line = lr.readLine();
139 : // reset if current is over
140 0 : if (line.length() == 0 || line[0] == '*' || line[0] == '$') {
141 : what = "";
142 : }
143 : // read items
144 0 : if (what == "$" + KEYS.getString(VISUM_POINT)) {
145 0 : lineParser.parseLine(line);
146 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_ID)));
147 0 : double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
148 0 : double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
149 : Position pos(x, y);
150 0 : if (!geoConvHelper.x2cartesian(pos)) {
151 0 : WRITE_WARNINGF(TL("Unable to project coordinates for point '%'."), toString(id));
152 : }
153 0 : punkte[id] = pos;
154 : continue;
155 0 : } else if (what == "$" + KEYS.getString(VISUM_EDGE)) {
156 0 : lineParser.parseLine(line);
157 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_ID)));
158 0 : long long int fromID = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FROMPOINTID)));
159 0 : long long int toID = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_TOPOINTID)));
160 0 : PositionVector vec;
161 0 : vec.push_back(punkte[fromID]);
162 0 : vec.push_back(punkte[toID]);
163 0 : kanten[id] = vec;
164 : continue;
165 0 : } else if (what == "$" + KEYS.getString(VISUM_EDGEITEM)) {
166 0 : lineParser.parseLine(line);
167 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_EDGEID)));
168 0 : int index = StringUtils::toInt(lineParser.get(KEYS.getString(VISUM_INDEX)));
169 0 : double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
170 0 : double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
171 : Position pos(x, y);
172 0 : if (!geoConvHelper.x2cartesian(pos)) {
173 0 : WRITE_WARNINGF(TL("Unable to project coordinates for edge '%'."), toString(id));
174 : }
175 0 : kanten[id].insert(kanten[id].begin() + index, pos);
176 : continue;
177 0 : } else if (what == "$" + KEYS.getString(VISUM_FACEITEM)) {
178 0 : lineParser.parseLine(line);
179 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FACEID)));
180 : //int index = StringUtils::toInt(lineParser.get("INDEX"));
181 : //index = 0; /// hmmmm - assume it's sorted...
182 0 : long long int kid = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_EDGEID)));
183 0 : int dir = StringUtils::toInt(lineParser.get(KEYS.getString(VISUM_DIRECTION)));
184 0 : if (teilflaechen.find(id) == teilflaechen.end()) {
185 0 : teilflaechen[id] = PositionVector();
186 : }
187 0 : if (dir == 0) {
188 0 : for (int i = 0; i < (int) kanten[kid].size(); ++i) {
189 0 : teilflaechen[id].push_back_noDoublePos(kanten[kid][i]);
190 : }
191 : } else {
192 0 : for (int i = (int) kanten[kid].size() - 1; i >= 0; --i) {
193 0 : teilflaechen[id].push_back_noDoublePos(kanten[kid][i]);
194 : }
195 : }
196 : continue;
197 0 : } else if (what == "$" + KEYS.getString(VISUM_SURFACEITEM)) {
198 0 : lineParser.parseLine(line);
199 0 : long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
200 0 : long long int tid = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FACEID)));
201 0 : flaechenelemente[id] = tid;
202 : continue;
203 0 : }
204 : // set if read
205 0 : if (line[0] == '$') {
206 : what = "";
207 0 : if (line.find("$" + KEYS.getString(VISUM_POINT) + ":") == 0) {
208 0 : what = "$" + KEYS.getString(VISUM_POINT);
209 0 : } else if (line.find("$" + KEYS.getString(VISUM_EDGE) + ":") == 0) {
210 0 : what = "$" + KEYS.getString(VISUM_EDGE);
211 0 : } else if (line.find("$" + KEYS.getString(VISUM_EDGEITEM) + ":") == 0) {
212 0 : what = "$" + KEYS.getString(VISUM_EDGEITEM);
213 0 : } else if (line.find("$" + KEYS.getString(VISUM_FACEITEM) + ":") == 0) {
214 0 : what = "$" + KEYS.getString(VISUM_FACEITEM);
215 0 : } else if (line.find("$" + KEYS.getString(VISUM_SURFACEITEM) + ":") == 0) {
216 0 : what = "$" + KEYS.getString(VISUM_SURFACEITEM);
217 : }
218 0 : if (what != "") {
219 0 : lineParser.reinit(line.substr(what.length() + 1));
220 : }
221 : }
222 : }
223 :
224 : // do some more sane job...
225 0 : RGBColor c = RGBColor::parseColor(oc.getString("color"));
226 : std::map<std::string, std::string> typemap;
227 : // load the pois/polys
228 0 : lr.reinit();
229 : bool parsingCategories = false;
230 : bool parsingPOIs = false;
231 : bool parsingDistrictsDirectly = false;
232 0 : PositionVector vec;
233 : std::string polyType, lastID;
234 : bool first = true;
235 0 : while (lr.hasMore()) {
236 0 : std::string line = lr.readLine();
237 : // do not parse empty lines
238 0 : if (line.length() == 0) {
239 0 : continue;
240 : }
241 : // do not parse comment lines
242 0 : if (line[0] == '*') {
243 0 : continue;
244 : }
245 :
246 0 : if (line[0] == '$') {
247 : // reset parsing on new entry type
248 : parsingCategories = false;
249 : parsingPOIs = false;
250 : parsingDistrictsDirectly = false;
251 : polyType = "";
252 : }
253 :
254 0 : if (parsingCategories) {
255 : // parse the category
256 0 : StringTokenizer st(line, ";");
257 0 : std::string catid = st.next();
258 0 : std::string catname = st.next();
259 0 : typemap[catid] = catname;
260 0 : }
261 0 : if (parsingPOIs) {
262 : // parse the poi
263 : // $POI:Nr;CATID;CODE;NAME;Kommentar;XKoord;YKoord;
264 0 : lineParser.parseLine(line);
265 0 : long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
266 0 : std::string id = toString(idL);
267 0 : std::string catid = lineParser.get(KEYS.getString(VISUM_CATID));
268 : // process read values
269 0 : double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
270 0 : double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
271 : Position pos(x, y);
272 0 : if (!geoConvHelper.x2cartesian(pos)) {
273 0 : WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), id);
274 : }
275 0 : std::string type = typemap[catid];
276 : // patch the values
277 0 : bool discard = oc.getBool("discard");
278 0 : std::string icon = oc.getString("icon");
279 0 : double layer = oc.getFloat("layer");
280 0 : RGBColor color;
281 0 : if (tm.has(type)) {
282 0 : const PCTypeMap::TypeDef& def = tm.get(type);
283 0 : id = def.prefix + id;
284 0 : type = def.id;
285 0 : color = def.color;
286 0 : discard = def.discard;
287 0 : icon = def.icon;
288 0 : layer = def.layer;
289 : } else {
290 0 : id = oc.getString("prefix") + id;
291 0 : color = c;
292 : }
293 0 : if (!discard) {
294 : const std::string origId = id;
295 : int index = 1;
296 0 : while (toFill.getPOIs().get(id) != nullptr) {
297 0 : id = origId + "#" + toString(index++);
298 : }
299 0 : PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer);
300 0 : toFill.add(poi);
301 : }
302 : }
303 :
304 : // poly
305 0 : if (polyType != "") {
306 0 : StringTokenizer st(line, ";");
307 0 : std::string id = st.next();
308 : std::string type;
309 0 : if (!first && lastID != id) {
310 : // we have parsed a polygon completely
311 0 : RGBColor color;
312 0 : double layer = oc.getFloat("layer");
313 0 : bool discard = oc.getBool("discard");
314 0 : if (tm.has(polyType)) {
315 0 : const PCTypeMap::TypeDef& def = tm.get(polyType);
316 0 : id = def.prefix + id;
317 0 : type = def.id;
318 0 : color = def.color;
319 0 : discard = def.discard;
320 0 : layer = def.layer;
321 : } else {
322 0 : id = oc.getString("prefix") + id;
323 0 : type = oc.getString("type");
324 0 : color = c;
325 : }
326 0 : if (!discard) {
327 : const std::string origId = id;
328 : int index = 1;
329 0 : while (toFill.getPolygons().get(id) != nullptr) {
330 0 : id = origId + "#" + toString(index++);
331 : }
332 0 : SUMOPolygon* poly = new SUMOPolygon(id, type, color, vec, false, false, 1, layer);
333 0 : toFill.add(poly);
334 : }
335 : vec.clear();
336 : }
337 : lastID = id;
338 : first = false;
339 : // parse current poly
340 0 : std::string index = st.next();
341 0 : std::string xpos = st.next();
342 0 : std::string ypos = st.next();
343 : Position pos2D((double) atof(xpos.c_str()), (double) atof(ypos.c_str()));
344 0 : if (!geoConvHelper.x2cartesian(pos2D)) {
345 0 : WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), id);
346 : }
347 0 : vec.push_back(pos2D);
348 0 : }
349 :
350 : // district refering a shape
351 0 : if (parsingDistrictsDirectly) {
352 : //$BEZIRK:NR CODE NAME TYPNR XKOORD YKOORD FLAECHEID BEZART IVANTEIL_Q IVANTEIL_Z OEVANTEIL METHODEANBANTEILE ZWERT1 ZWERT2 ZWERT3 ISTINAUSWAHL OBEZNR NOM_COM COD_COM
353 0 : lineParser.parseLine(line);
354 0 : long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
355 0 : std::string id = toString(idL);
356 0 : long long int area = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
357 0 : double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
358 0 : double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
359 : // patch the values
360 0 : std::string type = "district";
361 0 : bool discard = oc.getBool("discard");
362 0 : std::string icon = oc.getString("icon");
363 0 : double layer = oc.getFloat("layer");
364 0 : RGBColor color;
365 0 : if (tm.has(type)) {
366 0 : const PCTypeMap::TypeDef& def = tm.get(type);
367 0 : id = def.prefix + id;
368 0 : type = def.id;
369 0 : color = def.color;
370 0 : discard = def.discard;
371 0 : icon = def.icon;
372 0 : layer = def.layer;
373 : } else {
374 0 : id = oc.getString("prefix") + id;
375 0 : type = oc.getString("type");
376 0 : color = c;
377 : }
378 0 : if (!discard) {
379 0 : if (teilflaechen[flaechenelemente[area]].size() > 0) {
380 : const std::string origId = id;
381 : int index = 1;
382 0 : while (toFill.getPolygons().get(id) != nullptr) {
383 0 : id = origId + "#" + toString(index++);
384 : }
385 0 : const auto shape = teilflaechen[flaechenelemente[area]];
386 0 : SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, false, 1, layer);
387 0 : toFill.add(poly);
388 0 : } else {
389 : Position pos(x, y);
390 0 : if (!geoConvHelper.x2cartesian(pos)) {
391 0 : WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), id);
392 : }
393 : const std::string origId = id;
394 : int index = 1;
395 0 : while (toFill.getPOIs().get(id) != nullptr) {
396 0 : id = origId + "#" + toString(index++);
397 : }
398 0 : PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer);
399 0 : toFill.add(poi);
400 : }
401 : }
402 : }
403 :
404 :
405 0 : if (line.find("$POIKATEGORIEDEF:") == 0 || line.find("$" + KEYS.getString(VISUM_POICATEGORY) + ":") == 0) {
406 : // ok, got categories, begin parsing from next line
407 : parsingCategories = true;
408 0 : lineParser.reinit(line.substr(line.find(":") + 1));
409 : }
410 0 : if ((line.find("$POI:") == 0) || line.find("$POIOFCAT") != std::string::npos) {
411 : // ok, got pois, begin parsing from next line
412 : parsingPOIs = true;
413 0 : lineParser.reinit(line.substr(line.find(":") + 1));
414 : }
415 0 : if (line.find("$" + KEYS.getString(VISUM_DISTRICT)) == 0 && line.find(KEYS.getString(VISUM_SURFACEID)) != std::string::npos) {
416 : // ok, have a district header, and it seems like districts would reference shapes...
417 : parsingDistrictsDirectly = true;
418 0 : lineParser.reinit(line.substr(line.find(":") + 1));
419 : }
420 :
421 :
422 0 : if (line.find("$BEZIRKPOLY") != std::string::npos) {
423 : polyType = "district";
424 : }
425 0 : if (line.find("$GEBIETPOLY") != std::string::npos) {
426 : polyType = "area";
427 : }
428 :
429 : }
430 0 : }
431 :
432 :
433 : void
434 0 : PCLoaderVisum::loadLanguage(const std::string& file) {
435 0 : std::ifstream strm(file.c_str());
436 0 : if (!strm.good()) {
437 0 : throw ProcessError(TLF("Could not load VISUM language map from '%'.", file));
438 : }
439 0 : while (strm.good()) {
440 : std::string keyDE;
441 : std::string keyNew;
442 0 : strm >> keyDE;
443 0 : strm >> keyNew;
444 : if (KEYS.hasString(keyDE)) {
445 0 : VISUM_KEY key = KEYS.get(keyDE);
446 0 : KEYS.remove(keyDE, key);
447 0 : KEYS.insert(keyNew, key);
448 : } else if (keyDE != "") {
449 : // do not warn about network-related keys (NIImporter_VISUM)
450 : //WRITE_WARNINGF(TL("Unknown entry '%' in VISUM language map"), keyDE);
451 : }
452 : }
453 :
454 0 : }
455 :
456 : /****************************************************************************/
|