Path: blob/main/src/netedit/elements/additional/GNECalibrator.cpp
193723 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 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/GNEUndoList.h>25#include <utils/gui/div/GLHelper.h>26#include <utils/xml/NamespaceIDs.h>2728#include "GNECalibrator.h"2930// ===========================================================================31// member method definitions32// ===========================================================================3334GNECalibrator::GNECalibrator(SumoXMLTag tag, GNENet* net) :35GNEAdditional(net, tag),36myEdgeCalibratorContours(new std::vector<GNEContour*>()) {37}383940GNECalibrator::GNECalibrator(const std::string& id, GNENet* net, FileBucket* fileBucket, GNEEdge* edge, double pos, SUMOTime frequency, const std::string& name,41const std::string& output, const double jamThreshold, const std::vector<std::string>& vTypes, const Parameterised::Map& parameters) :42GNEAdditional(id, net, SUMO_TAG_CALIBRATOR, fileBucket, name),43Parameterised(parameters),44myPositionOverLane(pos),45myFrequency(frequency),46myOutput(output),47myJamThreshold(jamThreshold),48myVTypes(vTypes),49myEdgeCalibratorContours(new std::vector<GNEContour*>()) {50// set parents51setParent<GNEEdge*>(edge);52// update centering boundary without updating grid53updateCenteringBoundary(false);54}555657GNECalibrator::GNECalibrator(const std::string& id, GNENet* net, FileBucket* fileBucket, GNEEdge* edge, double pos, SUMOTime frequency, const std::string& name,58const std::string& output, GNEAdditional* routeProbe, const double jamThreshold, const std::vector<std::string>& vTypes,59const Parameterised::Map& parameters) :60GNEAdditional(id, net, SUMO_TAG_CALIBRATOR, fileBucket, name),61Parameterised(parameters),62myPositionOverLane(pos),63myFrequency(frequency),64myOutput(output),65myJamThreshold(jamThreshold),66myVTypes(vTypes),67myEdgeCalibratorContours(new std::vector<GNEContour*>()) {68// set parents69setParent<GNEEdge*>(edge);70setParent<GNEAdditional*>(routeProbe);71// update centering boundary without updating grid72updateCenteringBoundary(false);73}747576GNECalibrator::GNECalibrator(const std::string& id, GNENet* net, FileBucket* fileBucket, GNELane* lane, double pos, SUMOTime frequency, const std::string& name,77const std::string& output, const double jamThreshold, const std::vector<std::string>& vTypes, const Parameterised::Map& parameters) :78GNEAdditional(id, net, GNE_TAG_CALIBRATOR_LANE, fileBucket, name),79Parameterised(parameters),80myPositionOverLane(pos),81myFrequency(frequency),82myOutput(output),83myJamThreshold(jamThreshold),84myVTypes(vTypes),85myEdgeCalibratorContours(new std::vector<GNEContour*>()) {86// set parents87setParent<GNELane*>(lane);88// update centering boundary without updating grid89updateCenteringBoundary(false);90}919293GNECalibrator::GNECalibrator(const std::string& id, GNENet* net, FileBucket* fileBucket, GNELane* lane, double pos, SUMOTime frequency, const std::string& name,94const std::string& output, GNEAdditional* routeProbe, const double jamThreshold, const std::vector<std::string>& vTypes,95const Parameterised::Map& parameters) :96GNEAdditional(id, net, GNE_TAG_CALIBRATOR_LANE, fileBucket, name),97Parameterised(parameters),98myPositionOverLane(pos),99myFrequency(frequency),100myOutput(output),101myJamThreshold(jamThreshold),102myVTypes(vTypes),103myEdgeCalibratorContours(new std::vector<GNEContour*>()) {104// set parents105setParent<GNELane*>(lane);106setParent<GNEAdditional*>(routeProbe);107// update centering boundary without updating grid108updateCenteringBoundary(false);109}110111112GNECalibrator::~GNECalibrator() {113for (auto it = myEdgeCalibratorContours->begin(); it != myEdgeCalibratorContours->end(); it++) {114delete *it;115}116delete myEdgeCalibratorContours;117}118119120GNEMoveElement*121GNECalibrator::getMoveElement() const {122return nullptr;123}124125126Parameterised*127GNECalibrator::getParameters() {128return this;129}130131132const Parameterised*133GNECalibrator::getParameters() const {134return this;135}136137138void139GNECalibrator::writeAdditional(OutputDevice& device) const {140// open tag141device.openTag(SUMO_TAG_CALIBRATOR);142// write common additional attributes143writeAdditionalAttributes(device);144// write specific attributes145if (getParentEdges().size() > 0) {146device.writeAttr(SUMO_ATTR_EDGE, getParentEdges().front()->getID());147}148if (getParentLanes().size() > 0) {149device.writeAttr(SUMO_ATTR_LANE, getParentLanes().front()->getID());150}151device.writeAttr(SUMO_ATTR_POSITION, myPositionOverLane);152if (time2string(myFrequency) != "1.00") {153device.writeAttr(SUMO_ATTR_PERIOD, time2string(myFrequency));154}155if (!myOutput.empty()) {156device.writeAttr(SUMO_ATTR_OUTPUT, myOutput);157}158if (getParentAdditionals().size() > 0) {159device.writeAttr(SUMO_ATTR_ROUTEPROBE, getParentAdditionals().front()->getID());160}161if (myJamThreshold != 0.5) {162device.writeAttr(SUMO_ATTR_JAM_DIST_THRESHOLD, myJamThreshold);163}164if (myVTypes.size() > 0) {165device.writeAttr(SUMO_ATTR_VTYPES, myVTypes);166}167// write calibrator flows168for (const auto& calibratorFlow : getChildAdditionals()) {169if (calibratorFlow->getTagProperty()->getTag() == GNE_TAG_CALIBRATOR_FLOW) {170calibratorFlow->writeAdditional(device);171}172}173// write parameters (Always after children to avoid problems with additionals.xsd)174writeParams(device);175device.closeTag();176}177178179bool180GNECalibrator::isAdditionalValid() const {181return true;182}183184185std::string186GNECalibrator::getAdditionalProblem() const {187return "";188}189190191void192GNECalibrator::fixAdditionalProblem() {193// nothing to fix194}195196197void198GNECalibrator::updateGeometry() {199// get shape depending of we have a edge or a lane200if (getParentLanes().size() > 0) {201// simply update geometry202myAdditionalGeometry.updateGeometry(getParentLanes().front()->getLaneShape(), myPositionOverLane, 0);203} else if (getParentEdges().size() > 0) {204// clear all contours205for (auto it = myEdgeCalibratorContours->begin(); it != myEdgeCalibratorContours->end(); it++) {206delete *it;207}208// clear all edge geometries209myEdgeCalibratorGeometries.clear();210myEdgeCalibratorContours->clear();211// iterate over every lane and upadte geometries212for (const auto& lane : getParentEdges().front()->getChildLanes()) {213// this is needed for centering calibratorFlows as additional listed214if (lane == getParentEdges().front()->getChildLanes().front()) {215myAdditionalGeometry.updateGeometry(lane->getLaneShape(), myPositionOverLane, 0);216}217// add new calibrator geometry218GUIGeometry calibratorGeometry;219calibratorGeometry.updateGeometry(lane->getLaneShape(), myPositionOverLane, 0);220myEdgeCalibratorGeometries.push_back(calibratorGeometry);221// also add a new contour222myEdgeCalibratorContours->push_back(new GNEContour());223}224}225// update geometries of all children226for (const auto& rerouterElement : getChildAdditionals()) {227rerouterElement->updateGeometry();228}229}230231232Position233GNECalibrator::getPositionInView() const {234return myAdditionalGeometry.getShape().getPolygonCenter();235}236237238void239GNECalibrator::updateCenteringBoundary(const bool /*updateGrid*/) {240// nothing to update241}242243244void245GNECalibrator::splitEdgeGeometry(const double splitPosition, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* newElement, GNEUndoList* undoList) {246if (splitPosition < myPositionOverLane) {247// change lane or edge248if (newElement->getTagProperty()->getTag() == SUMO_TAG_LANE) {249setAttribute(SUMO_ATTR_LANE, newElement->getID(), undoList);250} else {251setAttribute(SUMO_ATTR_EDGE, newElement->getID(), undoList);252}253// now adjust start position254setAttribute(SUMO_ATTR_POSITION, toString(myPositionOverLane - splitPosition), undoList);255}256}257258259std::string260GNECalibrator::getParentName() const {261// get parent name depending of we have a edge or a lane262if (getParentLanes().size() > 0) {263return getParentLanes().front()->getID();264} else if (getParentEdges().size() > 0) {265return getParentEdges().front()->getChildLanes().at(0)->getID();266} else {267throw ProcessError(TL("Both myEdge and myLane aren't defined"));268}269}270271272void273GNECalibrator::drawGL(const GUIVisualizationSettings& s) const {274const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();275// first check if additional has to be drawn276if (myNet->getViewNet()->getDataViewOptions().showAdditionals()) {277// get values278const double exaggeration = getExaggeration(s);279// get detail level280const auto d = s.getDetailLevel(exaggeration);281if (myEdgeCalibratorGeometries.size() > 0) {282// draw all calibrator symbols283for (int i = 0; i < (int)myEdgeCalibratorGeometries.size(); i++) {284drawCalibratorSymbol(s, d, exaggeration, myEdgeCalibratorGeometries.at(i).getShape().front(),285myEdgeCalibratorGeometries.at(i).getShapeRotations().front(), i);286}287} else {288// draw single calibrator symbol289drawCalibratorSymbol(s, d, exaggeration, myAdditionalGeometry.getShape().front(),290myAdditionalGeometry.getShapeRotations().front(), -1);291}292// draw additional ID293drawAdditionalID(s);294// iterate over additionals and check if drawn295for (const auto& calibratorFlow : getChildAdditionals()) {296// if calibrator is being inspected or selected, then draw297if (myNet->getViewNet()->getNetworkViewOptions().showSubAdditionals() ||298isAttributeCarrierSelected() || inspectedElements.isACInspected(this) ||299calibratorFlow->isAttributeCarrierSelected() || inspectedElements.isACInspected(calibratorFlow) ||300calibratorFlow->isMarkedForDrawingFront()) {301calibratorFlow->drawGL(s);302}303}304}305}306307308bool309GNECalibrator::checkDrawMoveContour() const {310// get edit modes311const auto& editModes = myNet->getViewNet()->getEditModes();312// check if we're in move mode313if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&314!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&315(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {316// only move the first element317return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;318} else {319return false;320}321}322323324void325GNECalibrator::openAdditionalDialog(FXWindow* /* restoringFocusWindow */) {326// Open calibrator dialog327GNECalibratorDialog calibratorDialog(this);328}329330331std::string332GNECalibrator::getAttribute(SumoXMLAttr key) const {333switch (key) {334case SUMO_ATTR_ID:335return getMicrosimID();336case SUMO_ATTR_EDGE:337return getParentEdges().front()->getID();338case SUMO_ATTR_LANE:339return getParentLanes().front()->getID();340case SUMO_ATTR_POSITION:341return toString(myPositionOverLane);342case SUMO_ATTR_PERIOD:343case SUMO_ATTR_FREQUENCY:344return time2string(myFrequency);345case SUMO_ATTR_NAME:346return myAdditionalName;347case SUMO_ATTR_OUTPUT:348return myOutput;349case SUMO_ATTR_ROUTEPROBE:350if (getParentAdditionals().size() > 0) {351return getParentAdditionals().front()->getID();352} else {353return "";354}355case SUMO_ATTR_JAM_DIST_THRESHOLD:356return toString(myJamThreshold);357case SUMO_ATTR_VTYPES:358return toString(myVTypes);359case GNE_ATTR_SHIFTLANEINDEX:360return "";361default:362return getCommonAttribute(key);363}364}365366367double368GNECalibrator::getAttributeDouble(SumoXMLAttr key) const {369return getCommonAttributeDouble(key);370}371372373Position374GNECalibrator::getAttributePosition(SumoXMLAttr key) const {375return getCommonAttributePosition(key);376}377378379PositionVector380GNECalibrator::getAttributePositionVector(SumoXMLAttr key) const {381return getCommonAttributePositionVector(key);382}383384385void386GNECalibrator::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {387switch (key) {388case SUMO_ATTR_ID:389case SUMO_ATTR_EDGE:390case SUMO_ATTR_LANE:391case SUMO_ATTR_POSITION:392case SUMO_ATTR_PERIOD:393case SUMO_ATTR_FREQUENCY:394case SUMO_ATTR_NAME:395case SUMO_ATTR_OUTPUT:396case SUMO_ATTR_ROUTEPROBE:397case SUMO_ATTR_JAM_DIST_THRESHOLD:398case SUMO_ATTR_VTYPES:399case GNE_ATTR_SHIFTLANEINDEX:400GNEChange_Attribute::changeAttribute(this, key, value, undoList);401break;402default:403setCommonAttribute(key, value, undoList);404break;405}406407}408409410bool411GNECalibrator::isValid(SumoXMLAttr key, const std::string& value) {412switch (key) {413case SUMO_ATTR_ID:414return isValidAdditionalID(NamespaceIDs::calibrators, value);415case SUMO_ATTR_EDGE:416if (myNet->getAttributeCarriers()->retrieveEdge(value, false) != nullptr) {417return true;418} else {419return false;420}421case SUMO_ATTR_LANE:422if (myNet->getAttributeCarriers()->retrieveLane(value, false) != nullptr) {423return true;424} else {425return false;426}427case SUMO_ATTR_POSITION:428if (canParse<double>(value)) {429// obtain position and check if is valid430const double newPosition = parse<double>(value);431if (isTemplate()) {432return (newPosition >= 0);433}434// get shape435PositionVector shape = (getParentLanes().size() > 0) ? getParentLanes().front()->getLaneShape() : getParentEdges().front()->getChildLanes().at(0)->getLaneShape();436if ((newPosition < 0) || (newPosition > shape.length())) {437return false;438} else {439return true;440}441} else {442return false;443}444case SUMO_ATTR_PERIOD:445case SUMO_ATTR_FREQUENCY:446return canParse<SUMOTime>(value) ? (parse<SUMOTime>(value) >= 0) : false;447case SUMO_ATTR_NAME:448return SUMOXMLDefinitions::isValidAttribute(value);449case SUMO_ATTR_OUTPUT:450return SUMOXMLDefinitions::isValidFilename(value);451case SUMO_ATTR_ROUTEPROBE:452if (value.empty()) {453return true;454} else {455return (myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_ROUTEPROBE, value, false) != nullptr);456}457case SUMO_ATTR_JAM_DIST_THRESHOLD:458return canParse<double>(value) ? (parse<double>(value) >= 0) : false;459case SUMO_ATTR_VTYPES:460if (value.empty()) {461return true;462} else {463return SUMOXMLDefinitions::isValidListOfTypeID(value);464}465default:466return isCommonAttributeValid(key, value);467}468}469470471std::string472GNECalibrator::getPopUpID() const {473return getTagStr() + ": " + getID();474}475476477std::string478GNECalibrator::getHierarchyName() const {479return getTagStr();480}481482// ===========================================================================483// private484// ===========================================================================485486void487GNECalibrator::drawCalibratorSymbol(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const double exaggeration,488const Position& pos, const double rot, const int symbolIndex) const {489// draw geometry only if we'rent in drawForObjectUnderCursor mode490if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {491// push layer matrix492GLHelper::pushMatrix();493// translate to front494drawInLayer(GLO_CALIBRATOR);495// translate to position496glTranslated(pos.x(), pos.y(), 0);497// rotate over lane498GUIGeometry::rotateOverLane(rot + 90);499// scale500glScaled(exaggeration, exaggeration, 1);501// set drawing mode502glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);503// set color504GLHelper::setColor(drawUsingSelectColor() ? s.colorSettings.selectedAdditionalColor : s.additionalSettings.calibratorColor);505// base506glBegin(GL_TRIANGLES);507glVertex2d(0 - s.additionalSettings.calibratorWidth, 0);508glVertex2d(0 - s.additionalSettings.calibratorWidth, s.additionalSettings.calibratorHeight);509glVertex2d(0 + s.additionalSettings.calibratorWidth, s.additionalSettings.calibratorHeight);510glVertex2d(0 + s.additionalSettings.calibratorWidth, 0);511glVertex2d(0 - s.additionalSettings.calibratorWidth, 0);512glVertex2d(0 + s.additionalSettings.calibratorWidth, s.additionalSettings.calibratorHeight);513glEnd();514// draw text if isn't being drawn for selecting515if (d <= GUIVisualizationSettings::Detail::Text) {516// set color depending of selection status517RGBColor textColor = drawUsingSelectColor() ? s.colorSettings.selectionColor : RGBColor::BLACK;518// draw "C"519GLHelper::drawText("C", Position(0, 1.5), 0.1, 3, textColor, 180);520// draw "edge" or "lane "521if (getParentLanes().size() > 0) {522GLHelper::drawText("lane", Position(0, 3), .1, 1, textColor, 180);523} else if (getParentEdges().size() > 0) {524GLHelper::drawText("edge", Position(0, 3), .1, 1, textColor, 180);525} else {526throw ProcessError(TL("Both myEdge and myLane aren't defined"));527}528}529// pop layer matrix530GLHelper::popMatrix();531// draw dotted contours532if (symbolIndex == -1) {533myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);534} else {535myEdgeCalibratorContours->at(symbolIndex)->drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);536}537}538GUIGlObject* parentBoundary = nullptr;539if (getParentEdges().size() > 0) {540parentBoundary = getParentEdges().front();541} else if (getParentLanes().size() > 0) {542parentBoundary = getParentLanes().front();543}544// calculate dotted contour545if (symbolIndex == -1) {546myAdditionalContour.calculateContourRectangleShape(s, d, this, pos, s.additionalSettings.calibratorWidth,547s.additionalSettings.calibratorHeight * 0.5, getType(), 0, s.additionalSettings.calibratorHeight * 0.5, rot + 90,548exaggeration, parentBoundary);549} else {550if (symbolIndex == 0) {551myAdditionalContour.calculateContourRectangleShape(s, d, this, pos, s.additionalSettings.calibratorWidth,552s.additionalSettings.calibratorHeight * 0.5, getType(), 0, s.additionalSettings.calibratorHeight * 0.5, rot + 90,553exaggeration, parentBoundary);554}555myEdgeCalibratorContours->at(symbolIndex)->calculateContourRectangleShape(s, d, this, pos, s.additionalSettings.calibratorWidth,556s.additionalSettings.calibratorHeight * 0.5, getType(), 0, s.additionalSettings.calibratorHeight * 0.5, rot + 90,557exaggeration, parentBoundary);558}559}560561void562GNECalibrator::setAttribute(SumoXMLAttr key, const std::string& value) {563switch (key) {564case SUMO_ATTR_ID:565// update microsimID566setAdditionalID(value);567break;568case SUMO_ATTR_EDGE:569replaceAdditionalParentEdges(value);570break;571case SUMO_ATTR_LANE:572replaceAdditionalParentLanes(value);573break;574case SUMO_ATTR_POSITION:575myPositionOverLane = parse<double>(value);576break;577case SUMO_ATTR_PERIOD:578case SUMO_ATTR_FREQUENCY:579myFrequency = parse<SUMOTime>(value);580break;581case SUMO_ATTR_NAME:582myAdditionalName = value;583break;584case SUMO_ATTR_OUTPUT:585myOutput = value;586break;587case SUMO_ATTR_ROUTEPROBE:588replaceAdditionalParent(SUMO_TAG_ROUTEPROBE, value, 0);589break;590case SUMO_ATTR_JAM_DIST_THRESHOLD:591myJamThreshold = parse<double>(value);592break;593case SUMO_ATTR_VTYPES:594myVTypes = parse<std::vector<std::string> >(value);595break;596case GNE_ATTR_SHIFTLANEINDEX:597shiftLaneIndex();598break;599default:600setCommonAttribute(key, value);601break;602}603}604605/****************************************************************************/606607608