Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/guisim/GUIBusStop.cpp
169666 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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 GUIBusStop.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Johannes Rummel
19
/// @date Wed, 07.12.2005
20
///
21
// A lane area vehicles can halt at (gui-version)
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <string>
26
#include <utils/common/MsgHandler.h>
27
#include <utils/common/RGBColor.h>
28
#include <utils/geom/PositionVector.h>
29
#include <utils/geom/Boundary.h>
30
#include <utils/gui/div/GLHelper.h>
31
#include <utils/common/ToString.h>
32
#include <microsim/MSNet.h>
33
#include <microsim/MSLane.h>
34
#include <microsim/MSEdge.h>
35
#include <microsim/transportables/MSTransportable.h>
36
#include <microsim/transportables/MSStageDriving.h>
37
#include "GUINet.h"
38
#include "GUIEdge.h"
39
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
40
#include <utils/gui/windows/GUIAppEnum.h>
41
#include <gui/GUIGlobals.h>
42
#include <utils/gui/div/GUIParameterTableWindow.h>
43
#include <gui/GUIApplicationWindow.h>
44
#include <microsim/logging/FunctionBinding.h>
45
#include <utils/gui/div/GUIGlobalSelection.h>
46
#include <foreign/fontstash/fontstash.h>
47
#include <utils/geom/GeomHelper.h>
48
#include <guisim/GUIBusStop.h>
49
#include <utils/common/MsgHandler.h>
50
#include <utils/gui/globjects/GLIncludes.h>
51
52
53
54
// ===========================================================================
55
// method definitions
56
// ===========================================================================
57
GUIBusStop::GUIBusStop(const std::string& id, SumoXMLTag element, const std::vector<std::string>& lines, MSLane& lane,
58
double frompos, double topos, const std::string name, int personCapacity,
59
double parkingLength, const RGBColor& color, double angle) :
60
MSStoppingPlace(id, element, lines, lane, frompos, topos, name, personCapacity, parkingLength, color, angle),
61
GUIGlObject_AbstractAdd(GLO_BUS_STOP, id, GUIIconSubSys::getIcon(GUIIcon::BUSSTOP)),
62
myEmptyColor(RGBColor::INVISIBLE) {
63
// see MSVehicleControl defContainerType
64
myWidth = MAX2(1.0, ceil((double)myTransportableCapacity / getTransportablesAbreast()) * myTransportableDepth);
65
initShape(myFGShape, myFGShapeRotations, myFGShapeLengths, myFGSignPos, myFGSignRot);
66
if (myLane.getShape(true).size() > 0) {
67
initShape(myFGShape2, myFGShapeRotations2, myFGShapeLengths2, myFGSignPos2, myFGSignRot2, true);
68
}
69
}
70
71
72
GUIBusStop::~GUIBusStop() {}
73
74
75
void
76
GUIBusStop::initShape(PositionVector& fgShape,
77
std::vector<double>& fgShapeRotations, std::vector<double>& fgShapeLengths,
78
Position& fgSignPos, double& fgSignRot,
79
bool secondaryShape) {
80
const double offsetSign = MSGlobals::gLefthand ? -1 : 1;
81
const double lgf = myLane.getLengthGeometryFactor(secondaryShape);
82
fgShape = myLane.getShape(secondaryShape);
83
fgShape = fgShape.getSubpart(lgf * myBegPos, lgf * myEndPos);
84
fgShape.move2side(((myLane.getWidth() + myWidth) * 0.5 - 0.2) * offsetSign);
85
fgShapeRotations.reserve(fgShape.size() - 1);
86
fgShapeLengths.reserve(fgShape.size() - 1);
87
int e = (int) fgShape.size() - 1;
88
for (int i = 0; i < e; ++i) {
89
const Position& f = fgShape[i];
90
const Position& s = fgShape[i + 1];
91
fgShapeLengths.push_back(f.distanceTo(s));
92
fgShapeRotations.push_back((double) atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double) M_PI);
93
}
94
PositionVector tmp = fgShape;
95
tmp.move2side(myWidth / 2 * offsetSign);
96
fgSignPos = tmp.getLineCenter();
97
fgSignRot = 0;
98
if (tmp.length() != 0) {
99
fgSignRot = fgShape.rotationDegreeAtOffset(double((fgShape.length() / 2.)));
100
const double rotSign = MSGlobals::gLefthand ? -1 : 1;
101
fgSignRot -= 90 * rotSign;
102
}
103
}
104
105
106
void
107
GUIBusStop::finishedLoading() {
108
MSStoppingPlace::finishedLoading();
109
if (hasParameter("emptyColor")) {
110
try {
111
myEmptyColor = RGBColor::parseColor(getParameter("emptyColor"));
112
} catch (ProcessError& e) {
113
WRITE_WARNINGF("Could not parse color '%' (%)", getParameter("emptyColor"), e.what());
114
}
115
}
116
}
117
118
119
bool
120
GUIBusStop::addAccess(MSLane* const lane, const double startPos, const double endPos, double length, const MSStoppingPlace::AccessExit exit) {
121
const bool added = MSStoppingPlace::addAccess(lane, startPos, endPos, length, exit);
122
if (added) {
123
myAccessCoords.push_back(lane->geometryPositionAtOffset((startPos + endPos) / 2.));
124
}
125
return added;
126
}
127
128
129
GUIGLObjectPopupMenu*
130
GUIBusStop::getPopUpMenu(GUIMainWindow& app,
131
GUISUMOAbstractView& parent) {
132
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
133
buildPopupHeader(ret, app);
134
buildCenterPopupEntry(ret);
135
buildNameCopyPopupEntry(ret);
136
buildSelectionPopupEntry(ret);
137
buildShowParamsPopupEntry(ret);
138
buildPositionCopyEntry(ret, app);
139
return ret;
140
}
141
142
143
GUIParameterTableWindow*
144
GUIBusStop::getParameterWindow(GUIMainWindow& app,
145
GUISUMOAbstractView&) {
146
GUIParameterTableWindow* ret =
147
new GUIParameterTableWindow(app, *this);
148
// add items
149
ret->mkItem(TL("name"), false, getMyName());
150
ret->mkItem(TL("begin position [m]"), false, myBegPos);
151
ret->mkItem(TL("end position [m]"), false, myEndPos);
152
ret->mkItem(TL("lines"), false, joinToString(myLines, " "));
153
ret->mkItem(TL("parking length [m]"), false, (myEndPos - myBegPos) / myParkingFactor);
154
const std::string transportable = (myElement == SUMO_TAG_CONTAINER_STOP ? "container" : "person");
155
ret->mkItem((transportable + " capacity [#]").c_str(), false, myTransportableCapacity);
156
ret->mkItem((transportable + " number [#]").c_str(), true, new FunctionBinding<GUIBusStop, int>(this, &MSStoppingPlace::getTransportableNumber));
157
ret->mkItem(TL("stopped vehicles [#]"), true, new FunctionBinding<GUIBusStop, int>(this, &MSStoppingPlace::getStoppedVehicleNumber));
158
ret->mkItem(TL("last free pos [m]"), true, new FunctionBinding<GUIBusStop, double>(this, &GUIBusStop::getCroppedLastFreePos));
159
// rides-being-waited-on statistic
160
std::map<std::string, int> stats;
161
for (const MSTransportable* t : getTransportables()) {
162
MSStageDriving* s = dynamic_cast<MSStageDriving*>(t->getCurrentStage());
163
if (s != nullptr) {
164
if (s->getIntendedVehicleID() != "") {
165
stats[s->getIntendedVehicleID()] += 1;
166
} else {
167
stats[joinToString(s->getLines(), " ")] += 1;
168
}
169
}
170
}
171
if (stats.size() > 0) {
172
ret->mkItem(TL("waiting for:"), false, "[#]");
173
for (auto item : stats) {
174
ret->mkItem(item.first.c_str(), false, toString(item.second));
175
}
176
}
177
178
// close building
179
ret->closeBuilding();
180
return ret;
181
}
182
183
184
void
185
GUIBusStop::drawGL(const GUIVisualizationSettings& s) const {
186
// get colors
187
RGBColor color, colorSign;
188
if (myElement == SUMO_TAG_CONTAINER_STOP) {
189
color = s.colorSettings.containerStopColor;
190
colorSign = s.colorSettings.containerStopColorSign;
191
} else if (myElement == SUMO_TAG_TRAIN_STOP) {
192
color = s.colorSettings.trainStopColor;
193
colorSign = s.colorSettings.trainStopColorSign;
194
} else {
195
color = s.colorSettings.busStopColor;
196
colorSign = s.colorSettings.busStopColorSign;
197
}
198
// set color
199
if (getColor() != RGBColor::INVISIBLE) {
200
color = getColor();
201
}
202
if (myEmptyColor != RGBColor::INVISIBLE && myEndPositions.empty() && myWaitingTransportables.empty()) {
203
color = myEmptyColor;
204
}
205
const bool s2 = s.secondaryShape;
206
const Position& signPos = s2 ? myFGSignPos2 : myFGSignPos;
207
// recognize full transparency and simply don't draw
208
if (color.alpha() != 0) {
209
GLHelper::pushName(getGlID());
210
GLHelper::pushMatrix();
211
// draw the area
212
glTranslated(0, 0, getType());
213
GLHelper::setColor(color);
214
const double exaggeration = getExaggeration(s);
215
// only shrink the box but never enlarge it (only enlarge the sign)
216
if (s2) {
217
GLHelper::drawBoxLines(myFGShape2, myFGShapeRotations2, myFGShapeLengths2, myWidth * 0.5 * MIN2(1.0, exaggeration), 0, 0);
218
} else {
219
GLHelper::drawBoxLines(myFGShape, myFGShapeRotations, myFGShapeLengths, myWidth * 0.5 * MIN2(1.0, exaggeration), 0, 0);
220
}
221
const double signRot = s2 ? myFGSignRot2 : myFGSignRot;
222
// draw details unless zoomed out to far
223
if (s.drawDetail(10, exaggeration)) {
224
GLHelper::pushMatrix();
225
// draw the lines
226
const double rotSign = MSGlobals::gLefthand ? 1 : -1;
227
const double lineAngle = s.getTextAngle(signRot);
228
// Iterate over every line
229
RGBColor lineColor = color.changedBrightness(-51);
230
const double textOffset = s.flippedTextAngle(rotSign * signRot) ? -1 : 1;
231
const double textOffset2 = s.flippedTextAngle(rotSign * signRot) ? -1 : 0.3;
232
for (int i = 0; i < (int)myLines.size(); ++i) {
233
// push a new matrix for every line
234
GLHelper::pushMatrix();
235
// traslate and rotate
236
glTranslated(signPos.x(), signPos.y(), 0);
237
glRotated(-lineAngle, 0, 0, 1);
238
// draw line
239
GLHelper::drawText(myLines[i].c_str(), Position(1.2, i * textOffset + textOffset2), .1, 1.f, lineColor, 0, FONS_ALIGN_LEFT);
240
// pop matrix for every line
241
GLHelper::popMatrix();
242
}
243
GLHelper::setColor(color);
244
const Position accessOrigin = getCenterPos();
245
for (std::vector<Position>::const_iterator i = myAccessCoords.begin(); i != myAccessCoords.end(); ++i) {
246
GLHelper::drawBoxLine(*i, RAD2DEG(accessOrigin.angleTo2D(*i)) - 90, accessOrigin.distanceTo2D(*i), .05);
247
}
248
// draw the sign
249
glTranslated(signPos.x(), signPos.y(), 0);
250
int noPoints = 9;
251
if (s.scale * exaggeration > 25) {
252
noPoints = MIN2((int)(9.0 + (s.scale * exaggeration) / 10.0), 36);
253
}
254
glScaled(exaggeration, exaggeration, 1);
255
GLHelper::drawFilledCircle((double) 1.1, noPoints);
256
glTranslated(0, 0, .1);
257
GLHelper::setColor(colorSign);
258
GLHelper::drawFilledCircle((double) 0.9, noPoints);
259
if (myElement == SUMO_TAG_CONTAINER_STOP) {
260
GLHelper::drawText("C", Position(), .1, 1.6, color, signRot);
261
} else if (myElement == SUMO_TAG_TRAIN_STOP) {
262
GLHelper::drawText("T", Position(), .1, 1.6, color, signRot);
263
} else {
264
GLHelper::drawText("H", Position(), .1, 1.6, color, signRot);
265
}
266
GLHelper::popMatrix();
267
}
268
if (s.addFullName.show(this) && getMyName() != "") {
269
GLHelper::drawTextSettings(s.addFullName, getMyName(), signPos, s.scale, s.getTextAngle(signRot), GLO_MAX - getType());
270
}
271
GLHelper::popMatrix();
272
GLHelper::popName();
273
}
274
drawName(signPos, s.scale, s.addName, s.angle);
275
}
276
277
278
double
279
GUIBusStop::getExaggeration(const GUIVisualizationSettings& s) const {
280
return s.addSize.getExaggeration(s, this);
281
}
282
283
284
Boundary
285
GUIBusStop::getCenteringBoundary() const {
286
const PositionVector& shape = GUIGlobals::gSecondaryShape ? myFGShape2 : myFGShape;
287
Boundary b = shape.getBoxBoundary();
288
b.grow(myWidth);
289
for (const Position& p : myAccessCoords) {
290
b.add(p);
291
}
292
return b;
293
}
294
295
const std::string
296
GUIBusStop::getOptionalName() const {
297
return myName;
298
}
299
300
double
301
GUIBusStop::getCroppedLastFreePos() const {
302
return MAX2(0., getLastFreePos());
303
}
304
305
/****************************************************************************/
306
307