Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/demand/GNEDemandElementFlow.cpp
185790 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 GNEDemandElementFlow.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Jul 2023
17
///
18
// An auxiliar, asbtract class for flow elements (vehicles, person and containers)
19
/****************************************************************************/
20
21
#include <netedit/GNETagProperties.h>
22
#include <netedit/GNEUndoList.h>
23
#include <netedit/changes/GNEChange_Attribute.h>
24
#include <netedit/changes/GNEChange_ToggleAttribute.h>
25
#include <utils/gui/div/GLHelper.h>
26
27
#include "GNEDemandElementFlow.h"
28
29
// ===========================================================================
30
// member method definitions
31
// ===========================================================================
32
33
GNEDemandElementFlow::GNEDemandElementFlow(GNEDemandElement* flowElement) {
34
// set default flow attributes
35
setDefaultFlowAttributes(flowElement);
36
}
37
38
39
GNEDemandElementFlow::GNEDemandElementFlow(GNEDemandElement* flowElement, const SUMOVehicleParameter& vehicleParameters) :
40
SUMOVehicleParameter(vehicleParameters) {
41
// set default flow attributes
42
setDefaultFlowAttributes(flowElement);
43
}
44
45
46
GNEDemandElementFlow::~GNEDemandElementFlow() {}
47
48
49
void
50
GNEDemandElementFlow::drawFlowLabel(const Position& position, const double rotation, const double width,
51
const double length, const double exaggeration) const {
52
// declare contour width
53
const double contourWidth = (0.05 * exaggeration);
54
// Push matrix
55
GLHelper::pushMatrix();
56
// Traslate to bot
57
glTranslated(position.x(), position.y(), GLO_VEHICLELABELS);
58
// glTranslated(position.x(), position.y(), GLO_ROUTE + getType() + 0.1 + GLO_PERSONFLOW + 0.1);
59
glRotated(rotation, 0, 0, -1);
60
glTranslated(-1 * ((width * 0.5 * exaggeration) + (0.35 * exaggeration)) - 0.05, 0, 0);
61
// draw external box
62
GLHelper::setColor(RGBColor::GREY);
63
GLHelper::drawBoxLine(Position(), Position(), 0, (length * exaggeration), 0.3 * exaggeration);
64
// draw internal box
65
glTranslated(0, 0, 0.1);
66
GLHelper::setColor(RGBColor::CYAN);
67
GLHelper::drawBoxLine(Position(0, -contourWidth), Position(0, -contourWidth), 0, (length * exaggeration) - (contourWidth * 2), (0.3 * exaggeration) - contourWidth);
68
// draw stack label
69
GLHelper::drawText("Flow", Position(0, length * exaggeration * -0.5), (.1 * exaggeration), (0.6 * exaggeration), RGBColor::BLACK, 90, 0, -1);
70
// pop draw matrix
71
GLHelper::popMatrix();
72
}
73
74
75
std::string
76
GNEDemandElementFlow::getFlowAttribute(const GNEDemandElement* flowElement, SumoXMLAttr key) const {
77
switch (key) {
78
case SUMO_ATTR_DEPART:
79
case SUMO_ATTR_BEGIN:
80
if (departProcedure == DepartDefinition::TRIGGERED) {
81
return "triggered";
82
} else if (departProcedure == DepartDefinition::CONTAINER_TRIGGERED) {
83
return "containerTriggered";
84
} else if (departProcedure == DepartDefinition::NOW) {
85
return "now";
86
} else if (departProcedure == DepartDefinition::SPLIT) {
87
return "split";
88
} else if (departProcedure == DepartDefinition::BEGIN) {
89
return "begin";
90
} else {
91
return time2string(depart);
92
}
93
case SUMO_ATTR_END:
94
return time2string(repetitionEnd);
95
case SUMO_ATTR_VEHSPERHOUR:
96
case SUMO_ATTR_PERSONSPERHOUR:
97
case SUMO_ATTR_CONTAINERSPERHOUR:
98
return StringUtils::adjustDecimalValue(3600 / STEPS2TIME(repetitionOffset), 2);
99
case SUMO_ATTR_PERIOD:
100
return time2string(repetitionOffset);
101
case GNE_ATTR_POISSON:
102
return StringUtils::adjustDecimalValue(poissonRate, 10);
103
case SUMO_ATTR_PROB:
104
return StringUtils::adjustDecimalValue(repetitionProbability, 20);
105
case SUMO_ATTR_NUMBER:
106
return toString(repetitionNumber);
107
case GNE_ATTR_FLOW_TERMINATE:
108
if (isFlowAttributeEnabled(SUMO_ATTR_END)) {
109
if (isFlowAttributeEnabled(SUMO_ATTR_NUMBER)) {
110
return toString(SUMO_ATTR_END) + "-" + toString(SUMO_ATTR_NUMBER);
111
} else {
112
return toString(SUMO_ATTR_END);
113
}
114
} else if (isFlowAttributeEnabled(SUMO_ATTR_NUMBER)) {
115
return toString(SUMO_ATTR_NUMBER);
116
} else {
117
return "invalid terminate";
118
}
119
case GNE_ATTR_FLOW_SPACING:
120
if (flowElement->getTagProperty()->hasAttribute(SUMO_ATTR_VEHSPERHOUR) && isFlowAttributeEnabled(SUMO_ATTR_VEHSPERHOUR)) {
121
return toString(SUMO_ATTR_VEHSPERHOUR);
122
} else if (flowElement->getTagProperty()->hasAttribute(SUMO_ATTR_PERSONSPERHOUR) && isFlowAttributeEnabled(SUMO_ATTR_PERSONSPERHOUR)) {
123
return toString(SUMO_ATTR_PERSONSPERHOUR);
124
} else if (flowElement->getTagProperty()->hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR) && isFlowAttributeEnabled(SUMO_ATTR_CONTAINERSPERHOUR)) {
125
return toString(SUMO_ATTR_CONTAINERSPERHOUR);
126
} else if (isFlowAttributeEnabled(SUMO_ATTR_PERIOD)) {
127
return toString(SUMO_ATTR_PERIOD);
128
} else if (isFlowAttributeEnabled(SUMO_ATTR_PROB)) {
129
return toString(SUMO_ATTR_PROB);
130
} else if (isFlowAttributeEnabled(GNE_ATTR_POISSON)) {
131
return toString(GNE_ATTR_POISSON);
132
} else {
133
return "invalid flow spacing";
134
}
135
default:
136
return flowElement->getCommonAttribute(key);
137
}
138
}
139
140
141
double
142
GNEDemandElementFlow::getFlowAttributeDouble(SumoXMLAttr key) const {
143
switch (key) {
144
case SUMO_ATTR_DEPART:
145
case SUMO_ATTR_BEGIN:
146
return STEPS2TIME(depart);
147
default:
148
throw InvalidArgument("Flow doesn't have a double attribute of type '" + toString(key) + "'");
149
}
150
}
151
152
153
void
154
GNEDemandElementFlow::setFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
155
switch (key) {
156
case SUMO_ATTR_DEPART:
157
case SUMO_ATTR_BEGIN:
158
case SUMO_ATTR_END:
159
case SUMO_ATTR_NUMBER:
160
case SUMO_ATTR_VEHSPERHOUR:
161
case SUMO_ATTR_PERSONSPERHOUR:
162
case SUMO_ATTR_CONTAINERSPERHOUR:
163
case SUMO_ATTR_PERIOD:
164
case GNE_ATTR_POISSON:
165
case SUMO_ATTR_PROB:
166
case GNE_ATTR_FLOW_TERMINATE:
167
case GNE_ATTR_FLOW_SPACING:
168
GNEChange_Attribute::changeAttribute(flowElement, key, value, undoList);
169
break;
170
default:
171
return flowElement->setCommonAttribute(key, value, undoList);
172
}
173
}
174
175
176
bool
177
GNEDemandElementFlow::isValidFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, const std::string& value) {
178
// declare string error
179
std::string error;
180
switch (key) {
181
case SUMO_ATTR_DEPART:
182
case SUMO_ATTR_BEGIN: {
183
SUMOTime dummyDepart;
184
DepartDefinition dummyDepartProcedure;
185
parseDepart(value, flowElement->getTagProperty()->getTagStr(), id, dummyDepart, dummyDepartProcedure, error);
186
// if error is empty, given value is valid
187
return error.empty();
188
}
189
case SUMO_ATTR_END:
190
if (GNEAttributeCarrier::canParse<SUMOTime>(value)) {
191
return (GNEAttributeCarrier::parse<SUMOTime>(value) >= 0);
192
} else {
193
return false;
194
}
195
case SUMO_ATTR_VEHSPERHOUR:
196
case SUMO_ATTR_PERSONSPERHOUR:
197
case SUMO_ATTR_CONTAINERSPERHOUR:
198
case SUMO_ATTR_PERIOD:
199
case GNE_ATTR_POISSON:
200
if (GNEAttributeCarrier::canParse<double>(value)) {
201
return (GNEAttributeCarrier::parse<double>(value) > 0);
202
} else {
203
return false;
204
}
205
case SUMO_ATTR_PROB:
206
if (GNEAttributeCarrier::canParse<double>(value)) {
207
const double prob = GNEAttributeCarrier::parse<double>(value);
208
return ((prob >= 0) && (prob <= 1));
209
} else {
210
return false;
211
}
212
case SUMO_ATTR_NUMBER:
213
if (GNEAttributeCarrier::canParse<int>(value)) {
214
return (GNEAttributeCarrier::parse<int>(value) >= 0);
215
} else {
216
return false;
217
}
218
case GNE_ATTR_FLOW_TERMINATE:
219
case GNE_ATTR_FLOW_SPACING: {
220
const auto& flowValues = flowElement->getTagProperty()->getAttributeProperties(key)->getDiscreteValues();
221
if (std::find(flowValues.begin(), flowValues.end(), value) != flowValues.end()) {
222
return true;
223
} else {
224
return false;
225
}
226
}
227
default:
228
return flowElement->isCommonAttributeValid(key, value);
229
}
230
}
231
232
233
void
234
GNEDemandElementFlow::enableFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, GNEUndoList* undoList) {
235
switch (key) {
236
case SUMO_ATTR_END:
237
case SUMO_ATTR_NUMBER:
238
case SUMO_ATTR_VEHSPERHOUR:
239
case SUMO_ATTR_PERSONSPERHOUR:
240
case SUMO_ATTR_CONTAINERSPERHOUR:
241
case SUMO_ATTR_PERIOD:
242
case GNE_ATTR_POISSON:
243
case SUMO_ATTR_PROB:
244
undoList->add(new GNEChange_ToggleAttribute(flowElement, key, true), true);
245
return;
246
default:
247
throw InvalidArgument(flowElement->getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
248
}
249
}
250
251
252
void
253
GNEDemandElementFlow::disableFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, GNEUndoList* undoList) {
254
switch (key) {
255
case SUMO_ATTR_END:
256
case SUMO_ATTR_NUMBER:
257
case SUMO_ATTR_VEHSPERHOUR:
258
case SUMO_ATTR_PERSONSPERHOUR:
259
case SUMO_ATTR_CONTAINERSPERHOUR:
260
case SUMO_ATTR_PERIOD:
261
case GNE_ATTR_POISSON:
262
case SUMO_ATTR_PROB:
263
undoList->add(new GNEChange_ToggleAttribute(flowElement, key, false), true);
264
return;
265
default:
266
throw InvalidArgument(flowElement->getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
267
}
268
}
269
270
271
bool
272
GNEDemandElementFlow::isFlowAttributeEnabled(SumoXMLAttr key) const {
273
switch (key) {
274
case SUMO_ATTR_END:
275
return (parametersSet & VEHPARS_END_SET) != 0;
276
case SUMO_ATTR_NUMBER:
277
return (parametersSet & VEHPARS_NUMBER_SET) != 0;
278
case SUMO_ATTR_VEHSPERHOUR:
279
case SUMO_ATTR_PERSONSPERHOUR:
280
case SUMO_ATTR_CONTAINERSPERHOUR:
281
return (parametersSet & VEHPARS_VPH_SET) != 0;
282
case SUMO_ATTR_PERIOD:
283
return (parametersSet & VEHPARS_PERIOD_SET) != 0;
284
case GNE_ATTR_POISSON:
285
return (parametersSet & VEHPARS_POISSON_SET) != 0;
286
case SUMO_ATTR_PROB:
287
return (parametersSet & VEHPARS_PROB_SET) != 0;
288
case GNE_ATTR_FLOW_SPACING:
289
return !isFlowAttributeEnabled(SUMO_ATTR_END) || !isFlowAttributeEnabled(SUMO_ATTR_NUMBER);
290
default:
291
return true;
292
}
293
}
294
295
296
void
297
GNEDemandElementFlow::setFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, const std::string& value) {
298
// declare string error
299
std::string error;
300
switch (key) {
301
case SUMO_ATTR_DEPART:
302
case SUMO_ATTR_BEGIN: {
303
parseDepart(value, flowElement->getTagProperty()->getTagStr(), id, depart, departProcedure, error);
304
break;
305
}
306
case SUMO_ATTR_END:
307
repetitionEnd = string2time(value);
308
break;
309
case SUMO_ATTR_VEHSPERHOUR:
310
case SUMO_ATTR_PERSONSPERHOUR:
311
case SUMO_ATTR_CONTAINERSPERHOUR:
312
repetitionOffset = TIME2STEPS(3600 / GNEAttributeCarrier::parse<double>(value));
313
poissonRate = GNEAttributeCarrier::parse<double>(value) / 3600;
314
break;
315
case SUMO_ATTR_PERIOD:
316
repetitionOffset = string2time(value);
317
poissonRate = 1 / STEPS2TIME(repetitionOffset);
318
break;
319
case GNE_ATTR_POISSON:
320
poissonRate = GNEAttributeCarrier::parse<double>(value);
321
repetitionOffset = TIME2STEPS(1 / poissonRate);
322
break;
323
case SUMO_ATTR_PROB:
324
repetitionProbability = GNEAttributeCarrier::parse<double>(value);
325
break;
326
case SUMO_ATTR_NUMBER:
327
repetitionNumber = GNEAttributeCarrier::parse<int>(value);
328
break;
329
case GNE_ATTR_FLOW_TERMINATE:
330
if (value == (toString(SUMO_ATTR_END) + "-" + toString(SUMO_ATTR_NUMBER))) {
331
toggleFlowAttribute(SUMO_ATTR_END, true);
332
toggleFlowAttribute(SUMO_ATTR_NUMBER, true);
333
// in this special case, disable other spacing
334
toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, false);
335
toggleFlowAttribute(SUMO_ATTR_PERIOD, false);
336
toggleFlowAttribute(GNE_ATTR_POISSON, false);
337
toggleFlowAttribute(SUMO_ATTR_PROB, false);
338
} else {
339
// if previously end-number was enabled, enable perHour
340
if (isFlowAttributeEnabled(SUMO_ATTR_END) && isFlowAttributeEnabled(SUMO_ATTR_NUMBER)) {
341
toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, true);
342
}
343
if (value == toString(SUMO_ATTR_END)) {
344
toggleFlowAttribute(SUMO_ATTR_END, true);
345
toggleFlowAttribute(SUMO_ATTR_NUMBER, false);
346
} else if (value == toString(SUMO_ATTR_NUMBER)) {
347
toggleFlowAttribute(SUMO_ATTR_END, false);
348
toggleFlowAttribute(SUMO_ATTR_NUMBER, true);
349
}
350
}
351
break;
352
case GNE_ATTR_FLOW_SPACING:
353
if ((value == toString(SUMO_ATTR_VEHSPERHOUR)) ||
354
(value == toString(SUMO_ATTR_PERSONSPERHOUR)) ||
355
(value == toString(SUMO_ATTR_CONTAINERSPERHOUR))) {
356
toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, true);
357
toggleFlowAttribute(SUMO_ATTR_PERIOD, false);
358
toggleFlowAttribute(GNE_ATTR_POISSON, false);
359
toggleFlowAttribute(SUMO_ATTR_PROB, false);
360
} else if (value == toString(SUMO_ATTR_PERIOD)) {
361
toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, false);
362
toggleFlowAttribute(SUMO_ATTR_PERIOD, true);
363
toggleFlowAttribute(GNE_ATTR_POISSON, false);
364
toggleFlowAttribute(SUMO_ATTR_PROB, false);
365
} else if (value == toString(GNE_ATTR_POISSON)) {
366
toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, false);
367
toggleFlowAttribute(SUMO_ATTR_PERIOD, false);
368
toggleFlowAttribute(GNE_ATTR_POISSON, true);
369
toggleFlowAttribute(SUMO_ATTR_PROB, false);
370
} else if (value == toString(SUMO_ATTR_PROB)) {
371
toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, false);
372
toggleFlowAttribute(SUMO_ATTR_PERIOD, false);
373
toggleFlowAttribute(GNE_ATTR_POISSON, false);
374
toggleFlowAttribute(SUMO_ATTR_PROB, true);
375
}
376
break;
377
default:
378
flowElement->setCommonAttribute(key, value);
379
break;
380
}
381
}
382
383
384
void
385
GNEDemandElementFlow::toggleFlowAttribute(const SumoXMLAttr attribute, const bool value) {
386
// modify parameters depending of given Flow attribute
387
if (value) {
388
switch (attribute) {
389
case SUMO_ATTR_END:
390
parametersSet |= VEHPARS_END_SET;
391
break;
392
case SUMO_ATTR_NUMBER:
393
parametersSet |= VEHPARS_NUMBER_SET;
394
break;
395
case SUMO_ATTR_VEHSPERHOUR:
396
case SUMO_ATTR_PERSONSPERHOUR:
397
case SUMO_ATTR_CONTAINERSPERHOUR:
398
parametersSet |= VEHPARS_VPH_SET;
399
break;
400
case SUMO_ATTR_PERIOD:
401
parametersSet |= VEHPARS_PERIOD_SET;
402
break;
403
case GNE_ATTR_POISSON:
404
parametersSet |= VEHPARS_POISSON_SET;
405
break;
406
case SUMO_ATTR_PROB:
407
parametersSet |= VEHPARS_PROB_SET;
408
break;
409
default:
410
break;
411
}
412
} else {
413
switch (attribute) {
414
case SUMO_ATTR_END:
415
parametersSet &= ~VEHPARS_END_SET;
416
break;
417
case SUMO_ATTR_NUMBER:
418
parametersSet &= ~VEHPARS_NUMBER_SET;
419
break;
420
case SUMO_ATTR_VEHSPERHOUR:
421
case SUMO_ATTR_PERSONSPERHOUR:
422
case SUMO_ATTR_CONTAINERSPERHOUR:
423
parametersSet &= ~VEHPARS_VPH_SET;
424
break;
425
case SUMO_ATTR_PERIOD:
426
parametersSet &= ~VEHPARS_PERIOD_SET;
427
break;
428
case GNE_ATTR_POISSON:
429
parametersSet &= ~VEHPARS_POISSON_SET;
430
break;
431
case SUMO_ATTR_PROB:
432
parametersSet &= ~VEHPARS_PROB_SET;
433
break;
434
default:
435
break;
436
}
437
}
438
}
439
440
441
void
442
GNEDemandElementFlow::setDefaultFlowAttributes(GNEDemandElement* flowElement) {
443
// first check that this demand element is a flow
444
if (flowElement->getTagProperty()->isFlow()) {
445
// end
446
if ((parametersSet & VEHPARS_END_SET) == 0) {
447
setFlowAttribute(flowElement, SUMO_ATTR_END, flowElement->getTagProperty()->getDefaultStringValue(SUMO_ATTR_END));
448
}
449
// number
450
if ((parametersSet & VEHPARS_NUMBER_SET) == 0) {
451
setFlowAttribute(flowElement, SUMO_ATTR_NUMBER, flowElement->getTagProperty()->getDefaultStringValue(SUMO_ATTR_NUMBER));
452
}
453
// vehicles/person/container per hour
454
if (((parametersSet & VEHPARS_PERIOD_SET) == 0) &&
455
((parametersSet & VEHPARS_POISSON_SET) == 0) &&
456
((parametersSet & VEHPARS_VPH_SET) == 0)) {
457
setFlowAttribute(flowElement, SUMO_ATTR_PERIOD, flowElement->getTagProperty()->getDefaultStringValue(SUMO_ATTR_PERIOD));
458
}
459
// probability
460
if ((parametersSet & VEHPARS_PROB_SET) == 0) {
461
setFlowAttribute(flowElement, SUMO_ATTR_PROB, flowElement->getTagProperty()->getDefaultStringValue(SUMO_ATTR_PROB));
462
}
463
// poisson
464
if (repetitionOffset < 0) {
465
toggleFlowAttribute(SUMO_ATTR_PERIOD, false);
466
toggleFlowAttribute(GNE_ATTR_POISSON, true);
467
setFlowAttribute(flowElement, GNE_ATTR_POISSON, toString(poissonRate));
468
} else {
469
setFlowAttribute(flowElement, SUMO_ATTR_PERIOD, time2string(repetitionOffset));
470
}
471
}
472
}
473
474
/****************************************************************************/
475
476