Skip to content

Commit

Permalink
fix ponctual objects position computing
Browse files Browse the repository at this point in the history
  • Loading branch information
Akctarus committed Nov 22, 2023
1 parent 4e8db62 commit bc27d4f
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { WidgetProps } from '@rjsf/core';
import InputSNCF from 'common/BootstrapSNCF/InputSNCF';

export const CustomPosition: React.FC<WidgetProps> = (props) => {
const { schema, onChange, title, value } = props;
const POINT_NAME = 'point-parameter';

return (
<div key={`${POINT_NAME}-${schema.description}`}>
<p>{title}</p>
<InputSNCF
name={POINT_NAME}
id={`${POINT_NAME}-${schema.description}`}
value={value}
onChange={(e) => {
onChange(e.target.value);
}}
type="number"
min={0}
/>
</div>
);
};

export default CustomPosition;
20 changes: 15 additions & 5 deletions front/src/applications/editor/tools/pointEdition/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
TrackSectionEntity,
RouteEntity,
SignalEntity,
DetectorEntity,
BufferStopEntity,
} from 'types';
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import EditorForm from 'applications/editor/components/EditorForm';
Expand All @@ -38,12 +40,16 @@ import { getEditRouteState } from 'applications/editor/tools/routeEdition/utils'
import TOOL_TYPES from 'applications/editor/tools/toolTypes';
import { EditoastType } from 'applications/editor/tools/types';
import { getIsLoading } from 'reducers/main/mainSelector';
import length from '@turf/length';
import { CustomFlagSignalCheckbox } from './CustomFlagSignalCheckbox';
import { PointEditionState } from './types';
import { formatSignalingSystems } from './utils';
import { CustomPosition } from './CustomPosition';

export const POINT_LAYER_ID = 'pointEditionTool/new-entity';

type EditorPoint = BufferStopEntity | DetectorEntity | SignalEntity;

/**
* Generic component to show routes starting or ending from the edited waypoint:
*/
Expand Down Expand Up @@ -261,6 +267,9 @@ export const PointEditionLeftPanel: FC<{ type: EditoastType }> = <Entity extends
},
},
},
position: {
'ui:widget': CustomPosition,
},
}}
onSubmit={async (savedEntity) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -297,8 +306,8 @@ export const PointEditionLeftPanel: FC<{ type: EditoastType }> = <Entity extends
});
}
}}
onChange={(entity: Entity | SignalEntity) => {
const additionalUpdate: Partial<Entity> = {};
onChange={(entity: Entity | EditorPoint) => {
const additionalUpdate: Partial<EditorPoint> = {};
const additionalPropertiesUpdate: Partial<SignalEntity['properties']> = {};
const newPosition = entity.properties?.position;
const oldPosition = state.entity.properties?.position;
Expand All @@ -311,16 +320,17 @@ export const PointEditionLeftPanel: FC<{ type: EditoastType }> = <Entity extends
typeof oldPosition === 'number' &&
newPosition !== oldPosition
) {
const point = along(trackState.track, newPosition, { units: 'meters' });
const turfPosition =
(newPosition * (length(trackState.track) * 1000)) /
trackState.track.properties.length;
const point = along(trackState.track, turfPosition, { units: 'meters' });
additionalUpdate.geometry = point.geometry;
}

if (entity.objType === 'Signal' && entity.properties.logical_signals) {
additionalPropertiesUpdate.logical_signals = formatSignalingSystems(
entity as SignalEntity
);
}

setState({
...state,
entity: {
Expand Down
69 changes: 40 additions & 29 deletions front/src/applications/editor/tools/pointEdition/tool-factory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@ import { LAYER_TO_EDITOAST_DICT, LayerType } from '../types';
import { getNearestPoint } from '../../../../utils/mapHelper';
import { getPointEditionLeftPanel, POINT_LAYER_ID, PointEditionMessages } from './components';
import { PointEditionState } from './types';
import { NULL_GEOMETRY, BufferStopEntity, DetectorEntity, SignalEntity } from '../../../../types';
import {
NULL_GEOMETRY,
BufferStopEntity,
DetectorEntity,
SignalEntity,
TrackSectionEntity,
} from '../../../../types';
import { getEntity } from '../../data/api';
import { Tool } from '../editorContextTypes';
import { DEFAULT_COMMON_TOOL_STATE } from '../commonToolState';
import { approximateDistanceWithEditoastData } from '../utils';

type EditorPoint = BufferStopEntity | DetectorEntity | SignalEntity;
interface PointEditionToolParams<T extends EditorPoint> {
Expand All @@ -29,6 +36,14 @@ interface PointEditionToolParams<T extends EditorPoint> {
requiresAngle?: boolean;
}

export function calculateDistanceAlongTrack(track: Feature<LineString>, point: Point) {
const wrongPointOnTrack = nearestPointOnLine(track.geometry, point, { units: 'meters' });
return approximateDistanceWithEditoastData(
track as TrackSectionEntity,
wrongPointOnTrack.geometry
);
}

function getPointEditionTool<T extends EditorPoint>({
layer,
icon,
Expand Down Expand Up @@ -61,20 +76,6 @@ function getPointEditionTool<T extends EditorPoint>({
getInitialState,
actions: [
[
{
id: 'reset-entity',
icon: BiReset,
labelTranslationKey: `Editor.tools.${id}-edition.actions.reset-entity`,
onClick({ setState, state }) {
setState({
...getInitialState(),
entity: state.initialEntity,
});
},
isDisabled({ state }) {
return isEqual(state.entity, state.initialEntity);
},
},
{
id: 'new-entity',
icon: AiOutlinePlus,
Expand All @@ -83,6 +84,19 @@ function getPointEditionTool<T extends EditorPoint>({
setState(getInitialState());
},
},
{
id: 'reset-entity',
icon: BiReset,
labelTranslationKey: `Editor.tools.${id}-edition.actions.reset-entity`,
isDisabled({ state: { entity, initialEntity } }) {
return isEqual(entity, initialEntity);
},
onClick({ setState, state: { initialEntity } }) {
setState({
entity: cloneDeep(initialEntity),
});
},
},
],
[
{
Expand Down Expand Up @@ -116,6 +130,12 @@ function getPointEditionTool<T extends EditorPoint>({
],

// Interactions:
getCursor({ state }, { isDragging }) {
if (isDragging || !state.entity.geometry || isEqual(state.entity.geometry, NULL_GEOMETRY))
return 'move';
if (state.isHoveringTarget) return 'pointer';
return 'default';
},
onClickMap(_e, { setState, state, infraID, dispatch }) {
const { isHoveringTarget, entity, nearestPoint } = state;
if (entity.geometry && !isEqual(entity.geometry, NULL_GEOMETRY) && isHoveringTarget) {
Expand All @@ -125,7 +145,6 @@ function getPointEditionTool<T extends EditorPoint>({
entity: omit(entity, 'geometry') as T,
});
}

if ((!entity.geometry || isEqual(entity.geometry, NULL_GEOMETRY)) && nearestPoint) {
const newEntity = cloneDeep(entity);
newEntity.geometry = {
Expand All @@ -135,15 +154,13 @@ function getPointEditionTool<T extends EditorPoint>({
newEntity.properties = newEntity.properties || {};
newEntity.properties.track = nearestPoint.trackSectionID;

// retrieve the track section to be sure that the computation of the distance will be good
// we can't trust maplibre, because the stored gemetry is not necessary the real one
getEntity(infraID as number, newEntity.properties.track, 'TrackSection', dispatch).then(
(track) => {
newEntity.properties.position = nearestPointOnLine(
(track as Feature<LineString>).geometry,
newEntity.geometry as Point,
{ units: 'meters' }
).properties?.location;
const distanceAlongTrack = calculateDistanceAlongTrack(
track as TrackSectionEntity,
newEntity.geometry as Point
);
newEntity.properties.position = distanceAlongTrack;

setState({
...state,
Expand Down Expand Up @@ -244,12 +261,6 @@ function getPointEditionTool<T extends EditorPoint>({
getInteractiveLayers() {
return ['editor/geo/track-main', POINT_LAYER_ID];
},
getCursor({ state }, { isDragging }) {
if (isDragging || !state.entity.geometry || isEqual(state.entity.geometry, NULL_GEOMETRY))
return 'move';
if (state.isHoveringTarget) return 'pointer';
return 'default';
},

layersComponent,
leftPanelComponent: getPointEditionLeftPanel(LAYER_TO_EDITOAST_DICT[layer]),
Expand Down
16 changes: 11 additions & 5 deletions front/src/applications/editor/tools/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,19 @@ import { getEntity } from '../data/api';
* Since Turf and Editoast do not compute the lengths the same way (see #1751)
* we can have data "end" being larger than Turf's computed length, which
* throws an error. Until we find a way to get similar computations, we can
* approximate this way:
* approximate it with a rule of Three.
*
* This approximation is not good if the track is long.
*/
export function approximateDistanceWithEditoastData(track: TrackSectionEntity, point: Point) {
const distanceAlongTrack =
(length(lineSlice(track.geometry.coordinates[0], point, track)) * track.properties.length) /
length(track);
return distanceAlongTrack;
const wrongDistanceAlongTrack = length(lineSlice(track.geometry.coordinates[0], point, track));
const wrongTrackLength = length(track);
const realTrackLength = track.properties.length;

const distanceAlongTrack = (wrongDistanceAlongTrack * realTrackLength) / wrongTrackLength;

if (Math.abs(distanceAlongTrack - realTrackLength) < 0.1) return realTrackLength;
return Math.round(distanceAlongTrack * 100) / 100;
}

/** return the trackRanges near the mouse thanks to the hover event */
Expand Down

0 comments on commit bc27d4f

Please sign in to comment.