Path: blob/main/src/netedit/elements/data/GNETAZRelData.cpp
193692 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 GNETAZRelData.cpp14/// @author Pablo Alvarez Lopez15/// @date Jan 202016///17// class for TAZ relation data18/****************************************************************************/1920#include <netedit/GNENet.h>21#include <netedit/GNETagProperties.h>22#include <netedit/GNEUndoList.h>23#include <netedit/GNEViewNet.h>24#include <netedit/GNEViewParent.h>25#include <netedit/changes/GNEChange_Attribute.h>26#include <netedit/elements/additional/GNETAZ.h>27#include <netedit/frames/data/GNETAZRelDataFrame.h>28#include <utils/gui/div/GLHelper.h>29#include <utils/gui/div/GUIGlobalViewObjectsHandler.h>30#include <utils/gui/globjects/GLIncludes.h>3132#include "GNETAZRelData.h"33#include "GNEDataInterval.h"3435// ===========================================================================36// member method definitions37// ===========================================================================3839GNETAZRelData::GNETAZRelData(GNENet* net) :40GNEGenericData(SUMO_TAG_TAZREL, net),41myLastWidth(0) {42}434445GNETAZRelData::GNETAZRelData(GNEDataInterval* dataIntervalParent, GNEAdditional* fromTAZ, GNEAdditional* toTAZ,46const Parameterised::Map& parameters) :47GNEGenericData(SUMO_TAG_TAZREL, dataIntervalParent, parameters),48myLastWidth(0) {49// set parents50setParents<GNEAdditional*>({fromTAZ, toTAZ});51}525354GNETAZRelData::GNETAZRelData(GNEDataInterval* dataIntervalParent, GNEAdditional* TAZ,55const Parameterised::Map& parameters) :56GNEGenericData(SUMO_TAG_TAZREL, dataIntervalParent, parameters),57myLastWidth(0) {58// set parents59setParent<GNEAdditional*>(TAZ);60}616263GNETAZRelData::~GNETAZRelData() {}646566RGBColor67GNETAZRelData::setColor(const GUIVisualizationSettings& s) const {68RGBColor color;69if (isAttributeCarrierSelected()) {70color = s.colorSettings.selectedEdgeDataColor;71} else {72if (!setFunctionalColor(s.dataColorer.getActive(), color)) {73double val = getColorValue(s, s.dataColorer.getActive());74color = s.dataColorer.getScheme().getColor(val);75}76}77return color;78}798081double82GNETAZRelData::getColorValue(const GUIVisualizationSettings& s, int activeScheme) const {83switch (activeScheme) {84case 0:85return 0;86case 1:87return isAttributeCarrierSelected();88case 2:89return 0; // setfunctional color const GNEAdditional* TAZA = getParentAdditionals().front();90case 3:91return 0; // setfunctional color const GNEAdditional* TAZA = getParentAdditionals().back();92case 4:93// by numerical attribute value94try {95if (hasParameter(s.relDataAttr)) {96return StringUtils::toDouble(getParameter(s.relDataAttr, "-1"));97} else {98return GUIVisualizationSettings::MISSING_DATA;99}100} catch (NumberFormatException&) {101return GUIVisualizationSettings::MISSING_DATA;102}103default:104return 0;105}106}107108109double110GNETAZRelData::getScaleValue(const GUIVisualizationSettings& s, int activeScheme) const {111switch (activeScheme) {112case 0: // uniform113return 0;114case 1: // selection115return isAttributeCarrierSelected();116case 2: // by numerical attribute value117try {118if (hasParameter(s.relDataScaleAttr)) {119return StringUtils::toDouble(getParameter(s.relDataScaleAttr, "-1"));120} else {121return GUIVisualizationSettings::MISSING_DATA;122}123} catch (NumberFormatException&) {124return GUIVisualizationSettings::MISSING_DATA;125}126default:127return 0;128}129}130131132133bool134GNETAZRelData::isGenericDataVisible() const {135// obtain pointer to TAZ data frame (only for code legibly)136const GNETAZRelDataFrame* TAZRelDataFrame = myNet->getViewParent()->getTAZRelDataFrame();137// get current data edit mode138DataEditMode dataMode = myNet->getViewNet()->getEditModes().dataEditMode;139// check if we have to filter generic data140if ((dataMode == DataEditMode::DATA_INSPECT) || (dataMode == DataEditMode::DATA_DELETE) || (dataMode == DataEditMode::DATA_SELECT)) {141return /*isVisibleInspectDeleteSelect()*/ true;142} else if (TAZRelDataFrame->shown()) {143// check interval144if ((TAZRelDataFrame->getIntervalSelector()->getDataInterval() != nullptr) &&145(TAZRelDataFrame->getIntervalSelector()->getDataInterval() != myDataIntervalParent)) {146return false;147}148// check attribute149if ((TAZRelDataFrame->getAttributeSelector()->getFilteredAttribute().size() > 0) &&150(getParametersMap().count(TAZRelDataFrame->getAttributeSelector()->getFilteredAttribute()) == 0)) {151return false;152}153// all checks ok, then return true154return true;155} else {156// GNETAZRelDataFrame hidden, then return false157return false;158}159}160161162void163GNETAZRelData::updateGeometry() {164// remove from grid165myNet->removeGLObjectFromGrid(this);166// get both TAZs167const GNEAdditional* TAZA = getParentAdditionals().front();168const GNEAdditional* TAZB = getParentAdditionals().back();169// check if this is the same TAZ170if (TAZA == TAZB) {171// declare ring172PositionVector ring;173// declare first point174std::pair<double, double> p1 = GLHelper::getCircleCoords().at(GLHelper::angleLookup(0));175// add 8 segments176for (int i = 0; i <= 8; ++i) {177const std::pair<double, double>& p2 = GLHelper::getCircleCoords().at(GLHelper::angleLookup(0 + i * 45));178// make al line between 0,0 and p2179PositionVector line = {Position(), Position(p2.first, p2.second)};180// extrapolate181line.extrapolate(3, false, true);182// add line back to ring183ring.push_back(line.back());184// update p1185p1 = p2;186}187// make a copy of ring188PositionVector ringCenter = ring;189// move ring to first geometry point190ring.add(TAZA->getAdditionalGeometry().getShape().front());191myTAZRelGeometry.updateGeometry(ring);192// move ringCenter to center193ringCenter.add(TAZA->getAttributePosition(SUMO_ATTR_CENTER));194myTAZRelGeometryCenter.updateGeometry(ringCenter);195} else {196// calculate line between to TAZ centers197PositionVector line = {TAZA->getAttributePosition(SUMO_ATTR_CENTER), TAZB->getAttributePosition(SUMO_ATTR_CENTER)};198// check line199if (line.length() < 1) {200line = {TAZA->getAttributePosition(SUMO_ATTR_CENTER) - 0.5, TAZB->getAttributePosition(SUMO_ATTR_CENTER) + 0.5};201}202// add offset to line203line.move2side(0.5 + myLastWidth);204// calculate middle point205const Position middlePoint = line.getLineCenter();206// get closest points to middlePoint207Position posA = TAZA->getAdditionalGeometry().getShape().positionAtOffset2D(TAZA->getAdditionalGeometry().getShape().nearest_offset_to_point2D(middlePoint));208Position posB = TAZB->getAdditionalGeometry().getShape().positionAtOffset2D(TAZB->getAdditionalGeometry().getShape().nearest_offset_to_point2D(middlePoint));209// check positions210if (posA == Position::INVALID) {211posA = TAZA->getAdditionalGeometry().getShape().front();212}213if (posB == Position::INVALID) {214posB = TAZB->getAdditionalGeometry().getShape().front();215}216// update geometry217if (posA.distanceTo(posB) < 1) {218myTAZRelGeometry.updateGeometry({posA - 0.5, posB + 0.5});219} else {220myTAZRelGeometry.updateGeometry({posA, posB});221}222// update center geometry223myTAZRelGeometryCenter.updateGeometry(line);224}225// add into grid again226myNet->addGLObjectIntoGrid(this);227}228229230Position231GNETAZRelData::getPositionInView() const {232return getParentAdditionals().front()->getAttributePosition(SUMO_ATTR_CENTER);233}234235236void237GNETAZRelData::writeGenericData(OutputDevice& device) const {238// open device239device.openTag(SUMO_TAG_TAZREL);240// write from241device.writeAttr(SUMO_ATTR_FROM, getParentAdditionals().front()->getID());242// write to243device.writeAttr(SUMO_ATTR_TO, getParentAdditionals().back()->getID());244// iterate over attributes245for (const auto& attribute : getParametersMap()) {246// write attribute (don't use writeParams)247device.writeAttr(attribute.first, attribute.second);248}249// close device250device.closeTag();251}252253254bool255GNETAZRelData::isGenericDataValid() const {256return true;257}258259260std::string261GNETAZRelData::getGenericDataProblem() const {262return "";263}264265266void267GNETAZRelData::fixGenericDataProblem() {268throw InvalidArgument(getTagStr() + " cannot fix any problem");269}270271272void273GNETAZRelData::drawGL(const GUIVisualizationSettings& s) const {274// draw boundaries275GLHelper::drawBoundary(s, getCenteringBoundary());276// draw TAZRels277if (drawTAZRel()) {278// fixed detail level because tazRelations need high detail when zoomed out279const auto d = GUIVisualizationSettings::Detail::Level1;280// draw geometry only if we'rent in drawForObjectUnderCursor mode281if (!s.drawForViewObjectsHandler) {282const auto& color = setColor(s);283// get flag for only draw contour284const bool onlyDrawContour = !isGenericDataVisible();285// push matrix286GLHelper::pushMatrix();287// translate to front288drawInLayer(GLO_TAZ + 1);289GLHelper::setColor(color);290// check if update lastWidth291const double selectionScale = isAttributeCarrierSelected() ? s.selectorFrameScale : 1;292const double width = (onlyDrawContour ? 0.1 : 0.5 * s.tazRelWidthExaggeration * selectionScale293* s.dataScaler.getScheme().getColor(getScaleValue(s, s.dataScaler.getActive())));294if (width != myLastWidth) {295myLastWidth = width;296}297// draw geometry298if (onlyDrawContour) {299// draw depending of TAZRelDrawing300if (myNet->getViewNet()->getDataViewOptions().TAZRelDrawing()) {301GUIGeometry::drawGeometry(d, myTAZRelGeometryCenter, width);302} else {303GUIGeometry::drawGeometry(d, myTAZRelGeometry, width);304}305} else {306// draw depending of TAZRelDrawing307const GUIGeometry& geom = (myNet->getViewNet()->getDataViewOptions().TAZRelDrawing()308? myTAZRelGeometryCenter : myTAZRelGeometry);309GUIGeometry::drawGeometry(d, geom, width);310GLHelper::drawTriangleAtEnd(311*(geom.getShape().end() - 2),312*(geom.getShape().end() - 1),3131.5 + width, 1.5 + width, 0.5 + width);314}315// pop matrix316GLHelper::popMatrix();317// draw dotted contour318myTAZRelDataContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);319}320if (myNet->getViewNet()->getDataViewOptions().TAZRelDrawing()) {321// calculate contour and draw dotted geometry322myTAZRelDataContour.calculateContourExtrudedShape(s, d, this, myTAZRelGeometryCenter.getShape(), getType(),3230.5, 1, true, true, 0, nullptr, nullptr);324} else {325// calculate contour and draw dotted geometry326myTAZRelDataContour.calculateContourExtrudedShape(s, d, this, myTAZRelGeometry.getShape(), getType(),3270.5, 1, true, true, 0, nullptr, nullptr);328}329}330}331332333bool334GNETAZRelData::setFunctionalColor(int activeScheme, RGBColor& col) const {335switch (activeScheme) {336case 2: { // origin taz337const GNETAZ* from = dynamic_cast<const GNETAZ*>(getParentAdditionals().front());338col = from->getShapeColor();339return true;340}341case 3: { // destination taz342const GNETAZ* to = dynamic_cast<const GNETAZ*>(getParentAdditionals().back());343col = to->getShapeColor();344return true;345}346default:347return false;348}349}350351void352GNETAZRelData::computePathElement() {353// nothing to compute354}355356357void358GNETAZRelData::drawLanePartialGL(const GUIVisualizationSettings& /*s*/, const GNESegment* /*segment*/, const double /*offsetFront*/) const {359// nothing to draw360}361362363void364GNETAZRelData::drawJunctionPartialGL(const GUIVisualizationSettings& /*s*/, const GNESegment* /*segment*/, const double /*offsetFront*/) const {365// nothing to draw366}367368369GNELane*370GNETAZRelData::getFirstPathLane() const {371return nullptr;372}373374375GNELane*376GNETAZRelData::getLastPathLane() const {377return nullptr;378}379380381Boundary382GNETAZRelData::getCenteringBoundary() const {383Boundary b;384// add two shapes385b.add(myTAZRelGeometry.getShape().getBoxBoundary());386b.add(myTAZRelGeometryCenter.getShape().getBoxBoundary());387b.grow(20);388return b;389}390391392std::string393GNETAZRelData::getAttribute(SumoXMLAttr key) const {394switch (key) {395case SUMO_ATTR_ID:396if (getParentAdditionals().size() == 1) {397return getPartialID() + getParentAdditionals().front()->getID();398} else {399return getPartialID() + (getParentAdditionals().front()->getID() + "->" + getParentAdditionals().back()->getID());400}401case SUMO_ATTR_FROM:402return getParentAdditionals().front()->getID();403case SUMO_ATTR_TO:404return getParentAdditionals().back()->getID();405case GNE_ATTR_DATASET:406return myDataIntervalParent->getDataSetParent()->getID();407case SUMO_ATTR_BEGIN:408return myDataIntervalParent->getAttribute(SUMO_ATTR_BEGIN);409case SUMO_ATTR_END:410return myDataIntervalParent->getAttribute(SUMO_ATTR_END);411default:412return getCommonAttribute(key);413}414}415416417double418GNETAZRelData::getAttributeDouble(SumoXMLAttr key) const {419return getCommonAttributeDouble(key);420}421422423void424GNETAZRelData::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {425if (value == getAttribute(key)) {426return; //avoid needless changes, later logic relies on the fact that attributes have changed427}428switch (key) {429case SUMO_ATTR_FROM:430case SUMO_ATTR_TO:431GNEChange_Attribute::changeAttribute(this, key, value, undoList);432break;433default:434setCommonAttribute(key, value, undoList);435break;436}437}438439440bool441GNETAZRelData::isValid(SumoXMLAttr key, const std::string& value) {442switch (key) {443case SUMO_ATTR_FROM:444case SUMO_ATTR_TO:445return SUMOXMLDefinitions::isValidNetID(value) &&446(myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_TAZ, value, false) != nullptr);447default:448return isCommonAttributeValid(key, value);449}450}451452453bool GNETAZRelData::isAttributeEnabled(SumoXMLAttr key) const {454switch (key) {455case SUMO_ATTR_ID:456return false;457default:458return true;459}460}461462463std::string464GNETAZRelData::getPopUpID() const {465return getTagStr();466}467468469std::string470GNETAZRelData::getHierarchyName() const {471if (getParentAdditionals().size() == 1) {472return getTagStr() + ": " + getParentAdditionals().front()->getID();473} else {474return getTagStr() + ": " + getParentAdditionals().front()->getID() + "->" + getParentAdditionals().back()->getID();475}476}477478479bool480GNETAZRelData::drawTAZRel() const {481const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();482// first check supermode483if (!myNet->getViewNet()->getEditModes().isCurrentSupermodeData()) {484return false;485}486// check TAZRelFrame487if (myNet->getViewParent()->getTAZRelDataFrame()->shown()) {488// check dataSet489const GNEDataSet* dataSet = myNet->getViewParent()->getTAZRelDataFrame()->getDataSetSelector()->getDataSet();490if (dataSet && (myDataIntervalParent->getDataSetParent() != dataSet)) {491return false;492}493// check interval494const GNEDataInterval* dataInterval = myNet->getViewParent()->getTAZRelDataFrame()->getIntervalSelector()->getDataInterval();495if (dataInterval && (myDataIntervalParent != dataInterval)) {496return false;497}498}499// check if both draw TAZRel checkBox are disabled500if (!myNet->getViewNet()->getDataViewOptions().TAZRelOnlyFrom() && !myNet->getViewNet()->getDataViewOptions().TAZRelOnlyTo()) {501return false;502}503// check if we're inspecting a TAZ504if ((myNet->getViewNet()->getEditModes().dataEditMode == DataEditMode::DATA_INSPECT) &&505inspectedElements.isInspectingSingleElement() && (inspectedElements.getFirstAC()->getTagProperty()->getTag() == SUMO_TAG_TAZ)) {506// ignore TAZRels with one TAZParent507if (getParentAdditionals().size() == 2) {508if ((getParentAdditionals().front() == inspectedElements.getFirstAC()) &&509myNet->getViewNet()->getDataViewOptions().TAZRelOnlyFrom()) {510return true;511} else if ((getParentAdditionals().back() == inspectedElements.getFirstAC()) &&512myNet->getViewNet()->getDataViewOptions().TAZRelOnlyTo()) {513return true;514} else {515return false;516}517}518}519return true;520}521522523void524GNETAZRelData::setAttribute(SumoXMLAttr key, const std::string& value) {525switch (key) {526case SUMO_ATTR_FROM: {527// replace first TAZ Parent528replaceParentTAZElement(0, value);529// update geometry530updateGeometry();531break;532}533case SUMO_ATTR_TO: {534// replace second TAZ Parent535replaceParentTAZElement(1, value);536// update geometry537updateGeometry();538break;539}540default:541setCommonAttribute(key, value);542if (!isTemplate()) {543myDataIntervalParent->getDataSetParent()->updateAttributeColors();544}545break;546}547// mark interval toolbar for update548if (!isTemplate()) {549myNet->getViewNet()->getIntervalBar().markForUpdate();550}551}552553/****************************************************************************/554555556