Skip to content

Commit c6bc81c

Browse files
authored
Mongo: Fix reversing polygon coordinates (#4609)
* Fix reversing polygon coordinates * comments fix * real data test * improved tests
1 parent c723582 commit c6bc81c

File tree

3 files changed

+118
-11
lines changed

3 files changed

+118
-11
lines changed

spec/MongoTransform.spec.js

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,29 @@ describe('parseObjectToMongoObjectForCreate', () => {
6363
done();
6464
});
6565

66-
it('plain', (done) => {
67-
const geoPoint = {__type: 'GeoPoint', longitude: 180, latitude: -180};
66+
it('parse geopoint to mongo', (done) => {
67+
const lat = -45;
68+
const lng = 45;
69+
const geoPoint = {__type: 'GeoPoint', latitude: lat, longitude: lng};
6870
const out = transform.parseObjectToMongoObjectForCreate(null, {location: geoPoint},{
6971
fields: {location: {type: 'GeoPoint'}}
7072
});
71-
expect(out.location).toEqual([180, -180]);
73+
expect(out.location).toEqual([lng, lat]);
74+
done();
75+
});
76+
77+
it('parse polygon to mongo', (done) => {
78+
const lat1 = -45;
79+
const lng1 = 45;
80+
const lat2 = -55;
81+
const lng2 = 55;
82+
const lat3 = -65;
83+
const lng3 = 65;
84+
const polygon = {__type: 'Polygon', coordinates: [[lat1, lng1],[lat2, lng2],[lat3, lng3]]}
85+
const out = transform.parseObjectToMongoObjectForCreate(null, {location: polygon},{
86+
fields: {location: {type: 'Polygon'}}
87+
});
88+
expect(out.location.coordinates).toEqual([[[lng1, lat1],[lng2, lat2],[lng3, lat3],[lng1, lat1]]]);
7289
done();
7390
});
7491

@@ -144,26 +161,31 @@ describe('parseObjectToMongoObjectForCreate', () => {
144161
done();
145162
});
146163

147-
it('geopoint', (done) => {
148-
const input = {location: [45, -45]};
164+
it('mongo geopoint to parse', (done) => {
165+
const lat = -45;
166+
const lng = 45;
167+
const input = {location: [lng, lat]};
149168
const output = transform.mongoObjectToParseObject(null, input, {
150169
fields: { location: { type: 'GeoPoint' }},
151170
});
152171
expect(typeof output.location).toEqual('object');
153172
expect(output.location).toEqual(
154-
{__type: 'GeoPoint', longitude: 45, latitude: -45}
173+
{__type: 'GeoPoint', latitude: lat, longitude: lng}
155174
);
156175
done();
157176
});
158177

159-
it('polygon', (done) => {
160-
const input = {location: { type: 'Polygon', coordinates: [[[45, -45],[45, -45]]]}};
178+
it('mongo polygon to parse', (done) => {
179+
const lat = -45;
180+
const lng = 45;
181+
// Mongo stores polygon in WGS84 lng/lat
182+
const input = {location: { type: 'Polygon', coordinates: [[[lat, lng],[lat, lng]]]}};
161183
const output = transform.mongoObjectToParseObject(null, input, {
162184
fields: { location: { type: 'Polygon' }},
163185
});
164186
expect(typeof output.location).toEqual('object');
165187
expect(output.location).toEqual(
166-
{__type: 'Polygon', coordinates: [[45, -45],[45, -45]]}
188+
{__type: 'Polygon', coordinates: [[lng, lat],[lng, lat]]}
167189
);
168190
done();
169191
});

spec/ParsePolygon.spec.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,64 @@ describe('Parse.Polygon testing', () => {
160160
}, done.fail);
161161
});
162162

163+
it('polygonContain query no reverse input (Regression test for #4608)', (done) => {
164+
const points1 = [[.25,0],[.25,1.25],[.75,1.25],[.75,0]];
165+
const points2 = [[0,0],[0,2],[2,2],[2,0]];
166+
const points3 = [[10,10],[10,15],[15,15],[15,10],[10,10]];
167+
const polygon1 = new Parse.Polygon(points1);
168+
const polygon2 = new Parse.Polygon(points2);
169+
const polygon3 = new Parse.Polygon(points3);
170+
const obj1 = new TestObject({location: polygon1});
171+
const obj2 = new TestObject({location: polygon2});
172+
const obj3 = new TestObject({location: polygon3});
173+
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
174+
const where = {
175+
location: {
176+
$geoIntersects: {
177+
$point: { __type: 'GeoPoint', latitude: 0.5, longitude:1.0 }
178+
}
179+
}
180+
};
181+
return rp.post({
182+
url: Parse.serverURL + '/classes/TestObject',
183+
json: { where, '_method': 'GET' },
184+
headers: {
185+
'X-Parse-Application-Id': Parse.applicationId,
186+
'X-Parse-Javascript-Key': Parse.javaScriptKey
187+
}
188+
});
189+
}).then((resp) => {
190+
expect(resp.results.length).toBe(2);
191+
done();
192+
}, done.fail);
193+
});
194+
195+
it('polygonContain query real data (Regression test for #4608)', (done) => {
196+
const detroit = [[42.631655189280224,-83.78406753121705],[42.633047793854814,-83.75333640366955],[42.61625254348911,-83.75149921669944],[42.61526926650296,-83.78161794858735],[42.631655189280224,-83.78406753121705]];
197+
const polygon = new Parse.Polygon(detroit);
198+
const obj = new TestObject({location: polygon});
199+
obj.save().then(() => {
200+
const where = {
201+
location: {
202+
$geoIntersects: {
203+
$point: { __type: 'GeoPoint', latitude: 42.624599, longitude:-83.770162 }
204+
}
205+
}
206+
};
207+
return rp.post({
208+
url: Parse.serverURL + '/classes/TestObject',
209+
json: { where, '_method': 'GET' },
210+
headers: {
211+
'X-Parse-Application-Id': Parse.applicationId,
212+
'X-Parse-Javascript-Key': Parse.javaScriptKey
213+
}
214+
});
215+
}).then((resp) => {
216+
expect(resp.results.length).toBe(1);
217+
done();
218+
}, done.fail);
219+
});
220+
163221
it('polygonContain invalid input', (done) => {
164222
const points = [[0,0],[0,1],[1,1],[1,0]];
165223
const polygon = new Parse.Polygon(points);
@@ -255,6 +313,24 @@ describe_only_db('mongo')('Parse.Polygon testing', () => {
255313
}, done.fail);
256314
});
257315

316+
it('polygon coordinates reverse input', (done) => {
317+
const Config = require('../src/Config');
318+
const config = Config.get('test');
319+
320+
// When stored the first point should be the last point
321+
const input = [[12,11],[14,13],[16,15],[18,17]];
322+
const output = [[[11,12],[13,14],[15,16],[17,18],[11,12]]];
323+
const obj = new TestObject();
324+
obj.set('polygon', new Parse.Polygon(input));
325+
obj.save().then(() => {
326+
return config.database.adapter._rawFind('TestObject', {_id: obj.id});
327+
}).then((results) => {
328+
expect(results.length).toBe(1);
329+
expect(results[0].polygon.coordinates).toEqual(output);
330+
done();
331+
});
332+
});
333+
258334
it('polygon loop is not valid', (done) => {
259335
const coords = [[0,0],[0,1],[1,0],[1,1]];
260336
const obj = new TestObject();

src/Adapters/Storage/Mongo/MongoTransform.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,9 +1261,13 @@ var GeoPointCoder = {
12611261

12621262
var PolygonCoder = {
12631263
databaseToJSON(object) {
1264+
// Convert lng/lat -> lat/lng
1265+
const coords = object.coordinates[0].map((coord) => {
1266+
return [coord[1], coord[0]];
1267+
});
12641268
return {
12651269
__type: 'Polygon',
1266-
coordinates: object['coordinates'][0]
1270+
coordinates: coords
12671271
}
12681272
},
12691273

@@ -1283,7 +1287,8 @@ var PolygonCoder = {
12831287
},
12841288

12851289
JSONToDatabase(json) {
1286-
const coords = json.coordinates;
1290+
let coords = json.coordinates;
1291+
// Add first point to the end to close polygon
12871292
if (coords[0][0] !== coords[coords.length - 1][0] ||
12881293
coords[0][1] !== coords[coords.length - 1][1]) {
12891294
coords.push(coords[0]);
@@ -1306,6 +1311,10 @@ var PolygonCoder = {
13061311
'GeoJSON: Loop must have at least 3 different vertices'
13071312
);
13081313
}
1314+
// Convert lat/long -> long/lat
1315+
coords = coords.map((coord) => {
1316+
return [coord[1], coord[0]];
1317+
});
13091318
return { type: 'Polygon', coordinates: [coords] };
13101319
},
13111320

0 commit comments

Comments
 (0)