From 33dc4ae8acbbaab7047fa0dd03662cb975ddb753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Donk=C3=B3?= Date: Thu, 12 Mar 2026 12:43:40 +0100 Subject: [PATCH] feat: manipulate show origin via takeoff positions --- .../map/interactions/TransformFeatures.js | 4 ++- src/features/selection/selectors.ts | 21 +++++++++++++++- src/model/openlayers.js | 7 +++++- src/views/map/MapView.jsx | 25 ++++++++++++++++--- src/views/map/layers/mission-info.jsx | 9 +++++-- 5 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/components/map/interactions/TransformFeatures.js b/src/components/map/interactions/TransformFeatures.js index 301b28b3f..75f082cbf 100644 --- a/src/components/map/interactions/TransformFeatures.js +++ b/src/components/map/interactions/TransformFeatures.js @@ -21,6 +21,7 @@ import { getCenterOfFirstPointsOfTrajectoriesInWorldCoordinates } from '~/featur import { GROSS_CONVEX_HULL_AREA_ID, globalIdToAreaId, + isHomePositionId, isOriginId, } from '~/model/identifiers'; /** @@ -141,7 +142,8 @@ export class TransformFeaturesInteraction extends PointerInteraction { // investigate whether there is a way around it if ( globalIdToAreaId(this.lastFeature_.getId()) === - GROSS_CONVEX_HULL_AREA_ID + GROSS_CONVEX_HULL_AREA_ID || + isHomePositionId(this.lastFeature_.getId()) ) { const state = store.getState(); diff --git a/src/features/selection/selectors.ts b/src/features/selection/selectors.ts index daba51876..e909f34da 100644 --- a/src/features/selection/selectors.ts +++ b/src/features/selection/selectors.ts @@ -1,6 +1,12 @@ import { createSelector } from '@reduxjs/toolkit'; +import { + areaIdToGlobalId, + GROSS_CONVEX_HULL_AREA_ID, + homePositionIdToGlobalId, +} from '~/model/identifiers'; -import { type AppSelector } from '~/store/reducers'; +// import { getMissionMapping } from '~/features/mission/selectors'; +import { type RootState, type AppSelector } from '~/store/reducers'; import { rejectNullish } from '~/utils/arrays'; import { type Identifier } from '~/utils/collections'; @@ -14,6 +20,19 @@ import { type Identifier } from '~/utils/collections'; export const getSelection: AppSelector = (state) => state.selection.ids; +export const getVirtualSelection: AppSelector = createSelector( + getSelection, + // getMissionMapping, // TODO: This causes a dependency cycle + (state: RootState) => state.mission.mapping, + (selection, mapping) => + selection.includes(areaIdToGlobalId(GROSS_CONVEX_HULL_AREA_ID)) + ? [ + ...selection, + ...mapping.map((_, i) => String(i)).map(homePositionIdToGlobalId), + ] + : selection +); + /** * Selector factory that creates a selector that returns true if and only if a * feature with the given ID is selected. diff --git a/src/model/openlayers.js b/src/model/openlayers.js index 61f47864c..4767b6e7e 100644 --- a/src/model/openlayers.js +++ b/src/model/openlayers.js @@ -31,6 +31,7 @@ import { GROSS_CONVEX_HULL_AREA_ID, isAreaId, isFeatureId, + isHomePositionId, isMissionItemId, isOriginId, MAP_ORIGIN_ID, @@ -66,7 +67,11 @@ export function isFeatureTransformable(object) { const id = object.getId(); return ( - isFeatureId(id) || isAreaId(id) || isOriginId(id) || isMissionItemId(id) + isFeatureId(id) || + isAreaId(id) || + isOriginId(id) || + isMissionItemId(id) || + isHomePositionId(id) ); } diff --git a/src/views/map/MapView.jsx b/src/views/map/MapView.jsx index ceb321708..b9cb6cd13 100644 --- a/src/views/map/MapView.jsx +++ b/src/views/map/MapView.jsx @@ -38,7 +38,10 @@ import { getSelectedTool } from '~/features/map/tools'; import { updateMapViewSettings } from '~/features/map/view'; import { addNewMissionItem } from '~/features/mission/actions'; import { getGeofencePolygonId } from '~/features/mission/selectors'; -import { getSelection } from '~/features/selection/selectors'; +import { + getSelection, + getVirtualSelection, +} from '~/features/selection/selectors'; import { addToSelection, removeFromSelection, @@ -49,7 +52,12 @@ import NearestItemTooltip from '~/features/session/NearestItemTooltip'; import { setFeatureIdForTooltip } from '~/features/session/slice'; import { getFollowMapSelectionInUAVDetailsPanel } from '~/features/uavs/selectors'; import mapViewManager from '~/mapViewManager'; -import { featureIdToGlobalId } from '~/model/identifiers'; +import { + areaIdToGlobalId, + featureIdToGlobalId, + GROSS_CONVEX_HULL_AREA_ID, + isHomePositionId, +} from '~/model/identifiers'; import { canLayerTriggerTooltip, getVisibleEditableLayers, @@ -646,7 +654,15 @@ class MapViewPresentation extends React.Component { toggle: toggleInSelection, }; const action = actionMapping[mode] || setSelection; - const ids = features ? features.map((feature) => feature.getId()) : []; + const rawIds = features ? features.map((feature) => feature.getId()) : []; + + const ids = rawIds.some(isHomePositionId) + ? [ + ...rawIds.filter((id) => !isHomePositionId(id)), + areaIdToGlobalId(GROSS_CONVEX_HULL_AREA_ID), + ] + : rawIds; + if (action === setSelection || (ids && ids.length > 0)) { this.props.dispatch(action(ids)); } @@ -731,7 +747,8 @@ const MapView = connect( selectedFeatures: getSelectedFeatureIds(state), selectedTool: getSelectedTool(state), - selection: getSelection(state), + // selection: getSelection(state), + selection: getVirtualSelection(state), uavDetailsPanelFollowsSelection: getFollowMapSelectionInUAVDetailsPanel(state), diff --git a/src/views/map/layers/mission-info.jsx b/src/views/map/layers/mission-info.jsx index 4fdde74b9..f92ef1d23 100644 --- a/src/views/map/layers/mission-info.jsx +++ b/src/views/map/layers/mission-info.jsx @@ -41,7 +41,10 @@ import { getMissionItemsWithCoordinatesInOrder, getSelectedMissionIndicesForTrajectoryDisplay, } from '~/features/mission/selectors'; -import { getSelection } from '~/features/selection/selectors'; +import { + getSelection, + getVirtualSelection, +} from '~/features/selection/selectors'; import { getConvexHullOfShowInWorldCoordinates, getOutdoorShowOrientation, @@ -638,6 +641,7 @@ const MissionInfoVectorSource = ({ ? formatMissionId(homePositions.length - 1).length * TAKEOFF_LANDING_POSITION_CHARACTER_WIDTH : 0, + selection, }), landingPositionPoints(landingPositions, { minimumDistanceBetweenPositions: minimumDistanceBetweenLandingPositions, @@ -752,7 +756,8 @@ export const MissionInfoLayer = connect( state, MissionItemType.RETURN_TO_HOME ), - selection: getSelection(state), + // selection: getSelection(state), + selection: getVirtualSelection(state), uavIdsForTrajectories: layer?.parameters?.showTrajectoriesOfSelection ? getSelectedUAVIdsForTrajectoryDisplay(state) : undefined,