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 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 1694 : 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 1694 : double parkingLength, const RGBColor& color) :
60 : MSStoppingPlace(id, element, lines, lane, frompos, topos, name, personCapacity, parkingLength, color),
61 3388 : GUIGlObject_AbstractAdd(GLO_BUS_STOP, id, GUIIconSubSys::getIcon(GUIIcon::BUSSTOP)) {
62 : // see MSVehicleControl defContainerType
63 1694 : myWidth = MAX2(1.0, ceil((double)personCapacity / getTransportablesAbreast()) * myTransportableDepth);
64 1694 : initShape(myFGShape, myFGShapeRotations, myFGShapeLengths, myFGSignPos, myFGSignRot);
65 1694 : if (lane.getShape(true).size() > 0) {
66 1694 : initShape(myFGShape2, myFGShapeRotations2, myFGShapeLengths2, myFGSignPos2, myFGSignRot2, true);
67 : }
68 1694 : }
69 :
70 :
71 3384 : GUIBusStop::~GUIBusStop() {}
72 :
73 :
74 : void
75 3388 : GUIBusStop::initShape(PositionVector& fgShape,
76 : std::vector<double>& fgShapeRotations, std::vector<double>& fgShapeLengths,
77 : Position& fgSignPos, double& fgSignRot,
78 : bool secondaryShape) {
79 3388 : const double offsetSign = MSGlobals::gLefthand ? -1 : 1;
80 3388 : const double lgf = myLane.getLengthGeometryFactor(secondaryShape);
81 3388 : fgShape = myLane.getShape(secondaryShape);
82 6776 : fgShape = fgShape.getSubpart(lgf * myBegPos, lgf * myEndPos);
83 3388 : fgShape.move2side(((myLane.getWidth() + myWidth) * 0.5 - 0.2) * offsetSign);
84 3388 : fgShapeRotations.reserve(fgShape.size() - 1);
85 3388 : fgShapeLengths.reserve(fgShape.size() - 1);
86 3388 : int e = (int) fgShape.size() - 1;
87 8178 : for (int i = 0; i < e; ++i) {
88 4790 : const Position& f = fgShape[i];
89 4790 : const Position& s = fgShape[i + 1];
90 4790 : fgShapeLengths.push_back(f.distanceTo(s));
91 4790 : fgShapeRotations.push_back((double) atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double) M_PI);
92 : }
93 : PositionVector tmp = fgShape;
94 3388 : tmp.move2side(myWidth / 2 * offsetSign);
95 3388 : fgSignPos = tmp.getLineCenter();
96 3388 : fgSignRot = 0;
97 3388 : if (tmp.length() != 0) {
98 3388 : fgSignRot = fgShape.rotationDegreeAtOffset(double((fgShape.length() / 2.)));
99 3388 : const double rotSign = MSGlobals::gLefthand ? -1 : 1;
100 3388 : fgSignRot -= 90 * rotSign;
101 : }
102 3388 : }
103 :
104 :
105 : bool
106 229 : GUIBusStop::addAccess(MSLane* const lane, const double startPos, const double endPos, double length, const MSStoppingPlace::AccessExit exit) {
107 229 : const bool added = MSStoppingPlace::addAccess(lane, startPos, endPos, length, exit);
108 229 : if (added) {
109 227 : myAccessCoords.push_back(lane->geometryPositionAtOffset((startPos + endPos) / 2.));
110 : }
111 229 : return added;
112 : }
113 :
114 :
115 : GUIGLObjectPopupMenu*
116 0 : GUIBusStop::getPopUpMenu(GUIMainWindow& app,
117 : GUISUMOAbstractView& parent) {
118 0 : GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, *this);
119 0 : buildPopupHeader(ret, app);
120 0 : buildCenterPopupEntry(ret);
121 0 : buildNameCopyPopupEntry(ret);
122 0 : buildSelectionPopupEntry(ret);
123 0 : buildShowParamsPopupEntry(ret);
124 0 : buildPositionCopyEntry(ret, app);
125 0 : return ret;
126 : }
127 :
128 :
129 : GUIParameterTableWindow*
130 0 : GUIBusStop::getParameterWindow(GUIMainWindow& app,
131 : GUISUMOAbstractView&) {
132 : GUIParameterTableWindow* ret =
133 0 : new GUIParameterTableWindow(app, *this);
134 : // add items
135 0 : ret->mkItem(TL("name"), false, getMyName());
136 0 : ret->mkItem(TL("begin position [m]"), false, myBegPos);
137 0 : ret->mkItem(TL("end position [m]"), false, myEndPos);
138 0 : ret->mkItem(TL("lines"), false, joinToString(myLines, " "));
139 0 : ret->mkItem(TL("parking length [m]"), false, (myEndPos - myBegPos) / myParkingFactor);
140 0 : const std::string transportable = (myElement == SUMO_TAG_CONTAINER_STOP ? "container" : "person");
141 0 : ret->mkItem((transportable + " capacity [#]").c_str(), false, myTransportableCapacity);
142 0 : ret->mkItem((transportable + " number [#]").c_str(), true, new FunctionBinding<GUIBusStop, int>(this, &MSStoppingPlace::getTransportableNumber));
143 0 : ret->mkItem(TL("stopped vehicles [#]"), true, new FunctionBinding<GUIBusStop, int>(this, &MSStoppingPlace::getStoppedVehicleNumber));
144 0 : ret->mkItem(TL("last free pos [m]"), true, new FunctionBinding<GUIBusStop, double>(this, &GUIBusStop::getCroppedLastFreePos));
145 : // rides-being-waited-on statistic
146 : std::map<std::string, int> stats;
147 0 : for (const MSTransportable* t : getTransportables()) {
148 0 : MSStageDriving* s = dynamic_cast<MSStageDriving*>(t->getCurrentStage());
149 0 : if (s != nullptr) {
150 0 : if (s->getIntendedVehicleID() != "") {
151 0 : stats[s->getIntendedVehicleID()] += 1;
152 : } else {
153 0 : stats[joinToString(s->getLines(), " ")] += 1;
154 : }
155 : }
156 0 : }
157 0 : if (stats.size() > 0) {
158 0 : ret->mkItem(TL("waiting for:"), false, "[#]");
159 0 : for (auto item : stats) {
160 0 : ret->mkItem(item.first.c_str(), false, toString(item.second));
161 : }
162 : }
163 :
164 : // close building
165 0 : ret->closeBuilding();
166 0 : return ret;
167 : }
168 :
169 :
170 : void
171 52504 : GUIBusStop::drawGL(const GUIVisualizationSettings& s) const {
172 : // get colors
173 52504 : RGBColor color, colorSign;
174 52504 : if (myElement == SUMO_TAG_CONTAINER_STOP) {
175 8469 : color = s.colorSettings.containerStopColor;
176 8469 : colorSign = s.colorSettings.containerStopColorSign;
177 44035 : } else if (myElement == SUMO_TAG_TRAIN_STOP) {
178 8392 : color = s.colorSettings.trainStopColor;
179 8392 : colorSign = s.colorSettings.trainStopColorSign;
180 : } else {
181 35643 : color = s.colorSettings.busStopColor;
182 35643 : colorSign = s.colorSettings.busStopColorSign;
183 : }
184 : // set color
185 52504 : if (getColor() != RGBColor::INVISIBLE) {
186 14 : color = getColor();
187 : }
188 52504 : GLHelper::pushName(getGlID());
189 52504 : GLHelper::pushMatrix();
190 : // draw the area
191 52504 : glTranslated(0, 0, getType());
192 52504 : GLHelper::setColor(color);
193 52504 : const double exaggeration = getExaggeration(s);
194 : // only shrink the box but never enlarge it (only enlarge the sign)
195 52504 : const bool s2 = s.secondaryShape;
196 52504 : if (s2) {
197 0 : GLHelper::drawBoxLines(myFGShape2, myFGShapeRotations2, myFGShapeLengths2, myWidth * 0.5 * MIN2(1.0, exaggeration), 0, 0);
198 : } else {
199 105008 : GLHelper::drawBoxLines(myFGShape, myFGShapeRotations, myFGShapeLengths, myWidth * 0.5 * MIN2(1.0, exaggeration), 0, 0);
200 : }
201 52504 : const double signRot = s2 ? myFGSignRot2 : myFGSignRot;
202 52504 : const Position& signPos = s2 ? myFGSignPos2 : myFGSignPos;
203 : // draw details unless zoomed out to far
204 52504 : if (s.drawDetail(10, exaggeration)) {
205 4 : GLHelper::pushMatrix();
206 : // draw the lines
207 4 : const double rotSign = MSGlobals::gLefthand ? 1 : -1;
208 4 : const double lineAngle = s.getTextAngle(signRot);
209 : // Iterate over every line
210 4 : RGBColor lineColor = color.changedBrightness(-51);
211 4 : const double textOffset = s.flippedTextAngle(rotSign * signRot) ? -1 : 1;
212 4 : const double textOffset2 = s.flippedTextAngle(rotSign * signRot) ? -1 : 0.3;
213 4 : for (int i = 0; i < (int)myLines.size(); ++i) {
214 : // push a new matrix for every line
215 0 : GLHelper::pushMatrix();
216 : // traslate and rotate
217 0 : glTranslated(signPos.x(), signPos.y(), 0);
218 0 : glRotated(-lineAngle, 0, 0, 1);
219 : // draw line
220 0 : GLHelper::drawText(myLines[i].c_str(), Position(1.2, i * textOffset + textOffset2), .1, 1.f, lineColor, 0, FONS_ALIGN_LEFT);
221 : // pop matrix for every line
222 0 : GLHelper::popMatrix();
223 : }
224 4 : GLHelper::setColor(color);
225 4 : const Position accessOrigin = getCenterPos();
226 4 : for (std::vector<Position>::const_iterator i = myAccessCoords.begin(); i != myAccessCoords.end(); ++i) {
227 0 : GLHelper::drawBoxLine(*i, RAD2DEG(accessOrigin.angleTo2D(*i)) - 90, accessOrigin.distanceTo2D(*i), .05);
228 : }
229 : // draw the sign
230 4 : glTranslated(signPos.x(), signPos.y(), 0);
231 : int noPoints = 9;
232 4 : if (s.scale * exaggeration > 25) {
233 4 : noPoints = MIN2((int)(9.0 + (s.scale * exaggeration) / 10.0), 36);
234 : }
235 4 : glScaled(exaggeration, exaggeration, 1);
236 4 : GLHelper::drawFilledCircle((double) 1.1, noPoints);
237 4 : glTranslated(0, 0, .1);
238 4 : GLHelper::setColor(colorSign);
239 4 : GLHelper::drawFilledCircle((double) 0.9, noPoints);
240 4 : if (myElement == SUMO_TAG_CONTAINER_STOP) {
241 0 : GLHelper::drawText("C", Position(), .1, 1.6, color, signRot);
242 4 : } else if (myElement == SUMO_TAG_TRAIN_STOP) {
243 0 : GLHelper::drawText("T", Position(), .1, 1.6, color, signRot);
244 : } else {
245 8 : GLHelper::drawText("H", Position(), .1, 1.6, color, signRot);
246 : }
247 4 : GLHelper::popMatrix();
248 : }
249 52504 : if (s.addFullName.show(this) && getMyName() != "") {
250 0 : GLHelper::drawTextSettings(s.addFullName, getMyName(), signPos, s.scale, s.getTextAngle(signRot), GLO_MAX - getType());
251 : }
252 52504 : GLHelper::popMatrix();
253 52504 : GLHelper::popName();
254 52504 : drawName(signPos, s.scale, s.addName, s.angle);
255 52504 : }
256 :
257 :
258 : double
259 52504 : GUIBusStop::getExaggeration(const GUIVisualizationSettings& s) const {
260 52504 : return s.addSize.getExaggeration(s, this);
261 : }
262 :
263 :
264 : Boundary
265 1691 : GUIBusStop::getCenteringBoundary() const {
266 1691 : const PositionVector& shape = GUIGlobals::gSecondaryShape ? myFGShape2 : myFGShape;
267 1691 : Boundary b = shape.getBoxBoundary();
268 1691 : b.grow(myWidth);
269 1918 : for (const Position& p : myAccessCoords) {
270 227 : b.add(p);
271 : }
272 1691 : return b;
273 0 : }
274 :
275 : const std::string
276 0 : GUIBusStop::getOptionalName() const {
277 0 : return myName;
278 : }
279 :
280 : double
281 0 : GUIBusStop::getCroppedLastFreePos() const {
282 0 : return MAX2(0., getLastFreePos());
283 : }
284 :
285 : /****************************************************************************/
|