<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ian Turton</title>
    <description>The latest articles on DEV Community by Ian Turton (@ianturton).</description>
    <link>https://dev.to/ianturton</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F5331%2F122529.gif</url>
      <title>DEV Community: Ian Turton</title>
      <link>https://dev.to/ianturton</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ianturton"/>
    <language>en</language>
    <item>
      <title>Drawing a line on a GeoTools Map using Java Swing</title>
      <dc:creator>Ian Turton</dc:creator>
      <pubDate>Mon, 08 May 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/ianturton/drawing-a-line-on-a-geotools-map-using-java-swing-1pdj</link>
      <guid>https://dev.to/ianturton/drawing-a-line-on-a-geotools-map-using-java-swing-1pdj</guid>
      <description>&lt;p&gt;As anyone following the dismal news out of the UK recently will know we had some sort of royal extravaganza down south in England this weekend, so with nothing better to do (and an extra day off) I decided to do some playing with GeoTools. This was mostly motivated by the work I had already done in answering this &lt;a href="https://gis.stackexchange.com/q/458918/79"&gt;gis.stackexchange.com question&lt;/a&gt; about how to draw a line on top of a map. It seems that there isn’t much about how to do this in the &lt;a href="https://docs.geotools.org/stable/userguide/unsupported/swing/index.html"&gt;GeoTools documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I scratched my head and dredged up what I could remember about swing and particularly about the GeoTools swing module and came up with some code that answered the immediate question which was why the OP got many layers in the map rather than one. I decided that this might be useful for other people so I tidied the code up and created a &lt;a href="https://gitlab.com/ianturton/geotools-tools"&gt;small project&lt;/a&gt; that contains a &lt;code&gt;DigitizerAction&lt;/code&gt; and a &lt;code&gt;Digitizer&lt;/code&gt; class which is the actual tool. It’s pretty simple all it does is place a series of dots on the screen and then generates a &lt;code&gt;LineString&lt;/code&gt; which is added to a list, which is then used to generate a new &lt;code&gt;FeatureLayer&lt;/code&gt; and removes the old layer (if it exists).&lt;/p&gt;

&lt;p&gt;I finished up by adding a little demo program which adds a draw button to the toolbar and displays the US States for you to draw over.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pfNOEIC_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.ianturton.com/images/draw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pfNOEIC_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.ianturton.com/images/draw.png" alt="A screenshot of the demo" title="A screenshot of the demo" width="620" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All you do is click the draw button, then each click on the map will add a point to the current line, a double click finishes the line and forces a redraw of the screen with the line now in red.&lt;/p&gt;

&lt;h2&gt;
  
  
  Details
&lt;/h2&gt;

&lt;p&gt;For anyone who’s trying to create a new tool for their swing application with GeoTools here is a little more on how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Action
&lt;/h3&gt;

&lt;p&gt;We need to create an &lt;code&gt;Action&lt;/code&gt; to tell swing what we plan to do, I called mine &lt;code&gt;DigitizerAction&lt;/code&gt; and made it extend &lt;code&gt;MapAction&lt;/code&gt; which Michael Bedward (the original author of the gt-swing module) helpfully provided to save us typing (or pasting) in a lot of boiler plate code. All I have to provide is some code to initialise the action’s icon, name etc and an &lt;code&gt;actionPerformed&lt;/code&gt; method to set the tool up to actually do something when the button is clicked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tool
&lt;/h3&gt;

&lt;p&gt;Again to save time and effort the &lt;code&gt;Digitizer&lt;/code&gt; tool extends &lt;code&gt;CursorTool&lt;/code&gt; which extends &lt;code&gt;MapMouseAdapter&lt;/code&gt; so we don’t need to worry about how to listen to the mouse’s movements or how to get a real world position from a mouse click. Much of the code is either set up or book keeping. For set up we need to generate a &lt;code&gt;FeatureType&lt;/code&gt; for the &lt;code&gt;Feature&lt;/code&gt;s we’ll be building later, and a style so they show up on the map (a more advanced tool might let the user override that default style). The only other thing to take care of in the constructor is setting the cursor to a simple cross hair.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   public Digitizer() {
        SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
        b.setName("LineFeature");
        b.add("line", LineString.class);
        SimpleFeatureType TYPE = b.buildFeatureType();
        featureBuilder = new SimpleFeatureBuilder(TYPE);
        geometryFactory = JTSFactoryFinder.getGeometryFactory(JTSFactoryFinder.EMPTY_HINTS);
        style = SLD.createLineStyle(Color.red, 2.0f);

        ImageIcon imgIcon = new ImageIcon(getClass().getResource(ICON_IMAGE));
        cursor = new Cursor(Cursor.CROSSHAIR_CURSOR);
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class also has some fields that we’ll need later &lt;code&gt;lastX&lt;/code&gt; and &lt;code&gt;lastY&lt;/code&gt; which is the position of the last click, an &lt;code&gt;ArrayList&lt;/code&gt; of &lt;code&gt;Coordinate&lt;/code&gt;s which are the real world positions of the current line, and a list of &lt;code&gt;SimpleFeature&lt;/code&gt;s which hold the lines that we have already drawn. We need to keep track of the previous features as the display layer is recreated every time we add a line.&lt;/p&gt;

&lt;p&gt;The actual interaction with the user all occurs inside the &lt;code&gt;onMouseClicked&lt;/code&gt; method which is called each time a mouse button is clicked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public void onMouseClicked(MapMouseEvent e) {

        if (e.getClickCount() &amp;gt; 1) { // was it a double click
            drawTheLine(positions);
            first = true;
        } else { // add a new point
            DirectPosition2D pos = e.getWorldPos();

            positions.add(new Coordinate(pos.x, pos.y));
            // Put a marker at each digitized point
            Graphics graphics = (Graphics2D) ((JComponent) getMapPane()).getGraphics().create();
            int x = e.getX();
            int y = e.getY();
            if (!first) {
                graphics.drawLine(lastX, lastY, x, y);
            }
            first = false;
            lastX = x;
            lastY = y;
            graphics.fillRect(x - 3, y - 3, 6, 6);
        }
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we first check if the user has clicked twice within the system time limit (so it is a double click), if it is we call the &lt;code&gt;drawTheLine&lt;/code&gt; method on the positions list to add the line to the screen, we’ll look at that in a moment. We also reset the &lt;code&gt;first&lt;/code&gt; flag to say that the next click (if there is one) is the first in a line.&lt;/p&gt;

&lt;p&gt;If the user only clicked once (or this is the first click of a double click) we will go through the &lt;code&gt;else&lt;/code&gt; branch, where we get the world position of the click and add that to our list of coordinates. We then grab a &lt;code&gt;graphics&lt;/code&gt; from our map pane to draw a temporary mark so the user knows we’re listening and have seen their click, here we need the X and Y pixel coordinates. If this is not the first point in the line we draw a line from the last point (&lt;code&gt;lastX&lt;/code&gt;, &lt;code&gt;lastY&lt;/code&gt;) to the current point (&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;) and then we draw a point at the current point (&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;). We also make a note of this point for next click to be the start of the line and note that we now have previous point by making &lt;code&gt;first&lt;/code&gt; false.&lt;/p&gt;

&lt;p&gt;The last remaining step is to draw lines on the map as &lt;code&gt;SimpleFeature&lt;/code&gt;s, this is done in &lt;code&gt;drawTheLine&lt;/code&gt; where we generate a new &lt;code&gt;LineString&lt;/code&gt; using the &lt;code&gt;GeometryFactory&lt;/code&gt;, we then add that &lt;code&gt;LineString&lt;/code&gt; to the &lt;code&gt;FeatureBuilder&lt;/code&gt; and create a new &lt;code&gt;SimpleFeature&lt;/code&gt; from it. Note that we leave the &lt;code&gt;id&lt;/code&gt; set to &lt;code&gt;null&lt;/code&gt; so it generates a new &lt;code&gt;FID&lt;/code&gt; for each feature. The feature is then stored in the &lt;code&gt;features&lt;/code&gt; list, the existing layer is removed from the map (to prevent us ending up with an ever increasing number of map layers). Then we create a new &lt;code&gt;FeatureLayer&lt;/code&gt; using the &lt;code&gt;DataUtilities.collection&lt;/code&gt; method to convert our list of &lt;code&gt;SimpleFeature&lt;/code&gt;s to a &lt;code&gt;SimpleFeatureCollection&lt;/code&gt; and applying the style we made earlier. Finally, we reset the &lt;code&gt;positions&lt;/code&gt; list to empty to be ready to store the next line for the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;If you want to use this in your own map you can simply do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    mapFrame = new JMapFrame();
    mapFrame.enableToolBar(true);
    JToolBar toolBar = mapFrame.getToolBar();
    DigitizerAction d = new DigitizerAction(mapFrame.getMapPane());
    JButton btn = new JButton(d);
    toolBar.addSeparator();
    toolBar.add(btn);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then get the list of features by using &lt;code&gt;d.getFeatures()&lt;/code&gt; if you want to provide a save function or to send them to some other store.&lt;/p&gt;

</description>
      <category>geotools</category>
      <category>java</category>
      <category>swing</category>
    </item>
    <item>
      <title>Some interesting books I've read recently</title>
      <dc:creator>Ian Turton</dc:creator>
      <pubDate>Mon, 04 Jul 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/ianturton/some-interesting-books-ive-read-recently-b95</link>
      <guid>https://dev.to/ianturton/some-interesting-books-ive-read-recently-b95</guid>
      <description>&lt;h1&gt;
  
  
  Interesting Books
&lt;/h1&gt;

&lt;p&gt;This is a short post to let you know about some interesting books I’ve recently finished that you might find interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Atlas of Unusual Borders
&lt;/h2&gt;

&lt;p&gt;Or to give it its full title &lt;em&gt;The Atlas of Unusual Borders: Discover intriguing boundaries, territories and geographical curiosities&lt;/em&gt; by Zoran Nikolic. I blame Barry Rowlingson who threw a link to it into a twitter discussion on borders, so I had to buy it. And, to be honest I’m very happy I did, it is an atlas of “interesting” border enclaves and other geographic oddities. So if like me you’ve ever wondered why Belgium has some many enclaves (and &lt;a href="https://en.wikipedia.org/wiki/Enclave_and_exclave"&gt;exclaves&lt;/a&gt;, and counter-enclaves) (or you just wondered what those are) this is the book that you &lt;strong&gt;need&lt;/strong&gt; in your library. It also answers questions such as which capital city is a ghost town too? Plymouth, Montserrat to save you trying to look it up. This is a fascinating book with nearly every page leading to a “I didn’t know that”. My only minor quibble with it is the colour scheme of the maps, I really struggle with maps where the land is blue and the sea is grey, and with the highlights as yellow it is probably not a book for anyone with blue/yellow colour blindness.&lt;/p&gt;

&lt;h2&gt;
  
  
  git commit murder and git sync murder
&lt;/h2&gt;

&lt;p&gt;This pair of books by Michael Warren Lucas, are murder mysteries set at technical conferences. If you have ever been to an open source conference (such as &lt;a href="http://foss4g.org/"&gt;FOSS4G&lt;/a&gt;) then you will recognise many of the characters in these books. In the first book set at the (fictional) BSDNorth conference our hero Dale Whitehead sets out to give a technical talk but is sidetracked by the death of his room mate (and the weight of his laptop bag, which he seems to never get around to clearing out). I found this a very believable account of free software development, technical conferences and Unix hackers, though while I may have considered killing a user I’ve never actually done it!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;git sync murder&lt;/em&gt; sees Dale forced to attend another conference despite his promise to himself to never leave his apartment ever again. Once again, things quickly spin out of his control and that laptop bag is no lighter than last time. I loved both these books and can thoroughly recommend them if you are at all into whodunits.&lt;/p&gt;

&lt;p&gt;Finally, if you enjoy conferences/convention books then I’ll throw in Charlie Stross’ &lt;a href="https://epdf.tips/charles-stross-dechlorinating-the-moderator.html"&gt;&lt;em&gt;Dechlorinating the Moderator&lt;/em&gt;&lt;/a&gt; which I read in his collected Toast volume which reports from a futuristic 2018 Particulate 7: HiNRG &amp;amp; B-OND conference, for a fun short story.&lt;/p&gt;

</description>
      <category>books</category>
    </item>
    <item>
      <title>Open Source and Sanctions</title>
      <dc:creator>Ian Turton</dc:creator>
      <pubDate>Fri, 11 Mar 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/ianturton/open-source-and-sanctions-3ocm</link>
      <guid>https://dev.to/ianturton/open-source-and-sanctions-3ocm</guid>
      <description>&lt;h2&gt;
  
  
  Some Thoughts On Open Source Programs and Sanctions
&lt;/h2&gt;

&lt;p&gt;To start this post first let me state that this represents my personal view and may or may not be the view of any of the projects I mention and that I completely and utterly condemn the Russian invasion of Ukraine.&lt;/p&gt;

&lt;p&gt;In the last 2 weeks since Russia invaded Ukraine I have been seeing a number of tweets and other comments that a) ESRI should pull out of Russia and invalidate the licences it has sold in the country, and b) (usually from different people) what about the open source community? Should they ban downloads from Russia.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; : I’m firmly on the side of no, there is nothing open source programs and communities can do to prevent people they don’t like using their code to do things they don’t approve of.&lt;/p&gt;

&lt;p&gt;If you’re still reading then let me lay out some of my thinking, again this makes more sense if you remember that I’m old so I’ve seen most of these discussions in some form or another before. I can remember when the open source community went to court in the USA to try to determine that &lt;a href="https://hoffmang9.github.io/free-speech/the-history-code-is-free-speech.html"&gt;code was free speech&lt;/a&gt; as at the time it was illegal to export “munitions” in the form of encryption software from the USA. Interestingly we are still seeing remnants of this in (for example) &lt;a href="https://blog.cleverelephant.ca/2006/12/not-so-free-client-libraries.html"&gt;Oracle’s JDK and JDBC libraries&lt;/a&gt;. There is a certain arrogance to this sort of blocking moves. It screams (at least to me) “We Americans are so smart no puny European (or North Korean or …) can program like we do!” But I don’t think that’s true and I have worked with a lot of European, Russian, and other nationality programmers over the years and I have never noticed that they are in any way dumber than the Americans I’ve worked with. So I think that banning countries from downloading programs is a stupid idea, also it’s very hard to do well and make actually work in a world with easy VPNs. And does any one really think that say North Korea will be defeated by a click through licence that asks them not to do something.&lt;/p&gt;

&lt;p&gt;So in the abstract I don’t think banning will work, in the case of open source software it is doubly impossible because we don’t even know how many users we have or where they are or even who is distributing our code. As Jáchym Čepický said on twitter:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You do not understand the concept of open source software do you? Nobody can block the software to be downloaded and used for any purpose - even if it was evil. As community member, you can refuse support, you can cancel some other members. But nobody really “owns” the software.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve watched some of the other FOSS4G communities discuss this (often at some length) and essentially come to the same conclusion. QGis decided to put a notice in the News Tab of the new release, and someone promptly complained that they didn’t want “politics” in their software, Leaflet changed it’s &lt;a href="https://leafletjs.com/"&gt;home page&lt;/a&gt; to make clear their concerns for Vladimir Agafonkin who started the project 11 years ago and has been forced to leave his home in Ukraine due to the invasion. These are both great responses and I fully support them, GeoServer and GeoTools haven’t done anything similar, partly because no one raised the issue and partly because making a statement will not actually change anything, so I’d rather donate money to charities supporting Ukrainian refugees such as the &lt;a href="https://savelife.in.ua/en/donate/"&gt;https://savelife.in.ua/en/donate/&lt;/a&gt; charity, or the &lt;a href="https://redcross.org.ua/en/"&gt;Ukrainian Red Cross&lt;/a&gt;, where it will actually make life (marginally) better for someone.&lt;/p&gt;

&lt;p&gt;Finally, this leads us to the old argument from the &lt;a href="https://www.routledge.com/Ground-Truth-The-Social-Implications-of-Geographic-Information-Systems/Pickles/p/book/9780898622959"&gt;“postmodern geographers”&lt;/a&gt; (that I left academia to avoid) who always felt that GIS was a tool of the military industrial complex and so could never be used for good. To which I’ve always said so what, many things I use in every day life were developed by the military (or for the military), there is a reason for that the military has an almost unlimited budget (when did you last see a collection tin for a new tank rather than a new MRI machine?) so they can spend absurd amounts of money on research and development. More than once I’ve been happy to take that money and use it to develop open source computer programs that all of humanity can use (and prevent them buying more explosive toys with the cash instead). Does that mean I have blood on my hands when the UK Army uses (say) GeoServer to plan it’s deployments in Afghanistan? Or would it have been worse if I hadn’t cooperated and they had used another map server or just paper maps. Am I concerned to learn that &lt;a href="https://endofcap.tistory.com/1960"&gt;North Korea uses GeoServer, GeoTools and PostGIS&lt;/a&gt;? In both cases no, I am happy that we have another satisfied user and I hope they contribute back but like most of our users I expect to never hear from them once.&lt;/p&gt;

&lt;p&gt;In conclusion, there is no way for anyone to truly block access to open source software, in fact that is rather the point of open source software, and if there was a way to block people there is every chance that a government somewhere would object to me (or my country) or something about me to block my use of some software.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>How does contributing to open source work (for me)?</title>
      <dc:creator>Ian Turton</dc:creator>
      <pubDate>Sun, 26 Sep 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/ianturton/how-does-contributing-to-open-source-work-for-me-49ko</link>
      <guid>https://dev.to/ianturton/how-does-contributing-to-open-source-work-for-me-49ko</guid>
      <description>&lt;p&gt;Recently, we have been on boarding some new staff at &lt;a href="https://www.astuntechnology.com/"&gt;Astun&lt;/a&gt; (where I work) and one of the questions that seems to keep coming up is “how does open source work?” So I’ve been giving a bit more thought to how and why I contribute to open source projects than I usually do, and whether open source is sustainable in this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some history
&lt;/h2&gt;

&lt;p&gt;You have to remember that I’m old (really old in computing terms) such that when I started out if you wanted software on your Unix computer you compiled it yourself from open sources or wrote it yourself. There was of course some provided code on the machine after all you needed to use Sun’s &lt;code&gt;cc&lt;/code&gt; to compile &lt;code&gt;gcc&lt;/code&gt; so you could compile everything else you needed. Linux was just starting to be available when I started my first job but most of our work was done on Sun workstations. As I was working at a university (during the Thatcher years) the big draw of open source code was the cost (free) but over time I also came to appreciate the value of being able to look at the source code to see how a program worked so I could either write something similar or fix the problem I had found. I found my first compiler bug while I was working on my PhD and fortunately could print out that piece of code to take to the support team to show them why it was wrong.&lt;/p&gt;

&lt;p&gt;When we completed the program I was developing in that first job I released it under the GNU Public Licence (GPL). Partly because it was too hard to work out who owned it - the university (my employer) who claimed to own anything I wrote or the ESRC (the funder) who also claimed to own anything I wrote when funded by them. I could foresee spending time in small offices talking to lawyers if we tried to commercialise it, and that didn’t appeal.&lt;/p&gt;

&lt;p&gt;During the next few years, James Macgill and I started writing and collecting useful bits of Java code into what became &lt;a href="https://geotools.org"&gt;GeoTools&lt;/a&gt; version 1. Again we gave the code away under the GPL, partly for the same reasons as before but mostly so we could help other people produce repeatable science. We likened computational geography to (say) chemistry before commercial glass ware became available - your experiment might fail to replicate someone’s results not because their results were wrong but because you had built the apparatus wrong. We felt (and still do) that if the only way to check someone’s paper was to drop thousands of pounds (or dollars) on a copy of Arc/Info then that was a problem (and how could we know there were no bugs in Arc/Info). So we encouraged others to take our code and check it, extend it and pass it on to other users, in then hope that better science would be produced.&lt;/p&gt;

&lt;p&gt;Along the way we came across the Open Geospatial Consortium (OGC) and the web map test bed which fitted nicely with some work I was involved in on the public participation in planning which needed maps on the web (though in those days we still had to take computers out to the public to get useful numbers of users). We also met Chris Holmes and Rob Hranac of the Open Planning Project who were also working on this sort of thing. From those meetings &lt;a href="https://geoserver.org"&gt;GeoServer&lt;/a&gt; was born, again we all benefited from access to other open source code and again released the project under the GPL to encourage reuse and contributions.&lt;/p&gt;

&lt;p&gt;Overtime we pulled in code such as &lt;a href="https://web.archive.org/web/20120123115547/http://www.geotoolkit.org:80/history.html"&gt;Seagis&lt;/a&gt; or built on top of other open source code such as &lt;a href="https://projects.eclipse.org/projects/locationtech.jts"&gt;JTS&lt;/a&gt;. We also added support for a variety of new data sources in a plugable way that allowed others to add just the bits of code they needed.&lt;/p&gt;

&lt;p&gt;Next year sees the 20th anniversary of GeoTools version 2 and the project is still progressing nicely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;A lot of my job is now providing training and support to users of GeoServer (along with QGIS and other open source geospatial projects). Some of that “support” time is used to maintain the bits of GeoServer and GeoTools that are not actually fun (security updates and other technical debt). In my other working day of the week (when I freelance) I help out people who would like some custom GeoTools code written. For example, the ability to specify which transform you’d like to use when converting to and from a coordinate reference system (&lt;a href="https://osgeo-org.atlassian.net/browse/GEOT-6920"&gt;GEOT-6920&lt;/a&gt;) was funded by the Tanzanian Ministry of Home Affairs. And finally in my spare time I write code that interests me, there are many sources of ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://osgeo-org.atlassian.net/jira/software/c/projects/GEOT/issues"&gt;GeoTools&lt;/a&gt; and &lt;a href="https://osgeo-org.atlassian.net/jira/software/c/projects/GEOS/issues"&gt;GeoServer&lt;/a&gt; issue trackers are often fertile places to search.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gis.stackexchange.com/questions/tagged/geotools"&gt;GeoTools questions&lt;/a&gt; on gis.stackexchange.com are always likely too.&lt;/li&gt;
&lt;li&gt;Other questions I see around on twitter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically though something has to sound interesting for me to spend my limited free time on it. After all I don’t have a lot of free time to program and I really want to spend that time having fun (or I could be doing something else that is fun instead). The only other thing that motivates me is that some bug (or lack of feature) is embarrassing, for example I recently finished off &lt;a href="https://osgeo-org.atlassian.net/browse/GEOS-10067"&gt;Jody’s work that allows GeoServer administrators see which modules and extensions are loaded&lt;/a&gt; in their version. Every time we went to this page when I was running a GeoServer course I would have to explain why this page didn’t actually show &lt;em&gt;all&lt;/em&gt; the extensions (including the one we had just added) and there was really no go reason other than lack of time (and funding) so I just sat down and fixed the remaining modules (except the community ones, you are still on your own there). This means that the next GeoServer course will be slightly more fun for me to do (provided I’ve updated to 2.20.x).&lt;/p&gt;

&lt;p&gt;So recently “projects” have been adding some functionality to GeoTools that I was interested in such as &lt;a href="https://blog.ianturton.com/geotools/2020/12/24/contours.html"&gt;contouring point layers&lt;/a&gt;. I had always wondered how it was done, and GeoTools currently couldn’t do it and I had the whole of the christmas holiday to play. I’ve also recently had a look at how to maintain &lt;a href="https://blog.ianturton.com/geotools/2021/08/23/Topological-Adventures.html"&gt;topologically correct borders between polygons when simplifying them&lt;/a&gt;. This came from a &lt;a href="https://gis.stackexchange.com/q/407860/79"&gt;question&lt;/a&gt; on gis.stackexchange and again turned out to be an interesting problem that is probably useful for many users. The latest project is looking at adding a &lt;a href="https://blog.ianturton.com/geotools/2021/08/23/Skeletons.html"&gt;label line along the centre of a polygon&lt;/a&gt;. In asking for more help on this problem I’ve found that &lt;a href="https://github.com/MapServer/MapServer/pull/5854"&gt;MapServer is trying to add this functionality&lt;/a&gt; too (so now it’s a race). In the time this blog post has been languishing part written I’ve managed to finish this up (the &lt;a href="https://gis.stackexchange.com/a/411926/79"&gt;answer&lt;/a&gt; is to use Dijkstra to find the longest shortest path between nodes of index 1).&lt;/p&gt;

&lt;p&gt;So, I now have a much better handle on how JTS works (for some functions anyway) and more respect for topology than I used to. I think that next I might try to look at some problems that don’t require me to read up on graphs. The obvious next step is to package up the code with some unit tests, push it in the GeoTools code base and then add something to the GeoServer manual so that other people can use them. I promise I will get around to that some time (if you would like me to do it urgently then please get it touch and I can talk you through the process or give up a price).&lt;/p&gt;

&lt;p&gt;If you would like to know more of how I (and Andrea) spend our time please come and watch &lt;a href="https://2021-foss4g.venueless.events/schedule/talks/VCGQZX"&gt;our talk at FOSS4G 2021&lt;/a&gt; (it’s this Wednesday at 13:00UTC).&lt;/p&gt;

</description>
      <category>osgeo</category>
    </item>
    <item>
      <title>Beginners Python Books</title>
      <dc:creator>Ian Turton</dc:creator>
      <pubDate>Fri, 02 Oct 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ianturton/beginners-python-books-n9c</link>
      <guid>https://dev.to/ianturton/beginners-python-books-n9c</guid>
      <description>&lt;h1&gt;
  
  
  Beginners Python Books
&lt;/h1&gt;

&lt;p&gt;I recently found my self with some time to kill (you don’t have to watch the Tour De France that closely) and as I had a &lt;a href="https://astuntechnology.github.io/Python-For-QGIS/"&gt;Python for QGIS&lt;/a&gt; course coming up for the first time in a year I thought I could use some revision. I’m not a “native” python writer (lack of types while liberating is also scary to a Java boy like me), so brushing up on my Python seemed like a good idea. I had recently bought two new Python books from Manning. &lt;a href="https://www.manning.com/books/tiny-python-projects"&gt;&lt;strong&gt;Tiny Python Projects&lt;/strong&gt; by Ken Youens-Clark&lt;/a&gt; and &lt;a href="https://www.manning.com/books/python-workout"&gt;&lt;strong&gt;Python Workout&lt;/strong&gt; by Reuven M. Lerner&lt;/a&gt; and this was an ideal opportunity to read through them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tiny Python Projects
&lt;/h2&gt;

&lt;p&gt;Tiny Python Projects comes as a series of 22 chapters where you build a new program against a set of unit tests that the author provides via a git repository. They start off simple hello world program and building through strings, lists and dictionaries. Then adding functions (and testing functions) to algorithms and regular expressions to finish up with a working tic-tac-toe (noughts and crosses) game. I found this book great fun to read and in the later chapters to code along to as well. The emphasis on test driven development is, I think, a really useful process for new programmers to get used to. All to often I see students (and others) who write some code and hope that it works but often never check it (in some cases ever). If I’ve learnt anything in the 30 odd years I’ve been coding it’s that without a test that code is worthless, if only because when you come back to it the test will remind you how to run it if nothing else. One of the things that seems to upset new contributors to GeoServer and GeoTools is our insistence on a test case before we start to look into their issue, the trouble is that with no test how can we know if we fixed your problem. So any book which helps to instil this understanding of the necessity of testing in new coders is great.&lt;/p&gt;

&lt;p&gt;The topics covered a wide ranging and while often silly (e.g. spotting animals from the crows nest) they cover a good depth of python topics and I think a new python programmer could easily teach themselves how to produce complex (and correct) programs to could do useful work from this book. If you plan to go on to use Python in a specific domain then there would almost certainly be new modules and packages that you would want to explore and learn but this book would give you the grounding that you’d need to understand the documentation and examples that this would lead to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python Workout
&lt;/h2&gt;

&lt;p&gt;Python Workout’s subtitle is 50 ten-minute exercises, and this gives you a flavour of the book’s contents. As it sounds each chapter is a single exercise with discussion on the “best” solution and why it is in the author’s opinion the best way of solving it. There are also videos of the author solving each problem which some might find useful as it does give an insight into the way that the solution is developed. Most of the chapters also provide a link to &lt;a href="http://pythontutor.com/"&gt;Python Tutor&lt;/a&gt; which allows you to step through some python code and see what happens as each line is executed. This tool is new to me but I think I will be looking at adding it to my teaching in the future.&lt;/p&gt;

&lt;p&gt;Again the topics covered in Python Workout start at simple numbers, strings, lists, dictionaries before more complex functions, functional programming with comprehensions, modules and packages and finishing up with creating your own iterators and generators. There is something here for everyone from beginners to experienced python programmers, and it is all nicely packaged up to give you a daily workout. The style is less formal that Tiny Python Projects with less emphasis on writing tests to make sure you have solved the problem but with more discussion on how to approach solving the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Both of these books would be a great introduction to python to new programmers, and for programmers who are converting from another language. They provide a clear introduction to the language and the features that make python different from (or the same as) other languages, and take you through to the complex features that make programming with python fun (and challenging).&lt;/p&gt;

&lt;p&gt;At first sight the books might seem expensive but Manning produce very nice well made physical and electronic books and you get the source code too. If you by the physical book you get the e-book for free where ever you buy it so you can save on shipping by ordering it locally. Also if it looks expensive today, wait a day or two and Manning will almost certainly be having a 40% off sale, or a buy one get one free week or some other deal, I don’t think I have ever paid full price for one of their books.&lt;/p&gt;

</description>
      <category>review</category>
      <category>python</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How I made writing my code journal easier</title>
      <dc:creator>Ian Turton</dc:creator>
      <pubDate>Tue, 07 Apr 2020 08:32:07 +0000</pubDate>
      <link>https://dev.to/ianturton/how-i-made-writing-my-code-journal-easier-4hd3</link>
      <guid>https://dev.to/ianturton/how-i-made-writing-my-code-journal-easier-4hd3</guid>
      <description>&lt;p&gt;Liquid syntax error: 'raw' tag was never closed&lt;/p&gt;
</description>
      <category>journaling</category>
      <category>vim</category>
      <category>bash</category>
      <category>automation</category>
    </item>
    <item>
      <title>Speeding up like queries in PostGIS (and GeoServer)</title>
      <dc:creator>Ian Turton</dc:creator>
      <pubDate>Wed, 04 Apr 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/ianturton/speeding-up-like-queries-in-postgis-and-geoserver-2md4</link>
      <guid>https://dev.to/ianturton/speeding-up-like-queries-in-postgis-and-geoserver-2md4</guid>
      <description>&lt;p&gt;I often use &lt;code&gt;like&lt;/code&gt; queries in PostGIS and with GeoServer into a PostGIS datastore. But recently a trainee on course asked if they were fast enough to allow them to use in a CQL query to allow the end user to generate new layers on the fly.&lt;/p&gt;

&lt;p&gt;After some Googling we discovered that they probably are but that there are a few tricks you need to use to get the benefits of the index.&lt;/p&gt;

&lt;p&gt;I had always indexed any attribute (column) that I intended to use in the styling of a layer or that would be queried in requests. But it turns out that might not be good enough if you are making &lt;code&gt;like&lt;/code&gt; queries.&lt;/p&gt;

&lt;p&gt;To test this out I’m using the Ordnance Survey open data &lt;a href="https://www.ordnancesurvey.co.uk/business-and-government/products/vectormap-district.html"&gt;Vector Map District&lt;/a&gt;dataset for the whole of Great Britain, it’s large but not enormous. For example the roads table has 2.8 million road segments of which 800 thousand are named. Here is the “default” index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_distinictive_name
  ON vmd.road
  USING btree
  (distinctivename COLLATE pg_catalog."default");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, I ran a typical query to find how many roads are named after some sort of Oak tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select distinctivename, count(ogc_fid) 
from vmd.road 
where distinctivename
like '%oak%' 
group by distinctivename order by count desc;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On my desktop machine this takes 162 milliseconds to run, which is not too bad but it could probably be better. If we look at the query plan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sort (cost=83988.80..83988.97 rows=67 width=21)
  Sort Key: (count(ogc_fid)) DESC
  -&amp;gt; Finalize GroupAggregate (cost=83978.87..83986.77 rows=67 width=21)
      Group Key: distinctivename
      -&amp;gt; Gather Merge (cost=83978.87..83985.82 rows=56 width=21)
          Workers Planned: 2
          -&amp;gt; Partial GroupAggregate (cost=82978.84..82979.33 rows=28 width=21)
              Group Key: distinctivename
              -&amp;gt; Sort (cost=82978.84..82978.91 rows=28 width=17)
                    Sort Key: distinctivename
                    -&amp;gt; Parallel Seq Scan on road (cost=0.00..82978.17 rows=28 width=17)
                          Filter: ((distinctivename)::text ~~'%oak%'::text)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no mention of an index! Wow! I’d never really checked on this before so this was a bit of a shock. So after a bit of strategic googling I found this&lt;a href="https://stackoverflow.com/questions/1566717/postgresql-like-query-performance-variations"&gt;stackoverflow question and answer&lt;/a&gt;, which recommended that I add the &lt;code&gt;pg_trgm&lt;/code&gt; extension so that I had GIN and GiST trigram indexes that support all &lt;code&gt;like&lt;/code&gt; and &lt;code&gt;ilike&lt;/code&gt; patterns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE EXTENSION pg_trgm

CREATE INDEX idx_distinictive_name2
  ON vmd.road
    USING gin
      (distinctivename COLLATE pg_catalog."default" gin_trgm_ops);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the query takes a mere 20 milliseconds and the query plan looks a lot better with an index in use front and centre:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sort (cost=284.30..284.47 rows=67 width=21)
  Sort Key: (count(ogc_fid)) DESC
  -&amp;gt; GroupAggregate (cost=281.10..282.27 rows=67 width=21)
        Group Key: distinctivename
        -&amp;gt; Sort (cost=281.10..281.26 rows=67 width=17)
              Sort Key: distinctivename
              -&amp;gt; Bitmap Heap Scan on road (cost=16.52..279.07 rows=67 width=17)
                    Recheck Cond: ((distinctivename)::text ~~'%oak%'::text)
                    -&amp;gt; Bitmap Index Scan on idx_distinictive_name2 (cost=0.00..16.50 rows=67 width=0)
                          Index Cond: ((distinctivename)::text ~~'%oak%'::text)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of these speed ups are passed directly to GeoServer when you are using a PostGIS datastore as these queries are passed down to the database to handle. So it pays to make sure you have not just indexed an attribute but that you are using the right index for the type of queries you expect to see.&lt;/p&gt;

&lt;p&gt;For the larger &lt;a href="https://www.ordnancesurvey.co.uk/business-and-government/products/vectormap-local.html"&gt;Vector Map Local&lt;/a&gt; data using &lt;code&gt;ILIKE&lt;/code&gt; since the Ordnance Survey used all caps for the road names, the speed up is from 760ms to 122ms.&lt;/p&gt;

</description>
      <category>postgis</category>
    </item>
    <item>
      <title>Finding anagrams of place names (in GB)</title>
      <dc:creator>Ian Turton</dc:creator>
      <pubDate>Wed, 20 Dec 2017 00:00:00 +0000</pubDate>
      <link>https://dev.to/ianturton/finding-anagrams-of-place-names-in-gb-3o38</link>
      <guid>https://dev.to/ianturton/finding-anagrams-of-place-names-in-gb-3o38</guid>
      <description>&lt;p&gt;A little while ago &lt;a href="https://twitter.com/undertheraedar/status/940308258916585474"&gt;Alasdair Rae&lt;/a&gt; asked if any one had combined an anagram engine with a list of place names.&lt;/p&gt;

&lt;p&gt;Well, no one stepped forward so I thought it could be a fun project. And, it turns out it is quite fun though I got to think about data structures rather more than geography, but that is probably good for me.&lt;/p&gt;

&lt;p&gt;I made the assumption that Alasdair was probably not interested in just permutations of letters but wanted actual words (such as would be used in a crossword clue). I also limited my search to single word anagrams as I can’t see a simple solution to finding multi word solutions.&lt;/p&gt;

&lt;p&gt;First I stuffed the Ordnance Survey’s OpenNames data set into PostGIS (as who wants to be scanning hundreds of little csv files).&lt;/p&gt;

&lt;p&gt;I then set up a &lt;a href="http://geotools.org"&gt;GeoTool’s&lt;/a&gt; &lt;a href="http://docs.geotools.org/stable/userguide/library/jdbc/postgis.html"&gt;PostGIS datastore&lt;/a&gt; and grabbed the populated places.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Map&amp;lt;String, Object&amp;gt; params = new HashMap&amp;lt;String, Object&amp;gt;();
    params.put(PostgisNGDataStoreFactory.DBTYPE.key, PostgisNGDataStoreFactory.DBTYPE.sample);
    params.put(PostgisNGDataStoreFactory.USER.key, "username");
    params.put(PostgisNGDataStoreFactory.PASSWD.key, "password");
    params.put(PostgisNGDataStoreFactory.SCHEMA.key, "opennames");
    params.put(PostgisNGDataStoreFactory.DATABASE.key, "osdata");
    params.put(PostgisNGDataStoreFactory.HOST.key, "127.0.0.1");
    params.put(PostgisNGDataStoreFactory.PORT.key, "5432");

      DataStore ds = DataStoreFinder.getDataStore(params);
    if (ds == null) {
      throw new RuntimeException("No datastore");
    }
    SimpleFeatureSource fs = ds.getFeatureSource("opennames");
    SimpleFeatureCollection features = fs.getFeatures(CQL.toFilter("type = 'populatedPlace'"));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tried a naive approach of recursively finding every anagram possible from the name and looking each one up in a &lt;code&gt;HashMap&lt;/code&gt; of English words. Oddly, this took a long time so I thought (and Googled) some more and came up with the much more efficient way of sorting the letters in a word and using that as a key to all words that contained those letters. Then I could sort each place name’s letters and do a single lookup to find all the possible words that could be made with those letters. That speeded things up nicely.&lt;/p&gt;

&lt;p&gt;To build the lookup table I made use of Google’s &lt;code&gt;HashMultimap&lt;/code&gt; (from&lt;a href="https://github.com/google/guava"&gt;Guava&lt;/a&gt;) which allows you to create a &lt;code&gt;Map&lt;/code&gt; of&lt;code&gt;Collections&lt;/code&gt; keyed on a &lt;code&gt;String&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private Map&amp;lt;String, Collection&amp;lt;String&amp;gt;&amp;gt; dict;

  public AnagramLookup() throws FileNotFoundException, IOException {
    //change this to point to your dictionary (one word per line)
    File f = new File("/usr/share/dict/british-english");
    HashMultimap&amp;lt;String, String&amp;gt; indexedDictionary = HashMultimap.create();
    try (BufferedReader buf = new BufferedReader(new FileReader(f))) {
      String line;
      // read each word in the dictionary
      while ((line = buf.readLine()) != null) {
        //strip out non letters
        String word = line.toLowerCase().replaceAll("\\W", "");
        //store the word against the sorted key
        indexedDictionary.put(sort(word), word);
      }
    }
    dict = indexedDictionary.asMap();
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then all that is left to do is to iterate each populated place, grab it’s name and then remove all the non-letters and sort it’s letters and look the anagrams in the &lt;code&gt;HashMap&lt;/code&gt;. The final trick is to remove the name itself if it appears in the list of anagrams (i.e. the name itself is an English word).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try (SimpleFeatureIterator itr = features.features()) {

      while (itr.hasNext()) {

        SimpleFeature f = itr.next();
        String name = (String) f.getAttribute("name1");

        current = name.toLowerCase().replaceAll("\\W", "");
        Collection&amp;lt;String&amp;gt; anagrams = getAnagrams(current);

        if(anagrams!=null &amp;amp;&amp;amp; !anagrams.isEmpty()) {
          //remove the name itself if it happens to be a word
          anagrams.remove(current);
          if(!anagrams.isEmpty()) {
            results.put(name, new TreeSet&amp;lt;String&amp;gt;(anagrams));
          }
        }
      }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;It turns out that there are 6 11 letter anagrams for the list of GB place names.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Balnadelson - belladonnas&lt;/li&gt;
&lt;li&gt;Fortis Green - reforesting&lt;/li&gt;
&lt;li&gt;Gilling East - legislating&lt;/li&gt;
&lt;li&gt;Green Plains - spenglerian&lt;/li&gt;
&lt;li&gt;Morningside - modernising&lt;/li&gt;
&lt;li&gt;Sharrington - harringtons&lt;/li&gt;
&lt;li&gt;Stone Corner - cornerstone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;a href="https://www.merriam-webster.com/dictionary/Spenglerian"&gt;Spenglerian&lt;/a&gt; is “of or relating to the theory of world history developed by Oswald Spengler which holds that all major cultures undergo similar cyclical developments from birth to maturity to decay”. While a&lt;a href="https://en.oxforddictionaries.com/definition/harrington"&gt;Harrington&lt;/a&gt; is “a man’s short lightweight jacket with a collar and a zipped front.”&lt;/p&gt;

&lt;p&gt;Other highlights for crossword setters include Aimes Green as menageries and Westlinton as tinseltown.&lt;/p&gt;

&lt;p&gt;I have posted the &lt;a href="https://gitlab.com/snippets/1689724"&gt;full list of anagrams&lt;/a&gt; and the &lt;a href="https://gitlab.com/snippets/1689722"&gt;code to generate the list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See this &lt;a href="https://blog.ianturton.com/geotools/fun/anagram/2017/12/20/anagrams-world.html"&gt;follow up&lt;/a&gt; for world names.&lt;/p&gt;

</description>
      <category>geotools</category>
      <category>java</category>
      <category>fun</category>
      <category>anagrams</category>
    </item>
  </channel>
</rss>
