Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 NBPTStop.cpp
15 : /// @author Gregor Laemmel
16 : /// @date Tue, 20 Mar 2017
17 : ///
18 : // The representation of a single pt stop
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <utils/iodevices/OutputDevice.h>
23 : #include <utils/common/StringUtils.h>
24 : #include "NBEdge.h"
25 : #include "NBEdgeCont.h"
26 : #include "NBPTPlatform.h"
27 : #include "NBPTStop.h"
28 :
29 :
30 : // ===========================================================================
31 : // method definitions
32 : // ===========================================================================
33 2252 : NBPTStop::NBPTStop(SumoXMLTag tag, std::string ptStopId, Position position, std::string edgeId, std::string origEdgeId, double length,
34 2252 : std::string name, SVCPermissions svcPermissions, double parkingLength, const RGBColor color, double givenStartPos) :
35 2252 : myTag(tag),
36 2252 : myPTStopId(ptStopId),
37 2252 : myPosition(position),
38 2252 : myEdgeId(edgeId),
39 2252 : myOrigEdgeId(origEdgeId),
40 2252 : myPTStopLength(length),
41 2252 : myName(name),
42 2252 : myParkingLength(parkingLength),
43 2252 : myColor(color),
44 2252 : myPermissions(svcPermissions),
45 2252 : myStartPos(0),
46 2252 : myEndPos(0),
47 : myBidiStop(std::weak_ptr<NBPTStop>()),
48 2252 : myIsLoose(origEdgeId == ""),
49 2252 : myIsPlatform(false),
50 2252 : myIsMultipleStopPositions(false),
51 2252 : myAreaID(-1),
52 2252 : myGivenStartPos(givenStartPos) {
53 2252 : }
54 :
55 :
56 : std::string
57 14449 : NBPTStop::getID() const {
58 14449 : return myPTStopId;
59 : }
60 :
61 :
62 : const std::string
63 39351 : NBPTStop::getOrigEdgeId() const {
64 39351 : return myOrigEdgeId;
65 : }
66 :
67 :
68 : const std::string&
69 31038 : NBPTStop::getEdgeId() const {
70 31038 : return myEdgeId;
71 : }
72 :
73 :
74 : const std::string
75 9664 : NBPTStop::getName() const {
76 9664 : return myName;
77 : }
78 :
79 :
80 : const Position&
81 7718 : NBPTStop::getPosition() const {
82 7718 : return myPosition;
83 : }
84 :
85 :
86 : void
87 59 : NBPTStop::mirrorX() {
88 : myPosition.mul(1, -1);
89 59 : }
90 :
91 :
92 : void
93 2773 : NBPTStop::addLine(const std::string& line) {
94 2773 : const std::string l = StringUtils::escapeXML(line);
95 2773 : if (std::find(myLines.begin(), myLines.end(), l) == myLines.end()) {
96 2352 : myLines.push_back(l);
97 : }
98 2773 : }
99 :
100 :
101 : void
102 805 : NBPTStop::write(OutputDevice& device) {
103 805 : device.openTag(myTag);
104 805 : device.writeAttr(SUMO_ATTR_ID, myPTStopId);
105 805 : if (!myName.empty()) {
106 1558 : device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myName));
107 : }
108 805 : device.writeAttr(SUMO_ATTR_LANE, myLaneId);
109 805 : device.writeAttr(SUMO_ATTR_STARTPOS, myStartPos);
110 805 : device.writeAttr(SUMO_ATTR_ENDPOS, myEndPos);
111 805 : device.writeAttr(SUMO_ATTR_FRIENDLY_POS, "true");
112 805 : if (myLines.size() > 0) {
113 1112 : device.writeAttr(SUMO_ATTR_LINES, toString(myLines));
114 : }
115 805 : if (myParkingLength > 0) {
116 0 : device.writeAttr(SUMO_ATTR_PARKING_LENGTH, myParkingLength);
117 : }
118 805 : if (myColor.isValid()) {
119 0 : device.writeAttr(SUMO_ATTR_COLOR, myColor);
120 : }
121 805 : if (!myAccesses.empty()) {
122 199 : std::sort(myAccesses.begin(), myAccesses.end());
123 1098 : for (auto tuple : myAccesses) {
124 899 : device.openTag(SUMO_TAG_ACCESS);
125 899 : device.writeAttr(SUMO_ATTR_LANE, std::get<0>(tuple));
126 899 : device.writeAttr(SUMO_ATTR_POSITION, std::get<1>(tuple));
127 899 : device.writeAttr(SUMO_ATTR_LENGTH, std::get<2>(tuple));
128 899 : device.writeAttr(SUMO_ATTR_FRIENDLY_POS, true);
129 1798 : device.closeTag();
130 : }
131 : }
132 805 : writeParams(device);
133 805 : device.closeTag();
134 805 : }
135 :
136 :
137 : void
138 1865 : NBPTStop::reshiftPosition(const double offsetX, const double offsetY) {
139 : myPosition.add(offsetX, offsetY, 0);
140 2927 : for (NBPTPlatform& platformCand : myPlatformCands) {
141 1062 : platformCand.reshiftPosition(offsetX, offsetY);
142 : }
143 1865 : }
144 :
145 :
146 : SVCPermissions
147 10840 : NBPTStop::getPermissions() const {
148 10840 : return myPermissions;
149 : }
150 :
151 :
152 : void
153 1062 : NBPTStop::addPlatformCand(NBPTPlatform platform) {
154 1062 : myPlatformCands.push_back(platform);
155 1062 : }
156 :
157 :
158 : const std::vector<NBPTPlatform>&
159 1450 : NBPTStop::getPlatformCands() {
160 1450 : return myPlatformCands;
161 : }
162 :
163 :
164 : bool
165 1164 : NBPTStop::getIsMultipleStopPositions() const {
166 1164 : return myIsMultipleStopPositions;
167 : }
168 :
169 :
170 : void
171 916 : NBPTStop::setIsMultipleStopPositions(bool multipleStopPositions, long long int areaID) {
172 916 : myIsMultipleStopPositions = multipleStopPositions;
173 916 : myAreaID = areaID;
174 916 : }
175 :
176 :
177 : double
178 395 : NBPTStop::getLength() const {
179 395 : return myPTStopLength;
180 : }
181 :
182 :
183 : bool
184 347 : NBPTStop::setEdgeId(std::string edgeId, const NBEdgeCont& ec) {
185 347 : myEdgeId = edgeId;
186 347 : return findLaneAndComputeBusStopExtent(ec);
187 : }
188 :
189 :
190 : void
191 198 : NBPTStop::registerAdditionalEdge(std::string wayId, std::string edgeId) {
192 198 : myAdditionalEdgeCandidates[wayId] = edgeId;
193 198 : }
194 :
195 :
196 : bool
197 4262 : NBPTStop::findLaneAndComputeBusStopExtent(const NBEdgeCont& ec) {
198 4262 : NBEdge* edge = ec.getByID(myEdgeId);
199 4262 : return findLaneAndComputeBusStopExtent(edge);
200 : }
201 :
202 :
203 : bool
204 4740 : NBPTStop::findLaneAndComputeBusStopExtent(const NBEdge* edge) {
205 4740 : if (edge != nullptr) {
206 4483 : myEdgeId = edge->getID();
207 : int laneNr = -1;
208 5733 : for (const auto& it : edge->getLanes()) {
209 5140 : if ((it.permissions & getPermissions()) == getPermissions()) {
210 3890 : ++laneNr;
211 3890 : break;
212 : }
213 1250 : laneNr++;
214 : }
215 4483 : if (laneNr != -1) {
216 4483 : myLaneId = edge->getLaneID(laneNr);
217 4483 : const PositionVector& shape = edge->getLaneShape(laneNr);
218 4483 : double offset = shape.nearest_offset_to_point2D(getPosition(), false);
219 4483 : const double edgeLength = edge->getFinalLength();
220 4483 : offset *= edgeLength / shape.length2D();
221 4483 : if (wasLoaded()) {
222 160 : myStartPos = myGivenStartPos;
223 160 : myEndPos = myStartPos + myPTStopLength;
224 : } else {
225 4323 : myStartPos = MAX2(0.0, offset - myPTStopLength / 2.);
226 4323 : myEndPos = MIN2(myStartPos + myPTStopLength, edgeLength);
227 4323 : double missing = myPTStopLength - (myEndPos - myStartPos);
228 4323 : if (missing > 0) {
229 3034 : myStartPos = MAX2(0.0, myStartPos - missing);
230 : }
231 : }
232 4483 : return true;
233 : }
234 : }
235 257 : return myEdgeId == ""; // loose stop. Try later when processing lines
236 : }
237 :
238 :
239 : void
240 228 : NBPTStop::clearAccess() {
241 : myAccesses.clear();
242 228 : }
243 :
244 :
245 : void
246 2811 : NBPTStop::addAccess(std::string laneID, double offset, double length) {
247 5622 : const std::string newEdgeID = SUMOXMLDefinitions::getEdgeIDFromLane(laneID);
248 : // avoid duplicate access
249 8281 : for (auto it = myAccesses.begin(); it != myAccesses.end();) {
250 10940 : if (SUMOXMLDefinitions::getEdgeIDFromLane(std::get<0>(*it)) == newEdgeID) {
251 5 : it = myAccesses.erase(it);
252 : } else {
253 : it++;
254 : }
255 : }
256 5622 : myAccesses.push_back(std::make_tuple(laneID, offset, length));
257 2811 : }
258 :
259 :
260 : bool
261 478 : NBPTStop::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
262 478 : if (myEdgeId == edgeID) {
263 : // find best edge among replacement edges
264 : double bestDist = std::numeric_limits<double>::max();
265 : NBEdge* bestEdge = nullptr;
266 1109 : for (NBEdge* cand : replacement) {
267 631 : if (myPermissions == 0 || (cand->getPermissions() & myPermissions) != 0) {
268 1262 : const double dist = cand->getGeometry().distance2D(myPosition) + MAX2(0., myPTStopLength - cand->getLoadedLength());
269 631 : if (dist < bestDist) {
270 : bestDist = dist;
271 : bestEdge = cand;
272 : }
273 : }
274 : }
275 478 : if (bestEdge != nullptr) {
276 478 : if ((bestEdge->getPermissions() & SVC_PEDESTRIAN) != 0) {
277 : // no need for access
278 228 : clearAccess();
279 : }
280 478 : return findLaneAndComputeBusStopExtent(bestEdge);
281 : }
282 : return false;
283 : }
284 : return true;
285 : }
286 :
287 :
288 : /****************************************************************************/
|