I have a Google Map and a server sends a list of objects that have a position with a small radius (100m max). I need to quickly be able to know if a position is colliding with something in the list and draw on the map everything.
I'm thinking I should use a Quadtree (very useful in 2D collisions for games) but my issue is I'm not limited to a screen but to the earth !
Sure, if I have 100 objects it's not a problem but at any time the server can send me new objects that I need to add to the list and so my Quadtree could drastically change or become unbalanced.
What should I do ? Should I still use a Quadtree and modify the entire tree if a new element is added outside of the current boundaries ? Should I set the boundaries to the max latitude longitude (but could have issue with double precision) ? Or does someone knows a better data structure for that type of problem ?
rXp
To avoid issues with double precision, especially at the splitting border of a quad cell, it is advisable to use integer coordinates in the quad tree.
convert double lat/lon to int by multiplying with 1E6, this results in a precision of about 10cm.
You can use a space-filling-curve, for example a z curve.
Related
I've got a list of map coordinates [lat,lon]. I would like to filter out those that by some metric, are too far away from the rest of the main group, outliers.
A) A plain approach to it would be to get the median for lat,lon and then filter out whatever is further away from that median than said metric ( e.g distance ). This would only work for an absolute distance ( e.g 5km ).
B) An improvement to that approach could be to assume that no more than x% of the coordinate pairs would be outliers (essentially setting a threshold there ). Then I'd sort the coordinates array and remove the first x/2% and the final x/2%. Then find the max distance of that group of markers which would be the distance of the first marker to the last marker in that array. Finally, apply A) with the metric for the distance being the distance we just calculated ( so that the distance metric is not fixed )
This is simply an approach I very briefly came up with so if it has any obvious downsides please let me know. In a more open discussion spirit, how would you go about solving this problem? Thanks for your input
Working separately on the coordinates is not the best approach because it is not rotation invariant.
You can try by "onion peeling", i.e. building the convex hull of the point cloud and removing the hull vertices, repeatedly.
Read the paper "Onion-Peeling Outlier Detection in 2-D data Sets; Archit Harsh, John E. Ball & Pan Wei".
I have run the cyclone case from the OpenFOAM tutorials and want to view it using the builtin paraFOAM viewer which is based on Paraview 5.4.0.
The simulation has a number of particles in the diameter range of [2e-5, 1e-4] and i would like to scale the size of particles with the diameter array provided with the results.
To do this i select the Point Gaussian representation for the lagrangian fields (kinematiccloud), select Advanced properties, and select 'Scale by data array' after which the diameter array is chosen by default (although its not possible to change it to another field, which I suspect is a bug) but all the particles disappear from the view, as can be seen in the following screenshot:
My guess is that i need to chose proper values of the Gaussian radius and for the scale transfer function but there is no documentation to which it should be set. I have tried trial-and-error but i cannot find any settings for which i can get the particles back and have them render at different sizes.
Can someone enlighten me on how to set the Gaussian radius and scale transfer function properly?
The PointGaussian has just been improved and configuration is now automatic. You may want to try the last release of ParaView.
More info here :
https://blog.kitware.com/major-improvements-on-the-point-gaussian-representation/
I have stored some map zones to a table using Geometry type field.
So the inserts are like this:
INSERT INTO zones (zoneName, coords) VALUES ('name',
PolygonFromText('POLYGON((
41.11396418691335 1.2562662363052368,
41.11370552595821 1.2560248374938965,
41.11851079510035 1.2459397315979004,
41.11880984984478 1.2461864948272705,
41.11396418691335 1.2562662363052368))'));
Then I have the user position, and I need to know if he is inside some zone. This works well with this:
SELECT id
FROM zones
WHERE MBRContains(coords,GeomFromText('POINT(41.117783 1.260590)'))
But sometimes, user position is not perfect, so I think its better to know wich zone is closest to user position.
That is the part that I don't have any idea about... I found some queries to get distance between two points, but not a point and polygons.
The MBR series of functions (like MBRContains) are unsuitable for what you're trying to do; they only test bounding rectangle inclusion.
You may wish to jump forward to MySQL 5.6.1, and use the ST_ functions, like ST_Contains. These functions actually test the geometry.
The problem you're working on can be defined as an uncertainty in the position of your POINT when you go to compare it to your collection of boundary POLYGON items.
Try this: create a POLYGON from your point that is a square with the size of your uncertainty. You can think of this square as a "fuzzy" point. (You could also use an octagon or another closer approximation of a circle in place of a rectangle, but your querying speed will slow.)
Then use ST_Within to see if you have a unique polygon that entirely contains your fuzzy point. If you get just one polygon, you're done.
If you get multiple polygons that entirely contain your fuzzy point, that means some of your boundary polygons overlap other ones. You need to figure out what this means in your problem space. If your data is intended to be properly structured cartographic boundary data, it means you have a data mistake. (NOTE: This is not unheard of :-)
If you get no polygons that entirely contain your fuzzy point, then your fuzzy point may or may not overlap the boundary of at least one polygon. Use ST_Overlaps to find those polygons.
If you get just one, you're done -- your fuzzy point is near the boundary of just one polygon.
If you get none, you're done -- your fuzzy point is away from the boundaries of all your polygons.
If you get more than one hit, you have an ambiguity -- your fuzzy point is near the boundary of more than one polygon.
This is the hard case to sort out. You could reduce the size of the fuzzy point and try again. This MIGHT yield just one polygon result. But, you could deceive yourself into thinking that your points are more accurate than they are by doing this.
MySQL doesn't have the geometric operator Area(Intersection(Polygon, FuzzyPoint)). If it did you could choose the polygon with the biggest area of intersection with your fuzzy point, and that would be a good disambiguator. But it would still be as inaccurate as the position of your point.
Maybe your application should handle the category of result "too near the boundary of A, B, and C to be sure."
right now I store long and lat as two decimal, indexed fields in the DB.
I am wondering (without installing any bizzare engine) if there is an efficient way to do this, so the index will also help me to calculate distance. A sample query would be
get me all the location in 10M radios from long X lat Y
Use the float datatype for latitude and longitude. Anything of higher precision is most likely over-engineering.
Unless your results need to be accurate to less than a meter or so, the float datatype has PLENTY of precision for what you're trying to do. If you are working at resolutions of less than a meter, you're going to need to find out about projections (sphere-to-plane) like Universal Transverse Mercator and Lambert.
When you start doing the computations, keep in mind that one minute (one-sixtieth of a degree) of change in latitude (north-to-south) is one nautical mile.
Here's a nice presentation from a mySql person on doing this search.
http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
The performance optimization is to make an index on the latitudes, and maybe also longitudes, then do a search like this (positive radius)
where loctable.lat >= (mylat-radius)
and loctable.lat <= (mylat+radius)
and loctable.long >= (mylong-radius)
and loctable.long <= (mylong+radius)
and haversine_distance(mylat, mylong, loctable.lat, loctable.long) <= radius
This searches for a bounding box. That bounding box is the right size in latitude, and probably too big in longitude (unless you're near the equator). But it's OK if the box is too big, because the last line gets rid of any extra matches.
You want to look for a spatial index or a space-filling-curve. A si reduces the 2d complexity to a 1d complexity. It's looks like a quadtree and a bit like a fractal. If you don't mind the shape and an exact search you want to delete the harvesine formule because you can just search for a quadtree tile. Of course you need the mercantor projection. This is by far the fastest method. I uses it a lot with a hilbert curve. You want to look for Nick's hilbert curve spatial index quadtree blog.
My question is somewhat related to this similar one, which links to a pretty complex solution - but what I want to understand is the result of this:
Using a Mysql Geometry field to store a small polygon I duly ran
select AREA(myPolygon) where id =1
over it, and got an value like 2.345. So can anyone tell me, just what does that number represent seeing as the stored values were long/lat sets describing the polygon?
FYI, the areas I am working on are relatively small (car parks and the like) and the area does not have to be exact - I will not be concerned about the curvature of the earth.
2.345 of what? Thanks, this is bugging me.
The short answer is that the units for your area calculation are basically meaningless ([deg lat diff] * [deg lon diff]). Even though the curvature of the earth wouldn't come into play for the area calculation (since your areas are "small"), it does come into play for the calculation of distance between the lat/lon polygon coordinates.
Since a degree of longitude is different based on the distance from the equator (http://en.wikipedia.org/wiki/Longitude#Degree_length), there really is no direct conversion of your area into m^2 or km^2. It is dependent on the distance north/south of the equator.
If you always have rectangular polygons, you could just store the opposite corner coordinates and calculate area using something like this: PHP Library: Calculate a bounding box for a given lat/lng location
The most "correct" thing to do would be to store your polygons using X-Y (meters) coordinates (perhaps UTM using the WGS-84 ellipsoid), which can be calculated from lat/lon using various libraries like the following for Java: Java, convert lat/lon to UTM. You could then continue to use the MySQL AREA() function.