Path: blob/main/src/utils/gui/div/GUIViewObjectsHandler.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 GUIViewObjectsHandler.cpp14/// @author Pablo Alvarez Lopez15/// @date Jun 2216///17// class used for handle objects over view18/****************************************************************************/19#include <config.h>20#include <algorithm>2122#include <utils/shapes/Shape.h>2324#include "GUIViewObjectsHandler.h"252627// ===========================================================================28// method definitions29// ===========================================================================3031GUIViewObjectsHandler::GUIViewObjectsHandler() {}323334void35GUIViewObjectsHandler::reset() {36// reset recompute boundaries37recomputeBoundaries = GLO_NETWORK;38// clear objects containers39mySortedSelectedObjects.clear();40mySelectedObjects.clear();41myNumberOfSelectedObjects = 0;42myRedrawPathElements.clear();43// reset marked elements44myMergingJunctions.clear();45markedEdge = nullptr;46markedLane = nullptr;47markedTAZ = nullptr;48markedRoute = nullptr;49markedFirstGeometryPoint = nullptr;50markedSecondGeometryPoint = nullptr;51}525354const Position&55GUIViewObjectsHandler::getSelectionPosition() const {56return mySelectionPosition;57}585960const Triangle&61GUIViewObjectsHandler::getSelectionTriangle() const {62return mySelectionTriangle;63}646566void67GUIViewObjectsHandler::setSelectionPosition(const Position& pos) {68// set position selection69mySelectionPosition = pos;70// invalidate selection triangle71mySelectionTriangle = Triangle::INVALID;72}737475void76GUIViewObjectsHandler::setSelectionTriangle(const Triangle& triangle) {77// invalidate position selection78mySelectionPosition = Position::INVALID;79// set selection triangle80mySelectionTriangle = triangle;81}828384bool85GUIViewObjectsHandler::selectingUsingRectangle() const {86return mySelectionTriangle != Triangle::INVALID;87}888990bool91GUIViewObjectsHandler::checkBoundaryParentObject(const GUIGlObject* GLObject, const double layer,92const GUIGlObject* parent) {93// first check if we're selecting for boundary94if (mySelectionTriangle == Triangle::INVALID) {95return false;96}97// try to find parent in seleted object98auto finder = mySelectedObjects.find(parent);99// if parent was found and was inserted with full boundary, insert it100if (finder != mySelectedObjects.end() && finder->second.first && !isObjectSelected(GLObject)) {101// insert element with full boundary102return selectObject(GLObject, layer, false, true, nullptr);103} else {104return false;105}106}107108109bool110GUIViewObjectsHandler::checkCircleObject(const GUIVisualizationSettings::Detail d, const GUIGlObject* GLObject,111const Position& center, const double radius, const double layer) {112// first check that object doesn't exist113if (isObjectSelected(GLObject)) {114return false;115} else {116// declare squared radius117const double squaredRadius = (radius * radius);118// continue depending if we're selecting a position or a boundary119if (selectingUsingRectangle()) {120// continue depending of detail level121if (d <= GUIVisualizationSettings::Detail::PreciseSelection) {122// check if triangle intersect with circle123if (mySelectionTriangle.intersectWithCircle(center, radius)) {124return selectObject(GLObject, layer, false, false, nullptr);125} else {126return false;127}128} else {129// simply check if center is within triangle130if (mySelectionTriangle.isPositionWithin(center)) {131return selectObject(GLObject, layer, false, false, nullptr);132} else {133return false;134}135}136} else if (mySelectionPosition != Position::INVALID) {137// check distance between selection position and center138if (mySelectionPosition.distanceSquaredTo2D(center) <= squaredRadius) {139return selectObject(GLObject, layer, false, false, nullptr);140} else {141return false;142}143} else {144return false;145}146}147}148149150bool151GUIViewObjectsHandler::checkGeometryPoint(const GUIVisualizationSettings::Detail d, const GUIGlObject* GLObject,152const PositionVector& shape, const int index, const double layer, const double radius) {153// obtain geometry point pos154const auto geometryPointPos = shape[index];155// declare squared radius156const double squaredRadius = (radius * radius);157// continue depending if we're selecting a position or a boundary158if (selectingUsingRectangle()) {159// continue depending of detail level160if (d <= GUIVisualizationSettings::Detail::PreciseSelection) {161// calculate boundary for geometry point162Boundary geometryPointBoundary;163geometryPointBoundary.add(geometryPointPos);164// check if center is within mySelectionBoundary165if (mySelectionTriangle.intersectWithCircle(geometryPointPos, radius)) {166return selectGeometryPoint(GLObject, index, layer);167} else {168return false;169}170} else {171// simply check if center is within triangle172if (mySelectionTriangle.isPositionWithin(geometryPointPos)) {173return selectObject(GLObject, layer, false, false, nullptr);174} else {175return false;176}177}178} else if (mySelectionPosition != Position::INVALID) {179// check distance between selection position and center180if (mySelectionPosition.distanceSquaredTo2D(geometryPointPos) <= squaredRadius) {181return selectGeometryPoint(GLObject, index, layer);182} else {183return false;184}185} else {186return false;187}188}189190191bool192GUIViewObjectsHandler::checkPositionOverShape(const GUIVisualizationSettings::Detail d, const GUIGlObject* GLObject,193const PositionVector& shape, const double layer, const double distance) {194// only process if we're selecting a precise position195if ((mySelectionPosition != Position::INVALID) && (d <= GUIVisualizationSettings::Detail::PreciseSelection)) {196// obtain nearest position over shape197const auto nearestOffset = shape.nearest_offset_to_point2D(mySelectionPosition);198const auto nearestPos = shape.positionAtOffset2D(nearestOffset);199// check distance nearest position and pos200if (mySelectionPosition.distanceSquaredTo2D(nearestPos) <= (distance * distance)) {201return selectPositionOverShape(GLObject, nearestPos, layer, nearestOffset);202} else {203return false;204}205} else {206return false;207}208}209210211bool212GUIViewObjectsHandler::checkShapeObject(const GUIGlObject* GLObject, const PositionVector& shape, const Boundary& shapeBoundary,213const double layer, const GNESegment* segment) {214// first check that object doesn't exist215if (isObjectSelected(GLObject)) {216return false;217} else if (selectingUsingRectangle()) {218// avoid invalid boundaries219if (!shapeBoundary.isInitialised()) {220return false;221}222// check if triangle contains the given shape223if (mySelectionTriangle.intersectWithShape(shape, shapeBoundary)) {224return selectObject(GLObject, layer, false, true, segment);225}226// no intersection, then return false227return false;228} else if (mySelectionPosition != Position::INVALID) {229// check if selection position is around shape230if (shape.around(mySelectionPosition)) {231return selectObject(GLObject, layer, false, false, segment);232} else {233return false;234}235} else {236return false;237}238}239240241bool242GUIViewObjectsHandler::selectObject(const GUIGlObject* GLObject, const double layer, const bool checkDuplicated,243const bool fullBoundary, const GNESegment* segment) {244// first check that object doesn't exist245if (checkDuplicated && isObjectSelected(GLObject)) {246return false;247} else {248auto& layerContainer = mySortedSelectedObjects[layer * -1];249layerContainer.append(ObjectContainer(GLObject));250mySelectedObjects[GLObject] = std::make_pair(fullBoundary, segment);251myNumberOfSelectedObjects++;252return true;253}254}255256257bool258GUIViewObjectsHandler::selectGeometryPoint(const GUIGlObject* GLObject, const int newIndex,259const double layer) {260// avoid to insert duplicated elements261for (auto& elementLayer : mySortedSelectedObjects) {262for (auto& element : elementLayer.second) {263if (element.object == GLObject) {264// avoid double points265for (auto& index : element.geometryPoints) {266if (index == newIndex) {267return false;268}269}270// add new index271element.geometryPoints.push_back(newIndex);272return true;273}274}275}276// no element found then add it277auto& layerContainer = mySortedSelectedObjects[layer * -1];278layerContainer.append(ObjectContainer(GLObject));279layerContainer.back().geometryPoints.push_back(newIndex);280mySelectedObjects[GLObject] = std::make_pair(false, nullptr);281myNumberOfSelectedObjects++;282return true;283}284285286bool287GUIViewObjectsHandler::selectPositionOverShape(const GUIGlObject* GLObject, const Position& pos, const double layer,288const double offset) {289// avoid to insert duplicated elements290for (auto& elementLayer : mySortedSelectedObjects) {291for (auto& element : elementLayer.second) {292if (element.object == GLObject) {293if (element.posOverShape != Position::INVALID) {294return false;295} else {296// set position and offset over shape297element.posOverShape = pos;298element.offset = offset;299return true;300}301}302}303}304// no element found then add it305auto& layerContainer = mySortedSelectedObjects[layer * -1];306layerContainer.append(ObjectContainer(GLObject));307layerContainer.back().posOverShape = pos;308mySelectedObjects[GLObject] = std::make_pair(false, nullptr);309myNumberOfSelectedObjects++;310return true;311}312313314bool315GUIViewObjectsHandler::isObjectSelected(const GUIGlObject* GLObject) const {316return mySelectedObjects.find(GLObject) != mySelectedObjects.end();317}318319320bool321GUIViewObjectsHandler::checkRectangleSelection(const GUIVisualizationSettings& s, const GUIGlObject* GLObject,322const double layer, const GUIGlObject* parent) {323if (!s.drawForRectangleSelection) {324return false;325} else {326return checkBoundaryParentObject(GLObject, layer, parent);327}328}329330331const GUIViewObjectsHandler::GLObjectsSortedContainer&332GUIViewObjectsHandler::getSelectedObjects() const {333return mySortedSelectedObjects;334}335336337const GNESegment*338GUIViewObjectsHandler::getSelectedSegment(const GUIGlObject* GLObject) const {339auto finder = mySelectedObjects.find(GLObject);340if (finder != mySelectedObjects.end()) {341return finder->second.second;342} else {343return nullptr;344}345}346347348const std::vector<int>&349GUIViewObjectsHandler::getSelectedGeometryPoints(const GUIGlObject* GLObject) const {350// avoid to insert duplicated elements351for (auto& elementLayer : mySortedSelectedObjects) {352for (auto& element : elementLayer.second) {353if (element.object == GLObject) {354return element.geometryPoints;355}356}357}358return myEmptyGeometryPoints;359}360361362const Position&363GUIViewObjectsHandler::getSelectedPositionOverShape(const GUIGlObject* GLObject) const {364// avoid to insert duplicated elements365for (auto& elementLayer : mySortedSelectedObjects) {366for (auto& element : elementLayer.second) {367if (element.object == GLObject) {368return element.posOverShape;369}370}371}372return Position::INVALID;373}374375376int377GUIViewObjectsHandler::getNumberOfSelectedObjects() const {378return myNumberOfSelectedObjects;379}380381382void383GUIViewObjectsHandler::reverseSelectedObjects() {384for (auto& layerContainer : mySortedSelectedObjects) {385std::reverse(layerContainer.second.begin(), layerContainer.second.end());386}387}388389390const std::set<const GNEPathElement*>&391GUIViewObjectsHandler::getRedrawPathElements() const {392return myRedrawPathElements;393}394395396bool397GUIViewObjectsHandler::isPathElementMarkForRedraw(const GNEPathElement* pathElement) const {398if (myRedrawPathElements.empty()) {399return false;400} else {401return myRedrawPathElements.find(pathElement) != myRedrawPathElements.end();402}403}404405406void407GUIViewObjectsHandler::addToRedrawPathElements(const GNEPathElement* pathElement) {408myRedrawPathElements.insert(pathElement);409}410411412const std::vector<const GNEJunction*>&413GUIViewObjectsHandler::getMergingJunctions() const {414return myMergingJunctions;415}416417418bool419GUIViewObjectsHandler::addMergingJunctions(const GNEJunction* junction) {420// avoid insert duplicated junctions421for (const auto mergingJunctions : myMergingJunctions) {422if (mergingJunctions == junction) {423return false;424}425}426myMergingJunctions.push_back(junction);427return true;428}429430431void432GUIViewObjectsHandler::updateFrontObject(const GUIGlObject* GLObject) {433ObjectContainer frontElement(nullptr);434// extract element435for (auto& elementLayer : mySortedSelectedObjects) {436auto it = elementLayer.second.begin();437while (it != elementLayer.second.end()) {438if (it->object == GLObject) {439// copy element to front element440frontElement.object = it->object;441frontElement.geometryPoints = it->geometryPoints;442// remove element from myElementsUnderCursor443it = elementLayer.second.erase(it);444} else {445it++;446}447}448}449// add element again wit a new layer450if (frontElement.object) {451mySortedSelectedObjects[(double)GLO_FRONTELEMENT].append(frontElement);452}453}454455456void457GUIViewObjectsHandler::isolateEdgeGeometryPoints() {458// declare object container for edge459ObjectContainer edgeWithGeometryPoints(nullptr);460// check if there are edges with geometry points in mySortedSelectedObjects461for (auto& elementLayer : mySortedSelectedObjects) {462for (auto element : elementLayer.second) {463if ((element.object->getType() == GLO_EDGE) && (element.geometryPoints.size() > 0)) {464edgeWithGeometryPoints = element;465}466}467}468// continue if something was found469if (edgeWithGeometryPoints.object != nullptr) {470// clear all selected objects471mySortedSelectedObjects.clear();472// add edge with geometry points as front element473mySortedSelectedObjects[(double)GLO_FRONTELEMENT].append(edgeWithGeometryPoints);474}475}476477478void479GUIViewObjectsHandler::ObjectContainerLayer::append(const ObjectContainer& objectContainer) {480if (capacity() == size()) {481if (size() < 10) {482reserve(size() + 10);483} else {484reserve(size() + 1000);485}486}487push_back(objectContainer);488}489490/****************************************************************************/491492493