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 NIImporter_MATSim.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Tue, 26.04.2011
19 : ///
20 : // Importer for networks stored in MATSim format
21 : /****************************************************************************/
22 : #include <config.h>
23 : #include <set>
24 : #include <functional>
25 : #include <sstream>
26 : #include <utils/xml/SUMOSAXHandler.h>
27 : #include <utils/common/ToString.h>
28 : #include <utils/common/MsgHandler.h>
29 : #include <netbuild/NBEdge.h>
30 : #include <netbuild/NBEdgeCont.h>
31 : #include <netbuild/NBNode.h>
32 : #include <netbuild/NBNodeCont.h>
33 : #include <netbuild/NBNetBuilder.h>
34 : #include <utils/geom/GeoConvHelper.h>
35 : #include <utils/options/OptionsCont.h>
36 : #include <utils/common/FileHelpers.h>
37 : #include <utils/common/StringTokenizer.h>
38 : #include <utils/common/StringUtils.h>
39 : #include <utils/common/SUMOVehicleClass.h>
40 : #include <utils/xml/XMLSubSys.h>
41 : #include "NILoader.h"
42 : #include "NIImporter_MATSim.h"
43 :
44 :
45 :
46 : // ===========================================================================
47 : // static variables
48 : // ===========================================================================
49 : SequentialStringBijection::Entry NIImporter_MATSim::matsimTags[] = {
50 : { "network", NIImporter_MATSim::MATSIM_TAG_NETWORK },
51 : { "node", NIImporter_MATSim::MATSIM_TAG_NODE },
52 : { "link", NIImporter_MATSim::MATSIM_TAG_LINK },
53 : { "links", NIImporter_MATSim::MATSIM_TAG_LINKS },
54 : { "", NIImporter_MATSim::MATSIM_TAG_NOTHING }
55 : };
56 :
57 :
58 : SequentialStringBijection::Entry NIImporter_MATSim::matsimAttrs[] = {
59 : { "id", NIImporter_MATSim::MATSIM_ATTR_ID },
60 : { "x", NIImporter_MATSim::MATSIM_ATTR_X },
61 : { "y", NIImporter_MATSim::MATSIM_ATTR_Y },
62 : { "from", NIImporter_MATSim::MATSIM_ATTR_FROM },
63 : { "to", NIImporter_MATSim::MATSIM_ATTR_TO },
64 : { "length", NIImporter_MATSim::MATSIM_ATTR_LENGTH },
65 : { "freespeed", NIImporter_MATSim::MATSIM_ATTR_FREESPEED },
66 : { "capacity", NIImporter_MATSim::MATSIM_ATTR_CAPACITY },
67 : { "permlanes", NIImporter_MATSim::MATSIM_ATTR_PERMLANES },
68 : { "oneway", NIImporter_MATSim::MATSIM_ATTR_ONEWAY },
69 : { "modes", NIImporter_MATSim::MATSIM_ATTR_MODES },
70 : { "origid", NIImporter_MATSim::MATSIM_ATTR_ORIGID },
71 : { "capperiod", NIImporter_MATSim::MATSIM_ATTR_CAPPERIOD },
72 : { "capDivider", NIImporter_MATSim::MATSIM_ATTR_CAPDIVIDER },
73 :
74 : { "", NIImporter_MATSim::MATSIM_ATTR_NOTHING }
75 : };
76 :
77 :
78 : // ===========================================================================
79 : // method definitions
80 : // ===========================================================================
81 : // ---------------------------------------------------------------------------
82 : // static methods
83 : // ---------------------------------------------------------------------------
84 : void
85 1892 : NIImporter_MATSim::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
86 : // check whether the option is set properly and all files exist
87 3784 : if (!oc.isUsableFileList("matsim-files")) {
88 1883 : return;
89 : }
90 : /* Parse file(s)
91 : * Each file is parsed twice: first for nodes, second for edges. */
92 18 : const std::vector<std::string> files = oc.getStringVector("matsim-files");
93 : // load nodes, first
94 9 : NodesHandler nodesHandler(nb.getNodeCont());
95 18 : for (const std::string& file : files) {
96 9 : nodesHandler.setFileName(file);
97 27 : PROGRESS_BEGIN_MESSAGE("Parsing nodes from matsim-file '" + file + "'");
98 9 : if (!XMLSubSys::runParser(nodesHandler, file, false, false, true)) {
99 : return;
100 : }
101 9 : PROGRESS_DONE_MESSAGE();
102 : }
103 : // load edges, then
104 18 : EdgesHandler edgesHandler(nb.getNodeCont(), nb.getEdgeCont(), oc.getBool("matsim.keep-length"),
105 27 : oc.getBool("matsim.lanes-from-capacity"), NBCapacity2Lanes(oc.getFloat("lanes-from-capacity.norm")));
106 18 : for (const std::string& file : files) {
107 9 : edgesHandler.setFileName(file);
108 27 : PROGRESS_BEGIN_MESSAGE("Parsing edges from matsim-file '" + file + "'");
109 9 : XMLSubSys::runParser(edgesHandler, file, false, false, true);
110 9 : PROGRESS_DONE_MESSAGE();
111 : }
112 9 : }
113 :
114 :
115 : // ---------------------------------------------------------------------------
116 : // definitions of NIImporter_MATSim::NodesHandler-methods
117 : // ---------------------------------------------------------------------------
118 9 : NIImporter_MATSim::NodesHandler::NodesHandler(NBNodeCont& toFill)
119 : : GenericSAXHandler(matsimTags, MATSIM_TAG_NOTHING,
120 : matsimAttrs, MATSIM_ATTR_NOTHING,
121 18 : "matsim - file"), myNodeCont(toFill) {
122 9 : }
123 :
124 :
125 9 : NIImporter_MATSim::NodesHandler::~NodesHandler() {}
126 :
127 :
128 : void
129 599 : NIImporter_MATSim::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
130 599 : if (element != MATSIM_TAG_NODE) {
131 404 : return;
132 : }
133 : // get the id, report a warning if not given or empty...
134 195 : bool ok = true;
135 390 : const std::string id = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_ID, nullptr, ok));
136 195 : const double x = attrs.get<double>(MATSIM_ATTR_X, id.c_str(), ok);
137 195 : const double y = attrs.get<double>(MATSIM_ATTR_Y, id.c_str(), ok);
138 195 : if (!ok) {
139 : return;
140 : }
141 : Position pos(x, y);
142 195 : if (!NBNetBuilder::transformCoordinate(pos)) {
143 0 : WRITE_ERRORF(TL("Unable to project coordinates for node '%'."), id);
144 : }
145 195 : NBNode* node = new NBNode(id, pos);
146 195 : if (!myNodeCont.insert(node)) {
147 0 : delete node;
148 0 : WRITE_ERRORF(TL("Could not add node '%'. Probably declared twice."), id);
149 : }
150 : }
151 :
152 :
153 :
154 : // ---------------------------------------------------------------------------
155 : // definitions of NIImporter_MATSim::EdgesHandler-methods
156 : // ---------------------------------------------------------------------------
157 9 : NIImporter_MATSim::EdgesHandler::EdgesHandler(NBNodeCont& nc, NBEdgeCont& toFill,
158 : bool keepEdgeLengths, bool lanesFromCapacity,
159 9 : NBCapacity2Lanes capacity2Lanes)
160 : : GenericSAXHandler(matsimTags, MATSIM_TAG_NOTHING,
161 : matsimAttrs, MATSIM_ATTR_NOTHING, "matsim - file"),
162 9 : myNodeCont(nc), myEdgeCont(toFill), myCapacityNorm(3600),
163 9 : myKeepEdgeLengths(keepEdgeLengths), myLanesFromCapacity(lanesFromCapacity),
164 18 : myCapacity2Lanes(capacity2Lanes) {
165 9 : }
166 :
167 :
168 9 : NIImporter_MATSim::EdgesHandler::~EdgesHandler() {
169 9 : }
170 :
171 :
172 : void
173 378 : NIImporter_MATSim::EdgesHandler::insertEdge(const std::string& id, NBNode* fromNode, NBNode* toNode, double freeSpeed, int numLanes, double capacity, double length, SVCPermissions perm) {
174 756 : NBEdge* edge = new NBEdge(id, fromNode, toNode, "", freeSpeed, NBEdge::UNSPECIFIED_FRICTION, numLanes, -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, LaneSpreadFunction::RIGHT);
175 756 : edge->setParameter("capacity", toString(capacity));
176 378 : edge->setPermissions(perm, -1);
177 378 : if (myKeepEdgeLengths) {
178 46 : edge->setLoadedLength(length);
179 : }
180 378 : if (!myEdgeCont.insert(edge)) {
181 0 : delete edge;
182 0 : WRITE_ERRORF(TL("Could not add edge '%'. Probably declared twice."), id);
183 : }
184 378 : }
185 :
186 :
187 : SVCPermissions
188 378 : NIImporter_MATSim::EdgesHandler::computePermission(std::string modes) {
189 : // using the MATSim modes from org.matsim.api.core.v01.TransportMode
190 378 : if (modes.size() == 0) {
191 355 : return SVCAll;
192 : }
193 : SVCPermissions result(SVC_IGNORING);
194 69 : for (StringTokenizer st(modes); st.hasNext();) {
195 23 : std::string mode = st.next();
196 23 : if (mode == "car") {
197 23 : result |= SVC_PASSENGER;
198 0 : } else if (mode == "bike") {
199 0 : result |= SVC_BICYCLE;
200 0 : } else if (mode == "motorcycle") {
201 0 : result |= SVC_MOTORCYCLE | SVC_MOPED;
202 0 : } else if (mode == "truck") {
203 0 : result |= SVC_TRUCK | SVC_TRAILER;
204 0 : } else if (mode == "pt") {
205 0 : result |= SVC_BUS | SVC_TRAM;
206 0 : } else if (mode == "drt" || mode == "taxi") {
207 0 : result |= SVC_TAXI;
208 0 : } else if (mode == "walk" || mode == "transit_walk") {
209 0 : result |= SVC_PEDESTRIAN;
210 0 : } else if (mode == "train") {
211 0 : result |= SVC_RAIL_CLASSES;
212 0 : } else if (mode == "ship") {
213 0 : result |= SVC_SHIP;
214 : }
215 23 : }
216 23 : return result;
217 : }
218 :
219 :
220 : void
221 599 : NIImporter_MATSim::EdgesHandler::myStartElement(int element,
222 : const SUMOSAXAttributes& attrs) {
223 599 : if (element == MATSIM_TAG_NETWORK) {
224 9 : if (attrs.hasAttribute(MATSIM_ATTR_CAPDIVIDER)) {
225 0 : bool ok = true;
226 0 : int capDivider = attrs.get<int>(MATSIM_ATTR_CAPDIVIDER, "network", ok);
227 0 : if (ok) {
228 0 : myCapacityNorm = (double)(capDivider * 3600);
229 : }
230 : }
231 : }
232 599 : if (element == MATSIM_TAG_LINKS) {
233 9 : bool ok = true;
234 9 : std::string capperiod = attrs.get<std::string>(MATSIM_ATTR_CAPPERIOD, "links", ok);
235 27 : StringTokenizer st(capperiod, ":");
236 9 : if (st.size() != 3) {
237 0 : WRITE_ERROR(TL("Bogus capacity period format; requires 'hh:mm:ss'."));
238 0 : return;
239 : }
240 : try {
241 9 : int hours = StringUtils::toInt(st.next());
242 9 : int minutes = StringUtils::toInt(st.next());
243 9 : int seconds = StringUtils::toInt(st.next());
244 9 : myCapacityNorm = (double)(hours * 3600 + minutes * 60 + seconds);
245 0 : } catch (NumberFormatException&) {
246 0 : } catch (EmptyData&) {
247 0 : }
248 9 : return;
249 9 : }
250 :
251 : // parse "link" elements
252 590 : if (element != MATSIM_TAG_LINK) {
253 : return;
254 : }
255 377 : bool ok = true;
256 754 : const std::string id = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_ID, nullptr, ok));
257 754 : const std::string fromNodeID = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_FROM, id.c_str(), ok));
258 754 : const std::string toNodeID = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_TO, id.c_str(), ok));
259 377 : const double length = attrs.get<double>(MATSIM_ATTR_LENGTH, id.c_str(), ok); // override computed?
260 377 : const double freeSpeed = attrs.get<double>(MATSIM_ATTR_FREESPEED, id.c_str(), ok); //
261 377 : const double capacity = attrs.get<double>(MATSIM_ATTR_CAPACITY, id.c_str(), ok); // override permLanes?
262 377 : double permLanes = attrs.get<double>(MATSIM_ATTR_PERMLANES, id.c_str(), ok);
263 : //bool oneWay = attrs.getOpt<bool>(MATSIM_ATTR_ONEWAY, id.c_str(), ok, true); // mandatory?
264 377 : const std::string modes = attrs.getOpt<std::string>(MATSIM_ATTR_MODES, id.c_str(), ok, "");
265 377 : const std::string origid = attrs.getOpt<std::string>(MATSIM_ATTR_ORIGID, id.c_str(), ok, "");
266 377 : NBNode* fromNode = myNodeCont.retrieve(fromNodeID);
267 377 : NBNode* toNode = myNodeCont.retrieve(toNodeID);
268 377 : if (fromNode == nullptr) {
269 0 : WRITE_ERRORF(TL("Could not find from-node for edge '%'."), id);
270 : }
271 377 : if (toNode == nullptr) {
272 0 : WRITE_ERRORF(TL("Could not find to-node for edge '%'."), id);
273 : }
274 377 : if (fromNode == nullptr || toNode == nullptr) {
275 : return;
276 : }
277 377 : if (myLanesFromCapacity) {
278 46 : permLanes = myCapacity2Lanes.get(capacity);
279 : }
280 377 : if (permLanes < 0.5) {
281 0 : WRITE_WARNINGF(TL("Ignoring edge % which has no lanes."), id);
282 0 : return;
283 : }
284 377 : if (fromNode == toNode) {
285 : // adding node and edge with a different naming scheme to keep the original edge id for easier route repair
286 2 : NBNode* intermediate = new NBNode(id + ".0", toNode->getPosition() + Position(POSITION_EPS, POSITION_EPS));
287 1 : if (myNodeCont.insert(intermediate)) {
288 2 : insertEdge(id + ".0", intermediate, toNode, freeSpeed, (int)(permLanes + 0.5), capacity, length, computePermission(modes));
289 : toNode = intermediate;
290 : } else {
291 0 : delete intermediate;
292 0 : WRITE_ERRORF(TL("Could not add intermediate node to split loop edge '%'."), id);
293 : }
294 : }
295 754 : insertEdge(id, fromNode, toNode, freeSpeed, (int)(permLanes + 0.5), capacity, length, computePermission(modes));
296 : }
297 :
298 :
299 : /****************************************************************************/
|