Path: blob/main/src/netedit/elements/additional/GNECalibrator.cpp
169684 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GNECalibrator.cpp14/// @author Pablo Alvarez Lopez15/// @date Nov 201516///17// Calibrator over edge or lane18/****************************************************************************/19#include <config.h>2021#include <netedit/changes/GNEChange_Attribute.h>22#include <netedit/dialogs/elements/GNECalibratorDialog.h>23#include <netedit/GNENet.h>24#include <netedit/GNETagProperties.h>25#include <netedit/GNEUndoList.h>26#include <netedit/GNEViewNet.h>27#include <utils/gui/div/GLHelper.h>28#include <utils/gui/div/GUIGlobalViewObjectsHandler.h>29#include <utils/gui/globjects/GLIncludes.h>30#include <utils/xml/NamespaceIDs.h>3132#include "GNECalibrator.h"3334// ===========================================================================35// member method definitions36// ===========================================================================3738GNECalibrator::GNECalibrator(SumoXMLTag tag, GNENet* net) :39GNEAdditional("", net, "", tag, ""),40myCalibratorContours(new std::vector<GNEContour*>()) {41}424344GNECalibrator::GNECalibrator(const std::string& id, GNENet* net, const std::string& filename, GNEEdge* edge, double pos, SUMOTime frequency, const std::string& name,45const std::string& output, const double jamThreshold, const std::vector<std::string>& vTypes, const Parameterised::Map& parameters) :46GNEAdditional(id, net, filename, SUMO_TAG_CALIBRATOR, name),47Parameterised(parameters),48myPositionOverLane(pos),49myFrequency(frequency),50myOutput(output),51myJamThreshold(jamThreshold),52myVTypes(vTypes),53myCalibratorContours(new std::vector<GNEContour*>()) {54// set parents55setParent<GNEEdge*>(edge);56// update centering boundary without updating grid57updateCenteringBoundary(false);58}596061GNECalibrator::GNECalibrator(const std::string& id, GNENet* net, const std::string& filename, GNEEdge* edge, double pos, SUMOTime frequency, const std::string& name,62const std::string& output, GNEAdditional* routeProbe, const double jamThreshold, const std::vector<std::string>& vTypes,63const Parameterised::Map& parameters) :64GNEAdditional(id, net, filename, SUMO_TAG_CALIBRATOR, name),65Parameterised(parameters),66myPositionOverLane(pos),67myFrequency(frequency),68myOutput(output),69myJamThreshold(jamThreshold),70myVTypes(vTypes),71myCalibratorContours(new std::vector<GNEContour*>()) {72// set parents73setParent<GNEEdge*>(edge);74setParent<GNEAdditional*>(routeProbe);75// update centering boundary without updating grid76updateCenteringBoundary(false);77}787980GNECalibrator::GNECalibrator(const std::string& id, GNENet* net, const std::string& filename, GNELane* lane, double pos, SUMOTime frequency, const std::string& name,81const std::string& output, const double jamThreshold, const std::vector<std::string>& vTypes, const Parameterised::Map& parameters) :82GNEAdditional(id, net, filename, GNE_TAG_CALIBRATOR_LANE, name),83Parameterised(parameters),84myPositionOverLane(pos),85myFrequency(frequency),86myOutput(output),87myJamThreshold(jamThreshold),88myVTypes(vTypes),89myCalibratorContours(new std::vector<GNEContour*>()) {90// set parents91setParent<GNELane*>(lane);92// update centering boundary without updating grid93updateCenteringBoundary(false);94}959697GNECalibrator::GNECalibrator(const std::string& id, GNENet* net, const std::string& filename, GNELane* lane, double pos, SUMOTime frequency, const std::string& name,98const std::string& output, GNEAdditional* routeProbe, const double jamThreshold, const std::vector<std::string>& vTypes,99const Parameterised::Map& parameters) :100GNEAdditional(id, net, filename, GNE_TAG_CALIBRATOR_LANE, name),101Parameterised(parameters),102myPositionOverLane(pos),103myFrequency(frequency),104myOutput(output),105myJamThreshold(jamThreshold),106myVTypes(vTypes),107myCalibratorContours(new std::vector<GNEContour*>()) {108// set parents109setParent<GNELane*>(lane);110setParent<GNEAdditional*>(routeProbe);111// update centering boundary without updating grid112updateCenteringBoundary(false);113}114115116GNECalibrator::~GNECalibrator() {117for (auto it = myCalibratorContours->begin(); it != myCalibratorContours->end(); it++) {118delete *it;119}120delete myCalibratorContours;121}122123124void125GNECalibrator::writeAdditional(OutputDevice& device) const {126// open tag127device.openTag(SUMO_TAG_CALIBRATOR);128// write parameters129device.writeAttr(SUMO_ATTR_ID, getID());130if (getParentEdges().size() > 0) {131device.writeAttr(SUMO_ATTR_EDGE, getParentEdges().front()->getID());132}133if (getParentLanes().size() > 0) {134device.writeAttr(SUMO_ATTR_LANE, getParentLanes().front()->getID());135}136device.writeAttr(SUMO_ATTR_POSITION, myPositionOverLane);137if (time2string(myFrequency) != "1.00") {138device.writeAttr(SUMO_ATTR_PERIOD, time2string(myFrequency));139}140if (!myAdditionalName.empty()) {141device.writeAttr(SUMO_ATTR_NAME, myAdditionalName);142}143if (!myOutput.empty()) {144device.writeAttr(SUMO_ATTR_OUTPUT, myOutput);145}146if (getParentAdditionals().size() > 0) {147device.writeAttr(SUMO_ATTR_ROUTEPROBE, getParentAdditionals().front()->getID());148}149if (myJamThreshold != 0.5) {150device.writeAttr(SUMO_ATTR_JAM_DIST_THRESHOLD, myJamThreshold);151}152if (myVTypes.size() > 0) {153device.writeAttr(SUMO_ATTR_VTYPES, myVTypes);154}155// write calibrator flows156for (const auto& calibratorFlow : getChildAdditionals()) {157if (calibratorFlow->getTagProperty()->getTag() == GNE_TAG_CALIBRATOR_FLOW) {158calibratorFlow->writeAdditional(device);159}160}161// write parameters (Always after children to avoid problems with additionals.xsd)162writeParams(device);163device.closeTag();164}165166167bool168GNECalibrator::isAdditionalValid() const {169return true;170}171172173std::string174GNECalibrator::getAdditionalProblem() const {175return "";176}177178179void180GNECalibrator::fixAdditionalProblem() {181// nothing to fix182}183184185GNEMoveOperation*186GNECalibrator::getMoveOperation() {187// calibrators cannot be moved188return nullptr;189}190191192void193GNECalibrator::updateGeometry() {194// get shape depending of we have a edge or a lane195if (getParentLanes().size() > 0) {196// update geometry197myAdditionalGeometry.updateGeometry(getParentLanes().front()->getLaneShape(), myPositionOverLane, 0);198} else if (getParentEdges().size() > 0) {199// clear extra geometries and contours200if (getParentEdges().size() != myCalibratorContours->size()) {201for (auto it = myCalibratorContours->begin(); it != myCalibratorContours->end(); it++) {202delete *it;203}204myCalibratorContours->clear();205for (int i = 1; i < (int)getParentEdges().front()->getChildLanes().size(); i++) {206myCalibratorContours->push_back(new GNEContour());207}208}209myEdgeCalibratorGeometries.clear();210// iterate over every lane and upadte geometries211for (const auto& lane : getParentEdges().front()->getChildLanes()) {212if (lane == getParentEdges().front()->getChildLanes().front()) {213myAdditionalGeometry.updateGeometry(lane->getLaneShape(), myPositionOverLane, 0);214} else {215// add new calibrator geometry216GUIGeometry calibratorGeometry;217calibratorGeometry.updateGeometry(lane->getLaneShape(), myPositionOverLane, 0);218myEdgeCalibratorGeometries.push_back(calibratorGeometry);219}220}221} else {222throw ProcessError(TL("Both edges and lanes aren't defined"));223}224}225226227Position228GNECalibrator::getPositionInView() const {229return myAdditionalGeometry.getShape().getPolygonCenter();230}231232233void234GNECalibrator::updateCenteringBoundary(const bool /*updateGrid*/) {235// nothing to update236}237238239void240GNECalibrator::splitEdgeGeometry(const double splitPosition, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* newElement, GNEUndoList* undoList) {241if (splitPosition < myPositionOverLane) {242// change lane or edge243if (newElement->getTagProperty()->getTag() == SUMO_TAG_LANE) {244setAttribute(SUMO_ATTR_LANE, newElement->getID(), undoList);245} else {246setAttribute(SUMO_ATTR_EDGE, newElement->getID(), undoList);247}248// now adjust start position249setAttribute(SUMO_ATTR_POSITION, toString(myPositionOverLane - splitPosition), undoList);250}251}252253254std::string255GNECalibrator::getParentName() const {256// get parent name depending of we have a edge or a lane257if (getParentLanes().size() > 0) {258return getParentLanes().front()->getID();259} else if (getParentEdges().size() > 0) {260return getParentEdges().front()->getChildLanes().at(0)->getID();261} else {262throw ProcessError(TL("Both myEdge and myLane aren't defined"));263}264}265266267void268GNECalibrator::drawGL(const GUIVisualizationSettings& s) const {269const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();270// first check if additional has to be drawn271if (myNet->getViewNet()->getDataViewOptions().showAdditionals()) {272// get values273const double exaggeration = getExaggeration(s);274// get detail level275const auto d = s.getDetailLevel(exaggeration);276// draw first calibrator symbols277drawCalibratorSymbol(s, d, exaggeration, myAdditionalGeometry.getShape().front(),278myAdditionalGeometry.getShapeRotations().front() + 90, -1);279// draw rest of calibrator symbols280for (int i = 0; i < (int)myEdgeCalibratorGeometries.size(); i++) {281drawCalibratorSymbol(s, d, exaggeration, myEdgeCalibratorGeometries.at(i).getShape().front(),282myEdgeCalibratorGeometries.at(i).getShapeRotations().front() + 90, i);283}284// draw additional ID285drawAdditionalID(s);286// iterate over additionals and check if drawn287for (const auto& calibratorFlow : getChildAdditionals()) {288// if calibrator is being inspected or selected, then draw289if (myNet->getViewNet()->getNetworkViewOptions().showSubAdditionals() ||290isAttributeCarrierSelected() || inspectedElements.isACInspected(this) ||291calibratorFlow->isAttributeCarrierSelected() || inspectedElements.isACInspected(calibratorFlow) ||292calibratorFlow->isMarkedForDrawingFront()) {293calibratorFlow->drawGL(s);294}295}296}297}298299300bool301GNECalibrator::checkDrawMoveContour() const {302// get edit modes303const auto& editModes = myNet->getViewNet()->getEditModes();304// check if we're in move mode305if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&306!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&307(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {308// only move the first element309return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;310} else {311return false;312}313}314315316void317GNECalibrator::openAdditionalDialog() {318// Open calibrator dialog319GNECalibratorDialog calibratorDialog(this);320}321322323std::string324GNECalibrator::getAttribute(SumoXMLAttr key) const {325switch (key) {326case SUMO_ATTR_ID:327return getMicrosimID();328case SUMO_ATTR_EDGE:329return getParentEdges().front()->getID();330case SUMO_ATTR_LANE:331return getParentLanes().front()->getID();332case SUMO_ATTR_POSITION:333return toString(myPositionOverLane);334case SUMO_ATTR_PERIOD:335case SUMO_ATTR_FREQUENCY:336return time2string(myFrequency);337case SUMO_ATTR_NAME:338return myAdditionalName;339case SUMO_ATTR_OUTPUT:340return myOutput;341case SUMO_ATTR_ROUTEPROBE:342if (getParentAdditionals().size() > 0) {343return getParentAdditionals().front()->getID();344} else {345return "";346}347case SUMO_ATTR_JAM_DIST_THRESHOLD:348return toString(myJamThreshold);349case SUMO_ATTR_VTYPES:350return toString(myVTypes);351case GNE_ATTR_SHIFTLANEINDEX:352return "";353default:354return getCommonAttribute(this, key);355}356}357358359double360GNECalibrator::getAttributeDouble(SumoXMLAttr key) const {361throw InvalidArgument(getTagStr() + " doesn't have a double attribute of type '" + toString(key) + "'");362}363364365const Parameterised::Map&366GNECalibrator::getACParametersMap() const {367return getParametersMap();368}369370371void372GNECalibrator::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {373switch (key) {374case SUMO_ATTR_ID:375case SUMO_ATTR_EDGE:376case SUMO_ATTR_LANE:377case SUMO_ATTR_POSITION:378case SUMO_ATTR_PERIOD:379case SUMO_ATTR_FREQUENCY:380case SUMO_ATTR_NAME:381case SUMO_ATTR_OUTPUT:382case SUMO_ATTR_ROUTEPROBE:383case SUMO_ATTR_JAM_DIST_THRESHOLD:384case SUMO_ATTR_VTYPES:385case GNE_ATTR_SHIFTLANEINDEX:386GNEChange_Attribute::changeAttribute(this, key, value, undoList);387break;388default:389setCommonAttribute(key, value, undoList);390break;391}392393}394395396bool397GNECalibrator::isValid(SumoXMLAttr key, const std::string& value) {398switch (key) {399case SUMO_ATTR_ID:400return isValidAdditionalID(NamespaceIDs::calibrators, value);401case SUMO_ATTR_EDGE:402if (myNet->getAttributeCarriers()->retrieveEdge(value, false) != nullptr) {403return true;404} else {405return false;406}407case SUMO_ATTR_LANE:408if (myNet->getAttributeCarriers()->retrieveLane(value, false) != nullptr) {409return true;410} else {411return false;412}413case SUMO_ATTR_POSITION:414if (canParse<double>(value)) {415// obtain position and check if is valid416const double newPosition = parse<double>(value);417if (isTemplate()) {418return (newPosition >= 0);419}420// get shape421PositionVector shape = (getParentLanes().size() > 0) ? getParentLanes().front()->getLaneShape() : getParentEdges().front()->getChildLanes().at(0)->getLaneShape();422if ((newPosition < 0) || (newPosition > shape.length())) {423return false;424} else {425return true;426}427} else {428return false;429}430case SUMO_ATTR_PERIOD:431case SUMO_ATTR_FREQUENCY:432return canParse<SUMOTime>(value) ? (parse<SUMOTime>(value) >= 0) : false;433case SUMO_ATTR_NAME:434return SUMOXMLDefinitions::isValidAttribute(value);435case SUMO_ATTR_OUTPUT:436return SUMOXMLDefinitions::isValidFilename(value);437case SUMO_ATTR_ROUTEPROBE:438if (value.empty()) {439return true;440} else {441return (myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_ROUTEPROBE, value, false) != nullptr);442}443case SUMO_ATTR_JAM_DIST_THRESHOLD:444return canParse<double>(value) ? (parse<double>(value) >= 0) : false;445case SUMO_ATTR_VTYPES:446if (value.empty()) {447return true;448} else {449return SUMOXMLDefinitions::isValidListOfTypeID(value);450}451default:452return isCommonValid(key, value);453}454}455456457std::string458GNECalibrator::getPopUpID() const {459return getTagStr() + ": " + getID();460}461462463std::string464GNECalibrator::getHierarchyName() const {465return getTagStr();466}467468// ===========================================================================469// private470// ===========================================================================471472void473GNECalibrator::drawCalibratorSymbol(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const double exaggeration,474const Position& pos, const double rot, const int symbolIndex) const {475// draw geometry only if we'rent in drawForObjectUnderCursor mode476if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {477// push layer matrix478GLHelper::pushMatrix();479// translate to front480drawInLayer(GLO_CALIBRATOR);481// translate to position482glTranslated(pos.x(), pos.y(), 0);483// rotate over lane484GUIGeometry::rotateOverLane(rot);485// scale486glScaled(exaggeration, exaggeration, 1);487// set drawing mode488glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);489// set color490GLHelper::setColor(drawUsingSelectColor() ? s.colorSettings.selectedAdditionalColor : s.additionalSettings.calibratorColor);491// base492glBegin(GL_TRIANGLES);493glVertex2d(0 - s.additionalSettings.calibratorWidth, 0);494glVertex2d(0 - s.additionalSettings.calibratorWidth, s.additionalSettings.calibratorHeight);495glVertex2d(0 + s.additionalSettings.calibratorWidth, s.additionalSettings.calibratorHeight);496glVertex2d(0 + s.additionalSettings.calibratorWidth, 0);497glVertex2d(0 - s.additionalSettings.calibratorWidth, 0);498glVertex2d(0 + s.additionalSettings.calibratorWidth, s.additionalSettings.calibratorHeight);499glEnd();500// draw text if isn't being drawn for selecting501if (d <= GUIVisualizationSettings::Detail::Text) {502// set color depending of selection status503RGBColor textColor = drawUsingSelectColor() ? s.colorSettings.selectionColor : RGBColor::BLACK;504// draw "C"505GLHelper::drawText("C", Position(0, 1.5), 0.1, 3, textColor, 180);506// draw "edge" or "lane "507if (getParentLanes().size() > 0) {508GLHelper::drawText("lane", Position(0, 3), .1, 1, textColor, 180);509} else if (getParentEdges().size() > 0) {510GLHelper::drawText("edge", Position(0, 3), .1, 1, textColor, 180);511} else {512throw ProcessError(TL("Both myEdge and myLane aren't defined"));513}514}515// pop layer matrix516GLHelper::popMatrix();517// draw dotted contours518if (symbolIndex == -1) {519myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);520} else if (symbolIndex < (int)myCalibratorContours->size()) {521myCalibratorContours->at(symbolIndex)->drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);522}523}524GUIGlObject* parentBoundary = nullptr;525if (getParentEdges().size() > 0) {526parentBoundary = getParentEdges().front();527} else if (getParentLanes().size() > 0) {528parentBoundary = getParentLanes().front();529}530// calculate dotted contour531if (symbolIndex == -1) {532myAdditionalContour.calculateContourRectangleShape(s, d, this, pos, s.additionalSettings.calibratorWidth,533s.additionalSettings.calibratorHeight * 0.5, getType(), 0, s.additionalSettings.calibratorHeight * 0.5, rot,534exaggeration, parentBoundary);535} else if (symbolIndex < (int)myCalibratorContours->size()) {536myCalibratorContours->at(symbolIndex)->calculateContourRectangleShape(s, d, this, pos, s.additionalSettings.calibratorWidth,537s.additionalSettings.calibratorHeight * 0.5, getType(), 0, s.additionalSettings.calibratorHeight * 0.5, rot,538exaggeration, parentBoundary);539}540}541542void543GNECalibrator::setAttribute(SumoXMLAttr key, const std::string& value) {544switch (key) {545case SUMO_ATTR_ID:546// update microsimID547setAdditionalID(value);548break;549case SUMO_ATTR_EDGE:550replaceAdditionalParentEdges(value);551break;552case SUMO_ATTR_LANE:553replaceAdditionalParentLanes(value);554break;555case SUMO_ATTR_POSITION:556myPositionOverLane = parse<double>(value);557break;558case SUMO_ATTR_PERIOD:559case SUMO_ATTR_FREQUENCY:560myFrequency = parse<SUMOTime>(value);561break;562case SUMO_ATTR_NAME:563myAdditionalName = value;564break;565case SUMO_ATTR_OUTPUT:566myOutput = value;567break;568case SUMO_ATTR_ROUTEPROBE:569replaceAdditionalParent(SUMO_TAG_ROUTEPROBE, value, 0);570break;571case SUMO_ATTR_JAM_DIST_THRESHOLD:572myJamThreshold = parse<double>(value);573break;574case SUMO_ATTR_VTYPES:575myVTypes = parse<std::vector<std::string> >(value);576break;577case GNE_ATTR_SHIFTLANEINDEX:578shiftLaneIndex();579break;580default:581setCommonAttribute(this, key, value);582break;583}584}585586587void588GNECalibrator::setMoveShape(const GNEMoveResult& /*moveResult*/) {589// nothing to do590}591592593void594GNECalibrator::commitMoveShape(const GNEMoveResult& /*moveResult*/, GNEUndoList* /*undoList*/) {595// nothing to do596}597598599/****************************************************************************/600601602