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