<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tales From The Cloud &#187; mapping</title>
	<atom:link href="http://blog.newsplore.com/tag/mapping/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.newsplore.com</link>
	<description>Everything beta</description>
	<lastBuildDate>Sun, 05 Feb 2012 09:03:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Selecting location data from a spatial database</title>
		<link>http://blog.newsplore.com/2009/04/04/selecting-location-data-from-a-spatial-database</link>
		<comments>http://blog.newsplore.com/2009/04/04/selecting-location-data-from-a-spatial-database#comments</comments>
		<pubDate>Sat, 04 Apr 2009 15:52:57 +0000</pubDate>
		<dc:creator>Florin</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[gis]]></category>
		<category><![CDATA[mapping]]></category>
		<category><![CDATA[spatial DB]]></category>

		<guid isPermaLink="false">http://blog.newsplore.com/?p=1031</guid>
		<description><![CDATA[I have been thinking to write about this subject a while back when project Spincloud was still under development. I was even thinking about making this the first post on my blog. The idea is simple: you have location-based data (POIs for instance) stored in some database (preferably a spatial DB) and now you want [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="padding-right:0;margin-top:3px"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.newsplore.com%2F2009%2F04%2F04%2Fselecting-location-data-from-a-spatial-database"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.newsplore.com%2F2009%2F04%2F04%2Fselecting-location-data-from-a-spatial-database" height="61" width="51" /></a></div><p>I have been thinking to write about this subject a while back when project <a href="http://spincloud.com">Spincloud</a> was still under development. I was even thinking about making this the first post on my blog.<br />
The idea is simple: you have location-based data (POIs for instance) stored in some database (preferably a spatial DB) and now you want to perform a select statement that will indicate the area that should include the points we want. In case of Spincloud&#8217;s weather map, we want the weather reported by the stations located within a given area determined by the Google Map viewport that the user is currently browsing.<br />
In all my examples I&#8217;ll use <a href="http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html">SQL Spatial Extensions</a> support, specifically MSQL spatial extensions.<br />
Here&#8217;s a visual representation of the spatial select (the red grid is the area where we want to fetch the data):</p>
<p><img class="alignnone size-full wp-image-1032" src="http://blog.newsplore.com/wp-content/uploads/2009/04/select_smpl.png" alt="select_smpl" width="258" height="256" /></p>
<p>This is quite easy to accomplish by issuing a spatial select statement on the database:</p>
<pre>select * from POI where Contains(GeomFromText
    ('POLYGON ((-30 32, 30 -8, -89 -8, -89 32, -30 32))', LOCATION))</pre>
<p>But what about selecting an area that crosses the 180 degrees longitude? Let&#8217;s say we want to select data in an area around New Zealand that starts at 170 degrees latitude and ends at -160 degrees latitude going East. The selected area will look like this:<br />
<span id="more-1031"></span><br />
<img src="http://blog.newsplore.com/wp-content/uploads/2009/04/nz_box.png" alt="nz_box" width="457" height="345" class="alignnone size-full wp-image-1062" /></p>
<p>If we are to describe this with a polygon, we may be tempted write it like this using Spatial SQL parlance:</p>
<pre>
POLYGON ((-160 -23, -160 -55, 170 -55, 170 -23, -160 -23))
</pre>
<p>but you&#8217;d be wrong. In fact this polygon describes an area on the map that <i>excludes</i> exactly our area of interest:<br />
<img src="http://blog.newsplore.com/wp-content/uploads/2009/04/torsel.png" alt="torsel" width="507" height="156" class="alignnone size-full wp-image-1048" /></p>
<p>This happens specifically because the 180 degrees meridian is crossed (the next point of longitude beyond 180 degrees is -180 degrees).<br />
To fix this special case, you have to test for this occurrence and if so we&#8217;ll construct two polygons, split by the 180 degrees meridian (notice the exaggerated division between the polygons east and west of the 180&deg;):</p>
<p><img src="http://blog.newsplore.com/wp-content/uploads/2009/04/nz_box_split.png" alt="nz_box_split" width="272" height="152" class="alignnone size-full wp-image-1063" /></p>
<p>Two spatial selects will have to be issued in order to account for areas on each side of the 180&deg; meridian.</p>
<p>If you&#8217;re using Google Maps then you most likely use <a href='http://code.google.com/apis/maps/documentation/reference.html#GLatLngBounds'>getBounds()</a> to get the bounding box. The API reference specifically states that the returned box is &#8220;a rectangle in geographical coordinates, including one that crosses the 180 degrees meridian&#8221;. I use the excellent <a href='http://www.vividsolutions.com/jts/jtshome.htm'>Vividsolutions JTS</a> for all GIS related code so to construct the polygons I use the following logic:</p>
<pre>
public List getPOIsInArea(float neLng, float neLat, float swLng, float swLat) {
  GeometryFactory gf = new GeometryFactory();

  if((neLng &lt; swLng) ) { //cross lat or long 180 degree boundary
   Polygon eastPol = gf.createPolygon(gf.createLinearRing(new Coordinate[] {
    new Coordinate(neLng, neLat),
    new Coordinate(-180, neLat),
    new Coordinate(-180, swLat),
    new Coordinate(neLng, swLat),
    new Coordinate(neLng, neLat)
     }), new LinearRing[]{});

   Polygon westPol = gf.createPolygon(gf.createLinearRing(new Coordinate[] {
    new Coordinate(swLng, swLat),
    new Coordinate(180, swLat),
    new Coordinate(180, neLat),
    new Coordinate(swLng, neLat),
    new Coordinate(swLng, swLat)
     }), new LinearRing[]{});

     //select POIs inside both eastPol and westPol
  } else {
      Polygon pol = gf.createPolygon(gf.createLinearRing(new Coordinate[] {
     new Coordinate(neLng, neLat),
     new Coordinate(neLng, swLat),
     new Coordinate(swLng, swLat),
     new Coordinate(swLng, neLat),
     new Coordinate(neLng, neLat),
     }), new LinearRing[]{});

     //select POIs from pol
  }
}
</pre>
<p>The above code creates two polygons if the 180&deg; meridian is crossed (E longitude is greater than the W longitude for the bounding box):</p>
<pre>
East polygon:
POLYGON ((-160 -23, -180 -23, -180 -55, -160 -55, -160 -23))

West polygon:
POLYGON ((160 -55, 180 -55, 180 -23, 160 -23, 160 -55))
</pre>
<p>Both polygons will be used when selecting POIs from the database. The resulted POI list will be of course the union between the POIs in the east and west polygons.</p>
<p>What&#8217;s remaining is to present the data on the map but since the spatial select may return more points than the maximum we want to show on the map (i.e. 1000 returned versus 20 we want shown), we&#8217;ll have to employ some balanced point reduction step (we call it clustering) before the POIs are presented on the map. I&#8217;ll talk about point clustering and using the cool <a href='http://en.wikipedia.org/wiki/K-means_algorithm'>k-means</a> algorithm in a future post.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.newsplore.com/2009/04/04/selecting-location-data-from-a-spatial-database/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

