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