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