Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netimport/NIImporter_MATSim.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
NIImporter_MATSim::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
86
// check whether the option is set properly and all files exist
87
if (!oc.isUsableFileList("matsim-files")) {
88
return;
89
}
90
/* Parse file(s)
91
* Each file is parsed twice: first for nodes, second for edges. */
92
const std::vector<std::string> files = oc.getStringVector("matsim-files");
93
// load nodes, first
94
NodesHandler nodesHandler(nb.getNodeCont());
95
for (const std::string& file : files) {
96
nodesHandler.setFileName(file);
97
PROGRESS_BEGIN_MESSAGE("Parsing nodes from matsim-file '" + file + "'");
98
if (!XMLSubSys::runParser(nodesHandler, file, false, false, true)) {
99
return;
100
}
101
PROGRESS_DONE_MESSAGE();
102
}
103
// load edges, then
104
EdgesHandler edgesHandler(nb.getNodeCont(), nb.getEdgeCont(), oc.getBool("matsim.keep-length"),
105
oc.getBool("matsim.lanes-from-capacity"), NBCapacity2Lanes(oc.getFloat("lanes-from-capacity.norm")));
106
for (const std::string& file : files) {
107
edgesHandler.setFileName(file);
108
PROGRESS_BEGIN_MESSAGE("Parsing edges from matsim-file '" + file + "'");
109
XMLSubSys::runParser(edgesHandler, file, false, false, true);
110
PROGRESS_DONE_MESSAGE();
111
}
112
}
113
114
115
// ---------------------------------------------------------------------------
116
// definitions of NIImporter_MATSim::NodesHandler-methods
117
// ---------------------------------------------------------------------------
118
NIImporter_MATSim::NodesHandler::NodesHandler(NBNodeCont& toFill)
119
: GenericSAXHandler(matsimTags, MATSIM_TAG_NOTHING,
120
matsimAttrs, MATSIM_ATTR_NOTHING,
121
"matsim - file"), myNodeCont(toFill) {
122
}
123
124
125
NIImporter_MATSim::NodesHandler::~NodesHandler() {}
126
127
128
void
129
NIImporter_MATSim::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
130
if (element != MATSIM_TAG_NODE) {
131
return;
132
}
133
// get the id, report a warning if not given or empty...
134
bool ok = true;
135
const std::string id = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_ID, nullptr, ok));
136
const double x = attrs.get<double>(MATSIM_ATTR_X, id.c_str(), ok);
137
const double y = attrs.get<double>(MATSIM_ATTR_Y, id.c_str(), ok);
138
if (!ok) {
139
return;
140
}
141
Position pos(x, y);
142
if (!NBNetBuilder::transformCoordinate(pos)) {
143
WRITE_ERRORF(TL("Unable to project coordinates for node '%'."), id);
144
}
145
NBNode* node = new NBNode(id, pos);
146
if (!myNodeCont.insert(node)) {
147
delete node;
148
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
NIImporter_MATSim::EdgesHandler::EdgesHandler(NBNodeCont& nc, NBEdgeCont& toFill,
158
bool keepEdgeLengths, bool lanesFromCapacity,
159
NBCapacity2Lanes capacity2Lanes)
160
: GenericSAXHandler(matsimTags, MATSIM_TAG_NOTHING,
161
matsimAttrs, MATSIM_ATTR_NOTHING, "matsim - file"),
162
myNodeCont(nc), myEdgeCont(toFill), myCapacityNorm(3600),
163
myKeepEdgeLengths(keepEdgeLengths), myLanesFromCapacity(lanesFromCapacity),
164
myCapacity2Lanes(capacity2Lanes) {
165
}
166
167
168
NIImporter_MATSim::EdgesHandler::~EdgesHandler() {
169
}
170
171
172
void
173
NIImporter_MATSim::EdgesHandler::insertEdge(const std::string& id, NBNode* fromNode, NBNode* toNode, double freeSpeed, int numLanes, double capacity, double length, SVCPermissions perm) {
174
NBEdge* edge = new NBEdge(id, fromNode, toNode, "", freeSpeed, NBEdge::UNSPECIFIED_FRICTION, numLanes, -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, LaneSpreadFunction::RIGHT);
175
edge->setParameter("capacity", toString(capacity));
176
edge->setPermissions(perm, -1);
177
if (myKeepEdgeLengths) {
178
edge->setLoadedLength(length);
179
}
180
if (!myEdgeCont.insert(edge)) {
181
delete edge;
182
WRITE_ERRORF(TL("Could not add edge '%'. Probably declared twice."), id);
183
}
184
}
185
186
187
SVCPermissions
188
NIImporter_MATSim::EdgesHandler::computePermission(std::string modes) {
189
// using the MATSim modes from org.matsim.api.core.v01.TransportMode
190
if (modes.size() == 0) {
191
return SVCAll;
192
}
193
SVCPermissions result(SVC_IGNORING);
194
for (StringTokenizer st(modes); st.hasNext();) {
195
std::string mode = st.next();
196
if (mode == "car") {
197
result |= SVC_PASSENGER;
198
} else if (mode == "bike") {
199
result |= SVC_BICYCLE;
200
} else if (mode == "motorcycle") {
201
result |= SVC_MOTORCYCLE | SVC_MOPED;
202
} else if (mode == "truck") {
203
result |= SVC_TRUCK | SVC_TRAILER;
204
} else if (mode == "pt") {
205
result |= SVC_BUS | SVC_TRAM;
206
} else if (mode == "drt" || mode == "taxi") {
207
result |= SVC_TAXI;
208
} else if (mode == "walk" || mode == "transit_walk") {
209
result |= SVC_PEDESTRIAN;
210
} else if (mode == "train") {
211
result |= SVC_RAIL_CLASSES;
212
} else if (mode == "ship") {
213
result |= SVC_SHIP;
214
}
215
}
216
return result;
217
}
218
219
220
void
221
NIImporter_MATSim::EdgesHandler::myStartElement(int element,
222
const SUMOSAXAttributes& attrs) {
223
if (element == MATSIM_TAG_NETWORK) {
224
if (attrs.hasAttribute(MATSIM_ATTR_CAPDIVIDER)) {
225
bool ok = true;
226
int capDivider = attrs.get<int>(MATSIM_ATTR_CAPDIVIDER, "network", ok);
227
if (ok) {
228
myCapacityNorm = (double)(capDivider * 3600);
229
}
230
}
231
}
232
if (element == MATSIM_TAG_LINKS) {
233
bool ok = true;
234
std::string capperiod = attrs.get<std::string>(MATSIM_ATTR_CAPPERIOD, "links", ok);
235
StringTokenizer st(capperiod, ":");
236
if (st.size() != 3) {
237
WRITE_ERROR(TL("Bogus capacity period format; requires 'hh:mm:ss'."));
238
return;
239
}
240
try {
241
int hours = StringUtils::toInt(st.next());
242
int minutes = StringUtils::toInt(st.next());
243
int seconds = StringUtils::toInt(st.next());
244
myCapacityNorm = (double)(hours * 3600 + minutes * 60 + seconds);
245
} catch (NumberFormatException&) {
246
} catch (EmptyData&) {
247
}
248
return;
249
}
250
251
// parse "link" elements
252
if (element != MATSIM_TAG_LINK) {
253
return;
254
}
255
bool ok = true;
256
const std::string id = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_ID, nullptr, ok));
257
const std::string fromNodeID = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_FROM, id.c_str(), ok));
258
const std::string toNodeID = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_TO, id.c_str(), ok));
259
const double length = attrs.get<double>(MATSIM_ATTR_LENGTH, id.c_str(), ok); // override computed?
260
const double freeSpeed = attrs.get<double>(MATSIM_ATTR_FREESPEED, id.c_str(), ok); //
261
const double capacity = attrs.get<double>(MATSIM_ATTR_CAPACITY, id.c_str(), ok); // override permLanes?
262
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
const std::string modes = attrs.getOpt<std::string>(MATSIM_ATTR_MODES, id.c_str(), ok, "");
265
const std::string origid = attrs.getOpt<std::string>(MATSIM_ATTR_ORIGID, id.c_str(), ok, "");
266
NBNode* fromNode = myNodeCont.retrieve(fromNodeID);
267
NBNode* toNode = myNodeCont.retrieve(toNodeID);
268
if (fromNode == nullptr) {
269
WRITE_ERRORF(TL("Could not find from-node for edge '%'."), id);
270
}
271
if (toNode == nullptr) {
272
WRITE_ERRORF(TL("Could not find to-node for edge '%'."), id);
273
}
274
if (fromNode == nullptr || toNode == nullptr) {
275
return;
276
}
277
if (myLanesFromCapacity) {
278
permLanes = myCapacity2Lanes.get(capacity);
279
}
280
if (permLanes < 0.5) {
281
WRITE_WARNINGF(TL("Ignoring edge % which has no lanes."), id);
282
return;
283
}
284
if (fromNode == toNode) {
285
// adding node and edge with a different naming scheme to keep the original edge id for easier route repair
286
NBNode* intermediate = new NBNode(id + ".0", toNode->getPosition() + Position(POSITION_EPS, POSITION_EPS));
287
if (myNodeCont.insert(intermediate)) {
288
insertEdge(id + ".0", intermediate, toNode, freeSpeed, (int)(permLanes + 0.5), capacity, length, computePermission(modes));
289
toNode = intermediate;
290
} else {
291
delete intermediate;
292
WRITE_ERRORF(TL("Could not add intermediate node to split loop edge '%'."), id);
293
}
294
}
295
insertEdge(id, fromNode, toNode, freeSpeed, (int)(permLanes + 0.5), capacity, length, computePermission(modes));
296
}
297
298
299
/****************************************************************************/
300
301