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 NIVissimConnectionCluster.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sept 2002
19 : ///
20 : // -------------------
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <algorithm>
25 : #include <iostream>
26 : #include <cassert>
27 : #include <iterator>
28 : #include <utils/geom/Boundary.h>
29 : #include <utils/geom/GeomHelper.h>
30 : #include <utils/common/VectorHelper.h>
31 : #include <utils/common/MsgHandler.h>
32 : #include <utils/common/ToString.h>
33 : #include "NIVissimConnection.h"
34 : #include "NIVissimDisturbance.h"
35 : #include "NIVissimNodeCluster.h"
36 : #include "NIVissimNodeDef.h"
37 : #include "NIVissimEdge.h"
38 : #include "NIVissimTL.h"
39 : #include "NIVissimConnectionCluster.h"
40 :
41 :
42 : // ===========================================================================
43 : // static members
44 : // ===========================================================================
45 : NIVissimConnectionCluster::ContType NIVissimConnectionCluster::myClusters;
46 : int NIVissimConnectionCluster::myFirstFreeID = 100000;
47 : int NIVissimConnectionCluster::myStaticBlaID = 0;
48 :
49 :
50 :
51 : // ===========================================================================
52 : // method definitions
53 : // ===========================================================================
54 : // ---------------------------------------------------------------------------
55 : // NIVissimConnectionCluster::NodeSubCluster - methods
56 : // ---------------------------------------------------------------------------
57 0 : NIVissimConnectionCluster::NodeSubCluster::NodeSubCluster(NIVissimConnection* c) {
58 0 : add(c);
59 0 : }
60 :
61 :
62 0 : NIVissimConnectionCluster::NodeSubCluster::~NodeSubCluster() {}
63 :
64 :
65 : void
66 0 : NIVissimConnectionCluster::NodeSubCluster::add(NIVissimConnection* c) {
67 0 : myBoundary.add(c->getBoundingBox());
68 0 : myConnections.push_back(c);
69 0 : }
70 :
71 :
72 : void
73 0 : NIVissimConnectionCluster::NodeSubCluster::add(const NIVissimConnectionCluster::NodeSubCluster& c) {
74 0 : for (ConnectionCont::const_iterator i = c.myConnections.begin(); i != c.myConnections.end(); i++) {
75 0 : add(*i);
76 : }
77 0 : }
78 :
79 :
80 : int
81 0 : NIVissimConnectionCluster::NodeSubCluster::size() const {
82 0 : return (int)myConnections.size();
83 : }
84 :
85 :
86 : std::vector<int>
87 0 : NIVissimConnectionCluster::NodeSubCluster::getConnectionIDs() const {
88 : std::vector<int> ret;
89 0 : int id = NIVissimConnectionCluster::getNextFreeNodeID();
90 0 : for (ConnectionCont::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
91 0 : ret.push_back((*i)->getID());
92 0 : (*i)->setNodeCluster(id);
93 : }
94 0 : return ret;
95 0 : }
96 :
97 :
98 : bool
99 0 : NIVissimConnectionCluster::NodeSubCluster::overlapsWith(
100 : const NIVissimConnectionCluster::NodeSubCluster& c,
101 : double offset) {
102 : assert(myBoundary.xmax() >= myBoundary.xmin());
103 : assert(c.myBoundary.xmax() >= c.myBoundary.xmin());
104 0 : return myBoundary.overlapsWith(c.myBoundary, offset);
105 : }
106 :
107 :
108 :
109 : // ---------------------------------------------------------------------------
110 : // NIVissimConnectionCluster - methods
111 : // ---------------------------------------------------------------------------
112 1139 : NIVissimConnectionCluster::NIVissimConnectionCluster(
113 1139 : const std::vector<int>& connections, int nodeCluster, int edgeid)
114 2278 : : myConnections(connections), myNodeCluster(nodeCluster),
115 1139 : myBlaID(myStaticBlaID++) {
116 1139 : recomputeBoundary();
117 1139 : myClusters.push_back(this);
118 : assert(edgeid > 0);
119 1139 : if (edgeid >= 0) {
120 1139 : myEdges.push_back(edgeid);
121 : }
122 : // add information about incoming and outgoing edges
123 2993 : for (std::vector<int>::const_iterator i = connections.begin(); i != connections.end(); i++) {
124 1854 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
125 : assert(c != 0);
126 1854 : myOutgoingEdges.push_back(c->getToEdgeID());
127 1854 : myIncomingEdges.push_back(c->getFromEdgeID());
128 : assert(c->getFromEdgeID() == edgeid || c->getToEdgeID() == edgeid);
129 : }
130 1139 : VectorHelper<int>::removeDouble(myIncomingEdges);
131 1139 : VectorHelper<int>::removeDouble(myOutgoingEdges);
132 1139 : }
133 :
134 :
135 0 : NIVissimConnectionCluster::NIVissimConnectionCluster(
136 : const std::vector<int>& connections, const Boundary& boundary,
137 0 : int nodeCluster, const std::vector<int>& edges)
138 0 : : myConnections(connections), myBoundary(boundary),
139 0 : myNodeCluster(nodeCluster), myEdges(edges) {
140 0 : myClusters.push_back(this);
141 0 : recomputeBoundary();
142 : assert(myBoundary.xmax() >= myBoundary.xmin());
143 : // add information about incoming and outgoing edges
144 0 : for (std::vector<int>::const_iterator i = connections.begin(); i != connections.end(); i++) {
145 0 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
146 : assert(c != 0);
147 0 : myOutgoingEdges.push_back(c->getToEdgeID());
148 0 : myIncomingEdges.push_back(c->getFromEdgeID());
149 : assert(find(edges.begin(), edges.end(), c->getFromEdgeID()) != edges.end()
150 : ||
151 : std::find(edges.begin(), edges.end(), c->getToEdgeID()) != edges.end());
152 : }
153 0 : VectorHelper<int>::removeDouble(myIncomingEdges);
154 0 : VectorHelper<int>::removeDouble(myOutgoingEdges);
155 0 : }
156 :
157 :
158 1139 : NIVissimConnectionCluster::~NIVissimConnectionCluster() {}
159 :
160 :
161 :
162 : int
163 0 : NIVissimConnectionCluster::getNextFreeNodeID() {
164 0 : return myFirstFreeID++;
165 : }
166 :
167 :
168 : bool
169 74033 : NIVissimConnectionCluster::overlapsWith(NIVissimConnectionCluster* c,
170 : double offset) const {
171 : assert(myBoundary.xmax() >= myBoundary.xmin());
172 : assert(c->myBoundary.xmax() >= c->myBoundary.xmin());
173 74033 : return c->myBoundary.overlapsWith(myBoundary, offset);
174 : }
175 :
176 :
177 : void
178 791 : NIVissimConnectionCluster::add(NIVissimConnectionCluster* c) {
179 : assert(myBoundary.xmax() >= myBoundary.xmin());
180 : assert(c->myBoundary.xmax() >= c->myBoundary.xmin());
181 791 : myBoundary.add(c->myBoundary);
182 2127 : for (std::vector<int>::iterator i = c->myConnections.begin(); i != c->myConnections.end(); i++) {
183 1336 : myConnections.push_back(*i);
184 : }
185 791 : VectorHelper<int>::removeDouble(myConnections);
186 : assert(myNodeCluster == -1 || c->myNodeCluster == -1);
187 791 : if (myNodeCluster == -1) {
188 791 : myNodeCluster = c->myNodeCluster;
189 : }
190 : // inform edges about merging
191 : // !!! merge should be done within one method
192 1594 : for (std::vector<int>::iterator j = c->myEdges.begin(); j != c->myEdges.end(); j++) {
193 803 : NIVissimEdge::dictionary(*j)->mergedInto(c, this);
194 : }
195 791 : copy(c->myEdges.begin(), c->myEdges.end(), back_inserter(myEdges));
196 : copy(c->myIncomingEdges.begin(), c->myIncomingEdges.end(),
197 791 : back_inserter(myIncomingEdges));
198 : copy(c->myOutgoingEdges.begin(), c->myOutgoingEdges.end(),
199 791 : back_inserter(myOutgoingEdges));
200 791 : VectorHelper<int>::removeDouble(myEdges);
201 791 : VectorHelper<int>::removeDouble(myIncomingEdges);
202 791 : VectorHelper<int>::removeDouble(myOutgoingEdges);
203 791 : }
204 :
205 :
206 :
207 : void
208 9 : NIVissimConnectionCluster::joinBySameEdges(double offset) {
209 : // !!! ...
210 : // Further, we try to omit joining of overlaping nodes. This is done by holding
211 : // the lists of incoming and outgoing edges and incrementally building the nodes
212 : // regarding this information
213 : std::vector<NIVissimConnectionCluster*> joinAble;
214 : int pos = 0;
215 : ContType::iterator i = myClusters.begin();
216 : // step1 - faster but no complete
217 737 : while (i != myClusters.end()) {
218 : joinAble.clear();
219 : ContType::iterator j = i + 1;
220 :
221 : // check whether every combination has been processed
222 65070 : while (j != myClusters.end()) {
223 : // check whether the current clusters overlap
224 64342 : if ((*i)->joinable(*j, offset)) {
225 785 : joinAble.push_back(*j);
226 : }
227 : j++;
228 : }
229 728 : for (std::vector<NIVissimConnectionCluster*>::iterator k = joinAble.begin();
230 1513 : k != joinAble.end(); k++) {
231 : // add the overlaping cluster
232 785 : (*i)->add(*k);
233 : // erase the overlaping cluster
234 785 : delete *k;
235 785 : myClusters.erase(find(myClusters.begin(), myClusters.end(), *k));
236 : }
237 : //
238 728 : if (joinAble.size() > 0) {
239 : i = myClusters.begin() + pos;
240 : // clear temporary storages
241 : joinAble.clear();
242 : } else {
243 : i++;
244 354 : pos++;
245 : }
246 : }
247 : //
248 : pos = 0;
249 : i = myClusters.begin();
250 363 : while (i != myClusters.end()) {
251 : ContType::iterator j = i + 1;
252 : // check whether every combination has been processed
253 10581 : while (j != myClusters.end()) {
254 : // check whether the current clusters overlap
255 10227 : if ((*i)->joinable(*j, offset)) {
256 0 : joinAble.push_back(*j);
257 : }
258 : j++;
259 : }
260 354 : for (std::vector<NIVissimConnectionCluster*>::iterator k = joinAble.begin();
261 354 : k != joinAble.end(); k++) {
262 : // add the overlaping cluster
263 0 : (*i)->add(*k);
264 : // erase the overlaping cluster
265 0 : delete *k;
266 0 : myClusters.erase(find(myClusters.begin(), myClusters.end(), *k));
267 : }
268 : //
269 354 : if (joinAble.size() > 0) {
270 : i = myClusters.begin();
271 : // clear temporary storages
272 : joinAble.clear();
273 : pos = 0;
274 : } else {
275 : i++;
276 : pos++;
277 : }
278 : }
279 : // check for weak district connections
280 : // (junctions made up by district connections, where prohibitions are not
281 : // modelled properly)
282 : pos = 0;
283 : i = myClusters.begin();
284 582 : while (i != myClusters.end()) {
285 : ContType::iterator j = i + 1;
286 : // check whether every combination has been processed
287 20817 : while (j != myClusters.end()) {
288 : // check whether the current clusters overlap
289 20244 : if ((*i)->isWeakDistrictConnRealisation(*j)) {
290 6 : joinAble.push_back(*j);
291 : }
292 : j++;
293 : }
294 573 : for (std::vector<NIVissimConnectionCluster*>::iterator k = joinAble.begin();
295 579 : k != joinAble.end(); k++) {
296 : // add the overlaping cluster
297 6 : (*i)->add(*k);
298 : // erase the overlaping cluster
299 6 : delete *k;
300 6 : myClusters.erase(find(myClusters.begin(), myClusters.end(), *k));
301 : }
302 : //
303 573 : if (joinAble.size() > 0) {
304 : i = myClusters.begin();
305 : // clear temporary storages
306 : joinAble.clear();
307 : pos = 0;
308 : } else {
309 : i++;
310 : pos++;
311 : }
312 : }
313 9 : }
314 :
315 :
316 : bool
317 74569 : NIVissimConnectionCluster::joinable(NIVissimConnectionCluster* c2, double offset) {
318 : // join clusters which have at least one connection in common
319 74569 : if (VectorHelper<int>::subSetExists(myConnections, c2->myConnections)) {
320 : return true;
321 : }
322 :
323 : // connections shall overlap otherwise
324 74033 : if (!overlapsWith(c2, offset)) {
325 : return false;
326 : }
327 :
328 : // at least one of the clusters shall not be assigned to a node in previous (!!!??)
329 1113 : if (hasNodeCluster() && c2->hasNodeCluster()) {
330 : return false;
331 : }
332 :
333 : // join clusters which where connections do disturb each other
334 2226 : if (VectorHelper<int>::subSetExists(c2->getDisturbanceParticipators(), myConnections)
335 1113 : ||
336 1113 : VectorHelper<int>::subSetExists(getDisturbanceParticipators(), c2->myConnections)) {
337 :
338 : return true;
339 : }
340 :
341 :
342 : // join clusters which do share the same incoming or outgoing edges (not mutually)
343 : std::vector<int> extendedOutgoing1;
344 : std::vector<int> extendedIncoming1;
345 : std::vector<int> extendedOutgoing2;
346 : std::vector<int> extendedIncoming2;
347 1098 : if (myIncomingEdges.size() > 1 || c2->myIncomingEdges.size() > 1) {
348 : extendedOutgoing1 =
349 542 : extendByToTreatAsSame(myOutgoingEdges, myIncomingEdges);
350 : extendedIncoming1 =
351 542 : extendByToTreatAsSame(myIncomingEdges, myOutgoingEdges);
352 : extendedOutgoing2 =
353 542 : extendByToTreatAsSame(c2->myOutgoingEdges, c2->myIncomingEdges);
354 : extendedIncoming2 =
355 542 : extendByToTreatAsSame(c2->myIncomingEdges, c2->myOutgoingEdges);
356 : } else {
357 556 : extendedOutgoing1 = myIncomingEdges;
358 556 : extendedIncoming1 = myOutgoingEdges;
359 556 : extendedOutgoing2 = c2->myIncomingEdges;
360 556 : extendedIncoming2 = c2->myOutgoingEdges;
361 : }
362 :
363 1098 : if (VectorHelper<int>::subSetExists(extendedOutgoing1, extendedOutgoing2)
364 1098 : ||
365 1032 : VectorHelper<int>::subSetExists(extendedIncoming1, extendedIncoming2)
366 : ) {
367 : return true;
368 : }
369 : return false;
370 1098 : }
371 :
372 :
373 : bool
374 20244 : NIVissimConnectionCluster::isWeakDistrictConnRealisation(NIVissimConnectionCluster* c2) {
375 20740 : if ((myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1)) {
376 : return false;
377 : }
378 7877 : if ((c2->myIncomingEdges.size() == 1 && c2->myOutgoingEdges.size() == 1)) {
379 : return false;
380 : }
381 :
382 : // ok, may be the other way round
383 4253 : if (myIncomingEdges.size() == 1 && c2->myOutgoingEdges.size() == 1) {
384 : return c2->isWeakDistrictConnRealisation(this);
385 : }
386 : // connections must cross
387 : bool crosses = false;
388 21368 : for (std::vector<int>::const_iterator j1 = myConnections.begin(); j1 != myConnections.end() && !crosses; j1++) {
389 17611 : const PositionVector& g1 = NIVissimConnection::dictionary(*j1)->getGeometry();
390 81521 : for (const int j2 : c2->myConnections) {
391 63940 : const PositionVector& g2 = NIVissimConnection::dictionary(j2)->getGeometry();
392 63940 : if (g1.intersects(g2)) {
393 : crosses = true;
394 : break;
395 : }
396 : }
397 : }
398 3757 : if (!crosses) {
399 : return false;
400 : }
401 : // ok, check for connection
402 30 : if (myOutgoingEdges.size() != 1 || c2->myIncomingEdges.size() != 1) {
403 : return false;
404 : }
405 : // check whether the connection is bidirectional
406 15 : NIVissimEdge* oe = NIVissimEdge::dictionary(myOutgoingEdges[0]);
407 15 : NIVissimEdge* ie = NIVissimEdge::dictionary(c2->myIncomingEdges[0]);
408 15 : if (oe == nullptr || ie == nullptr) {
409 : return false;
410 : }
411 15 : return fabs(GeomHelper::angleDiff(oe->getGeometry().beginEndAngle(), ie->getGeometry().beginEndAngle())) < DEG2RAD(5);
412 : }
413 :
414 :
415 : bool
416 0 : NIVissimConnectionCluster::liesOnSameEdgesEnd(NIVissimConnectionCluster* cc2) {
417 : //
418 0 : for (std::vector<int>::iterator i = myConnections.begin(); i != myConnections.end(); i++) {
419 0 : NIVissimConnection* c1 = NIVissimConnection::dictionary(*i);
420 0 : for (std::vector<int>::iterator j = cc2->myConnections.begin(); j != cc2->myConnections.end(); j++) {
421 0 : NIVissimConnection* c2 = NIVissimConnection::dictionary(*j);
422 0 : if (c1->getFromEdgeID() == c2->getFromEdgeID()) {
423 0 : NIVissimEdge* e = NIVissimEdge::dictionary(c1->getFromEdgeID());
424 0 : const PositionVector& g = e->getGeometry();
425 0 : double pos1 = GeomHelper::nearest_offset_on_line_to_point2D(
426 0 : g.front(), g.back(), c1->getBoundary().getCenter());
427 0 : double pos2 = GeomHelper::nearest_offset_on_line_to_point2D(
428 0 : g.front(), g.back(), c2->getBoundary().getCenter());
429 0 : if (pos1 <= 5.0 && pos2 <= 5.0) {
430 : return true;
431 : }
432 : }
433 0 : if (c1->getToEdgeID() == c2->getToEdgeID()) {
434 0 : NIVissimEdge* e = NIVissimEdge::dictionary(c1->getFromEdgeID());
435 0 : const PositionVector& g = e->getGeometry();
436 0 : double pos1 = GeomHelper::nearest_offset_on_line_to_point2D(
437 0 : g.front(), g.back(), c1->getBoundary().getCenter());
438 0 : double pos2 = GeomHelper::nearest_offset_on_line_to_point2D(
439 0 : g.front(), g.back(), c2->getBoundary().getCenter());
440 0 : if (pos1 >= g.length() - 5.0 && pos2 >= g.length() - 5.0) {
441 : return true;
442 : }
443 : }
444 : }
445 : }
446 : return false;
447 : }
448 :
449 :
450 : std::vector<int>
451 2168 : NIVissimConnectionCluster::extendByToTreatAsSame(const std::vector<int>& iv1,
452 : const std::vector<int>& iv2) const {
453 2168 : std::vector<int> ret(iv1);
454 6179 : for (std::vector<int>::const_iterator i = iv1.begin(); i != iv1.end(); i++) {
455 4011 : NIVissimEdge* e = NIVissimEdge::dictionary(*i);
456 4011 : const std::vector<NIVissimEdge*> treatAsSame = e->getToTreatAsSame();
457 4275 : for (std::vector<NIVissimEdge*>::const_iterator j = treatAsSame.begin(); j != treatAsSame.end(); j++) {
458 264 : if (find(iv2.begin(), iv2.end(), (*j)->getID()) == iv2.end()) {
459 264 : ret.push_back((*j)->getID());
460 : }
461 : }
462 4011 : }
463 2168 : return ret;
464 0 : }
465 :
466 : std::vector<int>
467 2211 : NIVissimConnectionCluster::getDisturbanceParticipators() {
468 : std::vector<int> ret;
469 7188 : for (std::vector<int>::iterator i = myConnections.begin(); i != myConnections.end(); i++) {
470 4977 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
471 4977 : const std::vector<int>& disturbances = c->getDisturbances();
472 8995 : for (std::vector<int>::const_iterator j = disturbances.begin(); j != disturbances.end(); j++) {
473 4018 : NIVissimDisturbance* d = NIVissimDisturbance::dictionary(*j);
474 4018 : ret.push_back(d->getEdgeID());
475 4018 : ret.push_back(d->getDisturbanceID());
476 : }
477 : }
478 2211 : return ret;
479 0 : }
480 :
481 :
482 : void
483 9 : NIVissimConnectionCluster::buildNodeClusters() {
484 357 : for (ContType::iterator i = myClusters.begin(); i != myClusters.end(); i++) {
485 : std::vector<int> disturbances;
486 : std::vector<int> tls;
487 : std::vector<int> nodes;
488 : int tlsid = -1;
489 : int nodeid = -1;
490 348 : if ((*i)->myConnections.size() > 0) {
491 348 : (*i)->recomputeBoundary();
492 348 : disturbances = NIVissimDisturbance::getWithin((*i)->myBoundary);
493 : }
494 348 : nodes = (*i)->myNodes;//NIVissimTL::getWithin((*i)->myBoundary, 5.0);
495 348 : if (nodes.size() > 1) {
496 0 : WRITE_WARNING(TL("NIVissimConnectionCluster: More than a single node"));
497 : // throw 1; // !!! eigentlich sollte hier nur eine Ampelanlage sein
498 : }
499 348 : if (nodes.size() > 0) {
500 0 : nodeid = nodes[0];
501 : }
502 : //
503 : //
504 348 : int id = NIVissimNodeCluster::dictionary(
505 348 : nodeid, tlsid, (*i)->myConnections,
506 348 : disturbances, (*i)->myIncomingEdges.size() < 2);
507 : assert((*i)->myNodeCluster == id || (*i)->myNodeCluster < 0);
508 348 : (*i)->myNodeCluster = id;
509 348 : }
510 9 : }
511 :
512 :
513 : void
514 0 : NIVissimConnectionCluster::_debugOut(std::ostream& into) {
515 0 : for (ContType::iterator i = myClusters.begin(); i != myClusters.end(); i++) {
516 0 : std::vector<int> connections = (*i)->myConnections;
517 0 : for (std::vector<int>::iterator j = connections.begin(); j != connections.end(); j++) {
518 0 : if (j != connections.begin()) {
519 0 : into << ", ";
520 : }
521 0 : into << *j;
522 : }
523 0 : into << "(" << (*i)->myBoundary << ")" << std::endl;
524 0 : }
525 : into << "---------------------------" << std::endl;
526 0 : }
527 :
528 :
529 :
530 : bool
531 1113 : NIVissimConnectionCluster::hasNodeCluster() const {
532 1113 : return myNodeCluster != -1;
533 : }
534 :
535 :
536 : void
537 0 : NIVissimConnectionCluster::removeConnections(const NodeSubCluster& c) {
538 0 : for (NodeSubCluster::ConnectionCont::const_iterator i = c.myConnections.begin(); i != c.myConnections.end(); i++) {
539 0 : NIVissimConnection* conn = *i;
540 0 : int connid = conn->getID();
541 0 : std::vector<int>::iterator j = std::find(myConnections.begin(), myConnections.end(), connid);
542 0 : if (j != myConnections.end()) {
543 0 : myConnections.erase(j);
544 : }
545 : }
546 0 : recomputeBoundary();
547 0 : }
548 :
549 :
550 : void
551 1487 : NIVissimConnectionCluster::recomputeBoundary() {
552 1487 : myBoundary = Boundary();
553 4268 : for (std::vector<int>::iterator i = myConnections.begin(); i != myConnections.end(); i++) {
554 2781 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
555 2781 : if (c != nullptr) {
556 2781 : myBoundary.add(c->getFromGeomPosition());
557 2781 : myBoundary.add(c->getToGeomPosition());
558 2781 : if (c->getGeometry().size() != 0) {
559 2148 : myBoundary.add(c->getGeometry().getBoxBoundary());
560 : }
561 : }
562 : }
563 : assert(myBoundary.xmax() >= myBoundary.xmin());
564 1487 : }
565 :
566 :
567 : NBNode*
568 1061 : NIVissimConnectionCluster::getNBNode() const {
569 1061 : return NIVissimNodeCluster::dictionary(myNodeCluster)->getNBNode();
570 : }
571 :
572 :
573 : bool
574 1397 : NIVissimConnectionCluster::around(const Position& p, double offset) const {
575 : assert(myBoundary.xmax() >= myBoundary.xmin());
576 1397 : return myBoundary.around(p, offset);
577 : }
578 :
579 :
580 :
581 : void
582 0 : NIVissimConnectionCluster::recheckEdges() {
583 : assert(myConnections.size() != 0);
584 : // remove the cluster from all edges at first
585 : std::vector<int>::iterator i;
586 0 : for (i = myEdges.begin(); i != myEdges.end(); i++) {
587 0 : NIVissimEdge* edge = NIVissimEdge::dictionary(*i);
588 0 : edge->removeFromConnectionCluster(this);
589 : }
590 : // clear edge information
591 : myEdges.clear();
592 : // recheck which edges do still participate and add edges
593 0 : for (i = myConnections.begin(); i != myConnections.end(); i++) {
594 0 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
595 : assert(myBoundary.xmax() >= myBoundary.xmin());
596 0 : if (myBoundary.around(c->getFromGeomPosition(), 5)) {
597 0 : myEdges.push_back(c->getFromEdgeID());
598 : }
599 : assert(myBoundary.xmax() >= myBoundary.xmin());
600 0 : if (myBoundary.around(c->getToGeomPosition(), 5)) {
601 0 : myEdges.push_back(c->getToEdgeID());
602 : }
603 : }
604 : // connect edges
605 0 : for (i = myEdges.begin(); i != myEdges.end(); i++) {
606 0 : NIVissimEdge* edge = NIVissimEdge::dictionary(*i);
607 0 : edge->addToConnectionCluster(this);
608 : }
609 0 : }
610 :
611 :
612 : double
613 4282 : NIVissimConnectionCluster::getPositionForEdge(int edgeid) const {
614 : // return the middle of the connections when there are any
615 4282 : if (myConnections.size() != 0) {
616 : double sum = 0;
617 : int part = 0;
618 : std::vector<int>::const_iterator i;
619 20384 : for (i = myConnections.begin(); i != myConnections.end(); i++) {
620 16102 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
621 16102 : if (c->getFromEdgeID() == edgeid) {
622 3672 : part++;
623 3672 : sum += c->getFromPosition();
624 : }
625 16102 : if (c->getToEdgeID() == edgeid) {
626 3554 : part++;
627 3554 : sum += c->getToPosition();
628 : }
629 : }
630 4282 : if (part > 0) {
631 4282 : return sum / (double) part;
632 : }
633 : }
634 : // use the position of the node if possible
635 0 : if (myNodeCluster >= 0) {
636 : // try to find the nearest point on the edge
637 : // !!! only the main geometry is regarded
638 : NIVissimNodeDef* node =
639 0 : NIVissimNodeDef::dictionary(myNodeCluster);
640 0 : if (node != nullptr) {
641 0 : double pos = node->getEdgePosition(edgeid);
642 0 : if (pos >= 0) {
643 : return pos;
644 : }
645 : }
646 : /*
647 : double try1 = GeomHelper::nearest_offset_on_line_to_point(
648 : edge->getBegin2D(), edge->getEnd2D(), node->getPos());
649 : if(try1>=0) {
650 : return try1;
651 : }
652 : // try to use simple distance
653 : double dist1 =
654 : GeomHelper::distance(node->getPos(), edge->getBegin2D());
655 : double dist2 =
656 : GeomHelper::distance(node->getPos(), edge->getEnd2D());
657 : return dist1<dist2
658 : ? 0 : edge->getLength();
659 : */
660 : }
661 : // what else?
662 0 : WRITE_WARNING(TL("NIVissimConnectionCluster: how to get an edge's position?"));
663 : // !!!
664 : assert(myBoundary.xmin() <= myBoundary.xmax());
665 0 : NIVissimEdge* edge = NIVissimEdge::dictionary(edgeid);
666 0 : std::vector<int>::const_iterator i = std::find(myEdges.begin(), myEdges.end(), edgeid);
667 0 : if (i == myEdges.end()) {
668 : // edge does not exist!?
669 0 : throw 1;
670 : }
671 0 : const PositionVector& edgeGeom = edge->getGeometry();
672 0 : Position p = GeomHelper::crossPoint(myBoundary, edgeGeom);
673 0 : return GeomHelper::nearest_offset_on_line_to_point2D(
674 : edgeGeom.front(), edgeGeom.back(), p);
675 : }
676 :
677 :
678 :
679 : void
680 9 : NIVissimConnectionCluster::clearDict() {
681 357 : for (ContType::iterator i = myClusters.begin(); i != myClusters.end(); i++) {
682 348 : delete (*i);
683 : }
684 : myClusters.clear();
685 9 : myFirstFreeID = 100000;
686 9 : }
687 :
688 :
689 : PositionVector
690 0 : NIVissimConnectionCluster::getIncomingContinuationGeometry(NIVissimEdge* e) const {
691 : // collect connection where this edge is the incoming one
692 : std::vector<NIVissimConnection*> edgeIsIncoming;
693 0 : for (std::vector<int>::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
694 0 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
695 0 : if (c->getFromEdgeID() == e->getID()) {
696 0 : edgeIsIncoming.push_back(c);
697 : }
698 : }
699 : //
700 0 : if (edgeIsIncoming.size() == 0) {
701 0 : return PositionVector();
702 : }
703 : // sort connected edges in same direction
704 0 : sort(edgeIsIncoming.begin(), edgeIsIncoming.end(),
705 0 : same_direction_sorter(e->getGeometry().beginEndAngle()));
706 0 : NIVissimConnection* c = *(edgeIsIncoming.begin());
707 0 : return c->getGeometry();
708 0 : }
709 :
710 :
711 :
712 : NIVissimConnection*
713 0 : NIVissimConnectionCluster::getIncomingContinuation(NIVissimEdge* e) const {
714 : // collect connection where this edge is the incoming one
715 : std::vector<NIVissimConnection*> edgeIsIncoming;
716 0 : for (std::vector<int>::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
717 0 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
718 0 : if (c->getFromEdgeID() == e->getID()) {
719 0 : edgeIsIncoming.push_back(c);
720 : }
721 : }
722 : //
723 0 : if (edgeIsIncoming.size() == 0) {
724 : return nullptr;
725 : }
726 : // sort connected edges in same direction
727 0 : sort(edgeIsIncoming.begin(), edgeIsIncoming.end(),
728 0 : same_direction_sorter(e->getGeometry().beginEndAngle()));
729 0 : return *(edgeIsIncoming.begin());
730 0 : }
731 :
732 :
733 :
734 : PositionVector
735 0 : NIVissimConnectionCluster::getOutgoingContinuationGeometry(NIVissimEdge* e) const {
736 : // collect connection where this edge is the outgoing one
737 : std::vector<NIVissimConnection*> edgeIsOutgoing;
738 0 : for (std::vector<int>::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
739 0 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
740 0 : if (c->getToEdgeID() == e->getID()) {
741 0 : edgeIsOutgoing.push_back(c);
742 : }
743 : }
744 : //
745 0 : if (edgeIsOutgoing.size() == 0) {
746 0 : return PositionVector();
747 : }
748 : // sort connected edges in same direction
749 0 : sort(edgeIsOutgoing.begin(), edgeIsOutgoing.end(),
750 0 : same_direction_sorter(e->getGeometry().beginEndAngle()));
751 0 : NIVissimConnection* c = *(edgeIsOutgoing.begin());
752 0 : return c->getGeometry();
753 0 : }
754 :
755 :
756 : NIVissimConnection*
757 0 : NIVissimConnectionCluster::getOutgoingContinuation(NIVissimEdge* e) const {
758 : // collect connection where this edge is the outgoing one
759 : std::vector<NIVissimConnection*> edgeIsOutgoing;
760 0 : for (std::vector<int>::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
761 0 : NIVissimConnection* c = NIVissimConnection::dictionary(*i);
762 0 : if (c->getToEdgeID() == e->getID()) {
763 0 : edgeIsOutgoing.push_back(c);
764 : }
765 : }
766 : //
767 0 : if (edgeIsOutgoing.size() == 0) {
768 : return nullptr;
769 : }
770 : // sort connected edges in same direction
771 0 : sort(edgeIsOutgoing.begin(), edgeIsOutgoing.end(),
772 0 : same_direction_sorter(e->getGeometry().beginEndAngle()));
773 0 : return *(edgeIsOutgoing.begin());
774 0 : }
775 :
776 :
777 : /****************************************************************************/
|