mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-24 18:46:40 +07:00
faster distance calc
This commit is contained in:
parent
2e9b332012
commit
34f98fb08b
8 changed files with 101 additions and 80 deletions
|
@ -18,7 +18,7 @@ import {
|
|||
LatLngLiteral
|
||||
} from "leaflet";
|
||||
|
||||
import { distKm, distToSegment, getPolyLength, pointInArea } from "~/utils/geom";
|
||||
import { distKmHaversine, distToSegment, getPolyLength, pointInArea } from "~/utils/geom";
|
||||
|
||||
interface InteractivePolylineOptions extends PolylineOptions {
|
||||
maxMarkers?: number;
|
||||
|
@ -271,11 +271,11 @@ export class InteractivePoly extends Polyline {
|
|||
const prev = this.markers[index];
|
||||
const next = this.markers[index + 1];
|
||||
|
||||
const initial_distance = distKm(prev.getLatLng(), next.getLatLng());
|
||||
const initial_distance = distKmHaversine(prev.getLatLng(), next.getLatLng());
|
||||
|
||||
const current_distance =
|
||||
((prev && distKm(prev.getLatLng(), current)) || 0) +
|
||||
((next && distKm(next.getLatLng(), current)) || 0);
|
||||
((prev && distKmHaversine(prev.getLatLng(), current)) || 0) +
|
||||
((next && distKmHaversine(next.getLatLng(), current)) || 0);
|
||||
|
||||
this.distance += current_distance - initial_distance;
|
||||
|
||||
|
@ -377,12 +377,12 @@ export class InteractivePoly extends Polyline {
|
|||
index <= this.markers.length + 1 ? this.markers[index + 1] : null;
|
||||
|
||||
const initial_distance =
|
||||
((prev && distKm(prev.getLatLng(), initial)) || 0) +
|
||||
((next && distKm(next.getLatLng(), initial)) || 0);
|
||||
((prev && distKmHaversine(prev.getLatLng(), initial)) || 0) +
|
||||
((next && distKmHaversine(next.getLatLng(), initial)) || 0);
|
||||
|
||||
const current_distance =
|
||||
((prev && distKm(prev.getLatLng(), current)) || 0) +
|
||||
((next && distKm(next.getLatLng(), current)) || 0);
|
||||
((prev && distKmHaversine(prev.getLatLng(), current)) || 0) +
|
||||
((next && distKmHaversine(next.getLatLng(), current)) || 0);
|
||||
|
||||
this.distance += current_distance - initial_distance;
|
||||
|
||||
|
@ -460,7 +460,7 @@ export class InteractivePoly extends Polyline {
|
|||
? latlngs[latlngs.length - 1]
|
||||
: latlngs[0];
|
||||
|
||||
this.distance += distKm(point, latlng);
|
||||
this.distance += distKmHaversine(point, latlng);
|
||||
this.fire("distancechange", { distance: this.distance });
|
||||
};
|
||||
|
||||
|
@ -505,10 +505,10 @@ export class InteractivePoly extends Polyline {
|
|||
const next = index <= latlngs.length + 1 ? latlngs[index + 1] : null;
|
||||
|
||||
const initial_distance =
|
||||
((prev && distKm(prev, current)) || 0) +
|
||||
((next && distKm(next, current)) || 0);
|
||||
((prev && distKmHaversine(prev, current)) || 0) +
|
||||
((next && distKmHaversine(next, current)) || 0);
|
||||
|
||||
const current_distance = (prev && next && distKm(prev, next)) || 0;
|
||||
const current_distance = (prev && next && distKmHaversine(prev, next)) || 0;
|
||||
|
||||
this.distance += current_distance - initial_distance;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { divIcon, LatLngLiteral, Layer, LayerGroup, Map, marker, Marker } from "leaflet";
|
||||
import { arrowClusterIcon, createArrow } from "~/utils/arrow";
|
||||
import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js';
|
||||
import { allwaysPositiveAngleDeg, angleBetweenPoints, distKm } from "~/utils/geom";
|
||||
import { allwaysPositiveAngleDeg, angleBetweenPoints, distKmHaversine } from "~/utils/geom";
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface KmMarksOptions {
|
||||
|
@ -43,7 +43,7 @@ class Component extends LayerGroup {
|
|||
if (index >= latlngs.length - 1) return dist;
|
||||
|
||||
const next = latlngs[index + 1];
|
||||
const diff = distKm(current, next);
|
||||
const diff = distKmHaversine(current, next);
|
||||
const sum = dist + diff;
|
||||
const rounded = Math.floor(sum / this.options.kmMarksStep) * this.options.kmMarksStep;
|
||||
const count = Math.floor((rounded - last_km_mark) / this.options.kmMarksStep);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Map, LayerGroup, Layer, FeatureGroup } from 'leaflet';
|
||||
import { Map, FeatureGroup, FitBoundsOptions } from 'leaflet';
|
||||
|
||||
export class MapContainer extends Map {
|
||||
constructor(props) {
|
||||
|
@ -21,8 +21,16 @@ export class MapContainer extends Map {
|
|||
const bounds = layers[i].getBounds();
|
||||
if (Object.keys(bounds).length == 2) return bounds;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
fitVisibleBounds = (options: FitBoundsOptions) => {
|
||||
const bounds = this.getVisibleBounds();
|
||||
|
||||
if (!bounds) return;
|
||||
this.fitBounds(bounds, options)
|
||||
}
|
||||
|
||||
public clickable = true;
|
||||
|
||||
public routeLayer = new FeatureGroup();
|
||||
|
|
|
@ -183,7 +183,7 @@ function* locationChangeSaga({ location }: ReturnType<typeof editorLocationChang
|
|||
if (!ready) return;
|
||||
|
||||
yield call(loadMapFromPath);
|
||||
MainMap.fitBounds(MainMap.getVisibleBounds(), { animate: true });
|
||||
MainMap.fitVisibleBounds({ animate: true });
|
||||
}
|
||||
|
||||
function* keyPressedSaga({ key, target }: ReturnType<typeof editorKeyPressed>) {
|
||||
|
|
|
@ -29,8 +29,7 @@ import {
|
|||
editorSetSave,
|
||||
editorClearAll,
|
||||
} from '~/redux/editor/actions';
|
||||
import { pushLoaderState, getUrlData, pushPath, replacePath } from '~/utils/history';
|
||||
import { searchSetSagaWorker } from '~/redux/user/sagas';
|
||||
import { pushLoaderState, getUrlData, pushPath } from '~/utils/history';
|
||||
import { getStoredMap, postMap } from '~/utils/api';
|
||||
import { Unwrap } from '~/utils/middleware';
|
||||
import { selectMap, selectMapProvider } from './selectors';
|
||||
|
@ -150,7 +149,7 @@ export function* mapInitSaga() {
|
|||
|
||||
yield call(loadMapFromPath);
|
||||
yield call(setReadySaga);
|
||||
MainMap.fitBounds(MainMap.getVisibleBounds(), { animate: false });
|
||||
MainMap.fitVisibleBounds({ animate: false });
|
||||
pushLoaderState(100);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
import { LatLng, LatLngLiteral, point, Point, PointExpression } from "leaflet";
|
||||
import { LatLng, LatLngLiteral, point, Point, PointExpression } from 'leaflet';
|
||||
|
||||
interface ILatLng {
|
||||
lat: number,
|
||||
lng: number,
|
||||
lat: number;
|
||||
lng: number;
|
||||
}
|
||||
|
||||
export const middleCoord = (l1: ILatLng, l2: ILatLng): ILatLng => ({
|
||||
lat: (l2.lat + ((l1.lat - l2.lat) / 2)),
|
||||
lng: (l2.lng + ((l1.lng - l2.lng) / 2))
|
||||
lat: l2.lat + (l1.lat - l2.lat) / 2,
|
||||
lng: l2.lng + (l1.lng - l2.lng) / 2,
|
||||
});
|
||||
|
||||
export const middleCoordPx = (p1: Point, p2: Point): Point => point({
|
||||
x: (p1.x + ((p2.x - p1.x) / 2)),
|
||||
y: (p1.y + ((p2.y - p1.y) / 2))
|
||||
});
|
||||
export const middleCoordPx = (p1: Point, p2: Point): Point =>
|
||||
point({
|
||||
x: p1.x + (p2.x - p1.x) / 2,
|
||||
y: p1.y + (p2.y - p1.y) / 2,
|
||||
});
|
||||
|
||||
export const deg2rad = (deg: number): number => ((deg * Math.PI) / 180);
|
||||
export const rad2deg = (rad: number): number => ((rad / Math.PI) * 180);
|
||||
export const deg2rad = (deg: number): number => (deg * Math.PI) / 180;
|
||||
export const rad2deg = (rad: number): number => (rad / Math.PI) * 180;
|
||||
|
||||
export const findDistancePx = (p1: Point, p2: Point): number => {
|
||||
return Math.sqrt(((p1.x - p2.x) ** 2) + ((p1.y - p2.y) ** 2));
|
||||
return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
|
||||
};
|
||||
|
||||
export const findDistance = (t1: number, n1: number, t2: number, n2: number): number => {
|
||||
|
@ -34,40 +35,56 @@ export const findDistance = (t1: number, n1: number, t2: number, n2: number): nu
|
|||
const dlon = lon2 - lon1;
|
||||
|
||||
// here's the heavy lifting
|
||||
const a = (Math.sin(dlat / 2) ** 2) +
|
||||
(Math.cos(lat1) * Math.cos(lat2) * (Math.sin(dlon / 2) ** 2));
|
||||
const a = Math.sin(dlat / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dlon / 2) ** 2;
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // great circle distance in radians
|
||||
const dk = c * 6373; // great circle distance in km
|
||||
|
||||
return (Math.round(dk * 1000) / 1000);
|
||||
return Math.round(dk * 1000) / 1000;
|
||||
};
|
||||
|
||||
export const distKm = (A: LatLngLiteral, B: LatLngLiteral): number => findDistance(A.lat, A.lng, B.lat, B.lng);
|
||||
// probably faster one
|
||||
export const findDistanceHaversine = (t1: number, n1: number, t2: number, n2: number): number => {
|
||||
const R = 6371; // km
|
||||
const dLat = ((t2 - t1) * Math.PI) / 180;
|
||||
var dLon = ((n2 - n1) * Math.PI) / 180;
|
||||
var a =
|
||||
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos((t1 * Math.PI) / 180) *
|
||||
Math.cos((t2 * Math.PI) / 180) *
|
||||
Math.sin(dLon / 2) *
|
||||
Math.sin(dLon / 2);
|
||||
var c = 2 * Math.asin(Math.sqrt(a));
|
||||
return R * c;
|
||||
};
|
||||
|
||||
export const getLabelDirection = (angle: number): 'left' | 'right' => (
|
||||
((angle % Math.PI) >= -(Math.PI / 2) && (angle % Math.PI) <= (Math.PI / 2)) ? 'left' : 'right'
|
||||
);
|
||||
export const distKm = (A: LatLngLiteral, B: LatLngLiteral): number =>
|
||||
findDistance(A.lat, A.lng, B.lat, B.lng);
|
||||
|
||||
export const distKmHaversine = (A: LatLngLiteral, B: LatLngLiteral): number =>
|
||||
findDistanceHaversine(A.lat, A.lng, B.lat, B.lng);
|
||||
|
||||
export const getLabelDirection = (angle: number): 'left' | 'right' =>
|
||||
angle % Math.PI >= -(Math.PI / 2) && angle % Math.PI <= Math.PI / 2 ? 'left' : 'right';
|
||||
|
||||
export const getPolyLength = (latlngs: LatLngLiteral[]): number => {
|
||||
if (latlngs.length < 2) return 0;
|
||||
|
||||
return latlngs.reduce((dist, item, index) => (
|
||||
index < (latlngs.length - 1)
|
||||
? dist + distKm(item, latlngs[index + 1])
|
||||
: dist
|
||||
), 0)
|
||||
return latlngs.reduce(
|
||||
(dist, item, index) =>
|
||||
index < latlngs.length - 1 ? dist + distKmHaversine(item, latlngs[index + 1]) : dist,
|
||||
0
|
||||
);
|
||||
};
|
||||
|
||||
// if C between A and B
|
||||
export const pointInArea = (A: LatLng, B: LatLng, C: LatLng, radius: number = 0.001): boolean => (
|
||||
export const pointInArea = (A: LatLng, B: LatLng, C: LatLng, radius: number = 0.001): boolean =>
|
||||
C.lng <= Math.max(A.lng + radius, B.lng + radius) &&
|
||||
C.lat <= Math.max(A.lat + radius, B.lat + radius) &&
|
||||
C.lat >= Math.min(A.lat - radius, B.lat - radius) &&
|
||||
C.lng >= Math.min(A.lng - radius, B.lng - radius)
|
||||
);
|
||||
C.lng >= Math.min(A.lng - radius, B.lng - radius);
|
||||
|
||||
|
||||
export const dist2 = (A: LatLngLiteral, B: LatLngLiteral): number => (((A.lat - B.lat) ** 2) + ((A.lng - B.lng) ** 2));
|
||||
export const dist2 = (A: LatLngLiteral, B: LatLngLiteral): number =>
|
||||
(A.lat - B.lat) ** 2 + (A.lng - B.lng) ** 2;
|
||||
|
||||
const distToSegmentSquared = (A: LatLng, B: LatLng, C: LatLng): number => {
|
||||
const l2 = dist2(A, B);
|
||||
|
@ -75,29 +92,27 @@ const distToSegmentSquared = (A: LatLng, B: LatLng, C: LatLng): number => {
|
|||
|
||||
const t = Math.max(
|
||||
0,
|
||||
Math.min(
|
||||
1,
|
||||
(((C.lat - A.lat) * (B.lat - A.lat) + (C.lng - A.lng) * (B.lng - A.lng)) / l2)
|
||||
)
|
||||
Math.min(1, ((C.lat - A.lat) * (B.lat - A.lat) + (C.lng - A.lng) * (B.lng - A.lng)) / l2)
|
||||
);
|
||||
|
||||
return dist2(
|
||||
C,
|
||||
{
|
||||
lat: A.lat + t * (B.lat - A.lat),
|
||||
lng: A.lng + t * (B.lng - A.lng)
|
||||
});
|
||||
return dist2(C, {
|
||||
lat: A.lat + t * (B.lat - A.lat),
|
||||
lng: A.lng + t * (B.lng - A.lng),
|
||||
});
|
||||
};
|
||||
|
||||
export const distToSegment = (A: LatLng, B: LatLng, C: LatLng): number => Math.sqrt(distToSegmentSquared(A, B, C));
|
||||
export const distToSegment = (A: LatLng, B: LatLng, C: LatLng): number =>
|
||||
Math.sqrt(distToSegmentSquared(A, B, C));
|
||||
|
||||
export const pointBetweenPoints = (A: LatLng, B: LatLng, C: LatLng): boolean => (distToSegment(A, B, C) < 0.01);
|
||||
export const pointBetweenPoints = (A: LatLng, B: LatLng, C: LatLng): boolean =>
|
||||
distToSegment(A, B, C) < 0.01;
|
||||
|
||||
export const angleBetweenPoints = (A: Point, B: Point): number => parseFloat(((Math.atan2(B.y - A.y, B.x - A.x))* 180 / Math.PI).toFixed());
|
||||
export const angleBetweenPointsRad = (A: Point, B: Point): number => ((Math.atan2(B.x - A.x, B.y - A.y)));
|
||||
export const angleBetweenPoints = (A: Point, B: Point): number =>
|
||||
parseFloat(((Math.atan2(B.y - A.y, B.x - A.x) * 180) / Math.PI).toFixed());
|
||||
export const angleBetweenPointsRad = (A: Point, B: Point): number =>
|
||||
Math.atan2(B.x - A.x, B.y - A.y);
|
||||
|
||||
export const allwaysPositiveAngleDeg = (angle: number): number => (
|
||||
(angle >= -90 && angle <= 90) ? angle : (180 + angle)
|
||||
);
|
||||
export const allwaysPositiveAngleDeg = (angle: number): number =>
|
||||
angle >= -90 && angle <= 90 ? angle : 180 + angle;
|
||||
|
||||
export const nearestInt = (value: number, parts: number): number => (value - (value % parts));
|
||||
export const nearestInt = (value: number, parts: number): number => value - (value % parts);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { divIcon, LatLngLiteral, Layer, LayerGroup, Map, marker, Marker } from "leaflet";
|
||||
import { arrowClusterIcon, createArrow } from "~/utils/arrow";
|
||||
import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js';
|
||||
import { allwaysPositiveAngleDeg, angleBetweenPoints, distKm } from "~/utils/geom";
|
||||
import { allwaysPositiveAngleDeg, angleBetweenPoints, distKmHaversine } from "~/utils/geom";
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface KmMarksOptions {
|
||||
|
@ -43,7 +43,7 @@ class KmMarksLayer extends LayerGroup {
|
|||
if (index >= latlngs.length - 1) return dist;
|
||||
|
||||
const next = latlngs[index + 1];
|
||||
const diff = distKm(current, next);
|
||||
const diff = distKmHaversine(current, next);
|
||||
const sum = dist + diff;
|
||||
const rounded = Math.floor(sum / this.options.kmMarksStep) * this.options.kmMarksStep;
|
||||
const count = Math.floor((rounded - last_km_mark) / this.options.kmMarksStep);
|
||||
|
@ -72,7 +72,6 @@ class KmMarksLayer extends LayerGroup {
|
|||
|
||||
return sum;
|
||||
}, 0);
|
||||
|
||||
};
|
||||
|
||||
createMiddleMarker = (latlng: LatLngLiteral, angle: number, distance: number): Marker => marker(latlng, {
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
LatLngLiteral,
|
||||
} from 'leaflet';
|
||||
|
||||
import { distKm, distToSegment, getPolyLength, pointInArea } from '~/utils/geom';
|
||||
import { distKmHaversine, distToSegment, getPolyLength, pointInArea } from '~/utils/geom';
|
||||
|
||||
interface InteractivePolylineOptions extends PolylineOptions {
|
||||
maxMarkers?: number;
|
||||
|
@ -268,11 +268,11 @@ export class InteractivePoly extends Polyline {
|
|||
const prev = this.markers[index];
|
||||
const next = this.markers[index + 1];
|
||||
|
||||
const initial_distance = distKm(prev.getLatLng(), next.getLatLng());
|
||||
const initial_distance = distKmHaversine(prev.getLatLng(), next.getLatLng());
|
||||
|
||||
const current_distance =
|
||||
((prev && distKm(prev.getLatLng(), current)) || 0) +
|
||||
((next && distKm(next.getLatLng(), current)) || 0);
|
||||
((prev && distKmHaversine(prev.getLatLng(), current)) || 0) +
|
||||
((next && distKmHaversine(next.getLatLng(), current)) || 0);
|
||||
|
||||
this.distance += current_distance - initial_distance;
|
||||
|
||||
|
@ -369,12 +369,12 @@ export class InteractivePoly extends Polyline {
|
|||
const next = index <= this.markers.length + 1 ? this.markers[index + 1] : null;
|
||||
|
||||
const initial_distance =
|
||||
((prev && distKm(prev.getLatLng(), initial)) || 0) +
|
||||
((next && distKm(next.getLatLng(), initial)) || 0);
|
||||
((prev && distKmHaversine(prev.getLatLng(), initial)) || 0) +
|
||||
((next && distKmHaversine(next.getLatLng(), initial)) || 0);
|
||||
|
||||
const current_distance =
|
||||
((prev && distKm(prev.getLatLng(), current)) || 0) +
|
||||
((next && distKm(next.getLatLng(), current)) || 0);
|
||||
((prev && distKmHaversine(prev.getLatLng(), current)) || 0) +
|
||||
((next && distKmHaversine(next.getLatLng(), current)) || 0);
|
||||
|
||||
this.distance += current_distance - initial_distance;
|
||||
|
||||
|
@ -448,7 +448,7 @@ export class InteractivePoly extends Polyline {
|
|||
|
||||
const point = this.drawing_direction === 'forward' ? latlngs[latlngs.length - 1] : latlngs[0];
|
||||
|
||||
this.distance += distKm(point, latlng);
|
||||
this.distance += distKmHaversine(point, latlng);
|
||||
this.fire('distancechange', { distance: this.distance });
|
||||
};
|
||||
|
||||
|
@ -493,9 +493,9 @@ export class InteractivePoly extends Polyline {
|
|||
const next = index <= latlngs.length + 1 ? latlngs[index + 1] : null;
|
||||
|
||||
const initial_distance =
|
||||
((prev && distKm(prev, current)) || 0) + ((next && distKm(next, current)) || 0);
|
||||
((prev && distKmHaversine(prev, current)) || 0) + ((next && distKmHaversine(next, current)) || 0);
|
||||
|
||||
const current_distance = (prev && next && distKm(prev, next)) || 0;
|
||||
const current_distance = (prev && next && distKmHaversine(prev, next)) || 0;
|
||||
|
||||
this.distance += current_distance - initial_distance;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue