useUpdateAllTrainCarsCoordinates.tsx

mail@pastecode.io avatar
unknown
plain_text
7 months ago
6.1 kB
2
Indexable
Never
import {useEffect, useMemo, useRef} from 'react';
import {useSelector, useDispatch} from 'react-redux';
import GetLocation from 'react-native-get-location';

import {getConsistTrain} from '@Redux/train/selectors';
import {
  getRunningStatus,
  getUseSimulatedTestData,
  getUseTestData,
} from '@Redux/common/selectors';
import {getTrackGroupData} from '@Redux/track/selectors';

import {
  setAllTrainCarsInfo,
  setAngle,
  setPosition,
  setLocationData,
  getLiveDemoData,
  setTrainLineData,
} from '@Redux/info/actions';
import {setOutOfTrack} from '@Redux/common/actions';

import {getLocationData} from '@Redux/info/selectors';

import {getAngle} from '@Utils/getCorridorSegmentDetails';
import {getTrainCarsDetails, getLineEndCoord} from '@Utils/computeTrainData';
import {getDistanceToTrack} from '@Utils/geometryHelper';
import {getCleanedGpsPoint} from '@Utils/cleanGpsData';
import {generateSimulatedGpsPoints} from '@Utils/simulationModeHelper';

import {
  DEFAULT_LOCOMOTIVE_LENGTH_IN_MILES,
  DEFAULT_RAIL_CAR_LENGTH_IN_MILES,
  FT_TO_MILE,
  SNAP_TO_TRACK_DISTANCE,
} from '@Constants';

const useUpdateAllTrainCarsCoordinates = (
  trackCoords: any[][],
  track: any[],
  currentTripKey: string,
) => {
  const dispatch = useDispatch();

  const runningStatus = useSelector(getRunningStatus);
  const useTestData = useSelector(getUseTestData);
  const useSimulatedTestData = useSelector(getUseSimulatedTestData);
  const trackGroupData = useSelector(state => getTrackGroupData(state));
  const speedLimitList =
    trackGroupData[currentTripKey]?.data?.trackSpeedLimit || [];

  const absoluteStartTrackDistanceMiles =
    (track?.length > 0 && track[0]?.absoluteStartTrackDistanceMiles) || 0;
  const simulatedLocationData = useTestData
    ? useMemo(
        () =>
          generateSimulatedGpsPoints(
            track,
            trackCoords,
            speedLimitList,
            absoluteStartTrackDistanceMiles,
          ),
        [track, trackCoords],
      )
    : null;

  const locationData = useSelector(state => getLocationData(state));

  // Get consist data and create train cars info
  const consistTrain = useSelector(getConsistTrain);

  const trainLengthInFt = consistTrain?.totalLengthFt || 0;
  const trainLengthInMiles = trainLengthInFt * FT_TO_MILE;
  const locomotiveCount = consistTrain?.locomotiveCount || 1;
  const locomotivesLengthInMiles =
    locomotiveCount * DEFAULT_LOCOMOTIVE_LENGTH_IN_MILES;

  const trainCarsInfo: any = useMemo(() => {
    const locomotiveList = [...Array(consistTrain?.locomotiveCount || 0)].map(
      () => ({
        type: 'locomotive',
        carLengthInMiles: DEFAULT_LOCOMOTIVE_LENGTH_IN_MILES,
      }),
    );
    const carList = [...Array(consistTrain?.carCount || 0)].map(() => ({
      type: 'car',
      carLengthInMiles: DEFAULT_RAIL_CAR_LENGTH_IN_MILES,
    }));

    return [...locomotiveList, ...carList];
  }, [consistTrain]);

  const processTrainData = (location: any) => {
    const deviceCoord = [location.latitude, location.longitude];

    const withinSnapToTrackDistance =
      getDistanceToTrack(deviceCoord, trackCoords) <= SNAP_TO_TRACK_DISTANCE;

    // Apply cleaning algorithm if applicable
    if (withinSnapToTrackDistance) {
      const cleanCoord = getCleanedGpsPoint(deviceCoord, trackCoords);
      const angle = getAngle(cleanCoord, trackCoords);

      // Then compute start and end coordinates of train line
      const trainLineData = {
        locoStartCoord: cleanCoord,
        locoEndCoord: getLineEndCoord(
          cleanCoord,
          locomotivesLengthInMiles,
          trackCoords,
        ),
        trainEndCoord: getLineEndCoord(
          cleanCoord,
          trainLengthInMiles,
          trackCoords,
        ),
      };

      // Then compute info (coordinates, angle) of all train cars
      const updatedTrainCarsInfo = [
        {
          ...trainCarsInfo[0],
          coord: cleanCoord,
          angle,
        },
        ...trainCarsInfo.slice(1),
      ];

      const newTrainCarsInfo = getTrainCarsDetails(
        updatedTrainCarsInfo,
        trackCoords,
      );

      dispatch(setTrainLineData(trainLineData));
      dispatch(setAllTrainCarsInfo(newTrainCarsInfo));
      dispatch(setPosition(cleanCoord));
      dispatch(setAngle(angle));
      dispatch(setOutOfTrack(false));
    } else {
      dispatch(setPosition(deviceCoord));
      dispatch(setAngle(null));
      dispatch(setOutOfTrack(true));
    }
  };

  // Get location data from device
  const getDeviceLocationData = () => {
    try {
      GetLocation.getCurrentPosition({
        enableHighAccuracy: true,
        timeout: 15000,
      })
        .then(location => {
          dispatch(setLocationData(location));
          processTrainData(location);
        })
        .catch(error => {
          console.log(error?.message || '');
        });
    } catch (error: any) {
      console.log(error?.message || '');
    }
  };

  const locationIndex = useRef(0);

  const getSimulatedLocationData = () => {
    if (!simulatedLocationData) {
      return;
    }
    if (!runningStatus) {
      return;
    }
    if (locationIndex.current > simulatedLocationData.length - 1) {
      return;
    }
    const location = simulatedLocationData[locationIndex.current];
    dispatch(setLocationData(location));
    processTrainData(location);
    locationIndex.current++;
  };

  const getLiveSimulatedLocationData = () => {
    dispatch(getLiveDemoData());
  };

  useEffect(() => {
    if (locationData && useSimulatedTestData) {
      processTrainData(locationData);
    }
  }, [locationData]);

  useEffect(() => {
    locationIndex.current = 0;
    let interval = setInterval(() => {
      if (useTestData) {
        getSimulatedLocationData();
      } else if (useSimulatedTestData) {
        getLiveSimulatedLocationData();
      } else {
        getDeviceLocationData();
      }
    }, 1000);
    return () => {
      clearInterval(interval);
    };
  }, [currentTripKey, runningStatus]);
};

export default useUpdateAllTrainCarsCoordinates;