Skip to content

Commit

Permalink
Merge pull request #14 from zakjan/improve-performance
Browse files Browse the repository at this point in the history
Limit feature.toGeoJSON calls to improve performance
  • Loading branch information
zakjan authored Mar 27, 2022
2 parents 513937e + 774fde6 commit 5d13c34
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 17 deletions.
10 changes: 7 additions & 3 deletions src/utils/circle_geojson.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ export function createCircle(center, radius, properties = {}) {
};
}

export function isCircleByTypeAndProperties(type, properties) {
return type === Constants.geojsonTypes.POLYGON &&
typeof properties[Constants.properties.CIRCLE_RADIUS] === 'number' &&
properties[Constants.properties.CIRCLE_RADIUS] > 0;
}

export function isCircle(geojson) {
return geojson.geometry.type === Constants.geojsonTypes.POLYGON &&
typeof geojson.properties[Constants.properties.CIRCLE_RADIUS] === 'number' &&
geojson.properties[Constants.properties.CIRCLE_RADIUS] > 0;
return isCircleByTypeAndProperties(geojson.geometry.type, geojson.properties);
}

export function getCircleCenter(geojson) {
Expand Down
44 changes: 30 additions & 14 deletions src/utils/create_geodesic_geojson.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import createVertex from '@mapbox/mapbox-gl-draw/src/lib/create_vertex';
import * as Constants from '../constants';
import { isCircle, getCircleCenter, getCircleRadius } from './circle_geojson';
import { isCircleByTypeAndProperties, getCircleCenter, getCircleRadius } from './circle_geojson';
import createGeodesicLine from './create_geodesic_line';
import createGeodesicCircle from './create_geodesic_circle';
import { midpoint, destinationPoint } from './geodesy';

const STEPS = 32;
const HANDLE_BEARING = 45;

function getCoordinate(coordinates, path) {
const ids = path.split('.').map(x => parseInt(x, 10));
const coordinate = ids.reduce((coordinates, id) => coordinates[id], coordinates);
return JSON.parse(JSON.stringify(coordinate));
function isCircleFeature(feature) {
return isCircleByTypeAndProperties(feature.type, feature.properties);
}

// returns path with the last coord id subtracted by 1
function getMidpointStartCoordPath(path) {
return path.split('.').map((x, i, array) => i === array.length - 1 ? (parseInt(x, 10) - 1).toString() : x).join('.');
}

// returns path with the last coord id of a polygon overridden to 0
// see https://github.com/mapbox/mapbox-gl-draw/pull/998
function getMidpointEndCoordPath(feature, path) {
if (feature.type === Constants.geojsonTypes.POLYGON || feature.type === Constants.geojsonTypes.MULTI_POLYGON) {
try {
feature.getCoordinate(path);
return path;
} catch (e) {
return path.split('.').map((x, i, array) => i === array.length - 1 ? '0' : x).join('.');
}
} else {
return path;
}
}

function createGeodesicGeojson(geojson, options) {
Expand All @@ -23,10 +41,9 @@ function createGeodesicGeojson(geojson, options) {

const featureId = properties.parent || properties.id;
const feature = options.ctx.store.get(featureId);
const featureGeojson = feature.toGeoJSON();

if (type === Constants.geojsonTypes.POINT) {
if ((properties.meta === Constants.meta.VERTEX || properties.meta === Constants.meta.MIDPOINT) && isCircle(featureGeojson)) {
if (isCircleFeature(feature)) {
return []; // hide circle points, they are displayed in processCircle instead
} else if (properties.meta === Constants.meta.MIDPOINT) {
return processMidpoint(); // calculate geodesic midpoint
Expand All @@ -36,7 +53,7 @@ function createGeodesicGeojson(geojson, options) {
} else if (type === Constants.geojsonTypes.LINE_STRING) {
return processLine(); // calculate geodesic line
} else if (type === Constants.geojsonTypes.POLYGON) {
if (isCircle(featureGeojson)) {
if (isCircleFeature(feature)) {
return processCircle(); // calculate geodesic circle
} else {
return processPolygon(); // calculate geodesic polygon
Expand All @@ -55,13 +72,11 @@ function createGeodesicGeojson(geojson, options) {
function processMidpoint() {
const coordPath = properties.coord_path;

// subtract 1 from the last coord path id
const coordPathIds = coordPath.split('.').map(x => parseInt(x, 10));
const startCoordPath = coordPathIds.map((x, i) => x + (i === coordPathIds.length - 1 ? -1 : 0)).join('.');
const endCoordPath = coordPath;
const startCoordPath = getMidpointStartCoordPath(coordPath);
const endCoordPath = getMidpointEndCoordPath(feature, coordPath);

const startCoord = getCoordinate(featureGeojson.geometry.coordinates, startCoordPath);
const endCoord = getCoordinate(featureGeojson.geometry.coordinates, endCoordPath);
const startCoord = feature.getCoordinate(startCoordPath);
const endCoord = feature.getCoordinate(endCoordPath);
const midCoord = midpoint(startCoord, endCoord);

const geodesicGeojson = {
Expand Down Expand Up @@ -106,6 +121,7 @@ function createGeodesicGeojson(geojson, options) {
}

function processCircle() {
const featureGeojson = feature.toGeoJSON();
const center = getCircleCenter(featureGeojson);
const radius = getCircleRadius(featureGeojson);
const handleBearing = feature[Constants.properties.CIRCLE_HANDLE_BEARING] || HANDLE_BEARING;
Expand Down
32 changes: 32 additions & 0 deletions src/utils/create_geodesic_geojson.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,22 @@ describe('createGeodesicGeojson', () => {
expect(result).toMatchObject(expectedResult);
});

it('returns a polygon midpoint, last midpoint', () => {
const feature = mode.newFeature(createGeojson(Constants.geojsonTypes.POLYGON, [COORDINATES]));
mode.addFeature(feature);
const internalGeojson = createMidpoint(
feature.id,
createVertex(feature.id, feature.getCoordinate(`0.${COORDINATES.length - 2}`), `0.${COORDINATES.length - 2}`, false),
createVertex(feature.id, feature.getCoordinate('0.0'), `0.${COORDINATES.length - 1}`, false),
map
);

const expectedResult = [createGeojsonMatch(Constants.geojsonTypes.POINT)];
const result = createGeodesicGeojson(internalGeojson, { ctx: mode._ctx, steps: STEPS });
expect(result.length).toEqual(expectedResult.length);
expect(result).toMatchObject(expectedResult);
});

it('returns a multiline', () => {
const feature = mode.newFeature(createGeojson(Constants.geojsonTypes.MULTI_LINE_STRING, [COORDINATES]));
mode.addFeature(feature);
Expand Down Expand Up @@ -220,6 +236,22 @@ describe('createGeodesicGeojson', () => {
expect(result).toMatchObject(expectedResult);
});

it('returns a multipolygon midpoint, last midpoint', () => {
const feature = mode.newFeature(createGeojson(Constants.geojsonTypes.MULTI_POLYGON, [[COORDINATES]]));
mode.addFeature(feature);
const internalGeojson = createMidpoint(
feature.id,
createVertex(feature.id, feature.getCoordinate(`0.0.${COORDINATES.length - 2}`), `0.0.${COORDINATES.length - 2}`, false),
createVertex(feature.id, feature.getCoordinate('0.0.0'), `0.0.${COORDINATES.length - 1}`, false),
map
);

const expectedResult = [createGeojsonMatch(Constants.geojsonTypes.POINT)];
const result = createGeodesicGeojson(internalGeojson, { ctx: mode._ctx, steps: STEPS });
expect(result.length).toEqual(expectedResult.length);
expect(result).toMatchObject(expectedResult);
});

it('returns a circle', () => {
const feature = mode.newFeature(createCircle(COORDINATE, RADIUS));
mode.addFeature(feature);
Expand Down

1 comment on commit 5d13c34

@vercel
Copy link

@vercel vercel bot commented on 5d13c34 Mar 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.