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 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 1391 : 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 1391 : int detectPersons, bool show) :
51 : MSInductLoop(id, lane, position, length, name, vTypes, nextEdges, detectPersons, true),
52 1390 : myWrapper(nullptr),
53 1391 : myShow(show) {
54 1390 : }
55 :
56 :
57 2768 : GUIInductLoop::~GUIInductLoop() {}
58 :
59 :
60 : GUIDetectorWrapper*
61 1381 : GUIInductLoop::buildDetectorGUIRepresentation() {
62 2762 : if (hasParameter("hotkey")) {
63 192 : Command_Hotkey_InductionLoop::registerHotkey(getParameter("hotkey"), this);
64 : }
65 : // caller (GUINet) takes responsibility for pointer
66 1381 : myWrapper = new MyWrapper(*this, myPosition);
67 1381 : return myWrapper;
68 : }
69 :
70 :
71 : void
72 303670 : GUIInductLoop::setSpecialColor(const RGBColor* color) {
73 303670 : if (myWrapper != nullptr) {
74 : myWrapper->setSpecialColor(color);
75 : }
76 303670 : }
77 :
78 :
79 : // -------------------------------------------------------------------------
80 : // GUIInductLoop::MyWrapper-methods
81 : // -------------------------------------------------------------------------
82 :
83 1381 : GUIInductLoop::MyWrapper::MyWrapper(GUIInductLoop& detector, double pos) :
84 : GUIDetectorWrapper(GLO_E1DETECTOR, detector.getID(), GUIIconSubSys::getIcon(GUIIcon::E1)),
85 1381 : myDetector(detector), myPosition(pos),
86 1381 : myHaveLength(myPosition != detector.getEndPosition()),
87 1381 : mySpecialColor(nullptr) {
88 1381 : mySupportsOverride = true;
89 1381 : myFGPosition = detector.getLane()->geometryPositionAtOffset(pos);
90 1381 : myBoundary.add(myFGPosition.x() + (double) 5.5, myFGPosition.y() + (double) 5.5);
91 1381 : myBoundary.add(myFGPosition.x() - (double) 5.5, myFGPosition.y() - (double) 5.5);
92 1381 : myFGRotation = -detector.getLane()->getShape().rotationDegreeAtOffset(pos);
93 :
94 1381 : if (myHaveLength) {
95 : const MSLane& lane = *detector.getLane();
96 : const double endPos = detector.getEndPosition();
97 : myFGShape = lane.getShape();
98 6 : myFGShape = myFGShape.getSubpart(
99 : lane.interpolateLanePosToGeometryPos(pos),
100 : lane.interpolateLanePosToGeometryPos(endPos));
101 3 : myFGShapeRotations.reserve(myFGShape.size() - 1);
102 3 : myFGShapeLengths.reserve(myFGShape.size() - 1);
103 3 : int e = (int) myFGShape.size() - 1;
104 8 : for (int i = 0; i < e; ++i) {
105 5 : const Position& f = myFGShape[i];
106 5 : const Position& s = myFGShape[i + 1];
107 5 : myFGShapeLengths.push_back(f.distanceTo(s));
108 5 : myFGShapeRotations.push_back((double) atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double) PI);
109 : }
110 3 : myOutline.push_back(lane.geometryPositionAtOffset(pos, -1));
111 3 : myOutline.push_back(lane.geometryPositionAtOffset(pos, 1));
112 3 : myOutline.push_back(lane.geometryPositionAtOffset(endPos, 1));
113 3 : myOutline.push_back(lane.geometryPositionAtOffset(endPos, -1));
114 3 : myIndicators.push_back(lane.geometryPositionAtOffset(pos, -1.7));
115 3 : myIndicators.push_back(lane.geometryPositionAtOffset(pos, 1.7));
116 3 : myIndicators.push_back(lane.geometryPositionAtOffset(endPos, 1.7));
117 3 : myIndicators.push_back(lane.geometryPositionAtOffset(endPos, -1.7));
118 : }
119 1381 : }
120 :
121 :
122 2750 : GUIInductLoop::MyWrapper::~MyWrapper() {}
123 :
124 :
125 : Boundary
126 188199 : GUIInductLoop::MyWrapper::getCenteringBoundary() const {
127 : Boundary b(myBoundary);
128 188199 : b.grow(20);
129 188199 : return b;
130 : }
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 377607 : GUIInductLoop::MyWrapper::drawGL(const GUIVisualizationSettings& s) const {
182 377607 : if (!myDetector.isVisible()) {
183 : return;
184 : }
185 186819 : GLHelper::pushName(getGlID());
186 186819 : double width = (double) 2.0 * s.scale;
187 186819 : glLineWidth(1.0);
188 186819 : const double exaggeration = getExaggeration(s);
189 186819 : glColor3d(1, 1, 0);
190 186819 : if (myHaveLength) {
191 63 : GLHelper::pushMatrix();
192 63 : glTranslated(0, 0, GLO_JUNCTION + 0.4); // do not draw on top of linkRules
193 63 : GLHelper::drawBoxLines(myFGShape, myFGShapeRotations, myFGShapeLengths, MIN2(1.0, exaggeration), 0, 0);
194 63 : if (width * exaggeration > 1) {
195 :
196 : // outline
197 63 : setOutlineColor();
198 63 : glTranslated(0, 0, .01);
199 63 : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
200 63 : glBegin(GL_QUADS);
201 315 : for (const Position& p : myOutline) {
202 252 : glVertex2d(p.x(), p.y());
203 : }
204 63 : glEnd();
205 63 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
206 :
207 : // position indicator
208 63 : glBegin(GL_LINES);
209 63 : glVertex2d(myIndicators[0].x(), myIndicators[0].y());
210 63 : glVertex2d(myIndicators[1].x(), myIndicators[1].y());
211 63 : glEnd();
212 63 : glBegin(GL_LINES);
213 63 : glVertex2d(myIndicators[2].x(), myIndicators[2].y());
214 63 : glVertex2d(myIndicators[3].x(), myIndicators[3].y());
215 63 : glEnd();
216 :
217 : // jammed actuated-tls detector, draw crossed-out:
218 63 : 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 63 : GLHelper::popMatrix();
230 : } else {
231 : // classic shape
232 186756 : GLHelper::pushMatrix();
233 186756 : glTranslated(0, 0, GLO_JUNCTION + 0.4); // do not draw on top of linkRules
234 186756 : glTranslated(myFGPosition.x(), myFGPosition.y(), 0);
235 186756 : glRotated(myFGRotation, 0, 0, 1);
236 186756 : glScaled(exaggeration, exaggeration, 1);
237 186756 : glBegin(GL_QUADS);
238 186756 : glVertex2d(0 - 1.0, 2);
239 186756 : glVertex2d(-1.0, -2);
240 186756 : glVertex2d(1.0, -2);
241 186756 : glVertex2d(1.0, 2);
242 186756 : glEnd();
243 186756 : glTranslated(0, 0, .01);
244 186755 : setOutlineColor();
245 :
246 186755 : if (width * exaggeration > 1) {
247 : // outline
248 168956 : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
249 168956 : glBegin(GL_QUADS);
250 168956 : glVertex2d(0 - 1.0, 2);
251 168956 : glVertex2d(-1.0, -2);
252 168956 : glVertex2d(1.0, -2);
253 168956 : glVertex2d(1.0, 2);
254 168956 : glEnd();
255 168956 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
256 :
257 : // position indicator
258 168956 : glRotated(90, 0, 0, -1);
259 168956 : glBegin(GL_LINES);
260 168956 : glVertex2d(0, 1.7);
261 168956 : glVertex2d(0, -1.7);
262 168956 : glEnd();
263 :
264 : // jammed actuated-tls detector, draw crossed-out:
265 168956 : if (mySpecialColor != nullptr && *mySpecialColor == RGBColor::ORANGE) {
266 28 : glBegin(GL_LINES);
267 28 : glVertex2d(-1.0, 2);
268 28 : glVertex2d(1.0, -2);
269 28 : glEnd();
270 28 : glBegin(GL_LINES);
271 28 : glVertex2d(-1.0, -2);
272 28 : glVertex2d(1.0, 2);
273 28 : glEnd();
274 : }
275 : }
276 186755 : GLHelper::popMatrix();
277 : }
278 186818 : drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
279 186818 : GLHelper::popName();
280 : }
281 :
282 :
283 : void
284 186818 : GUIInductLoop::MyWrapper::setOutlineColor() const {
285 186818 : if (haveOverride()) {
286 0 : glColor3d(1, 0, 1);
287 186818 : } else if (mySpecialColor == nullptr) {
288 119127 : glColor3d(1, 1, 1);
289 : } else {
290 67691 : GLHelper::setColor(*mySpecialColor);
291 : }
292 186818 : }
293 :
294 : bool
295 186818 : GUIInductLoop::MyWrapper::haveOverride() const {
296 186818 : 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 : /****************************************************************************/
|