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 GUIInductLoop.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Aug 2003
19 : ///
20 : // The gui-version of the MSInductLoop, together with the according
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <utils/common/MsgHandler.h>
25 : #include <utils/gui/globjects/GUIGlObject.h>
26 : #include <utils/geom/PositionVector.h>
27 : #include <utils/gui/div/GLHelper.h>
28 : #include <utils/gui/div/GUIParameterTableWindow.h>
29 : #include <utils/gui/globjects/GLIncludes.h>
30 : #include <microsim/logging/FunctionBinding.h>
31 : #include <microsim/logging/FuncBinding_IntParam.h>
32 : #include <microsim/logging/CastingFunctionBinding_Param.h>
33 : #include <microsim/MSLane.h>
34 : #include <microsim/output/MSInductLoop.h>
35 : #include "GUIEdge.h"
36 : #include "Command_Hotkey_InductionLoop.h"
37 : #include "GUIInductLoop.h"
38 :
39 :
40 : // ===========================================================================
41 : // method definitions
42 : // ===========================================================================
43 : /* -------------------------------------------------------------------------
44 : * GUIInductLoop-methods
45 : * ----------------------------------------------------------------------- */
46 472 : GUIInductLoop::GUIInductLoop(const std::string& id, MSLane* const lane,
47 : double position, double length,
48 : std::string name, const std::string& vTypes,
49 : const std::string& nextEdges,
50 472 : int detectPersons, bool show) :
51 : MSInductLoop(id, lane, position, length, name, vTypes, nextEdges, detectPersons, true),
52 471 : myWrapper(nullptr),
53 472 : myShow(show) {
54 471 : }
55 :
56 :
57 938 : GUIInductLoop::~GUIInductLoop() {}
58 :
59 :
60 : GUIDetectorWrapper*
61 470 : GUIInductLoop::buildDetectorGUIRepresentation() {
62 940 : if (hasParameter("hotkey")) {
63 0 : Command_Hotkey_InductionLoop::registerHotkey(getParameter("hotkey"), this);
64 : }
65 : // caller (GUINet) takes responsibility for pointer
66 470 : myWrapper = new MyWrapper(*this, myPosition);
67 470 : return myWrapper;
68 : }
69 :
70 :
71 : void
72 26975 : GUIInductLoop::setSpecialColor(const RGBColor* color) {
73 26975 : if (myWrapper != nullptr) {
74 : myWrapper->setSpecialColor(color);
75 : }
76 26975 : }
77 :
78 :
79 : // -------------------------------------------------------------------------
80 : // GUIInductLoop::MyWrapper-methods
81 : // -------------------------------------------------------------------------
82 :
83 470 : GUIInductLoop::MyWrapper::MyWrapper(GUIInductLoop& detector, double pos) :
84 : GUIDetectorWrapper(GLO_E1DETECTOR, detector.getID(), GUIIconSubSys::getIcon(GUIIcon::E1)),
85 470 : myDetector(detector), myPosition(pos),
86 470 : myHaveLength(myPosition != detector.getEndPosition()),
87 470 : mySpecialColor(nullptr) {
88 470 : mySupportsOverride = true;
89 470 : myFGPosition = detector.getLane()->geometryPositionAtOffset(pos);
90 470 : myBoundary.add(myFGPosition.x() + (double) 5.5, myFGPosition.y() + (double) 5.5);
91 470 : myBoundary.add(myFGPosition.x() - (double) 5.5, myFGPosition.y() - (double) 5.5);
92 470 : myFGRotation = -detector.getLane()->getShape().rotationDegreeAtOffset(pos);
93 :
94 470 : if (myHaveLength) {
95 : const MSLane& lane = *detector.getLane();
96 : const double endPos = detector.getEndPosition();
97 : myFGShape = lane.getShape();
98 4 : myFGShape = myFGShape.getSubpart(
99 : lane.interpolateLanePosToGeometryPos(pos),
100 : lane.interpolateLanePosToGeometryPos(endPos));
101 2 : myFGShapeRotations.reserve(myFGShape.size() - 1);
102 2 : myFGShapeLengths.reserve(myFGShape.size() - 1);
103 2 : int e = (int) myFGShape.size() - 1;
104 6 : for (int i = 0; i < e; ++i) {
105 4 : const Position& f = myFGShape[i];
106 4 : const Position& s = myFGShape[i + 1];
107 4 : myFGShapeLengths.push_back(f.distanceTo(s));
108 4 : myFGShapeRotations.push_back((double) atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double) PI);
109 : }
110 2 : myOutline.push_back(lane.geometryPositionAtOffset(pos, -1));
111 2 : myOutline.push_back(lane.geometryPositionAtOffset(pos, 1));
112 2 : myOutline.push_back(lane.geometryPositionAtOffset(endPos, 1));
113 2 : myOutline.push_back(lane.geometryPositionAtOffset(endPos, -1));
114 2 : myIndicators.push_back(lane.geometryPositionAtOffset(pos, -1.7));
115 2 : myIndicators.push_back(lane.geometryPositionAtOffset(pos, 1.7));
116 2 : myIndicators.push_back(lane.geometryPositionAtOffset(endPos, 1.7));
117 2 : myIndicators.push_back(lane.geometryPositionAtOffset(endPos, -1.7));
118 : }
119 470 : }
120 :
121 :
122 936 : GUIInductLoop::MyWrapper::~MyWrapper() {}
123 :
124 :
125 : Boundary
126 33677 : GUIInductLoop::MyWrapper::getCenteringBoundary() const {
127 : Boundary b(myBoundary);
128 33677 : b.grow(20);
129 33677 : return b;
130 0 : }
131 :
132 :
133 :
134 : GUIParameterTableWindow*
135 0 : GUIInductLoop::MyWrapper::getParameterWindow(GUIMainWindow& app,
136 : GUISUMOAbstractView& /*parent !!! recheck this - never needed?*/) {
137 0 : GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
138 : // add items
139 : // parameter
140 0 : ret->mkItem(TL("name"), false, myDetector.getName());
141 0 : ret->mkItem(TL("position [m]"), false, myPosition);
142 0 : if (myDetector.getEndPosition() != myPosition) {
143 0 : ret->mkItem(TL("end position [m]"), false, myDetector.getEndPosition());
144 : }
145 0 : ret->mkItem(TL("lane"), false, myDetector.getLane()->getID());
146 0 : if (myDetector.isTyped()) {
147 0 : ret->mkItem(TL("vTypes"), false, toString(myDetector.getVehicleTypes()));
148 : }
149 : // values
150 0 : ret->mkItem(TL("entered vehicles [-]"), true,
151 0 : new FuncBinding_IntParam<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getEnteredNumber, 0));
152 0 : ret->mkItem(TL("speed [m/s]"), true,
153 0 : new FuncBinding_IntParam<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getSpeed, 0));
154 0 : ret->mkItem(TL("occupancy [%]"), true,
155 0 : new FunctionBinding<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getOccupancy));
156 0 : ret->mkItem(TL("vehicle length [m]"), true,
157 0 : new FuncBinding_IntParam<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getVehicleLength, 0));
158 0 : ret->mkItem(TL("empty time [s]"), true,
159 0 : new FunctionBinding<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getTimeSinceLastDetection));
160 0 : ret->mkItem(TL("occupied time [s]"), true,
161 0 : new FunctionBinding<GUIInductLoop, double>(&myDetector, &GUIInductLoop::getOccupancyTime));
162 0 : ret->mkItem(TL("interval entered vehicles [#]"), true,
163 0 : new CastingFunctionBinding_Param<GUIInductLoop, double, int, bool>(&myDetector, &GUIInductLoop::getIntervalVehicleNumber, false));
164 0 : ret->mkItem(TL("interval speed [m/s]"), true,
165 0 : new CastingFunctionBinding_Param<GUIInductLoop, double, double, bool>(&myDetector, &GUIInductLoop::getIntervalMeanSpeed, false));
166 0 : ret->mkItem(TL("interval occupancy [%]"), true,
167 0 : new CastingFunctionBinding_Param<GUIInductLoop, double, double, bool>(&myDetector, &GUIInductLoop::getIntervalOccupancy, false));
168 0 : ret->mkItem(TL("last interval entered vehicles [#]"), true,
169 0 : new CastingFunctionBinding_Param<GUIInductLoop, double, int, bool>(&myDetector, &GUIInductLoop::getIntervalVehicleNumber, true));
170 0 : ret->mkItem(TL("last interval speed [m/s]"), true,
171 0 : new CastingFunctionBinding_Param<GUIInductLoop, double, double, bool>(&myDetector, &GUIInductLoop::getIntervalMeanSpeed, true));
172 0 : ret->mkItem(TL("last interval occupancy [%]"), true,
173 0 : new CastingFunctionBinding_Param<GUIInductLoop, double, double, bool>(&myDetector, &GUIInductLoop::getIntervalOccupancy, true));
174 : // close building
175 0 : ret->closeBuilding(&myDetector);
176 0 : return ret;
177 : }
178 :
179 :
180 : void
181 63578 : GUIInductLoop::MyWrapper::drawGL(const GUIVisualizationSettings& s) const {
182 63578 : if (!myDetector.isVisible()) {
183 : return;
184 : }
185 33207 : GLHelper::pushName(getGlID());
186 33207 : double width = (double) 2.0 * s.scale;
187 33207 : glLineWidth(1.0);
188 33207 : const double exaggeration = getExaggeration(s);
189 33207 : glColor3d(1, 1, 0);
190 33207 : if (myHaveLength) {
191 14 : GLHelper::pushMatrix();
192 14 : glTranslated(0, 0, GLO_JUNCTION + 0.4); // do not draw on top of linkRules
193 14 : GLHelper::drawBoxLines(myFGShape, myFGShapeRotations, myFGShapeLengths, MIN2(1.0, exaggeration), 0, 0);
194 14 : if (width * exaggeration > 1) {
195 :
196 : // outline
197 14 : setOutlineColor();
198 14 : glTranslated(0, 0, .01);
199 14 : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
200 14 : glBegin(GL_QUADS);
201 70 : for (const Position& p : myOutline) {
202 56 : glVertex2d(p.x(), p.y());
203 : }
204 14 : glEnd();
205 14 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
206 :
207 : // position indicator
208 14 : glBegin(GL_LINES);
209 14 : glVertex2d(myIndicators[0].x(), myIndicators[0].y());
210 14 : glVertex2d(myIndicators[1].x(), myIndicators[1].y());
211 14 : glEnd();
212 14 : glBegin(GL_LINES);
213 14 : glVertex2d(myIndicators[2].x(), myIndicators[2].y());
214 14 : glVertex2d(myIndicators[3].x(), myIndicators[3].y());
215 14 : glEnd();
216 :
217 : // jammed actuated-tls detector, draw crossed-out:
218 14 : if (mySpecialColor != nullptr && *mySpecialColor == RGBColor::ORANGE) {
219 0 : glBegin(GL_LINES);
220 0 : glVertex2d(myOutline[0].x(), myOutline[0].y());
221 0 : glVertex2d(myOutline[2].x(), myOutline[2].y());
222 0 : glEnd();
223 0 : glBegin(GL_LINES);
224 0 : glVertex2d(myOutline[1].x(), myOutline[1].y());
225 0 : glVertex2d(myOutline[3].x(), myOutline[3].y());
226 0 : glEnd();
227 : }
228 : }
229 14 : GLHelper::popMatrix();
230 : } else {
231 : // classic shape
232 33193 : GLHelper::pushMatrix();
233 33193 : glTranslated(0, 0, GLO_JUNCTION + 0.4); // do not draw on top of linkRules
234 33193 : glTranslated(myFGPosition.x(), myFGPosition.y(), 0);
235 33193 : glRotated(myFGRotation, 0, 0, 1);
236 33193 : glScaled(exaggeration, exaggeration, 1);
237 33193 : glBegin(GL_QUADS);
238 33193 : glVertex2d(0 - 1.0, 2);
239 33193 : glVertex2d(-1.0, -2);
240 33193 : glVertex2d(1.0, -2);
241 33193 : glVertex2d(1.0, 2);
242 33193 : glEnd();
243 33193 : glTranslated(0, 0, .01);
244 33193 : setOutlineColor();
245 :
246 33193 : if (width * exaggeration > 1) {
247 : // outline
248 18714 : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
249 18714 : glBegin(GL_QUADS);
250 18714 : glVertex2d(0 - 1.0, 2);
251 18714 : glVertex2d(-1.0, -2);
252 18714 : glVertex2d(1.0, -2);
253 18714 : glVertex2d(1.0, 2);
254 18714 : glEnd();
255 18714 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
256 :
257 : // position indicator
258 18714 : glRotated(90, 0, 0, -1);
259 18714 : glBegin(GL_LINES);
260 18714 : glVertex2d(0, 1.7);
261 18714 : glVertex2d(0, -1.7);
262 18714 : glEnd();
263 :
264 : // jammed actuated-tls detector, draw crossed-out:
265 18714 : if (mySpecialColor != nullptr && *mySpecialColor == RGBColor::ORANGE) {
266 0 : glBegin(GL_LINES);
267 0 : glVertex2d(-1.0, 2);
268 0 : glVertex2d(1.0, -2);
269 0 : glEnd();
270 0 : glBegin(GL_LINES);
271 0 : glVertex2d(-1.0, -2);
272 0 : glVertex2d(1.0, 2);
273 0 : glEnd();
274 : }
275 : }
276 33193 : GLHelper::popMatrix();
277 : }
278 33207 : drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
279 33207 : GLHelper::popName();
280 : }
281 :
282 :
283 : void
284 33207 : GUIInductLoop::MyWrapper::setOutlineColor() const {
285 33207 : if (haveOverride()) {
286 0 : glColor3d(1, 0, 1);
287 33207 : } else if (mySpecialColor == nullptr) {
288 33207 : glColor3d(1, 1, 1);
289 : } else {
290 0 : GLHelper::setColor(*mySpecialColor);
291 : }
292 33207 : }
293 :
294 : bool
295 33207 : GUIInductLoop::MyWrapper::haveOverride() const {
296 33207 : return myDetector.getOverrideTime() >= 0;
297 : }
298 :
299 :
300 : void
301 0 : GUIInductLoop::MyWrapper::toggleOverride() const {
302 0 : if (haveOverride()) {
303 0 : myDetector.overrideTimeSinceDetection(-1);
304 : } else {
305 0 : myDetector.overrideTimeSinceDetection(0);
306 : }
307 0 : }
308 :
309 : /****************************************************************************/
|