SQL Server units question - sql

This may be a really dumb question, but...
What units does Geography.STLength return? The official MSDN page doesn't say anything about the units returned, and this blog entry here says STLength() returns a float indicating the length of the instance in units. Yes, that's right, it says it returns it in units.
Can anyone shed some light on what units STLength returns? Feet? Meters? Inches? Help!

The units are entirely dependent on the Spatial Reference ID (SRID) of the geography/geometry data being used. By convention, you would generally use an SRID of "0" for geometry types if all the data is in the same unit system.
However, usually the geography type uses an SRID of 4326, which is the reference ID of the latitude/longitude ellipsoidal earth coordinate system known as WGS 84. When you specify point coordinates in this system, it is in degrees of angle of latitude and longitude, rather than some distance from an origin. Length and area calculations on points in this reference system will return completely different results from geometric calculations on the exact same point positions (for a great example see Differences between Geography and Geometry here, and as for why this happens, see here).
So if your data columns were created with an SRID of "0", then the system is defined to be unitless and you would need some metadata about the data model to figure out the units. If they were defined with a real SRID, then you can use this query:
SELECT spatial_reference_id
, well_known_text
, unit_of_measure
, unit_conversion_factor
FROM sys.spatial_reference_systems
to check what units the SRID represents. Most are in metres, but a few are in feet.

Related

Checking if a Coordinate is Within a Range - BigQuery GIS

I'm looking at the freely available Solar potential dataset on Google BigQuery that may be found here: https://bigquery.cloud.google.com/table/bigquery-public-data:sunroof_solar.solar_potential_by_censustract?pli=1&tab=schema
Each record on the table has the following border definitions:
lat_max - maximum latitude for that region
lat_min - minimum latitude for that region
lng_max - maximum longitude for that region
lng_min - minimum longitude for that region
Now I have a coordinate (lat/lng pair) and I would like to query to see whether or not that coordinate is within the above range. How do I do that with BQ Standard SQL?
I've seen the Geo Functions here: https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions
But I'm still not sure how to write this query.
Thanks!
Assuming the points are just latitude and longitude as numbers, why can't you just do a standard numerical comparison?
Note: The first link doesn't work without a google account, so I can't see the data.
But if you want to become spatial, I'd suggest you're going to need to take the border coordinates that you have and turn them into a polygon using one of: ST_MAKEPOLYGON, ST_GEOGFROMGEOJSON, or ST_GEOGFROMTEXT. Then create a point using the coords you wish to test ST_MAKEPOINT.
Now you have two geographies you can compare them both using ST_INTERSECTION or ST_DISJOINT depending on what outcome you want.
If you want to get fancy and see how far aware from the border you are (which I guess means more efficient?) you can use ST_DISTANCE.
Agree with Jonathan, just checking if each of the lat/lon value is within the bounds is simplest way to achieve it (unless there are any issues around antimeridian, but most likely you can just ignore them).
If you do want to use Geography objects for that, you can construct Geography objects for these rectangles, using
ST_MakePolygon(ST_MakeLine(
[ST_GeogPoint(lon_min, lat_min), ST_GeogPoint(lon_max, lat_min),
ST_GeogPoint(lon_max, lat_max), ST_GeogPoint(lon_min, lat_max),
ST_GeogPoint(lon_min, lat_min)]))
And then check if the point is within particular rectangle using
ST_Intersects(ST_GeogPoint(lon, lat), <polygon-above>)
But it will likely be slower and would not provide any benefit for this particular case.

What is SRID 0 for geometry columns?

So I added geometry columns to a spatial table and using some of the msdn references I ended up specifying the SRID as 0 like so:
update dbo.[geopoint] set GeomPoint = geometry::Point([Longitude], [Latitude], 0)
However, I believe this was a mistake, but before having to update the column, is 0 actually the default = 4326? The query works as long as I specify the SRID as 0 on the query, but I'm getting weird results in comparison to the geography field I have... SRID 0 does not exist in sys.spatial_reference_systems and I haven't been able to dig up any information on it. Any help would be appreciated.
A SRID of 0 doesn't technically exist, it just means no SRID -- ie, the default if you forget to set it. So, technically, you can still perform distance, intersection and all other queries, so long as both sets of geometries have a SRID of 0. If you have one field of geometries with a SRID of 0 and another set with a SRID that actually exists, you will most likely get very strange results. I remember scratching my head once when not getting any results from a spatial query in exactly this situation and SQL Server did not complain, just 0 results (for what is is worth Postgis will actually fail, with a warning about non-matching SRIDs).
In my opinion, you should always explicitly set the SRID of your geometries (or geographies, which naturally will always be 4326), as not only does it prevent strange query results, but it means you can convert from one coordinate system to another. Being able to convert on the fly from lat/lon (4326), to Spherical Mercator (3857), as used in Google Maps/Bing, which is in meters, or some local coordinate system, such as 27700, British National Grid, also in meters, can be very useful. SQL Server does not to my knowledge support conversion from one SRID to another, but as spatial types are essentially CLR types, there are .NET libraries available should you ever need to do so, see Transform/ Project a geometry from one SRID to another for an example.
If you do decide to change you geometries, you can do something like:
UPDATE your_table SET newGeom = geometry::STGeomFromWKB(oldGeom.STAsBinary(), SRID);
which will create a new column or to do it in place:
UPDATE geom SET geom.STSrid=4326;
where 4326 is just an example SRID.
There is a good reference for SRIDs at http://spatialreference.org/, though this is essentially the same information as you find in sys.spatial_reference_systems.
SRIDs are a way to take into account that the distances that you're measuring on aren't on a flat, infinite plane but rather an oblong spheroid. They make sense for the geography data type, but not for geometry. So, if you're doing geographic calculations (as your statement of "in comparison to the geography field I have"), create geography points instead of geometry points. In order to do calculations on any geospatial data (like "find the distance from this point to this other point"), the SRID of all the objects involved need to be the same.
TL;DR: Is the point on the Cartesian plane? Use geometry. Is the point on the globe? Use geography.

Determine "reach" by geographic distribution

I have a large collection of checkins for products manufactured at a distinct geographic location. I'd like to create a summary metric used to rank these products by how far, globally, they have traveled from their point of origin. For example, a product produced in Maine that is found in California, Florida, and Dublin, Ireland should rank higher than a product made in California that hasn't been seen outside of California.
What kind of algorithms should I be looking at? How would you approach this?
MS SQL Server (which I've just spotted may not be relevant to you) includes spatial data types that allow you to calculate (among other things) the distance between two points defined by their latitude and longitude. So this code:-
DECLARE #p1 geography = geography::Point(#lat1, #long1, 4326);
SELECT #distance=#p1.STDistance(geography::Point(#lat2, #long2, 4326))
would load #distance with the distance in metres between the two points. I lifted the code from a scalar valued in line function that I wrote - but it could also be targeting table columns directly. The 4326 magic number is a reference to the Spatial Reference System Identifier (SRID) that provides answers in metres. This calculation doesn't take into account altitude and the distortion of the globe (other functions/SRIDs are available for this) but it's probably accurate enough for most purposes.
Unfortunately, if you are restricted to postgresql, this answer is of no use (though it may point you in a direction for further investigation).
A reference for Sql Server can be found here : http://technet.microsoft.com/en-us/library/bb933790.aspx

Lat Long or Long Lat

There seems to be no standard whether Longitude,Latitude or Latitude,Longitude should be used.
WSG84 and stuff based directly on it, seem to prefer Long,Lat.
"Normal people" always tend to speak of Lat, Long - so I've very often seen code or frameworks that use Lat, Long (e.g. google Maps)
Is there any strong argument for either way?
You are correct, there is no universal standard on the order:
In mathematical functions which do an universal conversion, between x,y or lon,lat or inverse, the lon,lat order should be used, because the x-axis relates to longitude and y to latitude and the x,y order is usually preferred.
Further, if you program a piece of code which is related to draw a lon,lat coordinate on x,y coordinates (screen), I also would use the lon,lat order because of the direct relation to x,y.
The order lat,lon is the classical one, coming from (old) navigation and geography. I assume that latitude in that field is used first because it was easier to measure (using only a ruler, the sun and a stick for length of shadow measuring).
The longitude was not determinable for long time. If you read old adventure reports, they only tell the latitude that their expeditions reached).
I think therefore they use latitude first, the measurement of longitude came later in history, once precise chronometers have been available and transportable.
So for apps that display coordinates info on a screen you should display latitude first.
As mentioned in the comments by #Midavalo, there is a standard for the representation of geographic locations by coordinates: ISO 6709.
It describes that a geographical point is specified by the following four items:
a first horizontal coordinate (y), such as latitude
a second horizontal coordinate (x), such as longitude
optionally, a vertical coordinate, i.e. height or depth
optionally, an identification of the coordinate reference system (CRS)
The order, positive direction, and units of coordinates are supposed to be defined by that CRS, but when such a CRS identification is missing -- which is very often -- the data must be interpreted by the following conventions:
Latitude comes before longitude
North latitude is positive
East longitude is positive
Fraction of degrees is preferred over sexagesimal (degrees, minutes, seconds) notation
So, unless another coordinate reference system is mentioned, the standard is "latitude, longitude, (elevation)".
There seems to be no standard whether Longitude,Latitude or Latitude,Longitude should be used.
The problem is the exact opposite: there are several competing standards. There's ISO 6709 which specifies Lat-Long and is followed by the EPSG:4326 Geodetic Parameter to represent coordinates on the World Geodetic System. But there's also the CRS:84 parameter which uses the same coordinate system but with inverted axis (Long-Lat).
It's a matter of choosing which standard to follow rather than lacking standardization. Still, that doesn't mean that all choices are equally convenient.
Is there any strong argument for either way?
Yes, prefer Lat-Long for GIS data unless you're catering to a specific audience or use case. As mentioned, most people default to Lat-Long and many GIS applications will too, so if you have no reason to prefer Long-Lat, stick to Lat-Long. Otherwise, it might be better to just pick whatever convention your tools will favor. For instance, Long-Lat is the choice for GeoJSON so if you're primarily processing GeoJSON data, it's your call to decide if it's worth it to convert back and forth. If you're not using GIS software and just want to store coordinates as if they were (x,y) points on a plane, Long-Lat is more intuitive - but beware the risks of rolling your own geodesic calculations instead of using a proper GIS library to interpret coordinate reference systems.

SimpleDB - Location comparative select expression

I have a coordinate, assume any latitude and longitude values.
I have a domain setup on SimpleDB that has many items (simple strings) with attributes of 'Latitude' and 'Longitude'. Now what I want to do is query SimpleDB and see if the current location coordinates are 'x' meters apart from SimpleDB's items' coordinates. 'x' should be 10.
My app uploads an item to SimpleDB with an attribute that contains the latitude and longitude. I detect the users location, get the coordinates and I want to use a select expression to see if the coordinates are 'x' meters apart. So is their a better approach to doing this? Or is this is the best way, if so, how can I do it?
Here is an example of what the select expression may look like, I just have no idea how to use it in this case and what the '%#' values would be filled in by. This whole format could be off, its just my idea.
select * from test-app-simpledb where Latitude >= '%#' AND Latitude <= '%#' AND Longitude >= '%#' AND Longitude <= '%#'
So "test-app-simpledb" is my SimpleDB domain name, Latitude and Longitude are the attributes I compare to the coordinates. They are all converted to string.
So, how can I do location comparative select expressions. Querying if the item's coordinate (latitude and longitude attribute) are 'x' (in this case 10) meters apart.
Any way to do this? Thanks!
In the revised question, it has become clear that the actual question is how to conduct a query against a Amazon SimpleDB database to see if locations in the database are within a certain radius of a location provided by an iOS app.
As you correctly identify, you really want to do this server-side, rather than client-side, if possible. And the particular solutions will be highly dependent upon the particular database technology (SimpleDB in this case).
This question is touched upon in Spatial queries on AWS SimpleDB. I would suggest checking that out for more information.
As a proxy for a proper distance algorithm, you could translate the distance in meters into a ranges of latitudes and longitudes. Thus, you could, in iOS, calculate a minimum and maximum for both latitude and longitude and then pass those along in the WHERE clause to your remote database. Then the server could filter results based upon those criteria. That admittedly gives you a square-shaped region (rather than a circular region that you get by calculating distances properly), but it makes it really easy to quickly limit the result set with no special geolocation logic required on the server. To do this, you could define a region with MKCoordinateRegionMakeWithDistance, and then grab its span.
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(originalCoordinate, 200, 200);
MKCoordinateSpan span = region.span;
That gives you span.latitudeDelta and span.longitudeDelta which you can center around a given location's latitude and longitude to define a square shaped region around a location. To demonstrate that in action, here the center pin is my location at Times Square, and the shaded area is a region (constructed using the above span which is 200m wide and tall), which covers longitudes between 100m east and 100m west of my current location, as well as latitudes 100m north and 100m south of my current location.
This is a way to employ MapKit.framework functions to greatly streamline your SQL queries for remote databases to filter locations based upon geographic distance. If the square region is problematic, you could also further filter the results once they're downloaded to the iOS app using the CLLocation instance method, distanceFromLocation to determine the actual distance. But by limiting the longitudes and latitudes of locations retrieved by the server, you dramatically streamline the server retrieval process while not encumbering it with too much geographic location calculations.
But you really want to have SimpleDB do the full, proper distance calculation, I'll have to leave that to others.
Below, is my original answer. In the original question, I misinterpreted it as being "how do I construct a list of coordinates going in a circle around a particular location?" As made clear by the revised question, that was not the issue at all, but I'll keep my old answer here for historical reference.
Original answer:
If you used Calculate new coordinate x meters and y degree away from one coordinate, the implementation might look like:
NSInteger numberOfPoints = 10;
for (double bearing = 0.0; bearing < 360.0; bearing += (360.0 / numberOfPoints))
{
CLLocationCoordinate2D coordinate = [self coordinateFromCoord:originalCoordinate
atDistanceKm:distanceKm
atBearingDegrees:bearing];
// do whatever you want with this coordinate
}
It seems to work fine. For example, I had an app use this routine to drop 10 pins 100m from me in Times Square: