1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file NIVissimDistrictConnection.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Michael Behrisch
14 /// @date Sept 2002
15 /// @version $Id$
16 ///
17 // -------------------
18 /****************************************************************************/
19
20
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25
26 #include <map>
27 #include <string>
28 #include <algorithm>
29 #include <cassert>
30 #include <utils/common/VectorHelper.h>
31 #include <utils/common/ToString.h>
32 #include <utils/geom/Position.h>
33 #include <utils/geom/GeomHelper.h>
34 #include <utils/geom/PositionVector.h>
35 #include <utils/options/OptionsCont.h>
36 #include "NIVissimAbstractEdge.h"
37 #include "NIVissimEdge.h"
38 #include <netbuild/NBEdge.h>
39 #include <netbuild/NBEdgeCont.h>
40 #include <netbuild/NBNode.h>
41 #include <netbuild/NBNodeCont.h>
42 #include <netbuild/NBDistrict.h>
43 #include <netbuild/NBDistrictCont.h>
44 #include "NIVissimDistrictConnection.h"
45 #include <utils/distribution/DistributionCont.h>
46 #include <utils/common/MsgHandler.h>
47
48
49 // ===========================================================================
50 // static member definitions
51 // ===========================================================================
52 NIVissimDistrictConnection::DictType NIVissimDistrictConnection::myDict;
53 std::map<int, std::vector<int> > NIVissimDistrictConnection::myDistrictsConnections;
54
55
56 // ===========================================================================
57 // method definitions
58 // ===========================================================================
NIVissimDistrictConnection(int id,const std::string & name,const std::vector<int> & districts,const std::vector<double> & percentages,int edgeid,double position,const std::vector<std::pair<int,int>> & assignedVehicles)59 NIVissimDistrictConnection::NIVissimDistrictConnection(int id,
60 const std::string& name,
61 const std::vector<int>& districts, const std::vector<double>& percentages,
62 int edgeid, double position,
63 const std::vector<std::pair<int, int> >& assignedVehicles)
64 : myID(id), myName(name), myDistricts(districts),
65 myEdgeID(edgeid), myPosition(position),
66 myAssignedVehicles(assignedVehicles) {
67 std::vector<int>::iterator i = myDistricts.begin();
68 std::vector<double>::const_iterator j = percentages.begin();
69 while (i != myDistricts.end()) {
70 myPercentages[*i] = *j;
71 i++;
72 j++;
73 }
74 }
75
76
~NIVissimDistrictConnection()77 NIVissimDistrictConnection::~NIVissimDistrictConnection() {}
78
79
80
81 bool
dictionary(int id,const std::string & name,const std::vector<int> & districts,const std::vector<double> & percentages,int edgeid,double position,const std::vector<std::pair<int,int>> & assignedVehicles)82 NIVissimDistrictConnection::dictionary(int id, const std::string& name,
83 const std::vector<int>& districts, const std::vector<double>& percentages,
84 int edgeid, double position,
85 const std::vector<std::pair<int, int> >& assignedVehicles) {
86 NIVissimDistrictConnection* o =
87 new NIVissimDistrictConnection(id, name, districts, percentages,
88 edgeid, position, assignedVehicles);
89 if (!dictionary(id, o)) {
90 delete o;
91 return false;
92 }
93 return true;
94 }
95
96
97 bool
dictionary(int id,NIVissimDistrictConnection * o)98 NIVissimDistrictConnection::dictionary(int id, NIVissimDistrictConnection* o) {
99 DictType::iterator i = myDict.find(id);
100 if (i == myDict.end()) {
101 myDict[id] = o;
102 return true;
103 }
104 return false;
105 }
106
107
108 NIVissimDistrictConnection*
dictionary(int id)109 NIVissimDistrictConnection::dictionary(int id) {
110 DictType::iterator i = myDict.find(id);
111 if (i == myDict.end()) {
112 return nullptr;
113 }
114 return (*i).second;
115 }
116
117 void
dict_BuildDistrictConnections()118 NIVissimDistrictConnection::dict_BuildDistrictConnections() {
119 // pre-assign connections to districts
120 for (DictType::iterator i = myDict.begin(); i != myDict.end(); i++) {
121 NIVissimDistrictConnection* c = (*i).second;
122 const std::vector<int>& districts = c->myDistricts;
123 for (std::vector<int>::const_iterator j = districts.begin(); j != districts.end(); j++) {
124 // assign connection to district
125 myDistrictsConnections[*j].push_back((*i).first);
126 }
127 }
128 }
129
130
131 void
dict_CheckEdgeEnds()132 NIVissimDistrictConnection::dict_CheckEdgeEnds() {
133 for (std::map<int, std::vector<int> >::iterator k = myDistrictsConnections.begin(); k != myDistrictsConnections.end(); k++) {
134 const std::vector<int>& connections = (*k).second;
135 for (std::vector<int>::const_iterator j = connections.begin(); j != connections.end(); j++) {
136 NIVissimDistrictConnection* c = dictionary(*j);
137 c->checkEdgeEnd();
138 }
139 }
140 }
141
142
143 void
checkEdgeEnd()144 NIVissimDistrictConnection::checkEdgeEnd() {
145 NIVissimEdge* edge = NIVissimEdge::dictionary(myEdgeID);
146 assert(edge != 0);
147 edge->checkDistrictConnectionExistanceAt(myPosition);
148 }
149
150
151 void
dict_BuildDistrictNodes(NBDistrictCont & dc,NBNodeCont & nc)152 NIVissimDistrictConnection::dict_BuildDistrictNodes(NBDistrictCont& dc,
153 NBNodeCont& nc) {
154 for (std::map<int, std::vector<int> >::iterator k = myDistrictsConnections.begin(); k != myDistrictsConnections.end(); k++) {
155 // get the connections
156 const std::vector<int>& connections = (*k).second;
157 // retrieve the current district
158 std::string dsid = toString<int>((*k).first);
159 NBDistrict* district = new NBDistrict(dsid);
160 dc.insert(district);
161 // compute the middle of the district
162 PositionVector pos;
163 for (std::vector<int>::const_iterator j = connections.begin(); j != connections.end(); j++) {
164 NIVissimDistrictConnection* c = dictionary(*j);
165 pos.push_back(c->geomPosition());
166 }
167 Position distCenter = pos.getPolygonCenter();
168 if (connections.size() == 1) { // !!! ok, ok, maybe not the best way just to add an offset
169 distCenter.add(10, 10);
170 }
171 district->setCenter(distCenter);
172 // build the node
173 std::string id = "District" + district->getID();
174 NBNode* districtNode =
175 new NBNode(id, district->getPosition(), district);
176 if (!nc.insert(districtNode)) {
177 throw 1;
178 }
179 }
180 }
181
182 void
dict_BuildDistricts(NBDistrictCont & dc,NBEdgeCont & ec,NBNodeCont & nc)183 NIVissimDistrictConnection::dict_BuildDistricts(NBDistrictCont& dc,
184 NBEdgeCont& ec,
185 NBNodeCont& nc) {
186 // add the sources and sinks
187 // their normalised probability is computed within NBDistrict
188 // to avoid double code writing and more securty within the converter
189 // go through the district table
190 for (std::map<int, std::vector<int> >::iterator k = myDistrictsConnections.begin(); k != myDistrictsConnections.end(); k++) {
191 // get the connections
192 const std::vector<int>& connections = (*k).second;
193 // retrieve the current district
194 NBDistrict* district =
195 dc.retrieve(toString<int>((*k).first));
196 NBNode* districtNode = nc.retrieve("District" + district->getID());
197 assert(district != 0 && districtNode != 0);
198
199 for (std::vector<int>::const_iterator l = connections.begin(); l != connections.end(); l++) {
200 NIVissimDistrictConnection* c = dictionary(*l);
201 // get the edge to connect the parking place to
202 NBEdge* e = ec.retrieve(toString<int>(c->myEdgeID));
203 if (e == nullptr) {
204 e = ec.retrievePossiblySplit(toString<int>(c->myEdgeID), c->myPosition);
205 }
206 if (e == nullptr) {
207 WRITE_WARNING("Could not build district '" + toString<int>((*k).first) + "' - edge '" + toString<int>(c->myEdgeID) + "' is missing.");
208 continue;
209 }
210 std::string id = "ParkingPlace" + toString<int>(*l);
211 NBNode* parkingPlace = nc.retrieve(id);
212 if (parkingPlace == nullptr) {
213 double pos = c->getPosition();
214 if (pos < e->getLength() - pos) {
215 parkingPlace = e->getFromNode();
216 parkingPlace->invalidateIncomingConnections();
217 } else {
218 parkingPlace = e->getToNode();
219 parkingPlace->invalidateOutgoingConnections();
220 }
221 }
222 assert(
223 e->getToNode() == parkingPlace
224 ||
225 e->getFromNode() == parkingPlace);
226
227 // build the connection to the source
228 if (e->getFromNode() == parkingPlace) {
229 id = "VissimFromParkingplace" + toString<int>((*k).first) + "-" + toString<int>(c->myID);
230 NBEdge* source =
231 new NBEdge(id, districtNode, parkingPlace,
232 "Connection", c->getMeanSpeed(/*distc*/) / (double) 3.6, 3, -1,
233 NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET);
234 if (!ec.insert(source)) { // !!! in den Konstruktor
235 throw 1; // !!!
236 }
237 double percNormed =
238 c->myPercentages[(*k).first];
239 if (!district->addSource(source, percNormed)) {
240 throw 1;
241 }
242 }
243
244 // build the connection to the destination
245 if (e->getToNode() == parkingPlace) {
246 id = "VissimToParkingplace" + toString<int>((*k).first) + "-" + toString<int>(c->myID);
247 NBEdge* destination =
248 new NBEdge(id, parkingPlace, districtNode,
249 "Connection", (double) 100 / (double) 3.6, 2, -1,
250 NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET);
251 if (!ec.insert(destination)) { // !!! (in den Konstruktor)
252 throw 1; // !!!
253 }
254 double percNormed2 =
255 c->myPercentages[(*k).first];
256 if (!district->addSink(destination, percNormed2)) {
257 throw 1; // !!!
258 }
259 }
260
261 /*
262 if(e->getToNode()==districtNode) {
263 double percNormed =
264 c->myPercentages[(*k).first];
265 district->addSink(e, percNormed);
266 }
267 if(e->getFromNode()==districtNode) {
268 double percNormed =
269 c->myPercentages[(*k).first];
270 district->addSource(e, percNormed);
271 }
272 */
273 }
274
275 /*
276 // add them as sources and sinks to the current district
277 for(std::vector<int>::const_iterator l=connections.begin(); l!=connections.end(); l++) {
278 // get the current connections
279 NIVissimDistrictConnection *c = dictionary(*l);
280 // get the edge to connect the parking place to
281 NBEdge *e = NBEdgeCont::retrieve(toString<int>(c->myEdgeID));
282 Position edgepos = c->geomPosition();
283 NBNode *edgeend = e->tryGetNodeAtPosition(c->myPosition,
284 e->getLength()/4.0);
285 if(edgeend==0) {
286 // Edge splitting omitted on build district connections by now
287 assert(false);
288 }
289
290 // build the district-node if not yet existing
291 std::string id = "VissimParkingplace" + district->getID();
292 NBNode *districtNode = nc.retrieve(id);
293 assert(districtNode!=0);
294
295 if(e->getToNode()==edgeend) {
296 // build the connection to the source
297 id = std::string("VissimFromParkingplace")
298 + toString<int>((*k).first) + "-"
299 + toString<int>(c->myID);
300 NBEdge *source =
301 new NBEdge(id, id, districtNode, edgeend,
302 "Connection", 100/3.6, 2, 100, 0,
303 NBEdge::EDGEFUNCTION_SOURCE);
304 NBEdgeCont::insert(source); // !!! (in den Konstruktor)
305 double percNormed =
306 c->myPercentages[(*k).first];
307 district->addSource(source, percNormed);
308 } else {
309 // build the connection to the destination
310 id = std::string("VissimToParkingplace")
311 + toString<int>((*k).first) + "-"
312 + toString<int>(c->myID);
313 NBEdge *destination =
314 new NBEdge(id, id, edgeend, districtNode,
315 "Connection", 100/3.6, 2, 100, 0,
316 NBEdge::EDGEFUNCTION_SINK);
317 NBEdgeCont::insert(destination); // !!! (in den Konstruktor)
318
319 // add both the source and the sink to the district
320 double percNormed =
321 c->myPercentages[(*k).first];
322 district->addSink(destination, percNormed);
323 }
324 }
325 */
326 }
327 }
328
329
330
331 Position
geomPosition() const332 NIVissimDistrictConnection::geomPosition() const {
333 NIVissimAbstractEdge* e = NIVissimEdge::dictionary(myEdgeID);
334 return e->getGeomPosition(myPosition);
335 }
336
337
338 NIVissimDistrictConnection*
dict_findForEdge(int edgeid)339 NIVissimDistrictConnection::dict_findForEdge(int edgeid) {
340 for (DictType::iterator i = myDict.begin(); i != myDict.end(); i++) {
341 if ((*i).second->myEdgeID == edgeid) {
342 return (*i).second;
343 }
344 }
345 return nullptr;
346 }
347
348
349 void
clearDict()350 NIVissimDistrictConnection::clearDict() {
351 for (DictType::iterator i = myDict.begin(); i != myDict.end(); i++) {
352 delete (*i).second;
353 }
354 myDict.clear();
355 }
356
357
358 double
getMeanSpeed() const359 NIVissimDistrictConnection::getMeanSpeed() const {
360 //assert(myAssignedVehicles.size()!=0);
361 if (myAssignedVehicles.size() == 0) {
362 WRITE_WARNING("No streams assigned at district'" + toString(myID) + "'.\n Using default speed 200km/h");
363 return (double) 200 / (double) 3.6;
364 }
365 double speed = 0;
366 std::vector<std::pair<int, int> >::const_iterator i;
367 for (i = myAssignedVehicles.begin(); i != myAssignedVehicles.end(); i++) {
368 speed += getRealSpeed((*i).second);
369 }
370 return speed / (double) myAssignedVehicles.size();
371 }
372
373
374 double
getRealSpeed(int distNo) const375 NIVissimDistrictConnection::getRealSpeed(int distNo) const {
376 std::string id = toString<int>(distNo);
377 Distribution* dist = DistributionCont::dictionary("speed", id);
378 if (dist == nullptr) {
379 WRITE_WARNING("The referenced speed distribution '" + id + "' is not known.");
380 WRITE_WARNING(". Using default.");
381 return OptionsCont::getOptions().getFloat("vissim.default-speed");
382 }
383 assert(dist != 0);
384 double speed = dist->getMax();
385 if (speed < 0 || speed > 1000) {
386 WRITE_WARNING(" False speed at district '" + id);
387 WRITE_WARNING(". Using default.");
388 speed = OptionsCont::getOptions().getFloat("vissim.default-speed");
389 }
390 return speed;
391 }
392
393
394
395 /****************************************************************************/
396
397