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    NIVissimDisturbance.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Michael Behrisch
13 /// @date    Sept 2002
14 /// @version $Id$
15 ///
16 // -------------------
17 /****************************************************************************/
18 
19 
20 // ===========================================================================
21 // included modules
22 // ===========================================================================
23 #include <config.h>
24 
25 
26 #include <map>
27 #include <string>
28 #include <iostream>
29 #include <cassert>
30 #include <utils/common/ToString.h>
31 #include <utils/common/MsgHandler.h>
32 #include <utils/geom/GeomHelper.h>
33 #include <utils/geom/Boundary.h>
34 #include <netbuild/NBEdge.h>
35 #include <netbuild/NBNode.h>
36 #include <netbuild/NBEdgeCont.h>
37 #include <netbuild/NBNodeCont.h>
38 #include "NIVissimEdge.h"
39 #include "NIVissimConnection.h"
40 #include "NIVissimNodeDef.h"
41 #include "NIVissimDisturbance.h"
42 #include "NIVissimNodeParticipatingEdgeVector.h"
43 
44 
45 // ===========================================================================
46 // static member variables
47 // ===========================================================================
48 NIVissimDisturbance::DictType NIVissimDisturbance::myDict;
49 int NIVissimDisturbance::myRunningID = 100000000;
50 
51 int NIVissimDisturbance::refusedProhibits = 0;
52 
53 
54 // ===========================================================================
55 // method definitions
56 // ===========================================================================
NIVissimDisturbance(int id,const std::string & name,const NIVissimExtendedEdgePoint & edge,const NIVissimExtendedEdgePoint & by)57 NIVissimDisturbance::NIVissimDisturbance(int id,
58         const std::string& name,
59         const NIVissimExtendedEdgePoint& edge,
60         const NIVissimExtendedEdgePoint& by)
61     : myID(id), myNode(-1), myName(name), myEdge(edge), myDisturbance(by) {}
62 
63 
~NIVissimDisturbance()64 NIVissimDisturbance::~NIVissimDisturbance() {}
65 
66 
67 
68 bool
dictionary(const std::string & name,const NIVissimExtendedEdgePoint & edge,const NIVissimExtendedEdgePoint & by)69 NIVissimDisturbance::dictionary(const std::string& name,
70                                 const NIVissimExtendedEdgePoint& edge,
71                                 const NIVissimExtendedEdgePoint& by) {
72     int nid = myRunningID++;
73     NIVissimDisturbance* o =
74         new NIVissimDisturbance(nid, name, edge, by);
75     if (!dictionary(nid, o)) {
76         delete o;
77     }
78     return true;
79 }
80 
81 
82 bool
dictionary(int id,NIVissimDisturbance * o)83 NIVissimDisturbance::dictionary(int id, NIVissimDisturbance* o) {
84     DictType::iterator i = myDict.find(id);
85     if (i == myDict.end()) {
86         myDict[id] = o;
87         return true;
88     }
89     return false;
90 }
91 
92 
93 NIVissimDisturbance*
dictionary(int id)94 NIVissimDisturbance::dictionary(int id) {
95     DictType::iterator i = myDict.find(id);
96     if (i == myDict.end()) {
97         return nullptr;
98     }
99     return (*i).second;
100 }
101 
102 std::vector<int>
getWithin(const AbstractPoly & poly)103 NIVissimDisturbance::getWithin(const AbstractPoly& poly) {
104     std::vector<int> ret;
105     for (DictType::iterator i = myDict.begin(); i != myDict.end(); i++) {
106         if ((*i).second->crosses(poly)) {
107             ret.push_back((*i).second->myID);
108         }
109     }
110     return ret;
111 }
112 
113 
114 void
computeBounding()115 NIVissimDisturbance::computeBounding() {
116     assert(myBoundary == 0);
117     Boundary* bound = new Boundary();
118     if (NIVissimAbstractEdge::dictionary(myEdge.getEdgeID()) != nullptr) {
119         bound->add(myEdge.getGeomPosition());
120     }
121     if (NIVissimAbstractEdge::dictionary(myDisturbance.getEdgeID()) != nullptr) {
122         bound->add(myDisturbance.getGeomPosition());
123     }
124     myBoundary = bound;
125     assert(myBoundary != 0 && myBoundary->xmax() >= myBoundary->xmin());
126 }
127 
128 
129 
130 bool
addToNode(NBNode * node,NBDistrictCont & dc,NBNodeCont & nc,NBEdgeCont & ec)131 NIVissimDisturbance::addToNode(NBNode* node, NBDistrictCont& dc,
132                                NBNodeCont& nc, NBEdgeCont& ec) {
133     myNode = 0;
134     NIVissimConnection* pc =
135         NIVissimConnection::dictionary(myEdge.getEdgeID());
136     NIVissimConnection* bc =
137         NIVissimConnection::dictionary(myDisturbance.getEdgeID());
138     if (pc == nullptr && bc == nullptr) {
139         // This has not been tested completely, yet
140         // Both competing abstract edges are normal edges
141         // We have to find a crossing point, build a node here,
142         //  split both edges and add the connections
143         NIVissimEdge* e1 = NIVissimEdge::dictionary(myEdge.getEdgeID());
144         NIVissimEdge* e2 = NIVissimEdge::dictionary(myDisturbance.getEdgeID());
145         WRITE_WARNING("Ugly split to prohibit '" + toString<int>(e1->getID()) + "' by '" + toString<int>(e2->getID()) + "'.");
146         Position pos = e1->crossesEdgeAtPoint(e2);
147         std::string id1 = toString<int>(e1->getID()) + "x" + toString<int>(e2->getID());
148         std::string id2 = toString<int>(e2->getID()) + "x" + toString<int>(e1->getID());
149         NBNode* node1 = nc.retrieve(id1);
150         NBNode* node2 = nc.retrieve(id2);
151         NBNode* node = nullptr;
152         assert(node1 == 0 || node2 == 0);
153         if (node1 == nullptr && node2 == nullptr) {
154             refusedProhibits++;
155             return false;
156             /*            node = new NBNode(id1, pos.x(), pos.y(), "priority");
157                         if(!myNodeCont.insert(node)) {
158                              "nope, NIVissimDisturbance" << endl;
159                             throw 1;
160                         }*/
161         } else {
162             node = node1 == nullptr ? node2 : node1;
163         }
164         ec.splitAt(dc, ec.retrievePossiblySplit(toString<int>(e1->getID()), myEdge.getPosition()), node);
165         ec.splitAt(dc, ec.retrievePossiblySplit(toString<int>(e2->getID()), myDisturbance.getPosition()), node);
166         // !!! in some cases, one of the edges is not being build because it's too short
167         // !!! what to do in these cases?
168         NBEdge* mayDriveFrom = ec.retrieve(toString<int>(e1->getID()) + "[0]");
169         NBEdge* mayDriveTo = ec.retrieve(toString<int>(e1->getID()) + "[1]");
170         NBEdge* mustStopFrom = ec.retrieve(toString<int>(e2->getID()) + "[0]");
171         NBEdge* mustStopTo = ec.retrieve(toString<int>(e2->getID()) + "[1]");
172         if (mayDriveFrom != nullptr && mayDriveTo != nullptr && mustStopFrom != nullptr && mustStopTo != nullptr) {
173             node->addSortedLinkFoes(
174                 NBConnection(mayDriveFrom, mayDriveTo),
175                 NBConnection(mayDriveFrom, mayDriveTo));
176         } else {
177             refusedProhibits++;
178             return false;
179             // !!! warning
180         }
181 //        }
182     } else if (pc != nullptr && bc == nullptr) {
183         // The prohibited abstract edge is a connection, the other
184         //  is not;
185         // The connection will be prohibitesd by all connections
186         //  outgoing from the "real" edge
187 
188         NBEdge* e = ec.retrievePossiblySplit(toString<int>(myDisturbance.getEdgeID()), myDisturbance.getPosition());
189         if (e == nullptr) {
190             WRITE_WARNING("Could not prohibit '" + toString<int>(myEdge.getEdgeID()) + "' by '" + toString<int>(myDisturbance.getEdgeID()) + "'. Have not found disturbance.");
191             refusedProhibits++;
192             return false;
193         }
194         if (e->getFromNode() == e->getToNode()) {
195             WRITE_WARNING("Could not prohibit '" + toString<int>(myEdge.getEdgeID()) + "' by '" + toString<int>(myDisturbance.getEdgeID()) + "'. Disturbance connects same node.");
196             refusedProhibits++;
197             // What to do with self-looping edges?
198             return false;
199         }
200         // get the begin of the prohibited connection
201         std::string id_pcoe = toString<int>(pc->getFromEdgeID());
202         std::string id_pcie = toString<int>(pc->getToEdgeID());
203         NBEdge* pcoe = ec.retrievePossiblySplit(id_pcoe, id_pcie, true);
204         NBEdge* pcie = ec.retrievePossiblySplit(id_pcie, id_pcoe, false);
205         // check whether it's ending node is the node the prohibited
206         //  edge end at
207         if (pcoe != nullptr && pcie != nullptr && pcoe->getToNode() == e->getToNode()) {
208             // if so, simply prohibit the connections
209             NBNode* node = e->getToNode();
210             const EdgeVector& connected = e->getConnectedEdges();
211             for (EdgeVector::const_iterator i = connected.begin(); i != connected.end(); i++) {
212                 node->addSortedLinkFoes(
213                     NBConnection(e, *i),
214                     NBConnection(pcoe, pcie));
215             }
216         } else {
217             WRITE_WARNING("Would have to split edge '" + e->getID() + "' to build a prohibition");
218             refusedProhibits++;
219             // quite ugly - why was it not build?
220             return false;
221             /*
222             std::string nid1 = e->getID() + "[0]";
223             std::string nid2 = e->getID() + "[1]";
224 
225             if(ec.splitAt(e, node)) {
226                 node->addSortedLinkFoes(
227                         NBConnection(
228                             ec.retrieve(nid1),
229                             ec.retrieve(nid2)
230                         ),
231                         getConnection(node, myEdge.getEdgeID())
232                     );
233             }
234             */
235         }
236     } else if (bc != nullptr && pc == nullptr) {
237         // The prohibiting abstract edge is a connection, the other
238         //  is not;
239         // We have to split the other one and add the prohibition
240         //  description
241 
242         NBEdge* e = ec.retrievePossiblySplit(toString<int>(myEdge.getEdgeID()), myEdge.getPosition());
243         if (e == nullptr) {
244             WRITE_WARNING("Could not prohibit '" + toString<int>(myEdge.getEdgeID()) + "' - it was not built.");
245             return false;
246         }
247         std::string nid1 = e->getID() + "[0]";
248         std::string nid2 = e->getID() + "[1]";
249         if (e->getFromNode() == e->getToNode()) {
250             WRITE_WARNING("Could not prohibit '" + toString<int>(myEdge.getEdgeID()) + "' by '" + toString<int>(myDisturbance.getEdgeID()) + "'.");
251             refusedProhibits++;
252             // What to do with self-looping edges?
253             return false;
254         }
255         // get the begin of the prohibiting connection
256         std::string id_bcoe = toString<int>(bc->getFromEdgeID());
257         std::string id_bcie = toString<int>(bc->getToEdgeID());
258         NBEdge* bcoe = ec.retrievePossiblySplit(id_bcoe, id_bcie, true);
259         NBEdge* bcie = ec.retrievePossiblySplit(id_bcie, id_bcoe, false);
260         // check whether it's ending node is the node the prohibited
261         //  edge end at
262         if (bcoe != nullptr && bcie != nullptr && bcoe->getToNode() == e->getToNode()) {
263             // if so, simply prohibit the connections
264             NBNode* node = e->getToNode();
265             const EdgeVector& connected = e->getConnectedEdges();
266             for (EdgeVector::const_iterator i = connected.begin(); i != connected.end(); i++) {
267                 node->addSortedLinkFoes(
268                     NBConnection(bcoe, bcie),
269                     NBConnection(e, *i));
270             }
271         } else {
272             WRITE_WARNING("Would have to split edge '" + e->getID() + "' to build a prohibition");
273             refusedProhibits++;
274             return false;
275             /*
276             // quite ugly - why was it not build?
277             if(ec.splitAt(e, node)) {
278                 node->addSortedLinkFoes(
279                         getConnection(node, myDisturbance.getEdgeID()),
280                         NBConnection(
281                             ec.retrieve(nid1),
282                             ec.retrieve(nid2)
283                         )
284                     );
285             }
286             */
287         }
288     } else {
289         // both the prohibiting and the prohibited abstract edges
290         //  are connections
291         // We can retrieve the conected edges and add the desription
292         NBConnection conn1 = getConnection(node, myDisturbance.getEdgeID());
293         NBConnection conn2 = getConnection(node, myEdge.getEdgeID());
294         if (!conn1.check(ec) || !conn2.check(ec)) {
295             refusedProhibits++;
296             return false;
297         }
298         node->addSortedLinkFoes(conn1, conn2);
299     }
300     return true;
301 }
302 
303 
304 NBConnection
getConnection(NBNode * node,int aedgeid)305 NIVissimDisturbance::getConnection(NBNode* node, int aedgeid) {
306     if (NIVissimEdge::dictionary(myEdge.getEdgeID()) == nullptr) {
307         NIVissimConnection* c = NIVissimConnection::dictionary(aedgeid);
308         NBEdge* from =
309             node->getPossiblySplittedIncoming(toString<int>(c->getFromEdgeID()));
310         NBEdge* to =
311             node->getPossiblySplittedOutgoing(toString<int>(c->getToEdgeID()));
312 
313         // source is a connection
314         return NBConnection(toString<int>(c->getFromEdgeID()), from,
315                             toString<int>(c->getToEdgeID()), to);
316     } else {
317         WRITE_WARNING("NIVissimDisturbance: no connection");
318         return NBConnection::InvalidConnection;
319 //        throw 1; // !!! what to do?
320     }
321 
322 }
323 
324 void
clearDict()325 NIVissimDisturbance::clearDict() {
326     for (DictType::iterator i = myDict.begin(); i != myDict.end(); i++) {
327         delete (*i).second;
328     }
329     myDict.clear();
330 }
331 
332 
333 void
dict_SetDisturbances()334 NIVissimDisturbance::dict_SetDisturbances() {
335     for (DictType::iterator i = myDict.begin(); i != myDict.end(); i++) {
336         NIVissimDisturbance* d = (*i).second;
337         NIVissimAbstractEdge::dictionary(d->myEdge.getEdgeID())->addDisturbance((*i).first);
338         NIVissimAbstractEdge::dictionary(d->myDisturbance.getEdgeID())->addDisturbance((*i).first);
339     }
340     /*    for(DictType::iterator i=myDict.begin(); i!=myDict.end(); i++) {
341             delete (*i).second;
342         }
343         */
344 }
345 
346 
347 void
reportRefused()348 NIVissimDisturbance::reportRefused() {
349     if (refusedProhibits > 0) {
350         WRITE_WARNING("Could not build " + toString<int>(refusedProhibits) + " of " + toString<int>((int)myDict.size()) + " disturbances.");
351     }
352 }
353 
354 
355 
356 /****************************************************************************/
357 
358