Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2012-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 NWWriter_DlrNavteq.cpp
15 : /// @author Jakob Erdmann
16 : /// @author Michael Behrisch
17 : /// @date 26.10.2012
18 : ///
19 : // Exporter writing networks using DlrNavteq (Elmar) format
20 : /****************************************************************************/
21 : #include <config.h>
22 : #include <algorithm>
23 : #include <ctime>
24 : #include <cmath>
25 : #include <utils/common/MsgHandler.h>
26 : #include <netbuild/NBEdge.h>
27 : #include <netbuild/NBEdgeCont.h>
28 : #include <netbuild/NBNode.h>
29 : #include <netbuild/NBNodeCont.h>
30 : #include <netbuild/NBNetBuilder.h>
31 : #include <utils/common/ToString.h>
32 : #include <utils/common/IDSupplier.h>
33 : #include <utils/common/StringUtils.h>
34 : #include <utils/common/StringTokenizer.h>
35 : #include <utils/options/OptionsCont.h>
36 : #include <utils/iodevices/OutputDevice.h>
37 : #include <utils/geom/GeoConvHelper.h>
38 : #include "NWFrame.h"
39 : #include "NWWriter_DlrNavteq.h"
40 :
41 :
42 : // ---------------------------------------------------------------------------
43 : // static members
44 : // ---------------------------------------------------------------------------
45 : const std::string NWWriter_DlrNavteq::UNDEFINED("-1");
46 :
47 : // ---------------------------------------------------------------------------
48 : // static methods
49 : // ---------------------------------------------------------------------------
50 : void
51 1689 : NWWriter_DlrNavteq::writeNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
52 : // check whether a matsim-file shall be generated
53 3378 : if (!oc.isSet("dlr-navteq-output")) {
54 1680 : return;
55 : }
56 : std::map<const NBEdge*, std::string> internalNodes;
57 9 : writeNodesUnsplitted(oc, nb.getNodeCont(), nb.getEdgeCont(), internalNodes);
58 9 : writeLinksUnsplitted(oc, nb.getEdgeCont(), internalNodes);
59 9 : writeTrafficSignals(oc, nb.getNodeCont());
60 9 : writeProhibitedManoeuvres(oc, nb.getNodeCont(), nb.getEdgeCont());
61 9 : writeConnectedLanes(oc, nb.getNodeCont());
62 : }
63 :
64 :
65 49 : void NWWriter_DlrNavteq::writeHeader(OutputDevice& device, const OptionsCont& oc) {
66 49 : device << "# Format matches Extraction version: V" << oc.getString("dlr-navteq.version") << " \n";
67 49 : std::stringstream tmp;
68 98 : oc.writeConfiguration(tmp, true, false, false);
69 49 : tmp.seekg(std::ios_base::beg);
70 : std::string line;
71 2292 : while (!tmp.eof()) {
72 2243 : std::getline(tmp, line);
73 2243 : device << "# " << line << "\n";
74 : }
75 49 : device << "#\n";
76 49 : }
77 :
78 :
79 : void
80 9 : NWWriter_DlrNavteq::writeNodesUnsplitted(const OptionsCont& oc, const NBNodeCont& nc, const NBEdgeCont& ec, std::map<const NBEdge*, std::string>& internalNodes) {
81 : // For "real" nodes we simply use the node id.
82 : // For internal nodes (geometry vectors describing edge geometry in the parlance of this format)
83 : // we use the id of the edge and do not bother with
84 : // compression (each direction gets its own internal node).
85 18 : OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_nodes_unsplitted.txt");
86 9 : writeHeader(device, oc);
87 : const GeoConvHelper& gch = GeoConvHelper::getFinal();
88 9 : const bool haveGeo = gch.usingGeoProjection();
89 9 : const double geoScale = pow(10.0f, haveGeo ? 5 : 2); // see NIImporter_DlrNavteq::GEO_SCALE
90 9 : device.setPrecision(oc.getInt("dlr-navteq.precision"));
91 9 : if (!haveGeo) {
92 2 : WRITE_WARNING(TL("DlrNavteq node data will be written in (floating point) cartesian coordinates"));
93 : }
94 : // write format specifier
95 9 : device << "# NODE_ID\tIS_BETWEEN_NODE\tamount_of_geocoordinates\tx1\ty1\t[x2 y2 ... xn yn]\n";
96 : // write header
97 9 : Boundary boundary = gch.getConvBoundary();
98 9 : Position min(boundary.xmin(), boundary.ymin());
99 9 : Position max(boundary.xmax(), boundary.ymax());
100 9 : gch.cartesian2geo(min);
101 : min.mul(geoScale);
102 9 : gch.cartesian2geo(max);
103 : max.mul(geoScale);
104 9 : int multinodes = 0;
105 1050 : for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
106 1041 : if ((*i).second->getGeometry().size() > 2) {
107 486 : multinodes++;
108 : }
109 : }
110 9 : device << "# [xmin_region] " << min.x() << "\n";
111 9 : device << "# [xmax_region] " << max.x() << "\n";
112 9 : device << "# [ymin_region] " << min.y() << "\n";
113 9 : device << "# [ymax_region] " << max.y() << "\n";
114 9 : device << "# [elements_multinode] " << multinodes << "\n";
115 9 : device << "# [elements_normalnode] " << nc.size() << "\n";
116 9 : device << "# [xmin] " << min.x() << "\n";
117 9 : device << "# [xmax] " << max.x() << "\n";
118 9 : device << "# [ymin] " << min.y() << "\n";
119 9 : device << "# [ymax] " << max.y() << "\n";
120 : // write normal nodes
121 555 : for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
122 546 : NBNode* n = (*i).second;
123 546 : Position pos = n->getPosition();
124 546 : gch.cartesian2geo(pos);
125 : pos.mul(geoScale);
126 546 : device << n->getID() << "\t0\t1\t" << pos.x() << "\t" << pos.y() << "\n";
127 : }
128 : // write "internal" nodes
129 : std::vector<std::string> avoid;
130 : std::set<std::string> reservedNodeIDs;
131 9 : const bool numericalIDs = oc.getBool("numerical-ids");
132 18 : if (oc.isSet("reserved-ids")) {
133 4 : NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "node:", reservedNodeIDs); // backward compatibility
134 4 : NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "junction:", reservedNodeIDs); // selection format
135 : }
136 9 : if (numericalIDs) {
137 9 : avoid = nc.getAllNames();
138 9 : std::vector<std::string> avoid2 = ec.getAllNames();
139 9 : avoid.insert(avoid.end(), avoid2.begin(), avoid2.end());
140 9 : avoid.insert(avoid.end(), reservedNodeIDs.begin(), reservedNodeIDs.end());
141 9 : }
142 18 : IDSupplier idSupplier("", avoid);
143 1050 : for (const auto& edgeIt : ec) {
144 1041 : const NBEdge* const e = edgeIt.second;
145 : PositionVector geom = e->getGeometry();
146 1041 : if (geom.size() > 2) {
147 : // the import NIImporter_DlrNavteq checks for the presence of a
148 : // negated edge id to determine spread type. We may need to do some
149 : // shifting to make this consistent
150 486 : const bool hasOppositeID = ec.getOppositeByID(e->getID()) != nullptr;
151 486 : if (e->getLaneSpreadFunction() == LaneSpreadFunction::RIGHT && !hasOppositeID) {
152 : // need to write center-line geometry instead
153 : try {
154 247 : geom.move2side(e->getTotalWidth() / 2);
155 0 : } catch (InvalidArgument& exception) {
156 0 : WRITE_WARNINGF(TL("Could not reconstruct shape for edge:'%' (%)."), e->getID(), exception.what());
157 0 : }
158 239 : } else if (e->getLaneSpreadFunction() == LaneSpreadFunction::CENTER && hasOppositeID) {
159 : // need to write left-border geometry instead
160 : try {
161 0 : geom.move2side(-e->getTotalWidth() / 2);
162 0 : } catch (InvalidArgument& exception) {
163 0 : WRITE_WARNINGF(TL("Could not reconstruct shape for edge:'%' (%)."), e->getID(), exception.what());
164 0 : }
165 : }
166 :
167 486 : if (geom.size() > 2) { // move2side might have changed the number of nodes
168 486 : std::string internalNodeID = e->getID();
169 486 : if (internalNodeID == UNDEFINED
170 486 : || (nc.retrieve(internalNodeID) != nullptr)
171 486 : || reservedNodeIDs.count(internalNodeID) > 0
172 : ) {
173 : // need to invent a new name to avoid clashing with the id of a 'real' node or a reserved name
174 1 : if (numericalIDs) {
175 2 : internalNodeID = idSupplier.getNext();
176 : } else {
177 : internalNodeID += "_geometry";
178 : }
179 : }
180 486 : internalNodes[e] = internalNodeID;
181 486 : device << internalNodeID << "\t1\t" << geom.size() - 2;
182 2095 : for (int ii = 1; ii < (int)geom.size() - 1; ++ii) {
183 1609 : Position pos = geom[(int)ii];
184 1609 : gch.cartesian2geo(pos);
185 : pos.mul(geoScale);
186 1609 : device << "\t" << pos.x() << "\t" << pos.y();
187 : }
188 486 : device << "\n";
189 : }
190 : }
191 1041 : }
192 9 : device.close();
193 18 : }
194 :
195 :
196 : void
197 9 : NWWriter_DlrNavteq::writeLinksUnsplitted(const OptionsCont& oc, const NBEdgeCont& ec, const std::map<const NBEdge*, std::string>& internalNodes) {
198 27 : const int majorVersion = StringUtils::toInt(StringTokenizer(oc.getString("dlr-navteq.version"), ".").next());
199 : std::map<const std::string, std::string> nameIDs;
200 18 : OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_links_unsplitted.txt");
201 9 : writeHeader(device, oc);
202 : // write format specifier
203 9 : device << "# LINK_ID\tNODE_ID_FROM\tNODE_ID_TO\tBETWEEN_NODE_ID\tLENGTH\tVEHICLE_TYPE\tFORM_OF_WAY\tBRUNNEL_TYPE\t"
204 9 : << "FUNCTIONAL_ROAD_CLASS\tSPEED_CATEGORY\tNUMBER_OF_LANES\tSPEED_LIMIT\tSPEED_RESTRICTION\t"
205 9 : << "NAME_ID1_REGIONAL\tNAME_ID2_LOCAL\tHOUSENUMBERS_RIGHT\tHOUSENUMBERS_LEFT\tZIP_CODE\t"
206 9 : << "AREA_ID\tSUBAREA_ID\tTHROUGH_TRAFFIC\tSPECIAL_RESTRICTIONS\tEXTENDED_NUMBER_OF_LANES\tISRAMP\tCONNECTION";
207 9 : if (majorVersion > 6) {
208 1 : device << "\tMAXHEIGHT\tMAXWIDTH\tMAXWEIGHT\tSURFACE";
209 : }
210 9 : device << "\n";
211 : // write edges
212 1050 : for (const auto& edgeIt : ec) {
213 1041 : const NBEdge* const e = edgeIt.second;
214 1041 : const int kph = speedInKph(e->getSpeed());
215 : const auto& internalIt = internalNodes.find(e);
216 1041 : const std::string& betweenNodeID = internalIt != internalNodes.end() ? internalIt->second : UNDEFINED;
217 : std::string nameID = UNDEFINED;
218 : std::string nameIDRegional = UNDEFINED;
219 2082 : if (oc.getBool("output.street-names")) {
220 : const std::string& name = e->getStreetName();
221 912 : if (name != "") {
222 : if (nameIDs.count(name) == 0) {
223 51 : const int tmp = (int)nameIDs.size();
224 102 : nameIDs[name] = toString(tmp);
225 : }
226 366 : nameID = nameIDs[name];
227 : }
228 1824 : const std::string& name2 = e->getParameter("ref", "");
229 912 : if (name2 != "") {
230 : if (nameIDs.count(name2) == 0) {
231 4 : const int tmp = (int)nameIDs.size();
232 8 : nameIDs[name2] = toString(tmp);
233 : }
234 44 : nameIDRegional = nameIDs[name2];
235 : }
236 : }
237 1041 : device << e->getID() << "\t"
238 1041 : << e->getFromNode()->getID() << "\t"
239 1041 : << e->getToNode()->getID() << "\t"
240 1041 : << betweenNodeID << "\t"
241 1041 : << getGraphLength(e) << "\t"
242 1041 : << getAllowedTypes(e->getPermissions()) << "\t"
243 1041 : << getFormOfWay(e) << "\t"
244 1041 : << getBrunnelType(e) << "\t"
245 1041 : << getRoadClass(e) << "\t"
246 1041 : << getSpeedCategory(kph) << "\t"
247 1041 : << getNavteqLaneCode(e->getNumLanes()) << "\t"
248 1041 : << getSpeedCategoryUpperBound(kph) << "\t"
249 1041 : << kph << "\t"
250 1041 : << nameIDRegional << "\t"
251 1041 : << nameID << "\t" // NAME_ID2_LOCAL
252 1041 : << UNDEFINED << "\t" // housenumbers_right
253 1041 : << UNDEFINED << "\t" // housenumbers_left
254 4164 : << getSinglePostalCode(e->getParameter("postal_code", UNDEFINED), e->getID()) << "\t" // ZIP_CODE
255 1041 : << UNDEFINED << "\t" // AREA_ID
256 1041 : << UNDEFINED << "\t" // SUBAREA_ID
257 1041 : << "1\t" // through_traffic (allowed)
258 1041 : << UNDEFINED << "\t" // special_restrictions
259 1041 : << UNDEFINED << "\t" // extended_number_of_lanes
260 1041 : << UNDEFINED << "\t" // isRamp
261 1041 : << "0"; // connection (between nodes always in order)
262 1041 : if (majorVersion > 6) {
263 825 : device << "\t" << e->getParameter("maxheight", UNDEFINED)
264 825 : << "\t" << e->getParameter("maxwidth", UNDEFINED)
265 825 : << "\t" << e->getParameter("maxweight", UNDEFINED)
266 825 : << "\t" << e->getParameter("surface", UNDEFINED);
267 : }
268 1041 : device << "\n";
269 : }
270 18 : if (oc.getBool("output.street-names")) {
271 8 : OutputDevice& namesDevice = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_names.txt");
272 4 : writeHeader(namesDevice, oc);
273 : // write format specifier
274 4 : namesDevice << "# NAME_ID\tPERMANENT_ID_INFO\tName\n";
275 4 : namesDevice << "# [elements] " << nameIDs.size() << "\n";
276 59 : for (std::map<const std::string, std::string>::const_iterator i = nameIDs.begin(); i != nameIDs.end(); ++i) {
277 : namesDevice
278 55 : << i->second << "\t"
279 110 : << 0 << "\t"
280 55 : << i->first << "\n";
281 : }
282 4 : namesDevice.close();
283 : }
284 9 : device.close();
285 9 : }
286 :
287 :
288 : std::string
289 3555 : NWWriter_DlrNavteq::getAllowedTypes(SVCPermissions permissions) {
290 3555 : if (permissions == SVCAll) {
291 625 : return "100000000000";
292 : }
293 2930 : std::ostringstream oss;
294 2930 : oss << "0";
295 4637 : oss << ((permissions & SVC_PASSENGER) > 0 ? 1 : 0);
296 2930 : oss << ((permissions & SVC_PASSENGER) > 0 ? 1 : 0); // residential
297 4637 : oss << ((permissions & SVC_HOV) > 0 ? 1 : 0);
298 4637 : oss << ((permissions & SVC_EMERGENCY) > 0 ? 1 : 0);
299 4637 : oss << ((permissions & SVC_TAXI) > 0 ? 1 : 0);
300 4637 : oss << ((permissions & (SVC_BUS | SVC_COACH)) > 0 ? 1 : 0);
301 3698 : oss << ((permissions & SVC_DELIVERY) > 0 ? 1 : 0);
302 4637 : oss << ((permissions & (SVC_TRUCK | SVC_TRAILER)) > 0 ? 1 : 0);
303 4582 : oss << ((permissions & SVC_MOTORCYCLE) > 0 ? 1 : 0);
304 3379 : oss << ((permissions & SVC_BICYCLE) > 0 ? 1 : 0);
305 3174 : oss << ((permissions & SVC_PEDESTRIAN) > 0 ? 1 : 0);
306 : return oss.str();
307 2930 : }
308 :
309 :
310 : int
311 1741 : NWWriter_DlrNavteq::getRoadClass(const NBEdge* const edge) {
312 : // quoting the navteq manual:
313 : // As a general rule, Functional Road Class assignments have no direct
314 : // correlation with other road attributes like speed, controlled access, route type, etc.
315 : // if the network is based on OSM, we can use the highway types for determining FRC
316 : std::string type = edge->getTypeID();
317 3482 : if (StringUtils::startsWith(type, "highway.")) {
318 3280 : type = type.substr(8);
319 : }
320 3482 : if (StringUtils::startsWith(type, "motorway")) {
321 : return 0;
322 3426 : } else if (StringUtils::startsWith(type, "trunk")) {
323 : return 1;
324 3426 : } else if (StringUtils::startsWith(type, "primary")) {
325 : return 1;
326 3282 : } else if (StringUtils::startsWith(type, "secondary")) {
327 : return 2;
328 3152 : } else if (StringUtils::startsWith(type, "tertiary")) {
329 : return 3;
330 1411 : } else if (type == "unclassified") {
331 : return 3;
332 1220 : } else if (type == "living_street" || type == "residential" || type == "road" || type == "service" || type == "track" || type == "cycleway" || type == "path" || type == "footway") {
333 : return 4;
334 : }
335 : // as a fallback we do a simple speed / lane-count mapping anyway
336 : // the resulting functional road class layers probably won't be connected as required
337 110 : const int kph = speedInKph(edge->getSpeed());
338 110 : if ((kph) > 100) {
339 : return 0;
340 : }
341 108 : if ((kph) > 70) {
342 : return 1;
343 : }
344 68 : if ((kph) > 50) {
345 0 : return (edge->getNumLanes() > 1 ? 2 : 3);
346 : }
347 68 : if ((kph) > 30) {
348 : return 3;
349 : }
350 : return 4;
351 : }
352 :
353 :
354 : int
355 1041 : NWWriter_DlrNavteq::getSpeedCategory(int kph) {
356 1041 : if ((kph) > 130) {
357 : return 1;
358 : }
359 1039 : if ((kph) > 100) {
360 : return 2;
361 : }
362 1039 : if ((kph) > 90) {
363 : return 3;
364 : }
365 999 : if ((kph) > 70) {
366 : return 4;
367 : }
368 918 : if ((kph) > 50) {
369 : return 5;
370 : }
371 916 : if ((kph) > 30) {
372 : return 6;
373 : }
374 483 : if ((kph) > 10) {
375 422 : return 7;
376 : }
377 : return 8;
378 : }
379 :
380 :
381 : int
382 1041 : NWWriter_DlrNavteq::getSpeedCategoryUpperBound(int kph) {
383 1041 : if ((kph) > 130) {
384 : return 131;
385 : }
386 1039 : if ((kph) > 100) {
387 : return 130;
388 : }
389 1039 : if ((kph) > 90) {
390 : return 100;
391 : }
392 999 : if ((kph) > 70) {
393 : return 90;
394 : }
395 918 : if ((kph) > 50) {
396 : return 70;
397 : }
398 916 : if ((kph) > 30) {
399 : return 50;
400 : }
401 483 : if ((kph) > 10) {
402 422 : return 30;
403 : }
404 : return 10;
405 : }
406 :
407 :
408 : int
409 1041 : NWWriter_DlrNavteq::getNavteqLaneCode(const int numLanes) {
410 1041 : const int code = (numLanes == 1 ? 1 :
411 123 : (numLanes < 4 ? 2 : 3));
412 1041 : return numLanes * 10 + code;
413 : }
414 :
415 :
416 : int
417 1041 : NWWriter_DlrNavteq::getBrunnelType(const NBEdge* const edge) {
418 2082 : if (edge->hasParameter("bridge")) {
419 : return 1;
420 2050 : } else if (edge->hasParameter("tunnel")) {
421 : return 4;
422 1025 : } else if (edge->getTypeID() == "route.ferry") {
423 0 : return 10;
424 : }
425 : return -1; // UNDEFINED
426 : }
427 :
428 :
429 : int
430 1041 : NWWriter_DlrNavteq::getFormOfWay(const NBEdge* const edge) {
431 1041 : if (edge->getPermissions() == SVC_PEDESTRIAN) {
432 : return 15;
433 952 : } else if (edge->getJunctionPriority(edge->getToNode()) == NBEdge::JunctionPriority::ROUNDABOUT) {
434 : return 4;
435 952 : } else if (edge->getTypeID() == "highway.service") {
436 : return 14;
437 712 : } else if (edge->getTypeID().find("_link") != std::string::npos) {
438 2 : return 10;
439 : }
440 : return 3; // speed category 1-8;
441 : }
442 :
443 :
444 : double
445 1041 : NWWriter_DlrNavteq::getGraphLength(const NBEdge* const edge) {
446 : PositionVector geom = edge->getGeometry();
447 1041 : geom.push_back_noDoublePos(edge->getToNode()->getPosition());
448 1041 : geom.push_front_noDoublePos(edge->getFromNode()->getPosition());
449 2082 : return geom.length();
450 1041 : }
451 :
452 :
453 : std::string
454 1041 : NWWriter_DlrNavteq::getSinglePostalCode(const std::string& zipCode, const std::string edgeID) {
455 : // might be multiple codes
456 1041 : if (zipCode.find_first_of(" ,;") != std::string::npos) {
457 72 : WRITE_WARNINGF("ambiguous zip code '%' for edge '%'. (using first value)", zipCode, edgeID);
458 72 : StringTokenizer st(zipCode, " ,;", true);
459 24 : std::vector<std::string> ret = st.getVector();
460 : return ret[0];
461 1041 : } else if (zipCode.size() > 16) {
462 0 : WRITE_WARNINGF("long zip code '%' for edge '%'", zipCode, edgeID);
463 : }
464 : return zipCode;
465 : }
466 :
467 : void
468 9 : NWWriter_DlrNavteq::writeTrafficSignals(const OptionsCont& oc, NBNodeCont& nc) {
469 18 : OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_traffic_signals.txt");
470 9 : writeHeader(device, oc);
471 : const GeoConvHelper& gch = GeoConvHelper::getFinal();
472 9 : const bool haveGeo = gch.usingGeoProjection();
473 9 : const double geoScale = pow(10.0f, haveGeo ? 5 : 2); // see NIImporter_DlrNavteq::GEO_SCALE
474 9 : device.setPrecision(oc.getInt("dlr-navteq.precision"));
475 : // write format specifier
476 9 : device << "#Traffic signal related to LINK_ID and NODE_ID with location relative to driving direction.\n#column format like pointcollection.\n#DESCRIPTION->LOCATION: 1-rechts von LINK; 2-links von LINK; 3-oberhalb LINK -1-keineAngabe\n#RELATREC_ID\tPOICOL_TYPE\tDESCRIPTION\tLONGITUDE\tLATITUDE\tLINK_ID\n";
477 : // write record for every edge incoming to a tls controlled node
478 555 : for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
479 546 : NBNode* n = (*i).second;
480 546 : if (n->isTLControlled()) {
481 14 : Position pos = n->getPosition();
482 14 : gch.cartesian2geo(pos);
483 : pos.mul(geoScale);
484 : const EdgeVector& incoming = n->getIncomingEdges();
485 65 : for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
486 51 : NBEdge* e = *it;
487 51 : device << e->getID() << "\t"
488 51 : << "12\t" // POICOL_TYPE
489 51 : << "LSA;NODEIDS#" << n->getID() << "#;LOCATION#-1#;\t"
490 51 : << pos.x() << "\t"
491 102 : << pos.y() << "\t"
492 51 : << e->getID() << "\n";
493 : }
494 : }
495 : }
496 9 : device.close();
497 9 : }
498 :
499 :
500 : void
501 9 : NWWriter_DlrNavteq::writeProhibitedManoeuvres(const OptionsCont& oc, const NBNodeCont& nc, const NBEdgeCont& ec) {
502 18 : OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_prohibited_manoeuvres.txt");
503 9 : writeHeader(device, oc);
504 : // need to invent id for relation
505 : std::set<std::string> reservedRelIDs;
506 18 : if (oc.isSet("reserved-ids")) {
507 4 : NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "rel:", reservedRelIDs);
508 : }
509 9 : std::vector<std::string> avoid = ec.getAllNames(); // already used for tls RELATREC_ID
510 9 : avoid.insert(avoid.end(), reservedRelIDs.begin(), reservedRelIDs.end());
511 9 : IDSupplier idSupplier("", avoid); // @note: use a global relRecIDsupplier if this is used more often
512 : // write format specifier
513 9 : device << "#No driving allowed from ID1 to ID2 or the complete chain from ID1 to IDn\n";
514 9 : device << "#RELATREC_ID\tPERMANENT_ID_INFO\tVALIDITY_PERIOD\tTHROUGH_TRAFFIC\tVEHICLE_TYPE\tNAVTEQ_LINK_ID1\t[NAVTEQ_LINK_ID2 ...]\n";
515 : // write record for every pair of incoming/outgoing edge that are not connected despite having common permissions
516 555 : for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
517 546 : NBNode* n = (*i).second;
518 : const EdgeVector& incoming = n->getIncomingEdges();
519 : const EdgeVector& outgoing = n->getOutgoingEdges();
520 1587 : for (EdgeVector::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
521 1041 : NBEdge* inEdge = *j;
522 1041 : const SVCPermissions inPerm = inEdge->getPermissions();
523 3671 : for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); ++k) {
524 2630 : NBEdge* outEdge = *k;
525 2630 : const SVCPermissions outPerm = outEdge->getPermissions();
526 2630 : const SVCPermissions commonPerm = inPerm & outPerm;
527 2630 : if (commonPerm != 0 && commonPerm != SVC_PEDESTRIAN && !inEdge->isConnectedTo(outEdge)) {
528 : device
529 16 : << idSupplier.getNext() << "\t"
530 8 : << 1 << "\t" // permanent id
531 8 : << UNDEFINED << "\t"
532 8 : << 1 << "\t"
533 16 : << getAllowedTypes(SVCAll) << "\t"
534 8 : << inEdge->getID() << "\t" << outEdge->getID() << "\n";
535 : }
536 : }
537 : }
538 : }
539 9 : device.close();
540 18 : }
541 :
542 :
543 : void
544 9 : NWWriter_DlrNavteq::writeConnectedLanes(const OptionsCont& oc, NBNodeCont& nc) {
545 18 : OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_connected_lanes.txt");
546 9 : writeHeader(device, oc);
547 : // write format specifier
548 9 : device << "#Lane connections related to LINK-IDs and NODE-ID.\n";
549 9 : device << "#column format like pointcollection.\n";
550 9 : device << "#NODE-ID\tVEHICLE-TYPE\tFROM_LANE\tTO_LANE\tTHROUGH_TRAFFIC\tLINK_IDs[2..*]\n";
551 : // write record for every connection
552 555 : for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
553 546 : NBNode* n = (*i).second;
554 : const EdgeVector& incoming = n->getIncomingEdges();
555 1587 : for (EdgeVector::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
556 1041 : NBEdge* from = *j;
557 1041 : const SVCPermissions fromPerm = from->getPermissions();
558 : const std::vector<NBEdge::Connection>& connections = from->getConnections();
559 3547 : for (std::vector<NBEdge::Connection>::const_iterator it_c = connections.begin(); it_c != connections.end(); it_c++) {
560 : const NBEdge::Connection& c = *it_c;
561 : device
562 2506 : << n->getID() << "\t"
563 5012 : << getAllowedTypes(fromPerm & c.toEdge->getPermissions()) << "\t"
564 2506 : << c.fromLane + 1 << "\t" // one-based
565 2506 : << c.toLane + 1 << "\t" // one-based
566 5012 : << 1 << "\t" // no information regarding permissibility of through traffic
567 2506 : << from->getID() << "\t"
568 2506 : << c.toEdge->getID() << "\t"
569 2506 : << "\n";
570 : }
571 : }
572 : }
573 9 : device.close();
574 9 : }
575 :
576 :
577 : /****************************************************************************/
|