tag:blogger.com,1999:blog-11270143837864937692024-02-20T19:51:06.045-05:00SpatialNotesOdds and ends, primarily about working with spatial applications.mgleahyhttp://www.blogger.com/profile/17482269158762010855noreply@blogger.comBlogger6125tag:blogger.com,1999:blog-1127014383786493769.post-16821205671079633072011-06-15T12:05:00.000-04:002011-06-15T12:05:27.279-04:00Fix for Quantum GIS and Python bindings mismatch in Ubuntu 10.10<div dir="ltr" style="text-align: left;" trbidi="on">I'm one version behind on my Ubuntu distro (I've decided to wait until the next LTS before upgrading again, since I really need the time to get work done), so this may not be applicable to the latest version of Ubuntu (11.04). In any case, I recently noticed that Quantum GIS (QGIS) installed from the Ubutnu GIS 'unstable' repository was unable to link to the "Python/C++ bindings generator runtime library" (python-sip). The reported error when starting QGIS is as follows:<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Traceback (most recent call last):</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> File "", line 1, in </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">RuntimeError: the sip module implements API v8.0 but the qgis.core module requires API v7.1</span><br />
<br />
<div style="-qt-block-indent: 0; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-indent: 0px;"><br />
</div><div style="-qt-block-indent: 0; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-indent: 0px;">This shouldn't be a big surprise, since QGIS is being installed from a repository deliberately labelled 'unstable'. However, I was not interested in downgrading QGIS and/or any of the other packages that I draw from the Ubuntu GIS repository, and as far as I can tell, 'unstable' for this repository usually just means 'up-to-date', considering that the projects delivered through this repository are high quality as far as I am aware. Although, using this repo does require a bit of care; you may have to account for significant changes in new software versions in any dependent applications you have (e.g., MapServer brought a number of changes in the latest 6.0 release, which would have required users/web developers to update their mapfiles and/or scripted code).</div><br />
<br />
After a bit of googling around, I eventually found that I needed to downgrade two packages to maintain compatibility with QGIS: python-sip and python-qt4. I don't recall the original source (this was a few months ago), but if you a) want the latest Open Source GIS packages, and b) want to be able to use python-based capabilities/plug-ins on Ubuntu 10.10, then here's the steps:<br />
<br />
1. If you don't have it already, setup the Ubuntu GIS unstable repo, and install the latest QGIS package (1.7.0 at the time of this writing):<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> # sudo add-apt-repository </span><span class="Apple-style-span" style="line-height: 18px;"><span style="font-style: normal;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ppa:ubuntugis/ubuntugis-unstable</span></span></span><br />
<span class="Apple-style-span" style="line-height: 18px;"><span style="font-style: normal;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> # sudo apt-get install qgis</span></span></span><br />
<span class="Apple-style-span" style="line-height: 18px;"><span style="font-style: normal;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="line-height: normal;"></span></span></span></span><br />
<div style="font-family: 'Times New Roman'; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><span class="Apple-style-span" style="font-family: inherit;">2. Downgrade python-sip and python-qt4:</span></div><div style="font-family: 'Times New Roman'; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> # sudo apt-get install python-sip=4.10.5-0ubuntu1 python-qt4=4.7.4-0ubuntu1</span></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><span class="Apple-style-span" style="font-family: inherit;">3. If this works for you, you can consider 'pinning' the versions of these two packages so they don't get replaced the next time you install updates. You can choose whichever method is most appropriate for you here: <a href="https://help.ubuntu.com/community/PinningHowto">https://help.ubuntu.com/community/PinningHowto</a></span></div><div><span class="Apple-style-span" style="font-family: inherit;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: inherit;">I should note that QGIS will run without downgrading these python packages (albeit, after reporting the Python API errors on each startup). However, it will be necessary if you want to use plug-ins that require Python (e.g., the OpenLayers plugin - I've been using this version: <a href="https://github.com/TheGeoist/qgis-openlayers-plugin/">https://github.com/TheGeoist/qgis-openlayers-plugin/</a>).</span></div><div><span class="Apple-style-span" style="font-family: inherit;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: inherit;">I'd be interested to know if anyone has run into this problem with Ubuntu 11.04.</span></div><br />
<br />
</div>mgleahyhttp://www.blogger.com/profile/17482269158762010855noreply@blogger.com0tag:blogger.com,1999:blog-1127014383786493769.post-36439833993998451382011-02-28T20:44:00.001-05:002011-02-28T20:47:37.525-05:00Converting WKT projection info to Proj4 (and back) - the PHP editionAs noted in a <a href="http://spatialnotes.blogspot.com/2010/11/converting-wkt-projection-info-to-proj4.html">previous post</a>, it is fairly easy to utilize the language bindings for the GDAL project to work with projections. However, if you're working in PHP, the corresponding GDAL bindings are not maintained and currently do not work as-is from the GDAL project. As-of GDAL 1.8.0, a bit of tinkering will get the PHP modules to compile, but they still do not work as expected.<br />
<br />
However, you can get the php_osr.so module to work with some basic functions using the patch posted at <a href="http://pastebin.com/SXKKfe6v">http://pastebin.com/SXKKfe6v</a>. Save this to a file, and apply the patch to the gdal 1.8.0 source like so:<br />
<br />
<pre>cd /path/to/gdal/src
patch -p0 < /path/to/patch
</pre>
Then build and install the gdal code as follows:
<pre>./configure --with-php
make
make install
sudo cp swig/php/php_osr.so /usr/lib/php5/20090626/
sudo su -c \
'echo extension=php_osr.so > /etc/php5/conf.d/osr.ini'
sudo service apache2 restart
</pre>The above assumes:
- You're doing this on a typical/recent Ubuntu installation
- You already have Apache and PHP configured
- You already have all the required dependencies for building gdal and the swig bindings installed (if not, run "<pre style="display:inline">sudo apt-get build-dep libgdal-1.x.x</pre>", and also you may need to install php5-devel and php5-cli packages).
Once you've got gdal and the php_osr.so module compiled and installed, try the following PHP script:
<pre><?php
include("/path/to/gdal/src/swig/php/osr.php");
$sr = new SpatialReference();
$sr->ImportFromProj4('+init=epsg:4326');
echo $sr->ExportToProj4();
?>
</pre>The result from that script should be the following Proj4 string:
<pre>+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs
</pre><br />
Clearly, this is not as good as having all of the GDAL/OGR libraries accessible from PHP, but it's a start. You can review the swig/php/osr.php file to see what objects/functions are available through the php_osr.so module.mgleahyhttp://www.blogger.com/profile/17482269158762010855noreply@blogger.com0tag:blogger.com,1999:blog-1127014383786493769.post-47845896771372658542011-02-05T14:01:00.001-05:002011-02-05T14:04:18.805-05:00A web page hit counter that plots your visitors on a globe.<div dir="ltr" style="text-align: left;" trbidi="on">While reading someone's NASA blog, I came across this neat little widget that plots all of your visitors as points on a revolving globe (or flat static map if you prefer): <a href="http://www.revolvermaps.com/">http://www.revolvermaps.com</a><br />
<br />
It's free to use, and you can select from a variety of options to choose the coloring and style so that it fits into the layout of your website, and it can run using Flash or it will fail-over to Java (or neither if you choose a static map). I'm sure this isn't entirely new to everyone, as the site has been around for over two years, but it's fairly impressive regardless. I also gather that it collects visitor information for your site in their own database somewhere (it's not clear from the info available how this is done), so if privacy is a concern for users on your site, you may not want to add this to your site.<br />
<br />
I've added a sample below - I imagine the dots will remain fairly sparse for this blog. :)<br />
<br />
<script type="text/javascript" src="http://jc.revolvermaps.com/r.js"></script><script type="text/javascript">rm_f1st('6','220','true','false','000000','2ng16dtxv3k','true','4bc4bc');</script><noscript><applet codebase="http://rc.revolvermaps.com/j" code="core.RE" width="220" height="220" archive="g.jar"><param name="cabbase" value="g.cab" /><param name="r" value="true" /><param name="n" value="false" /><param name="i" value="2ng16dtxv3k" /><param name="m" value="6" /><param name="s" value="220" /><param name="c" value="4bc4bc" /><param name="v" value="true" /><param name="b" value="000000" /><param name="rfc" value="true" /></applet></noscript><br />
<br />
</div>mgleahyhttp://www.blogger.com/profile/17482269158762010855noreply@blogger.com0tag:blogger.com,1999:blog-1127014383786493769.post-21228814466736371942011-01-13T14:30:00.000-05:002011-01-13T14:30:13.937-05:00Creating a global control in OpenLayers for specific key combinationsThis is largely a follow-up to a previous post I made discussing how to effectively <a href="http://spatialnotes.blogspot.com/2010/11/capturing-right-click-events-in.html">capture right clicks</a> on an OpenLayers map object. That had been related to another objective that I had, which was to have a global control that always responds to the right click in order to display a basic context menu on the map. It's easy enough to get this working on the right-click, with all other controls working using the left click event - but what about Mac users, or people suffering from some kind of right-click impairment? This needs a modifier key to go along with the left-click, but then there needs to be some way to prevent other controls from being triggered at the same time.<br />
<br />
In OpenLayers, there is a common property that can be passed to handlers/controls, called keyMask. It is used in a bitwise comparison in the checkModifiers method of the OpenLayers.Handler class. The main issue I had was that it currently only works to allow a given control to be restricted to a specified key combination. It also does not allow you to have a single control that responds to different keys. Rather, any event keys added to the keyMask property of a control/handler must ALL be present in order for checkModifers to return true. However, here's the situation I wanted:<br />
<br />
<ol><li>Global control (context menu): triggers on right click, or left-click + alt, or left-click + ctrl (this allows users with a one-button mouse to still access the menu), and</li>
<li>All other controls: trigger on any left-click event that <b>excludes</b> the alt or ctrl keys.</li>
</ol>So to accomplish what I needed, I added a bit of code the checkModifiers function in the OpenLayers.Handler class to make it also check for a keyIMask property (i.e., an inverse key mask...though maybe that's not the best name for it). Where the current keyMask must match all keys included in the event in order for checkModifiers function to return true, if the keyIMask matches <b>any</b> keys included in the event, then checkModifiers returns false. Here's what it looks like:<br />
<div><br />
</div><div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">checkModifiers: function (evt) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if(this.keyMask == null && this.keyIMask == null) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return true;</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>/* calculate the keyboard modifier mask for this event */</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>var keyModifiers =</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>(evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>(evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>(evt.altKey ? OpenLayers.Handler.MOD_ALT : 0);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>/* if it differs from the handler object's key mask,</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>bail out of the event handler */</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return ((this.keyMask == null || keyModifiers == this.keyMask)</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>&& (this.keyIMask == null || (keyModifiers & this.keyIMask) == 0));</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></div></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div>With the Handler modified in this way, I can tell any control to <b>not</b> respond if any key in an event matches keyIMask. In my global control, it internally checks if the event is either right-click, or if it's a left-click with either the ctrlKey or altKey present. All of my other controls are set with the property "<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">keyIMask = OpenLayers.Handler.MOD_CTRL | OpenLayers.Handler.MOD_ALT;</span>", which prevents controls from being triggered when the menu is displayed, and still leaves room for MOD_SHIFT to be used either as a keyMask, or to internally modify the behaviour of control's events (e.g., the freehand toggle in the OpenLayers.Handler.Path class).</div>mgleahyhttp://www.blogger.com/profile/17482269158762010855noreply@blogger.com0tag:blogger.com,1999:blog-1127014383786493769.post-23486370160169101192010-11-21T19:59:00.002-05:002011-02-28T20:49:39.779-05:00Capturing right-click events in OpenLayersI've been looking at using OpenLayers as the mapping API for an application I've been working on for some time. One of the key features of the application requires capturing mouse click events on the map. This is fairly normal with OpenLayers for many of its controls, but when the right-click event is involved, I would always get the default context menu from the browser, and OpenLayers didn't seem to capture the rightclick event on its own. There are a few workarounds posted on the web...but I found they were not easily adaptable, or didn't quite work the way I wanted. So here's what I came up with - paste the code below at the end of the init() function in any of OpenLayers' examples:<br />
<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">===================================================</span><br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">// Get control of the right-click event:</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">document.getElementById('map').oncontextmenu = function(e){</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> e = e?e:window.event;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> if (e.preventDefault) e.preventDefault(); // For non-IE browsers.</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> else return false; // For IE browsers.</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">};</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">// A control class for capturing click events...</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, { </span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="white-space: pre;"></span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> defaultHandlerOptions: {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> 'single': true,</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> 'double': true,</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> 'pixelTolerance': 0,</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> 'stopSingle': false,</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> 'stopDouble': false</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> },</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> handleRightClicks:true,</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> initialize: function(options) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> this.handlerOptions = OpenLayers.Util.extend(</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> {}, this.defaultHandlerOptions</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> );</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> OpenLayers.Control.prototype.initialize.apply(</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> this, arguments</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> ); </span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> this.handler = new OpenLayers.Handler.Click(</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> this, this.eventMethods, this.handlerOptions</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> );</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> },</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> CLASS_NAME: "OpenLayers.Control.Click"</span><br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">});</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">// Add an instance of the Click control that listens to various click events:</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">var oClick = new OpenLayers.Control.Click({eventMethods:{</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">'rightclick': function(e) {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">alert('rightclick at '+e.xy.x+','+e.xy.y);</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">},</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">'click': function(e) {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">alert('click at '+e.xy.x+','+e.xy.y);</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">},</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">'dblclick': function(e) {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">alert('dblclick at '+e.xy.x+','+e.xy.y);</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">},</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">'dblrightclick': function(e) {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">alert('dblrightclick at '+e.xy.x+','+e.xy.y);</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}});</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">map.addControl(oClick);</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">oClick.activate();</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span><br />
<div style="font-family: 'Times New Roman'; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">===================================================</span></span></div><div style="font-family: 'Times New Roman'; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div><br />
<br />
<br />
<span class="Apple-style-span" style="font-family: inherit;">The first bit overrides the oncontextmenu event that causes the browser to display a context menu when the right-click event happens. The next bit creates a simple control class for handling the click events, with the handleRightClicks option enabled. After that, an instance of the control class is created, with functions for the four different click event types included in the eventMethods option. Finally, this control is added to the map and activated...any better solutions are welcome.</span><br />
<span class="Apple-style-span" style="font-family: inherit;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: inherit;"><b>EDIT: </b>This has been corrected to<span class="Apple-style-span" style="font-family: inherit;"> utilize the '</span></span><span class="Apple-style-span" style="font-family: inherit;">handleRightClicks' property in the OpenLayers class. Other than this, all that is essentially needed is the overridden oncontextmenu function, which uses preventDefault (for non-IE browsers), or returns false (for IE browsers).</span>mgleahyhttp://www.blogger.com/profile/17482269158762010855noreply@blogger.com8tag:blogger.com,1999:blog-1127014383786493769.post-72853590337923822392010-11-21T16:43:00.000-05:002010-11-21T20:51:25.975-05:00Converting WKT projection info to Proj4 (and back)I've had many occasions where I've had WKT-style projection text (e.g., the contents of the *.prj files that normally accompany ESRI Shapefiles, or the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">srtext</span> field in the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">spatial_ref_sys</span> table in PostGIS), and I needed to get that to an equivalent Proj4-compatible projection string (and vice versa). I've known for some time there had to be an automated way to do this...as the GDAL/OGR libraries have been doing this internally for some time. I ran into the issue again today, so I decided to poke around a bit, and found the API functions that are available to do this...I wrote my first ever Python scripts that use the GDAL/OGR python bindings (specifically, OSR). These scripts simply convert WKT projection text to Proj4 (wkt2proj.py) and back (proj2wkt.py). Maybe there are some better examples elsewhere...but I didn't quite find what I was looking for. Since my work is mostly in PHP right now, I'd love to see the GDAL/OGR PHP bindings maintained someday, but this will do for now:<br />
<div><br />
</div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">================== wkt2proj.py =======================</span></div><div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">#!/usr/bin/env python</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import os</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import sys</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import string</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import osgeo.osr</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">if (len(sys.argv) <> 2):</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> print 'Usage: wkt2proj.py [WKT Projection Text]'</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">else:</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> srs = osgeo.osr.SpatialReference()</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> srs.ImportFromWkt(sys.argv[1])</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> print srs.ExportToProj4()</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">======================================================</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">================== proj2wkt.py =======================</span></div><div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">#!/usr/bin/env python</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import os</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import sys</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import string</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import osgeo.osr</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">if (len(sys.argv) <> 2):</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> print 'Usage: proj2wkt.py [Proj4 Projection Text]'</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">else:</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> srs = osgeo.osr.SpatialReference()</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> srs.ImportFromProj4(sys.argv[1])</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> print srs.ExportToWkt()</span></div></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">======================================================</span></div></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: inherit;">On Ubuntu, provided you have the python-gdal package installed, the above files executed by python will accept the first argument as a wkt/proj projection string, and return the proj/wkt equivalent. For proj2wkt.py, you can also take advantage of known EPSG numbers. For example, the WKT for the Spherical Mercator projection used by most free online mapping services (e.g., Google Maps, OpenStreetMap, etc) will be returned by: </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">proj2wkt.py '+init=epsg:3857'</span></div><div><span class="Apple-style-span" style="font-family: inherit;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: inherit;">I haven't tested this on Windows - but as long as the Proj library is installed and the GDAL Python modules are installed and accessible to the Python environment, I imagine they will work the same. </span></div>mgleahyhttp://www.blogger.com/profile/17482269158762010855noreply@blogger.com0