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