<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Ian&apos;s random blog</title>
    <description>A place to store random thoughts, snippets of  &lt;a href=&apos;http://geotools.org&apos;&gt;GeoTools&lt;/a&gt; code and other bits and pieces of stuff I write sometimes. If you enjoyed the post or it helped you out, please consider &lt;a href=&quot;https://ko-fi.com/ianturton&quot;&gt;buying me a coffee&lt;/a&gt;&lt;br/&gt; &lt;a href=&quot;https://stackexchange.com/users/195980&quot;&gt; &lt;img src=&quot;https://stackexchange.com/users/flair/195980.png&quot; width=&quot;208&quot; height=&quot;58&quot; alt=&quot;profile for Ian Turton on Stack Exchange, a network of free, community-driven Q&amp;amp;A sites&quot; title=&quot;profile for Ian Turton on Stack Exchange, a network of free, community-driven Q&amp;amp;A sites&quot;&gt;&lt;/a&gt;
</description>
    <link>https://blog.ianturton.com/</link>
    <atom:link href="https://blog.ianturton.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sun, 09 Nov 2025 11:55:43 +0000</pubDate>
    <lastBuildDate>Sun, 09 Nov 2025 11:55:43 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Repair, Reuse and Recycle</title>
        <description>&lt;h1 id=&quot;how-i-created-a-spare-monitor&quot;&gt;How I created a spare monitor&lt;/h1&gt;

&lt;p&gt;I’m big on reuse, repair and recycling which is one of the reasons I volunteer at &lt;a href=&quot;https://repaircafeglasgow.org/&quot;&gt;Glasgow Repair 
Cafe&lt;/a&gt; – I blame being exposed to &lt;a href=&quot;https://en.wikipedia.org/wiki/Stig_of_the_Dump&quot;&gt;“Stig of the 
Dump”&lt;/a&gt; at an impressionable age. As a result I struggle to 
throw out broken things let alone things that still work. However, space limitations mean that I do 
occasionally have to tidy out some stuff. I discovered that I have way too many old laptops that will come in 
useful sometime recently. So I installed a light weight linux on two of them and donated one of them to the 
repair café (where we have several laptops that really should be retired as they lack some keys), the other 
one is an old ThinkPad which I will use in my workshop/garage so that I don’t get sawdust in my work laptop.&lt;/p&gt;

&lt;p&gt;Two of them proved to be beyond repair (or wouldn’t talk to the network with a modern linux), this left me 
looking at a pile of potential e-waste. And, while they didn’t work as computers any more there were still 
some useful bits on them. There was also the question of what to do with all the nice stickers I had on the 
back of them.&lt;/p&gt;

&lt;h2 id=&quot;the-build&quot;&gt;The Build&lt;/h2&gt;

&lt;p&gt;I decided that I could use an(other) 2nd monitor, and since the screen was still good I thought I could reuse 
a. The first step is to disassemble the laptop and extract the display. You then search for the serial number 
on the back (in my case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NT156FHM-N31&lt;/code&gt;) which lead me to an Amazon or E-Bay page where for about £20 I could 
buy a pair of small PCBs. The thin ribbon cable coming out of the screen goes in one side and a USB-C cable an 
HDMI cable go in the other. Plugging the other ends in to the relevant ports on my laptop and hey presto I had 
a 2nd monitor. Unfortunately (but unsurprisingly) it was set to Chinese, but it turns out Google lens can do 
sufficient real time translation to allow me to figure out the language settings. After that it has a menu 
system that is remarkably similar to ever TV I’ve used in the past decade.&lt;/p&gt;

&lt;p&gt;I could have stopped there but it looked a little rough and was a bit fragile. So, I toyed with 3D printing an 
enclosure or building one out of wood (this one is &lt;a href=&quot;http://technovelgy.com/ct/content.asp?Bnum=80&quot;&gt;William Gibson’s 
fault&lt;/a&gt;). But &lt;a href=&quot;/update/2025/11/08/update.html&quot;&gt;life got in the 
way&lt;/a&gt;, so about 6 months ago I was looking to tidy up enough office space to 
start thinking about dping something when I found an LCD screen and some PCBs. This is when I had the break 
through I already had an enclosure that was exactly the right size and shape for the screen – the laptop lid. 
If I removed it from the hinges (which I saved as they are sure to be useful one day) it would clip back 
together nicely and make the screen nice and safe. I just needed to work out how to hold it upright, here I 
found an old microphone stand that I had picked up in a charity shop thinking I could build an angle poise 
style light out of it. With the addition of a VESA monitor bracket plate and a ball head mount I had a working 
monitor which was height and angle adjustable.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/PXL_20251108_113346097.jpg&quot; alt=&quot;The Monitor&quot; title=&quot;the sky was the color of a television tuned to a dead 
channel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The final problem was where to put the control boards, again I should really build them an enclosure, but for 
the time being they are attached with stand offs to the back of the case. I also had to cut a small hole in 
the bottom of the case to pass the ribbon cable through but as its soft plastic this was easy enough.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/PXL_20251108_115433633.jpg&quot; alt=&quot;The back of the screen&quot; title=&quot;The back of the screen complete with mounting 
plate, controls and original stickers&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that it is finished and in regular use as my main second monitor it is working really well and for about 
£30 I can’t complain. If I ever need to take it apart I will probably drill some new holes and move the 
control panel to be vertical and nearer the edge as where it is at the moment is a little fiddly to turn it on 
and off. I have another partly disassembled laptop which might well find its screen going the same way as I 
can always use more displays around the house.&lt;/p&gt;
</description>
        <pubDate>Sun, 09 Nov 2025 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/cheap/2025/11/09/spare-monitor.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/cheap/2025/11/09/spare-monitor.html</guid>
        
        
        <category>cheap</category>
        
      </item>
    
      <item>
        <title>Health and Employment Update</title>
        <description>&lt;p&gt;It appears that I haven’t posted anything here for a year! There are some mitigating circumstances though.&lt;/p&gt;

&lt;p&gt;TL;DR; I didn’t die and I have a new job.&lt;/p&gt;

&lt;h2 id=&quot;the-build-up&quot;&gt;The Build Up&lt;/h2&gt;

&lt;p&gt;Coincidently, about a year ago I started to struggle with my mental health. Initially I didn’t worry too much 
as the onset of winter and the clocks going back always adversely affects my mood, and living in Scotland 
makes this worse as it gets lighter later and dark earlier than when we lived further south. Normally, I would 
expect for my mood to pick up in the new year when the days lengthen and its safe to go outside again. But 
this year it didn’t, I don’t know why, maybe working at a university wasn’t as much fun as I had hoped it to 
a. Certainly it turns out that just being called a research software engineer didn’t make as much of a 
difference to my quality of life as I had hoped it would. I struggled on until Easter time (which was clearly 
a mistake with hindsight), when it became clear to everyone and even me that I needed to take some time off. 
So anyone who was hoping to meet up with me at GISRUK I’m sorry but I really couldn’t face travelling or 
meeting people. I spent much of April in bed sleeping while I waited for a bigger dose of anti-depressants to 
kick in (this can be between 6 and 10 weeks, on top of the fortnight to wean off the previous ones).&lt;/p&gt;

&lt;p&gt;I also started taking Manjaro to help with my weight and diabetes along with a tailored exercise program, so 
by the end of May I had lost 10 kilos and was feeling pretty good about life in general. Then …&lt;/p&gt;

&lt;h2 id=&quot;the-incident&quot;&gt;The Incident&lt;/h2&gt;

&lt;p&gt;As many of you will have heard I suffered a significant health issue in early June when my colon decided that 
it had had enough and decided to start bleeding unexpectedly. I went out for dinner one evening with some 
friends from university and the next thing I really knew was I was in a critical care ward with the staff 
explaining to me again and again that I was unwell. Between the loss of blood and morphine I was handling this 
information very poorly. This confusion wasn’t helped by the fact that I knew the Royal Victoria Infirmary 
(RVI) in Newcastle very well from my student days as we used to use its historic corridors as a (dry) short 
cut to and from the university most days. This hospital was clearly much newer and shinier than the one I 
remembered. It turns out the old one was knocked down and replaced by student flats some years ago.&lt;/p&gt;

&lt;p&gt;I had to come to terms with a) having nearly died (though I don’t remember), b) no longer having a 
&lt;a href=&quot;https://en.wikipedia.org/wiki/Large_intestine#Structure&quot;&gt;colon&lt;/a&gt; and an 
&lt;a href=&quot;https://en.wikipedia.org/wiki/Ileostomy&quot;&gt;Ileostomy&lt;/a&gt;  and having a scar from waist to sternum (held together 
with massive staples) and c) having a &lt;a href=&quot;https://en.wikipedia.org/wiki/Stoma_(medicine)&quot;&gt;stoma&lt;/a&gt; bag attached to 
me (most of the time).&lt;/p&gt;

&lt;p&gt;Anyway, after 10 days or so I was considered well enough to move to a normal ward, though I promptly let my 
blood pressure collapse and was moved back to ICU for some magnesium, but eventually I was well enough to 
transfer back to Scotland. I can’t say I recommend travelling up the M74 in an ambulance but it was good to be 
back near to home, especially for Lesley.&lt;/p&gt;

&lt;p&gt;After another week on a high dependency ward in East Kilbride (since I had transferred  from ICU as there were 
no “normal” beds available for me to take in Newcastle) I had to go into an HDU bed (I know). I was easting 
normally, finally, and could walk from one end of the ward to another (lying in bed for a fortnight really 
kills your muscle tone) and I was allowed to go home.&lt;/p&gt;

&lt;p&gt;Early the next week I went back for a stoma clinic checkup and the nurses took one look at me and decided that 
maybe I should visit the ambulatory emergency unit (despite, or because, needing a wheelchair to get there). 
They promptly readmitted me as my blood pressure was down below 80, which explained why I wasn’t feeling too 
chipper. I spent a few more days in hospital being given IV magnesium and antibiotics to sort out my blood 
pressure and inflammatory markers. Things could have been worse, the guy in the next bed had a gall stone the 
size of a tennis ball taken out of his intestines as it had bored its way out off his gall bladder. The 
surgeons were very excited and had taken pictures of it to show him.&lt;/p&gt;

&lt;p&gt;Recovering, took much longer than I expected though all the medical staff kept saying how tough an operation 
was. This meant that I wasn’t well enough to travel to Mostar for FOSS4GEU which again was a shame (especially 
since I had been organised enough to actually book travel and hotels in advance). So again sorry if you were 
hoping to catch up with me there.&lt;/p&gt;

&lt;h2 id=&quot;the-recovery&quot;&gt;The Recovery&lt;/h2&gt;

&lt;p&gt;My contract at Glasgow ended at the start of October, which was about when my doctors were becoming happy for 
me to go back to work. I had half heartedly filled out some applications for new university jobs and dumped my 
CV on various job sites. Though to be honest I was really looking forward to being able to say in January that 
clearly I was unemployable and should consider retirement. Sadly (or happily) I got a call from a recruiter 
who seemed desperate to hire me (but couldn’t really say why). He was offering a quite silly amount of money 
with the only catch being the need to incorporate. So, I agreed to an interview and it turned out to be with a 
system integrator who was working for His Majesty’s Land Registry (HMLR) who maintain the English and Welsh 
cadastral register. Quite why they were so keen to hire me was still unclear but I said yes to a six month 
contract. When I started at the HMLR it became clear why they wanted me, they are trying to update part of the 
register (the only vectorized part) from a proprietary format that was developed by Envitia (who I had worked 
for back in 2011-15) and were trying to convert to a PostGIS DB using GeoTools to build a Java tool.&lt;/p&gt;

</description>
        <pubDate>Sat, 08 Nov 2025 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/update/2025/11/08/update.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/update/2025/11/08/update.html</guid>
        
        
        <category>update</category>
        
      </item>
    
      <item>
        <title>Adjustable, draggable circles around markers in leaflet</title>
        <description>&lt;p&gt;I recently needed to implement a way of showing the uncertainty of a marker in a web map (the final 
application isn’t ready yet) and while I found a bunch of tutorials and stackoverflow answers that covered 
parts of this I couldn’t find a single page on how to do it. So I’m going to write it up here so that next 
time I need to do this a search will find this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR;&lt;/strong&gt; You can see a simple demo &lt;a href=&quot;https://www.ianturton.com/demos/circles/circles.html&quot;&gt;here&lt;/a&gt;, and here’s 
a picture to show you what I’m talking about.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/circles.png&quot; alt=&quot;A map with uncertain markers&quot; title=&quot;opt title&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are 3 markers (in my app anyway) and they are represented using a coloured flag. At its simplest the 
user can just pick a position and if they are happy with that move on to the next step (in the image above 
this is the blue flag). If however they are less sure of the location they can double click on the marker 
which will add a 100m circle (in a matching colour) around the point (the green flag above). Clicking on the 
circle will display a popup which allows them to adjust the radius of the circle (the red flag above). Also at 
any time the user can click on a flag and drag it (and it’s circle) to a new position on the map.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addMarker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DomUtil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-flag-cursor-enabled`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;lastClick&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;positions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DomUtil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-flag-cursor-enabled`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setMarker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;panTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;positions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getLatLng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;positions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// proceed to remainder of the app&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When the user clicks on one of the buttons, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addMarker&lt;/code&gt; is called, this clears the previous cursor if it was 
set and then if this colour of marker hasn’t been set changes the cursor to match the flag we are adding or 
pans to that marker if it has been placed on the map. Then we attach the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setMarker&lt;/code&gt; method to the map’s click 
event, so when they click we can place a marker there.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setMarker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setMarker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;positions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;iconUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;icons&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;iconSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;iconAnchor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;27&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;latlng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;latlng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;//Add a marker to show where you clicked.&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;latlng&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;latLng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;latlng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;draggable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;clickable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;autoPan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;dblclick&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;addCircle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mapClickListen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;cm&quot;&gt;/* this is all to work around dragend triggering a click
         * see https://gis.stackexchange.com/questions/190049/leaflet-map-draggable-marker-events
         */&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;dragstart&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;marker dragstart event&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mapClickListen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;dragend&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dragging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;//pointsValid();&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mapClickListen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;positions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;panTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;positions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getLatLng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DomUtil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-flag-cursor-enabled`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Again, we check if the marker has already been placed (I’m paranoid) and if not go ahead and create a flag 
icon with the correctly coloured image. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IconAnchor&lt;/code&gt; makes sure that the base of the flag pole is placed 
on the click location. Then we create a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Marker&lt;/code&gt; using the icon at the latitude and longitude of the 
click, we set it to be clickable but not draggable. The idea is (was) that the user should need to click on a 
marker to move it, which works but the end of the drag seems to click on the marker again so it never turns 
off. So I found a &lt;a href=&quot;https://gis.stackexchange.com/questions/190049/leaflet-map-draggable-marker-events&quot;&gt;workaround from 2016 to the 
bug&lt;/a&gt; and which was 
apparently fixed some years ago but I can’t seem to make it work. Any way the key step is the add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addCircle&lt;/code&gt; 
to the double click event.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addCircle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;circles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;popup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;popup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;adjust radius &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;INPUT&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;circles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;popup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spinner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;circle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getLatLng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;fillcolor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;fillopacity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bindPopup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;popup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;drag&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;circles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setLatLng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;latlng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;circles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As is usual we check if there is already a circle with this name before we create one. Then we generate the 
popup that allows the user to change the radius of the circle. This is a basic HTML &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;div&lt;/code&gt; with a spinner (or 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;number&lt;/code&gt; as HTML calls them for some reason), we can set the minimum, maximum and step for this in the HTML as 
per normal. The trick then to add a function to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input&lt;/code&gt; event that is fired when ever the user clicks the 
spinner (or uses their up/down arrows on it). The remaining issue is to make sure that the right circle gets 
updated when the input changes, to do this I set the id of the spinner to the same name that keys the 
dictionary of circles (these keys match the markers too). Then we can simply use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setRadius&lt;/code&gt; method of the 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CircleMarker&lt;/code&gt; that we are about to create. Then we create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CircleMaker&lt;/code&gt; and attach the popup to it and 
add it to the map. Finally, when we drag the matching marker we want to move we need to change the centre of 
the circle. This needs a function for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drag&lt;/code&gt; event to do this, it’s slightly more complex to look up the 
required circle from a marker due to makers having nice long titles so there’s a double lookup, if I had 
millions of markers this might be a problem but with 3 it’s fine.&lt;/p&gt;

&lt;p&gt;And that’s all there is too it, that’s not to say I like JavaScript or web development but in the end its not 
too hard!&lt;/p&gt;
</description>
        <pubDate>Tue, 05 Nov 2024 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/leaflet/2024/11/05/circles-in-leaflet.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/leaflet/2024/11/05/circles-in-leaflet.html</guid>
        
        
        <category>leaflet</category>
        
      </item>
    
      <item>
        <title>How to reproject features in QGIS</title>
        <description>&lt;p&gt;I came across a &lt;a href=&quot;https://fosstodon.org/@sarahdalgulls@ecoevo.social/112922177589370381&quot;&gt;brilliant thread on 
Mastodon&lt;/a&gt; by Sarah Dal discussing how 
she worked out what the most remote post box in the UK was. But there was one remark that bothered me, she 
said that to convert her lat, lon points to OSGB (EPSG:4326 to EPSG:27700 for the nerds) she had to go to the 
Ordnance Survey site to find some software to do this. Since she already had the points in QGIS this seemed 
like an unnecessary side quest to me. When I commented that she could have done this in QGIS she said that she 
always seemed to get it wrong.&lt;/p&gt;

&lt;p&gt;I’m confused by this (and by the many other people who ask questions on gis.stackexchange.com about the same 
thing) so I’ve put together this video showing how I would do this. Basically, you right click on the layer 
you want to reproject and select &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export-&amp;gt;Save features as&lt;/code&gt; and then just change the drop down box to the 
projection you need. QGIS will then save the features and add that layer to your project. You shouldn’t see 
any difference other than the colour of the points will change (as QGIS assigns a new random colour to the new 
layer).&lt;/p&gt;

&lt;iframe width=&quot;420&quot; height=&quot;315&quot; src=&quot;/images/postboxes-2024-08-09_10.28.30.mp4&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;And yes, I really should have split the Northern Irish post boxes out into a separate file and projected them 
to the Irish grid but this is just a demo.&lt;/p&gt;
</description>
        <pubDate>Fri, 09 Aug 2024 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/foss/2024/08/09/reprojection-in-qgis.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/foss/2024/08/09/reprojection-in-qgis.html</guid>
        
        
        <category>foss</category>
        
      </item>
    
      <item>
        <title>Adding a spell check to QGIS</title>
        <description>&lt;h1 id=&quot;adding-a-spell-check-to-qgis&quot;&gt;Adding a Spell Check to QGIS&lt;/h1&gt;

&lt;p&gt;(Or what to do on a rainy bank holiday in Glasgow)&lt;/p&gt;

&lt;p&gt;This Monday was a local bank holiday in Glasgow (or at least the university) as a remnant of when the whole 
town took a train to Blackpool in the same two weeks so that the ship builders and steel works could stop in a 
coordinated fashion. As is required in the UK the weather was awful so I stayed in and being bored looked at 
my long list of possible projects. I picked one that has been kicking around on the list for a while adding a 
spell checker for QGIS. As a dyslexic I have spell checking turned on in nearly every program I enter text 
into including &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InteliJ&lt;/code&gt; and my browser. So I have always felt that what QGIS really needed was a way 
to spell check maps before I printed them at A3 and put them on the wall.&lt;/p&gt;

&lt;p&gt;Back in 2019 North Road wrote a i&lt;a href=&quot;https://north-road.com/2019/01/14/on-custom-layout-checks-in-qgis-3-6-and-how-they-can-do-your-work-for-you/&quot;&gt;blog post about custom layout checks 
&lt;/a&gt; 
and ended it with a throw away comment “It’d even be possible to hook into one of the available Python spell 
checking libraries to write a spelling check!”. I came across this when I was trying to see if there was an 
easy way for my students (many of whom have English as a second language) to avoid handing in projects with 
glaring (i.e. I can see them) spelling errors in the title. So I stuck the link on my backlog, until the 
proverbial rainy day came along.&lt;/p&gt;

&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;

&lt;p&gt;Obviously I’m the last person who should be allowed to write spell checking software, but the joy of open 
source is that for things like this someone else has almost certainly already done it. So a quick duck-duck-go 
found me installing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyspellcheck&lt;/code&gt; which seemed like it would do what I want. It has a pretty easy interface 
in that once you’ve created a spell checker object, you can just pass in a list of words and it will return a 
list of (probably) misspelled words and a method to give the most likely correction and another method to give 
you list of other possibilities. Armed with this I could create a method to find and check all the text 
elements of a print layout.&lt;/p&gt;

&lt;div class=&quot;language-py highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;QgsAbstractValidityCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TypeLayoutCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;layout_check_spelling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feedback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;checker&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpellChecker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;isinstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;QgsLayoutItemLabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;tokens&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;punctuation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()]&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;misspelled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;checker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;misspelled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;QgsValidityCheckResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;QgsValidityCheckResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Warning&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Spelling Error?&apos;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
                &amp;lt;strong&amp;gt;&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;/strong&amp;gt;&apos; may be misspelled, would
                &apos;&amp;lt;strong&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;checker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;correction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;/strong&amp;gt;&apos; be a better choice?
                &quot;&quot;&quot;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;possibles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;checker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;candidates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;possibles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
                    Or one of:&amp;lt;br/&amp;gt;
                    &amp;lt;ul&amp;gt;
                    &quot;&quot;&quot;&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possibles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&amp;lt;/ul&amp;gt;&apos;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;detailedDescription&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And in theory, that was that! But I’m pretty sure that my students (and everyone else) probably didn’t want to 
cut and paste that into the console every time they wanted to spell check a map. So, I looked at how to 
package this up for QGIS. I built a plugin (using the plugin builder tool), but then things got a little 
tricky as I can’t see any way for a plugin to add itself to the print layout rather than the main QGIS window 
(please let me know if it is possible), and it seemed unintuitive to make people press a button in one window 
to effect another one, besides the whole point of being a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QgsAbstractValidityCheck&lt;/code&gt; was that the method is 
automatically run on print. So I didn’t need most of the plugin code or did I? On further thought I did, there 
is a need for some GUI as the user can pick which language they want to use in the spell check. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyspellcheck&lt;/code&gt; 
can spell check English, Spanish, French, Portuguese, German, Italian, Russian, Arabic, Basque, Latvian and 
Dutch (so if those are your language then please test this for me). I also thought that providing the option 
to supply a different to the default personal dictionary might be useful. So that made use of the dialog that 
pops up when you hit the plugin.&lt;/p&gt;

&lt;p&gt;But it turns out you can’t register a class method as as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QgsAbstractValidityCheck&lt;/code&gt; since it gets confused 
when QGIS calls it later. So I had to move my checker method outside the plugin class. But then I couldn’t 
access the language and dictionary that was set in the GUI! Some more searching gave me the following code:&lt;/p&gt;

&lt;div class=&quot;language-py highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;_instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;qgis-spellcheck&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;checker&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;checker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Whereby I can pull out the named plugin and grab it’s spell checker, which was created in the plugin’s 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__init__&lt;/code&gt; method. I seem to have a small issue that the user’s profile is not set when that runs which messes 
up where the personal dictionary is put (again if you know how to fix this let me know).&lt;/p&gt;

&lt;h2 id=&quot;future-work&quot;&gt;Future Work&lt;/h2&gt;

&lt;p&gt;Ideally, I’d like the spell checker to scan and highlight the text in the boxes as I typed but I fear that is 
beyond my understanding of the QGIS/Qt interface. Next highest on my wish list is for the list of spelling 
issues to be non-modal so I can cut and paste fixes into the text box, rather than having to memorise the 
correct spelling, close the window and then type it in (again answers on a github issue).&lt;/p&gt;

&lt;p&gt;I’m sure all sorts of things will come up once people start using it, so as usual issues and PRs are welcome 
at https://github.com/ianturton/qgis-spellcheck.&lt;/p&gt;

</description>
        <pubDate>Tue, 16 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/foss/2024/07/16/spelling.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/foss/2024/07/16/spelling.html</guid>
        
        
        <category>foss</category>
        
      </item>
    
      <item>
        <title>Is GeoJSON a spatial data format?</title>
        <description>&lt;h1 id=&quot;is-geojson-a-good-spatial-data-format&quot;&gt;Is GeoJSON a good spatial data format?&lt;/h1&gt;

&lt;p&gt;A few days ago on Mastodon &lt;a href=&quot;https://fosstodon.org/@elipousson@dads.cool&quot;&gt;Eli Pousson&lt;/a&gt;
asked:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Can anyone suggest examples of files that can contain location info but aren’t often considered spatial data 
file formats?&lt;/p&gt;

&lt;/blockquote&gt;

&lt;p&gt;He suggested EXIF, &lt;a href=&quot;@IvanSanchez@mastodon.social&quot;&gt;Iván Sánchez Ortega&lt;/a&gt;
followed up with spreadsheets, and being devilish I said GeoJSON.&lt;/p&gt;

&lt;p&gt;This led to more discussion, with people asking why I thought that, so I instead of being flippant I thought 
about it. This blog post is the result of those thoughts which I thought were kind of obvious but from things 
people have said since may be aren’t that obvious.&lt;/p&gt;

&lt;p&gt;I’ve mostly been a developer for most of my career so my main interest in a spatial data format is that:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;it stores my spatial data as I want it to,&lt;/li&gt;
  &lt;li&gt;it’s fast to read and to a lesser extent, write.&lt;/li&gt;
  &lt;li&gt;It’s easy to manage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One, seems to be obvious, if I store a point then ask for it back I want to get that point back (to the limit 
of the precision of the processor’s floating point). If a format can’t manage that then please don’t use it. 
This is not common but Excel comes to mind as a program that takes good data and trashes it. If it isn’t 
changing &lt;a href=&quot;https://www.theverge.com/2020/8/6/21355674/human-genes-rename-microsoft-excel-misreading-dates&quot;&gt;gene names into 
dates&lt;/a&gt; then 
it’s &lt;a href=&quot;https://gis.stackexchange.com/questions/132359/how-is-attribute-data-in-dbf-file-tied-to-shapefile-location-data-in-shp-file&quot;&gt;reordering the dbf file to destroy your 
shapefile&lt;/a&gt;. 
GeoJSON also can fail at this as the standard says that I must store the data in WGS:84 (lon/lat), which is 
fine if that is the format that I store my data in already, but suppose I have some high quality OSGB data 
that is carefully surveyed to fractions of a millimetre and the underlying code does a conversion to WGS:84 in 
the background and further the developer wanted to save space and limited the number of decimal places to say 
6 (OK, &lt;a href=&quot;https://osgeo-org.atlassian.net/browse/GEOT-6650&quot;&gt;that was me&lt;/a&gt;) when it gets converted back to OSGB 
I’m looking at centimetres (or worse) but given the vagaries of floating point representation I may not be 
able to tell.&lt;/p&gt;

&lt;p&gt;Two, comes from being a GeoServer developer, a largish chunk of the time taken to draw a web map (or stream 
out a WFS file) is taken up by reading the data from the disk. Much of the rest of the time is converting the 
data into a form that we can draw. Ideally, we only want to read in the features needed for the map the user 
has requested (actually, ideally we want to &lt;strong&gt;not&lt;/strong&gt; read in most of the data by having it already be in the 
cache, but that is hard to do). So we like indexed datasets both spatial indexes and attribute indexes can 
help substantially speed up map drawing. As the size of spatial datasets increases the time taken to fetch the 
next feature from the store becomes more and more important. An index allows the program to skip to the 
correct place in the file for either a specific feature or for features that are in a specific place or 
contain a certain attribute with the requested value. This is a great time saver, imagine trying to look 
something up in a big book by using the index compared to paging through it reading each page in turn.&lt;/p&gt;

&lt;p&gt;After one or more indexes the main thing I look for in a format is a binary format that is easy to read (and 
write). GeoJSON (and GML) are both problematic here as they are text formats (which is great in a transfer 
format) and so for every coordinate of every spatial object the computer has to read in a series of digits 
(and punctuation) and convert that into an actual binary number that it can understand. This is a slow 
operation (by computer speeds anyway) and if I have a couple of million points in my coastline file then I 
don’t want to do 4 million slow operations before I even think of drawing something.&lt;/p&gt;

&lt;p&gt;Three, I have to interact with users on a fairly regular basis and in a lot of cases these are not spatial 
data experts. If a format comes with up to a dozen similarly named files (that are all important) that a GIS 
will refuse to process unless you guess which is the important one then it is more of a pain than a help. And 
yes shapefile I’m looking at you. If your process still makes use of Shapefiles please, please stop doing that 
to your users (and the support team) and switch over to GeoPackages which can store hundreds of data sets 
inside a single file, All good GIS products can process them by now, they have been an OGC standard for nearly 
10 years. If you don’t think that shapefiles are confusing go and ask your support team how often they have 
been sent just the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.shp&lt;/code&gt; file (or 11 files but not the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sbn&lt;/code&gt;) or how often they have seen people who have 
deleted all the none &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.shp&lt;/code&gt; files to save disk space.&lt;/p&gt;

&lt;p&gt;My other objection to GeoJSON is that I don’t know what the structure (or schema) of the data set is until I 
have read the entire file. That last record could add several bonus attributes, in fact any (or all) of the 
records could do that, from a parsers view it is a nightmare. At least GML provides me with a fixed schema and 
enforces it through out the file.&lt;/p&gt;

&lt;p&gt;When I’m storing data (as opposed to transferring it) I use PostGIS, it’s fast and accurate, can store my data 
in whatever projection I chose and is capable of interfacing with any GIS program I am likely to use, and if 
I’m writing new code then it provides good, well tested libraries in all the languages I care about so I don’t 
have to get into the weeds of parsing binary formats. If I fetch a feature from PostGIS it will have exactly 
the attributes I was expecting no more or less. It has good indexes and a nifty DSL (SQL) that I can use to 
express my queries that get dealt with by a cool query optimiser that knows way more than I do about how to 
access data in the database.&lt;/p&gt;

&lt;p&gt;If for some reason I need to access my data while I’m travelling or share it with a colleague then I will use 
a GeoPackage which is a neat little database all packaged up in a single file. It’s not a quick as PostGIS so 
I wouldn’t use it for millions of records but for most day to day GIS data sets it’s great. You can even store 
you QGIS styles and project in it to make it a single file project transfer format.&lt;/p&gt;

&lt;p&gt;One final point, I sometimes see people preaching that we should go cloud native (and often serverless) by 
embracing “modern” standards like GeoJSON and COGs. GeoJSON should never be used as a cloud native storage 
option (unless it’s so small you can read it once and cache it in memory in which case why are you using the 
cloud) as it is large (yes, I know it compresses well) and slow to parse (and slower still if you compressed 
it first) and can’t be indexed. So that means you have to copy the whole file from a disk on the far side of a 
slow internet connection. I don’t care if you have fibre to the door it is still slow compared to the disk in 
your machine!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/geojson.jpg&quot; alt=&quot;The Jack Sparrow worst pirate meme but for GeoJSON&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 11 Nov 2023 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/gis/2023/11/11/geojson.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/gis/2023/11/11/geojson.html</guid>
        
        
        <category>gis</category>
        
      </item>
    
      <item>
        <title>How much fun was FOSS4g 2023?</title>
        <description>&lt;h1 id=&quot;review-of-foss4g-2023&quot;&gt;Review of FOSS4G 2023&lt;/h1&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;FOSS4G 2023 was held in Prizren, Kosovo and there were 800+ attendees from 120+ countries. This was a great 
attendance despite Kosovo not being the easiest place to get to, especially if you were me. I had booked 
flights to and from Belgrade, Serbia because they were a relatively good times for me (I am missing being only 
1 hour from a London airport). It looked like an easy 4 hour drive from the airport to Prizren. Then about a 
fortnight before the conference Kosovo closed it border to Serbian registered cars! A subsequent check all 
showed that most of the hire companies wouldn’t let you drive one of their cars over a border (and apparently 
despite the Serbian Government’s claims they considered Kosovo a separate country). So I fell back on the 9 
hour overnight bus trip, which wasn’t as bad as it could have been but did mean I started the conference 
already somewhat sleep deprived.&lt;/p&gt;

&lt;h2 id=&quot;sort-of-historical-side-note&quot;&gt;Sort of Historical Side Note&lt;/h2&gt;

&lt;p&gt;When I was at school learning Geography all of this area was called Yugoslavia and it was behind an “iron 
curtain” so we knew little about it and cared even less (it was not on the exam). In history it was covered by 
the break up of the Ottoman Empire and the meddling of Bismarck as an “honest broker” at the 1878 Congress of 
Berlin (as I recall he rigged the Balkans in such a way as to start World War I, but history O-Level was a 
long time ago). So you can already see that there is a long a complex history and geography in the region. It 
became more complex in the 1990s when Yugoslavia broke up in a series of bloody conflicts, which I remember 
from the evening news. Kosovo only really came to my attention in 2008 when I was walking through New York 
with James Macgill and his kids and we saw a large group of cars flying large red flags with double headed 
eagles on them (and the one thing I retained from my history lessons is the ability to spot a double headed 
eagle at 200 metres). These were Kosovans celebrating the declaration of independence being proclaimed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kosovo.jpg&quot; alt=&quot;A man holding a red flag&quot; title=&quot;opt title&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So squabbling about car number plates was pretty peaceful really. Fortunately, for us most of KFOR (the 
UN/Nato peace keeping force) had gone home, except for some in the Northern predominately Serb areas where 
they were out keeping the piece over disputed elections for city mayors. This meant we could use their old 
base as a conference venue, which was great except for the lack of lifts.&lt;/p&gt;

&lt;h2 id=&quot;cool-talks&quot;&gt;Cool talks&lt;/h2&gt;

&lt;p&gt;This is a list of talks I found particularly interesting or fun and that stuck in my mind long enough to 
remember for this post. There were lots of great talks that I either failed to see because the room was too 
full or was too hot for my brain to have taken in the details, so I’m looking forward to the videos coming out 
so I can refresh my memory later.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Neiene Boeijen &lt;a href=&quot;https://presentations.this-way.nl/foss4g_2023.html&quot;&gt;Let’s put it on the map!&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Interesting discussion on why graphic designers shouldn’t make maps and geographers shouldn’t design user 
interfaces&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Benjamin Trigona-Harany &lt;a href=&quot;https://www.jaxartes.net/Trigona-Harany%20-%20Aircraft%20trajectories%20in%20PostGIS%20-%20FOSS4G%202023.pdf&quot;&gt;Aircraft trajectory analysis using 
PostGIS&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Explains how PostGIS handles trajectories which are really just a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Linestring&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MZ&lt;/code&gt; values on the 
points where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt; increases along the line&lt;/li&gt;
      &lt;li&gt;We can create a foreign table based on a foreign “server” that converts to a REST API call in the 
background this allows real time mapping filtered by the bounds of the map and any other filters the API 
can handle.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Jody Garnett and Andrea Aime &lt;a href=&quot;https://docs.google.com/presentation/d/1PP2qk7eH8TzAf1tvEWH7Geattd0YFh7ZEDx1_tlrRWY/edit#slide=id.g4014d08f50_0_0&quot;&gt;GeoServer used in fun and interesting 
ways&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://docs.google.com/presentation/d/1nRKIILXWGLMGXZ6thfJgPR9kZ6Wh8Hp1dwZdQGw2YRc/edit#slide=id.p&quot;&gt;State of 
  GeoServer&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;As usual Andrea and Jody were presenting way too many talks including this useful review of what GeoServer 
is capable of in production and a review of new features in GeoServer for this year.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Iván Sánchez Ortega &lt;a href=&quot;https://ivan.sanchezortega.es/2023-gleo-slides&quot;&gt;Gleo&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;I was going to say this is a  new WebGL mapping library, but apparently Iván has been going on about this 
for 8+ years now. Any way there is lots of object orientated style javascript code in there so you can 
extend your semi-transparent markers with bouncing. I don’t think it’s quite cool enough for me to start 
learning JavaScript or WebGL but the demo with 10,000 randomly coloured bouncing map markers is fun in a 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; sort of way.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Sanghee Shin Let’s defense my country using FOSS4G!
    &lt;ul&gt;
      &lt;li&gt;Discussed how South Korea is modernising its military mapping with GeoServer, PostGIS, Cesium and 
OpenLayers, which makes me feel better about knowing North Korea is using GeoServer and PostGIS too.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Andrea Aime &lt;a href=&quot;https://speakerdeck.com/simboss/processing-and-publishing-big-data-with-geoserver-and-databricks-in-azure&quot;&gt;Processing and publishing Maritime AIS data with GeoServer and Databricks in 
Azure&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Andrea standing in for Nuno discussed how to handle 1.5 Billion records in GeoServer. Looking at the AIS 
ship location data over 7 years at second intervals (I think) and how you could get GeoServer to display 
the relevant data in a fast way.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Logan Williams &lt;a href=&quot;https://space.cloud68.co/s/rAMZAiqPjfw5afJ?dir=undefined&amp;amp;path=%2FUBT%20C%2FN111%20-%20Second%20Floor%2F28.06.2023&amp;amp;openfile=1353216&quot;&gt;Investigating war crimes, animal trafficking, and more with open source geospatial 
data&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Logan is a Bellingcat reporter who uses open source tools to look at open source data to help confirm 
stories. For example he described how they looked at tracking a GRAD missile launcher from Russia to 
Ukraine before Malaysian Airliner was shoot down. This included spotting scuffs on the road and 
distinctive power lines in posted dash camera footage of the convoy.&lt;/li&gt;
      &lt;li&gt;What ever you do don’t play GeoGuesser against these guys as they are going to be very good.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Tue, 18 Jul 2023 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/foss4g/2023/07/18/foss4g-2023.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/foss4g/2023/07/18/foss4g-2023.html</guid>
        
        
        <category>foss4g</category>
        
      </item>
    
      <item>
        <title>Drawing a line on a GeoTools Map</title>
        <description>&lt;h1 id=&quot;drawing-a-line-on-a-geotools-map&quot;&gt;Drawing a line on a GeoTools Map&lt;/h1&gt;

&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=&quot;https://gis.stackexchange.com/q/458918/79&quot;&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=&quot;https://docs.geotools.org/stable/userguide/unsupported/swing/index.html&quot;&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=&quot;https://gitlab.com/ianturton/geotools-tools&quot;&gt;small project&lt;/a&gt; that contains a 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DigitizerAction&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&gt;LineString&lt;/code&gt; which is added to a list, which is then used to 
generate a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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;img src=&quot;/images/draw.png&quot; alt=&quot;A screenshot of the demo&quot; title=&quot;A screenshot of the demo&quot; /&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 id=&quot;details&quot;&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 id=&quot;action&quot;&gt;Action&lt;/h3&gt;

&lt;p&gt;We need to create an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Action&lt;/code&gt; to tell swing what we plan to do, I called mine &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DigitizerAction&lt;/code&gt; and made it 
extend &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&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 id=&quot;tool&quot;&gt;Tool&lt;/h3&gt;

&lt;p&gt;Again to save time and effort the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Digitizer&lt;/code&gt; tool extends &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CursorTool&lt;/code&gt; which extends &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&gt;FeatureType&lt;/code&gt; 
for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Digitizer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;SimpleFeatureTypeBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleFeatureTypeBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LineFeature&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;line&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LineString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;SimpleFeatureType&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;buildFeatureType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;featureBuilder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleFeatureBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;geometryFactory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JTSFactoryFinder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getGeometryFactory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JTSFactoryFinder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;EMPTY_HINTS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SLD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;createLineStyle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.0f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;ImageIcon&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imgIcon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ImageIcon&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getResource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ICON_IMAGE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CROSSHAIR_CURSOR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The class also has some fields that we’ll need later &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastX&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastY&lt;/code&gt; which is the position of the last 
click, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrayList&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Coordinate&lt;/code&gt;s which are the real world positions of the current line, and a list of 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&gt;onMouseClicked&lt;/code&gt; method which is called each time a 
mouse button is clicked.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;onMouseClicked&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MapMouseEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClickCount&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// was it a double click&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;drawTheLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;positions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// add a new point&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;DirectPosition2D&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getWorldPos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;positions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Coordinate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Put a marker at each digitized point&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;Graphics&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Graphics2D&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JComponent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getMapPane&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getGraphics&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;drawLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;lastX&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;lastY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&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 class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastX&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastY&lt;/code&gt;) to the current point (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt;) and then we draw a point at the current 
point (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleFeature&lt;/code&gt;s, this is done in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drawTheLine&lt;/code&gt; where 
we generate a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LineString&lt;/code&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GeometryFactory&lt;/code&gt;, we then add that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LineString&lt;/code&gt; to the 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FeatureBuilder&lt;/code&gt; and create a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleFeature&lt;/code&gt; from it. Note that we leave the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; so it 
generates a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FID&lt;/code&gt; for each feature. The feature is then stored in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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 class=&quot;language-plaintext highlighter-rouge&quot;&gt;FeatureLayer&lt;/code&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DataUtilities.collection&lt;/code&gt; method to convert our list of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleFeature&lt;/code&gt;s to a 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleFeatureCollection&lt;/code&gt; and applying the style we made earlier. Finally, we reset the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;positions&lt;/code&gt; list to 
empty to be ready to store the next line for the user.&lt;/p&gt;

&lt;h2 id=&quot;usage&quot;&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;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&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;/div&gt;

&lt;p&gt;You can then get the list of features by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&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>
        <pubDate>Mon, 08 May 2023 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/geotools/2023/05/08/drawing-on-a-geotools-map.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/geotools/2023/05/08/drawing-on-a-geotools-map.html</guid>
        
        
        <category>GeoTools</category>
        
      </item>
    
      <item>
        <title>Some Open Source Tools I&apos;ve Found Recently</title>
        <description>&lt;p&gt;I use open source tools nearly all the time and I’m always on the look out for new and useful tools to help 
make my life easier, so in this post I’m going to list some of the ones I’ve found recently.&lt;/p&gt;

&lt;h2 id=&quot;mailhog&quot;&gt;MailHog&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/mailhog/MailHog&quot;&gt;MailHog&lt;/a&gt; is an email testing took for developers. That doesn’t sound like 
much but when you are trying to configure a program to send you email notifications then it can be a life 
saver especially if you don’t happen to have an open SMTP server (or you are using AWS SES which requires all 
the addresses to be pre-validated in sandbox mode). You simply run MailHog on your local machine (or add the 
docker container to your swarm) and then set that machine as the SMTP server and the port to 1025. Then when 
ever your program sends an email you can check the web page at port 8025 to see the mail that was sent.&lt;/p&gt;

&lt;p&gt;MailHog is released under an MIT licence and does the one thing it does very well.&lt;/p&gt;

&lt;h2 id=&quot;paperless-ngx&quot;&gt;Paperless-ngx&lt;/h2&gt;

&lt;p&gt;I am a book collector, especially with technical books and since discovering &lt;a href=&quot;https://www.humblebundle.com/books&quot;&gt;Humble 
Bundle&lt;/a&gt; some years ago it has only got worse. At last count I had over 300 
technical e-books and I have read fewer than 20 of them completely (and those are mostly Manning ones that I 
bought as a paper book and got the e-book for free). This is actually fine as mostly I own the books as 
reference material to help me solve problems when they come up in the future. The problem is remeasuring which 
books I own and knowing which one will be helpful to solving the current problem. I was always planning in the 
back of my mind to write a “simple” python program to read the books and generate an index I could search when 
I had a problem to solve, but I never got very far with it.&lt;/p&gt;

&lt;p&gt;However, I recently came across &lt;a href=&quot;https://github.com/paperless-ngx/paperless-ngx&quot;&gt;Paperless-ngx&lt;/a&gt; which is a 
document management system that transforms your physical documents into a searchable online archive so you can 
keep, well, &lt;em&gt;less paper&lt;/em&gt;. So I think the developers think that it is for managing paper documents but I’m 
using it more like an Electric Monk:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“The Electric Monk was a labour-saving device, like a dishwasher or a video recorder. Dishwashers washed 
tedious dishes for you, thus saving you the bother of washing them yourself, video recorders watched tedious 
television for you, thus saving you the bother of looking at it yourself; Electric Monks believed things for 
you, thus saving you what was becoming an increasingly onerous task, that of believing all the things the 
world expected you to believe.”&lt;/p&gt;

  &lt;p&gt;― Douglas Adams, Dirk Gently’s Holistic Detective Agency&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Paperless is easily installed using Docker and provides an easy to use web interface. I simply pointed it at 
my books folder and it (over the next day or so) read all my books for me and created an index so I can search 
all of them by title and content. It also allows me to tag them (and is slowly learning to suggest tags for 
new books) so I can limit searches to specific groups of books. It also has a consumption directory that I can 
save new documents into and it will automatically ingest them into the system. I’m pretty sure it can do all 
sorts of other clever things but I haven’t fully explored it (or read the manual). Any way I can now buy new 
e-books with a clear conscience as I know the books will get read now.&lt;/p&gt;

&lt;h2 id=&quot;pandoc&quot;&gt;Pandoc&lt;/h2&gt;

&lt;p&gt;I’m easily distracted when writing so I prefer to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim&lt;/code&gt; to do my writing so I don’t spend half the morning 
playing with the styling of my headings and leave myself 10 minutes to finish the document. However, the 
management team are very much into nicely formatted documents in word or Google Docs, so I write my documents 
in &lt;a href=&quot;https://daringfireball.net/projects/markdown/&quot;&gt;markdown&lt;/a&gt;. I also keep my daily journal/work log in 
markdown so it’s easy to cut and paste from that to a report, but to convert that markdown to a format that I 
can import in Google docs or word (or whatever) I use &lt;a href=&quot;https://pandoc.org/index.html&quot;&gt;pandoc&lt;/a&gt; which describes 
it self as your swiss-army knife for documents. Its fantastic and can even generate the right type of wiki 
markup to allow me to paste formatted text in to what ever weird format Basecamp uses. Sadly, it still can’t 
match whatever Atlassian use for their wiki editor in Jira but you can’t have everything (though I believe we 
may have found a Jira plugin that reads markdown).&lt;/p&gt;

&lt;p&gt;But even better I can read in a word doc and convert that to markdown (it’s best if the person generating the 
file knows how styles work but it’s easier to reformat the markdown than the word document.) You can even use 
it to generate presentations for you.&lt;/p&gt;

&lt;p&gt;It can even produce PDF which means that I can print out the recipe for tea directly from the markdown file I 
store on github (or when I get organised to put a spare laptop/raspberryPi in the kitchen directly display 
it).&lt;/p&gt;

&lt;p&gt;Give it a try next time you get a document in a format you can’t handle.&lt;/p&gt;
</description>
        <pubDate>Sat, 21 Jan 2023 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/foss/2023/01/21/tools.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/foss/2023/01/21/tools.html</guid>
        
        
        <category>foss</category>
        
      </item>
    
      <item>
        <title>Moving...</title>
        <description>&lt;h1 id=&quot;moving&quot;&gt;Moving&lt;/h1&gt;

&lt;p&gt;If you’ve been following me on twitter you may have noticed that I’ve gone a bit quiet there, and possibly other places that you expected to see me like stackexchange and the GeoServer lists.&lt;/p&gt;

&lt;p&gt;There are two reasons for this, first I’ve abandoned my twitter account, partly because of Elon Musk and co but mostly because there is now a critical mass of people I know and people I find interesting on Mastodon. So I can now be found tooting at &lt;a href=&quot;http://fosstodon.org/@ianturton&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://fosstodon.org/@ianturton&lt;/code&gt;&lt;/a&gt; for my open source ramblings and snark, and at &lt;a href=&quot;http://mastodon.scot/@ianturton&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://mastodon.scot/@ianturton&lt;/code&gt;&lt;/a&gt; for more random social stuff.&lt;/p&gt;

&lt;p&gt;That second address gives a clue as to the other reason I’ve been quieter than usual, I’ve moved to Scotland this autumn as well. Many people have asked does that mean I’ve changed jobs or something but no Astun was a mostly remote company when I joined and has become a fully remote one during the pandemic so I realised I could live any where I wanted (subject to the constraints of Brexit) so why did I continue to live in the Tory heartlands of southern England when I disagreed with most of what it stood for.&lt;/p&gt;

&lt;p&gt;There were many reasons to move to Scotland, it’s where my wife’s family are, it’s where we met and got married (30 years ago). But also, it has a proportional electoral system for it’s government so there is a chance to finally have people I voted for making decisions. It has higher taxes and better public services and finally, a good chance of getting an EU passport back in my lifetime.&lt;/p&gt;

&lt;p&gt;Moving house is a stressful process, especially when you are as uninterested in planning as I am, but from a sudden idea in August, we had sold our house by September and moved out in November. In Scotland we found a house we liked and had completed the purchase 20 days later! Now we’re just waiting for the removal men to have time to deliver our belongings next week and things should settle down by the new year.&lt;/p&gt;

&lt;p&gt;So I should be back to having an office with an ergonomic workstation rather than my current laptop on a dining table in an AirBnB that I’m currently using and I’ll be back to full speed coding and writing then.&lt;/p&gt;
</description>
        <pubDate>Sun, 04 Dec 2022 00:00:00 +0000</pubDate>
        <link>https://blog.ianturton.com/2022/12/04/moving.html</link>
        <guid isPermaLink="true">https://blog.ianturton.com/2022/12/04/moving.html</guid>
        
        
      </item>
    
  </channel>
</rss>
