<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3523038529731701286</id><updated>2012-01-31T13:12:29.904+11:00</updated><category term='mapinfo'/><category term='COIN-OR'/><category term='optimisation'/><category term='postgresql'/><category term='installing'/><category term='javascript'/><category term='SimPy'/><category term='vehicle routing'/><category term='graphs'/><category term='algorithms'/><category term='curl'/><category term='operations research'/><category term='C++'/><category term='kdtree'/><category term='visualisation'/><category term='developers'/><category term='excel'/><category term='python'/><category term='shortcuts'/><category term='IDEs'/><category term='workbench'/><category term='vim'/><category term='linux'/><category term='ogr'/><category term='computer science'/><category term='QGIS'/><category term='tricks'/><category term='business'/><category term='shapefiles'/><category term='geocoding'/><category term='research'/><category term='discrete-event simulation'/><category term='sqlite'/><category term='gis'/><category term='xslt'/><category term='fibre'/><category term='postgis'/><category term='cross-platform'/><category term='code performance'/><category term='Linear Programming'/><category term='VBA'/><category term='jquery'/><category term='cplex'/><category term='pre-emptive optimisation'/><category term='people'/><category term='lxml'/><category term='hosted solutions'/><category term='spatial clustering'/><category term='sql'/><category term='convex hull'/><category term='jabref'/><category term='html'/><category term='alpha shapes'/><category term='point solutions'/><category term='Design - Open up a World'/><category term='OSM'/><category term='OSI'/><title type='text'>Biarri Blog</title><subtitle type='html'>Accessible optimisation for business improvement</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Sebastian Bourges</name><uri>http://www.blogger.com/profile/06378459118214320316</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-RVEEYgpctcg/TpYxpVoey_I/AAAAAAAAAAQ/9DwQUjC4hgw/s220/sebastian-bourges.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>69</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-3672551763450316344</id><published>2012-01-25T12:01:00.000+11:00</published><updated>2012-01-25T14:32:36.030+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><category scheme='http://www.blogger.com/atom/ns#' term='jabref'/><category scheme='http://www.blogger.com/atom/ns#' term='research'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>An efficient and effective research environment (on linux, with vim, jabref and more)</title><content type='html'>&lt;p&gt;So, I would like to share the environment that I have created for the purposes of    doing research. Specifically it is an environment that allows me to:&lt;/p&gt;    &lt;ul&gt;        &lt;li&gt;Gather research papers,&lt;/li&gt;        &lt;li&gt;Comment on them in various ways, and review these comments at large,&lt;/li&gt;        &lt;li&gt;Store this information in source control for the purposes of sharing            between my machines, and&lt;/li&gt;        &lt;li&gt;Write up and deal with ideas in a systematic fashion.&lt;/li&gt;    &lt;/ul&gt;    &lt;p&gt;    So, the perhaps the first component of this system is, what operating system? Happily,    it doesn't exactly matter. I use Ubuntu, but I also use Windows 7. The great thing about    this scheme is that it is adaptable to any environment that runs the tools (well, obviously)    and the tools all have multi-platform support.     &lt;/p&gt;    &lt;p&gt;    I personally find editing in vim &lt;b&gt;nicer&lt;/b&gt; on Ubuntu, and there is one or two arguably    minor things that linux has that Windows does not (XMonad, for example), but I will elaborate    on these later.    &lt;/p&gt;    &lt;h2&gt;The general scheme&lt;/h2&gt;    &lt;p&gt;This approach is, obviously, tailored specifically for me, and given that I have a    significant programming background, I am happy to solve some problems with actual programming.    I also quite enjoy "systematic" approaches; i.e. things that may not neccessarily be the    most user friendly or easy, but ones that follow a specific and clear pattern that makes    logical sense.    &lt;/p&gt;    &lt;p&gt;This approach may not suit everyone, but hopefully there are at least interesting and useful    ideas here that you could adapt to your own situation.    &lt;/p&gt;    &lt;h2&gt;The beginning - reference management&lt;/h2&gt;    &lt;p&gt;So, of course in order to gather research papers it is neccessary to store them in a useful    way. JabRef is free, and is a very nice option for this. I've described my custom JabRef    set up on my own personal blog a few months ago, please read     &lt;a href="http://dnoondt.wordpress.com/2010/12/06/a-beautifully-organised-research-library/"&gt;that&lt;/a&gt; for how to do this.    &lt;/p&gt;    &lt;p&gt;    One thing on using JabRef is that sometimes you need to correct the format that bibtex exports    give you. For example, one thing I am often changing is lists of authors like:    "Billy Smith, Joey Anderson"    to    "Billy Smith and Joey Anderson"    &lt;/p&gt;    &lt;p&gt;    It's not immediately clear to me why the bibtex are generated the wrong way from some of these    sites, but nevertheless. This simple correction is neccessary for the data to be stored properly,    and the authors to be picked up correctly, etc.    &lt;/p&gt;    &lt;p&gt;    Okay, now that you've read that, you understand that I save all my PDFs to a specific location,    a folder like ".../research/reference library". Where is this folder? It's in the research    repository.    &lt;/p&gt;    &lt;h2&gt;The "research" repository&lt;/h2&gt;    &lt;p&gt;I keep all my research, on any topic, in one generic folder, called "research". This is a    private git repository hosted on BitBucket.org. I chose bitbucket over github because bitbucket    has free unlimited-space private repositories, while githubs cost money. It is neccessary for    the research repository to be private for two reasons, one obvious one is that it contains    paywall-restricted PDFs, and the other is that it's just not appropriate to have in-progress    research notes be viewable by anyone, mainly because people may see how silly my comments really    are!&lt;/p&gt;    &lt;p&gt;So, the general structure of my research repository is as follows:&lt;/p&gt;&lt;pre&gt;~/research&lt;br /&gt;    /articles&lt;br /&gt;    /conferences&lt;br /&gt;    /diary&lt;br /&gt;    /jabref&lt;br /&gt;    /reference library&lt;br /&gt;    /projects&lt;br /&gt;        /semigroups&lt;br /&gt;        /...&lt;br /&gt;    /quantum-lunch&lt;br /&gt;    /...&lt;/pre&gt;    &lt;p&gt;The contents of these folders are as follows:&lt;/p&gt;    &lt;h3&gt;~/research/articles - Articles&lt;/h3&gt;    &lt;p&gt;This contains folders that map directly to papers that I'm trying to write (or more correctly    at the moment, scholarships that I'm applying for, and misc notes). These are all, unsurprisingly,    LaTeX documents that I edit with Vim.&lt;/p&gt;    &lt;p&gt;When I complete an article, I created a "submitted" folder under the specific article, and    put the generated PDF in there, but up until that time I only add the non-generated files to    source control (this is the generally correct practice for using any kind of source control;    only "source" files are included, anything that is generated from the source files is not).    &lt;/p&gt;    &lt;h3&gt;~/research/conferences - Notes on conferences&lt;/h3&gt;    &lt;p&gt;In here I have folders that map to the short conference name, for example "ACC" for Australian    Control Conference. Under that, I have the year, and within that I have my notes, and also any    agenda's that I may have needed, to see what lectures I would attend. The notes should be    in vimwiki format (I will describe this later) for easy/nice reading and editing.&lt;/p&gt;    &lt;h3&gt;~/research/dairy - Research diary and general ideas area&lt;/h3&gt;    &lt;p&gt;This is the main place I work on day-to-day. It contains all my notes, and minutes from various    meetings and lectures I attend. It contains a somewhat-daily research diary, and a list of current    research ideas, past research ideas (that were bad, and reasons why) and so on.&lt;/p&gt;    &lt;p&gt;My preferred note taking form is vimwiki (to be described below), so in here are purely vimwiki    files.&lt;/p&gt;    &lt;p&gt;It's not essential that you also use vim (and hence vimwiki), but it is appropriate that whatever    mechanism you use, it is a format that is ameneable to source control (i.e. allows nice text-based    diffs). Emacs or any plain-text editor will be sufficient here.&lt;/p&gt;    &lt;h3&gt;~/research/jabref - Bibtex files&lt;/h3&gt;    &lt;p&gt;This is perhaps not the most appropriately named folder, but nevertheless. It contains all my    .bib databases. I actually only have 3. One is very inappropriately called "2010.bib", with the    view that I would store research by the year I gathered it. I'm not following this approach and    I actually just keep all my research related to quantum computing (and more general subjects) in    here.&lt;/p&gt;    &lt;p&gt;I have two other bib files, one is related to a secondary field of that I am interested in researching.    That is to suggest, in 2010.bib I have only documents related to quantum computing, theoretical    physics and some theoretical computer science. I have a different .bib for research in completely    seperate fields, say investment. The other is "lectures.bib", and it is obvious what that contains.&lt;/p&gt;    &lt;p&gt;It's worth noting that I actually have two systems for storing lectures. One is the above, where    the lecture set fits into a nice single PDF. The other is when the lecture series is split over    several PDFs. These I store under a generic "University" repository that I use for my current    studies (including assignments and so on). This component of my current setup needs work, and    I'm open to suggestions here.&lt;/p&gt;    &lt;h3&gt;~/research/reference library - All the PDFs&lt;/h3&gt;    &lt;p&gt;Every PDF releated to my research is stored in here, prefixed with the bibtex key. So, for example    I have "Datta2005, 0505213v1.pdf". JabRef associates this with the relevant item in the .bib file    by the prefix, and virtue of this link in the .bib I have a trivial way to programmatically (if    I'm so inclined) get this PDF.&lt;/p&gt;    &lt;p&gt;I don't ever browse this folder directly, and currently it contains ~600 PDFs and is about 1 gig    in size. Storing this much data in a git repository may offend some people, but essentially they    are wrong to be offended. It is okay to store binary files as long as they are not constantly changing,    and they are considered a key component of the repository; which in this case they are.&lt;/p&gt;    &lt;p&gt;There are some downsides to this, though, and I think it's plausible to consider alternative arrangements.&lt;/p&gt;    &lt;p&gt;The viable alternatives are:&lt;/p&gt;    &lt;ul&gt;        &lt;li&gt;Dropbox for PDFs,&lt;/li&gt;        &lt;li&gt;Secondary git repository for PDFs only, and include as submodule, or&lt;/li&gt;        &lt;li&gt;Some other non-local storage (say, the one offered by Zotero).&lt;/li&gt;    &lt;/ul&gt;    &lt;p&gt;I dislike all of them because for me I prefer to have everything together. I could see dropbox    being suitable, because technically it's not neccessary to have verioned PDFs.&lt;/p&gt;    &lt;p&gt;If you have any comments on this, please share them.&lt;/p&gt;    &lt;h3&gt;~/research/projects - Specific Projects&lt;/h3&gt;    &lt;p&gt;You'll notice I have one folder here, "semigroups". This relates directly to a research scholarship    I completed at RMIT. This actually involved a python program, which I have in this directory, as well    as some miscellaneous files. It may be appropriate to have nicer codenames for projects, or somehow    related them directly to the scholarship details. I think the best approach here is to have a codename,    which is detailed in the "diary" folder, and then there is no risk on confusion or duplicate names. The    scholarship details could be held seperately in the folder, because perhaps the work could be continued    across scholarships.&lt;/p&gt;    &lt;p&gt;Anyway, it's probably not neccessary to overwork this structure. It can always be changed, and it shouldn't    be prohibitively difficult.&lt;/p&gt;    &lt;h3&gt;~/research/quantum-lunch - Files related to my reading group&lt;/h3&gt;    &lt;p&gt;This folder is indicative of the other types of folders you may find in this directory. In here, I have    some misc python scripts related to this group. There are no notes in here, they are kept in the "dairy"    folder.&lt;/p&gt;    &lt;p&gt;Technically this should be a transition area, where scripts and programs that reach an appropriate    level of maturity/usefulness are either published publically (in a different repository), or moved    to an appropriate folder under project, but I've not yet gotten to that stage.&lt;/p&gt;    &lt;p&gt;It's worth noting that I do have a public &lt;a href="http://github.com/silky"&gt;github profile: silky&lt;/a&gt;,     underwhich I will, and do, publish and tools that are worthwhile being public. If one of these projects    reaches that stage, I'd essentially move it out of here (delete it) and continue it in that area.&lt;/p&gt;    &lt;h2&gt;The tools&lt;/h2&gt;    &lt;p&gt;So, with the repository layout described, let me know discuss the tools I use. We've already    covered JabRef, for reference management, so we have:&lt;/p&gt;    &lt;ul&gt;        &lt;li&gt;JabRef (as mentioned), for reference management,&lt;/li&gt;        &lt;li&gt;Vim + Vimwiki plugin, for taking notes, keeping ideas, and writing LaTeX,&lt;/li&gt;        &lt;li&gt;Okular, for reading PDFs, and annotating them [linux],&lt;/li&gt;        &lt;li&gt;Python, for programming small scripts,&lt;/li&gt;        &lt;li&gt;XMonad, for window management [linux], and&lt;/li&gt;        &lt;li&gt;pdflatex and bibtex, for compiling latex (from the TeXLive distribution).&lt;/li&gt;    &lt;/ul&gt;    &lt;p&gt;So, almost all of these are available on any platform. Okular is worth commenting on, because it    has an important feature that I make use of - it stores annotations not in the PDF but in a    seperate file, that can then be programmatically investigated. If you can't use okular, then you    may find that your annotations to PDFs are written back into the PDF itself, and it will be     difficult to extract this. You can decide whether or not this bothers you when I describe how    I use my annotations.&lt;/p&gt;    &lt;p&gt;I will now describe the usage pattern for the various tools, starting in order for easiest    to hardest.&lt;/p&gt;    &lt;h3&gt;Tools - Okular&lt;/h3&gt;    &lt;p&gt;So, install okular via your favourite method, say "sudo apt-get install okoular", and then    open it. You will want to make it your default PDF editor, and I also choose to have it be    very minimal in it's display; setting the toolbar to text only, hiding the menu, and hiding    the list of pages on the left. I also configured a shortcut for exiting, namely pressing "qq".&lt;/p&gt;    &lt;p&gt;For me this is indicative of an important principle - make small customisations that    improve your life. It's worth thinking about, as they can often be trivial, but provide    a nice noticable benefit.&lt;/p&gt;    &lt;p&gt;You will also want to enable the 'Review' toolbar. This allows you to highlight lines of interest,    and also add comments. Your comments are saved in a location like:&lt;/p&gt;    &lt;pre&gt;~/.kde/share/apps/okular/docdata/[number].[pdf-name].xml&lt;/pre&gt;    &lt;p&gt;This is where it gets fun. I've written a program to capture these comments, as well as comments    in the 'Review' field of the .bib file. This tool is available on my github: &lt;a href="https://github.com/silky/utils/tree/master/get-notes"&gt;get-notes&lt;/a&gt;.    &lt;p&gt;You may need to adjust the 'main.conf' to suit your needs, or even change the source in    some fashion. The code is pretty trivial, but requires some python libraries that you can    install with easy_install.&lt;/p&gt;    &lt;p&gt;This file products vimwiki output (you can trivially change this however you like, if    you program in python). I then symbolically link this generated file ("AutoGeneratedNotes.wiki")    to my "~/research/diary". Of course, following the general strategy of not including generated    files in the source code, I do not break this rule for this file. There is one perhaps    obvious downside to this: The output might be different on different machines, because the    ~/.kde/... folder is not under source control. I consider this acceptable, because this    file is a "transitional" file, in that it is not supposed to be for long-term storage of ideas    and comments.&lt;/p&gt;    &lt;p&gt;The contents of this file should be reviewed, occasionally, and then moved into either a    PDF of comments, or into the research diary for an idea to investiage, or removed because    you've dealt with it.&lt;/p&gt;    &lt;p&gt;For example, I have a comment in the "Review" field of the file "Arora2002". It says:    "Has a section on the Fourier Transform that might be interesting". This should, eventually,    be transitioned into a minor topic to investigate further, or a small writeup in a    private "Comments on things" LaTeX document, where you write up, slightly more formally, and    with maths, your thoughts on things you've learned. I have this document under my "articles"    folder.&lt;/p&gt;    &lt;p&gt;With this in mind, it is then not an issue that the generated output is different bewteen    machines, because ideally there will be no output on any machine, one it has been sufficiently    transitioned.&lt;/p&gt;    &lt;h3&gt;Tools - LaTeX&lt;/h3&gt;    &lt;p&gt;As indicated, I use LaTeX to write up maths and more detailed notes, proposals, applications,    etc. You may wish to use some front-end for LaTeX authoring, for example LyX, but as I already    do a lot of work in vim, I prefer to also do LaTeX in here. If I were to switch to another    editor, it would probably be Emacs.&lt;/p&gt;    &lt;h3&gt;Tools - Python&lt;/h3&gt;    &lt;p&gt;As mentioned in the above comment, I use python to write small scripts. Because they're    in python, they are essentially directly runnable on any system (provided the associated    packages can be installed).&lt;/p&gt;    &lt;p&gt;I also like python because it provides various packages that are actually useful for my    research (like, for example, numpy). You can get similar funcionality from free Math    environments, though, such as Octave.&lt;/p&gt;    &lt;h3&gt;Tools - XMonad&lt;/h3&gt;    &lt;p&gt;XMonad is not particularly neccessary for this workflow, but I include it because I find    it's ease of use aids in efficient reading and editing. I don't want to go into significant    detail of XMonad configuration (but it's a fun way to spend your time), you may simply    review my &lt;a href="https://github.com/silky/dotfiles/tree/master/.xmonad"&gt;XMonad configuration&lt;/a&gt;    on github.    &lt;/p&gt;    &lt;p&gt;What I like about it is the concept of focus. You can simply and easily make a PDF full screen,    for distraction-free reading, and then switch things around to have vim side-by-side for    commenting with context.&lt;/p&gt;    &lt;p&gt;Feel free to disregard this, if you are using Windows, as it's equally possible to do fullscreen    and side-by-side editing in Windows 7. XMonad also offers other benefits for general programming,    which is the main reason I have it.&lt;/p&gt;    &lt;h3&gt;Tools - Vim + Vimwiki + LaTeX Box&lt;/h3&gt;    &lt;p&gt;Essentially the last item in my setup is Vim. It's hard to express the level of obsession    one has for Vim, after a while of using it. It is highly customisable, and includes and    inbuilt help system, which I used all the time, when initially learning it.&lt;/p&gt;    &lt;p&gt;Most people will find Vim initially difficult to use (I did, when I first learned it    when starting work here), but if you dedicate a few days to using it correctly, and you    make significant use of the ":help [topic]" command, you will get the hang of it.&lt;/p&gt;    &lt;p&gt;You aren't truly using Vim correctly (or, indeed, living a full life), if you don't get    various plugins. The neccessary ones for LaTeX + note taking are: &lt;a href="http://vim-latex.sourceforge.net/"&gt;Vimwiki&lt;/a&gt;    and &lt;a href="http://www.vim.org/scripts/script.php?script_id=3109"&gt;LaTeX Box&lt;/a&gt; or &lt;a href="http://vim-latex.sourceforge.net/"&gt;Vim-LaTeX&lt;/a&gt;. &lt;/p&gt;    &lt;p&gt;You can find the current state of my Vim configuration, again on my &lt;a href="https://github.com/silky/dotfiles/tree/master/.vim"&gt;github - .vim&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;I actually currently use Vim-LaTeX, but I am planning on changing to LaTeX Box because    it is more lightweight, so I would recommend starting with LaTeX Box.&lt;/p&gt;    &lt;p&gt;The nice thing about using okular is that you can recompile your LaTeX document with    the PDF open, and it will refresh it, keeping the current page open. This is very    useful when typing long formulas, and reviewing your work.    &lt;/p&gt;    &lt;p&gt;I have configured Vimwiki to open with "&lt;leader&gt;rw", so I can type this at any time, in    Vim, and be looking at the index to all my research notes. In this I have links to    all my diaries, my storage spots for old search ideas, and a big list of topics to look    into. I also make "TODO" notes in here, and review them with one of my other tools,    "find-todo" (on the aforemention github, under /utils). This gives me a list inside Vim,    and I can easily navigate to the appropriate file. Again, the TODO's are items that should    be transitioned.    &lt;/p&gt;    &lt;h2&gt;Review&lt;/h2&gt;    &lt;p&gt;I have documented my reseach environment, as it stands currently. It allows me to make    notes easily, transition them in an appropriate workflow, and access all my documents    at any time, from any computer.    &lt;/p&gt;    &lt;p&gt;The proof of a good research environment obviously in the blogging, it's in the producing    of legitimately good research output, and of course that's yet to be delivered (by myself    personally), so it's not possible to objectively rate this strategy for it's actual    effectiveness. Nevertheless, I do feel comfortable with this layout; I feel like I can take    the appropriate amount of notes; I feel my notes are always tracked, and I feel that I have    a nice and readable history of what I've done. I like that I can track bad ideas; I like    that I can make comments "anywhere" (i.e. in Okular or in JabRef) and have them captured    automatically for later review, and I like the feeling of having everything organised.    &lt;/p&gt;    &lt;p&gt;I hope this description has been useful, and I would love to hear about any adjustments    you'd propose, or just your own research strategies.    &lt;/p&gt;--Noon&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-3672551763450316344?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/3672551763450316344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2012/01/efficient-and-effective-research.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3672551763450316344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3672551763450316344'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2012/01/efficient-and-effective-research.html' title='An efficient and effective research environment (on linux, with vim, jabref and more)'/><author><name>Noon Silk</name><uri>http://www.blogger.com/profile/12853926028827251858</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-8692645948456293103</id><published>2011-12-15T16:57:00.001+11:00</published><updated>2011-12-15T17:04:03.998+11:00</updated><title type='text'>Vim (and Emacs)</title><content type='html'>&lt;p&gt;Biarri now has a few dedicated vim users with their configuration files available online: &lt;a href="https://github.com/loki42/dotfiles"&gt;Myself (Loki)&lt;/a&gt; and &lt;a href="https://github.com/silky/dotfiles"&gt;Noon.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;My configuration file is based on Sontek's with a few changes and additions. His description at &lt;a href="http://sontek.net/turning-vim-into-a-modern-python-ide"&gt;http://sontek.net/turning-vim-into-a-modern-python-ide&lt;/a&gt; is worth a read.&lt;/p&gt;&lt;p&gt;You'll notice that I have disabled my arrow keys. Despite liking the Cure and The Smiths this isn't to hurt myself. It's not ever so I keep my hands on the home row and use hjkl. Instead it's to force me out of insert mode. I now stay in normal mode as much as possible. Since disabling my arrows I've found the combination of traditional vim motions (especially f/F) combined with Easy Motion is fantastic. I usually use f for short jumps and Easy Motion for longer movements.&lt;/p&gt;&lt;p&gt;&lt;a href="https://github.com/Lokaltog/vim-easymotion"&gt;Easy Motion&lt;/a&gt; is really best explained by watching the demo video closely, or just using it. It's quite wonderful and works well with visual mode. I'm also enjoying Command-T, PyFlakes, snipmate and ack. I'm still confused about what the best autocomplete solution is. Supertab doesn't seem to work right for me and ACP, which I was using for a while is useful but somewhat annoying. I would like it to show call signatures and if requested, docstrings in a non-annoying way too. Command-T is the greatest thing imaginable for opening files, buffers and tags. &lt;/p&gt;&lt;p&gt;I've also installed vimwiki but i'm so far unsure about it. I used it to store my ideas and todos in a more organised manner. I suspect it's a bit like a less awesome org mode. Speaking of which we now also have an Emacs user: &lt;a href="https://bitbucket.org/tobyodavies/shared/src"&gt;https://bitbucket.org/tobyodavies/shared/src&lt;/a&gt; If anyone knows a good python autocomplete solution I'd love to hear about it. &lt;/p&gt;&lt;p&gt;&lt;b&gt;Loki&lt;/b&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-8692645948456293103?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/8692645948456293103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/12/vim-and-emacs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8692645948456293103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8692645948456293103'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/12/vim-and-emacs.html' title='Vim (and Emacs)'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-896924445879629407</id><published>2011-12-09T17:36:00.001+11:00</published><updated>2011-12-09T17:42:08.429+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Subscription payments</title><content type='html'>Selling things on the internet is quite easy and there are plenty of way to process credit cards and accept online payments. However subscriptions / recurring payments aren't easy. They aren't easy at all. Subscription changes, card failures, multiple subscriptions for a single user (different workbench products in our case) and multiple currency billing make it hard. Dealing with banks 80's style systems makes it even harder. &lt;br /&gt;&lt;br /&gt;When we were first working out how to cope with online payments we found lots of good looking options, all of which were only available to American companies or via paypal. (&lt;a href="http://recurly.com/"&gt;Recurly&lt;/a&gt;,&amp;nbsp;&lt;a href="https://cheddargetter.com/"&gt;CheddarGetter&lt;/a&gt;&lt;a href="http://spreedly.com/"&gt;Spreedly)&lt;/a&gt; Eventually we found RBS Worldpay.Worldpay turned out to be too inflexible and far to much effort to set up. The time required was also insane. From the start of our application to ready to get our payments up took 7 months and significant amounts of cash. We gave up on Worldpay when we were trying (hard) to integrate it. Their system for recurring payments is so ill documented and inflexible to be useless. Users appear to require a separate login and password for Worldpay. This is unacceptable. Currently we're looking into &lt;a href="http://saasy.com/"&gt;Saasy&lt;/a&gt;, from fastspring. They respond fantastically quickly to support request and got our testing site up and approved us in a day. So far it looks great, flexible and easy but I'll post another blog when we've got it all live. I'll also put some code for the server side part in python using cherrypy up on github, when it's a bit more polished. &lt;br /&gt;&lt;p&gt;&lt;b&gt;Loki&lt;/b&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-896924445879629407?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/896924445879629407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/12/subscription-payments.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/896924445879629407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/896924445879629407'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/12/subscription-payments.html' title='Subscription payments'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-2379198517966587524</id><published>2011-12-01T08:22:00.000+11:00</published><updated>2011-12-01T08:22:38.813+11:00</updated><title type='text'>Gartner’s top-10 strategic technologies for 2012</title><content type='html'>&lt;a href="http://www.analytics-magazine.org/special-articles/479-gartners-top-10-strategic-technologies-for-2012#.Ttaeh0Rr1hw.blogger"&gt;Gartner’s top-10 strategic technologies for 2012&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-2379198517966587524?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.analytics-magazine.org/special-articles/479-gartners-top-10-strategic-technologies-for-2012#.Ttaeh0Rr1hw.blogger' title='Gartner’s top-10 strategic technologies for 2012'/><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/2379198517966587524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/12/gartners-top-10-strategic-technologies.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/2379198517966587524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/2379198517966587524'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/12/gartners-top-10-strategic-technologies.html' title='Gartner’s top-10 strategic technologies for 2012'/><author><name>Joe</name><uri>http://www.blogger.com/profile/12875745156578898029</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-Ahp5frY7EQk/TpY7bm2GcNI/AAAAAAAAAAo/gcnqBIjwXr0/s220/joe-forbes.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-6006728851632686724</id><published>2011-11-01T14:46:00.005+11:00</published><updated>2011-11-01T15:08:13.587+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Selecting a cell in an HTML table with jQuery</title><content type='html'>I wanted to get (and set) a cell value in a table using &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;, selecting it by row and column index (its &lt;span style="font-style: italic;"&gt;x&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;y&lt;/span&gt; position in the table, if you like).  Frustratingly, I couldn't find a simple one-liner to do it: I could find code that &lt;a href="http://stackoverflow.com/questions/376081/how-to-get-a-table-cell-value-using-jquery"&gt;gets all the cells&lt;/a&gt;, or &lt;a href="http://stackoverflow.com/questions/1945844/using-jquery-how-to-check-whether-a-table-cell-is-empty-or-not"&gt;get them by ID&lt;/a&gt; (but I don't want to have to make explicit IDs for each cell of my table), or &lt;a href="http://stackoverflow.com/questions/5612128/how-to-get-a-table-cell-value-using-jquery"&gt;get all the values in a given column&lt;/a&gt; (close, and did lead me in the right direction).&lt;br /&gt;&lt;br /&gt;So here's two similar ways to select a given cell, where &lt;span style="font-family:courier new;"&gt;row&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;col&lt;/span&gt; are my &lt;span style="font-style: italic;"&gt;x&lt;/span&gt;,&lt;span style="font-style: italic;"&gt; y&lt;/span&gt; positions, and my_table is the &lt;span style="font-family:courier new;"&gt;ID&lt;/span&gt; of the table:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;$('#my_table tr:eq('+row+') td').eq(col)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and&lt;br /&gt;     &lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;$('#my_table tbody tr:eq('+row+') td:eq('+col+')')&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-6006728851632686724?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/6006728851632686724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/11/selecting-cell-in-html-table-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6006728851632686724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6006728851632686724'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/11/selecting-cell-in-html-table-with.html' title='Selecting a cell in an HTML table with jQuery'/><author><name>Andrew</name><uri>http://www.blogger.com/profile/14439386212899881028</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-929051569496651945</id><published>2011-10-18T15:29:00.003+11:00</published><updated>2011-10-18T16:02:07.954+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tricks'/><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='postgresql'/><title type='text'>PostgreSQL Tricks</title><content type='html'>Over the last year or so I've gathered a little trick bag of &lt;a href="http://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; recipes.  Here are some of the best.&lt;br /&gt;&lt;br /&gt;These all work in PostgreSQL version 8.4.7 and probably most other versions.  The "--" below are PostgreSQL comments.&lt;br /&gt;&lt;br /&gt;To see your PostgreSQL version, use:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;select version();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It's sometimes useful to be able to discover the tables in a schema automatically.  To do this you can use the following command:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt;&amp;gt; \dt my_schema.*               -- here the * is a wildcard&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Or this command, which uses the PostgreSQL internal tables pg_class and pg_namespace:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt;&amp;gt; select n.nspname, c.relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname='my_schema';&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Where "&lt;span style="font-family: courier new;"&gt;my_schema&lt;/span&gt;" is a schema name.  Once you've found the table you're interested in, &lt;span style="font-family: courier new;"&gt;\d table_name&lt;/span&gt; gives you the columns and their types.&lt;br /&gt;&lt;br /&gt;To discover the columns in a table (that is in a schema):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt;&amp;gt; select a.attname from pg_class as c, pg_namespace as n, pg_attribute as a where n.oid=c.relnamespace and n.nspname='my_schema' and c.relname='my_table' and a.attrelid=c.oid;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Where "&lt;span style="font-family: courier new;"&gt;my_table&lt;/span&gt;" is the table name in your schema.  This uses the PostgreSQL internal tables pg_class, pg_namespace and pg_attribute.&lt;br /&gt;&lt;br /&gt;To discover the type of a column in a table (that is in a schema)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt;&amp;gt; select a.attname, t.typname, a.atttypid from pg_class as c, pg_namespace as n, pg_attribute as a, pg_type as t where n.oid=c.relnamespace and n.nspname='&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;my_schema&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;' &lt;/span&gt;&lt;span style="font-family: courier new;"&gt;and c.relname='my_table' &lt;/span&gt;&lt;span style="font-family: courier new;"&gt;and a.attrelid=c.oid and a.attname='my_column' and t.oid=a.atttypid;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Where "&lt;span style="font-family: courier new;"&gt;my_column&lt;/span&gt;" is the column name in the table.  This is similar to the previous command, but also uses internal table pg_type.&lt;br /&gt;&lt;br /&gt;If you have some duplicate rows in your table, you can delete them using the hidden ctid column, e.g.:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt;&amp;gt; select ctid, * from my_table;    -- show me the repeats&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; &amp;gt;&amp;gt;&amp;gt; delete from &lt;/span&gt;&lt;span style="font-family: courier new;"&gt;my_table &lt;/span&gt;&lt;span style="font-family: courier new;"&gt;where CAST("ctid" as text) like '%3%';    -- kill some according to some wildcard pattern&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A more automatic way is:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; &amp;gt;&amp;gt;&amp;gt; delete form  my_table where ctid not in (select max(dup.ctid) from my_table as dup group by dup.x, dup.y, dup.z);    -- substitute appropriate column names for x, y, z&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Allowable &lt;a href="http://www.postgresql.org/docs/8.2/static/runtime-config-client.html#GUC-DATESTYLE"&gt;formats for dates&lt;/a&gt; are controlled by the PostgreSQL setting '&lt;span style="font-family: courier new;"&gt;datestyle&lt;/span&gt;'.  To see it, type:&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;br /&gt;show datestyle;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To change the datestyle you can use (for example):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;set datestyle to 'iso, dmy';&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;But note that this change is not a permanent change (it only applies to this session/cursor).&lt;br /&gt;&lt;br /&gt;Lastly, I sometimes use this command:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;table my_table;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;as a shorthand for &lt;span style="font-family: courier new;"&gt;select * from my_table&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-929051569496651945?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/929051569496651945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/10/postgresql-tricks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/929051569496651945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/929051569496651945'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/10/postgresql-tricks.html' title='PostgreSQL Tricks'/><author><name>Andrew</name><uri>http://www.blogger.com/profile/14439386212899881028</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-9011690170442198576</id><published>2011-10-14T12:12:00.002+11:00</published><updated>2011-11-11T15:20:11.372+11:00</updated><title type='text'>Debugging Internet Traffic</title><content type='html'>Below are some tools and thoughts that may be useful to people who  are having difficulties trying to debug issues related to internet  traffic.&lt;br /&gt;There are a number of other tools (e.g. Firebug,  Wireshark/ethereal, etc) that are not mentioned below.  However I  thought a quick one pager on some of the tools that I have used and  found useful might be useful to someone else.&lt;br /&gt;&lt;h2&gt;Tamper (Firefox plug-in)  &lt;/h2&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/tamper-data/"&gt;https://addons.mozilla.org/en-US/firefox/addon/tamper-data/&lt;/a&gt;&lt;br /&gt;This  is a Firefox plugin which allows users to view the exact data they're  sending out through their browser.  It's useful for debugging traffic,  as well as those times when your browser has remembered your password  and you've forgotten your password (as you can see the password that is being sent).  It also  gives you the opportunity to intercept this data and change it which  can also be useful for debugging purposes.  The disadvantage with this  tool though is that it will only work on data sent through Firefox.  Fiddler2 (below) can be used to intecept traffic from a wider range of  sources (e.g. iexplorer, firefox, wget, curl, ... and other  applications).&lt;br /&gt;&lt;h2&gt;wget and curl&lt;/h2&gt;&lt;a href="http://www.gnu.org/s/wget/"&gt;http://www.gnu.org/s/wget/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://curl.haxx.se/"&gt;http://curl.haxx.se&lt;/a&gt;&lt;br /&gt;These  tools are very similar and are useful for sending web requests via  command line.  They both work in Linux and Windows (and other OSes).  I  was using this to help debug an issue we were having at a client site  that was not allowing our newt traffic to be sent to our servers.   It means you can easily change things like proxy settings,  username/passwords, URLs, the posted data - without having to recompile  an exe and copy it onto the client machine.  I personally found curl  worked better than wget. I couldn't get the username/password  information to be sent correctly with wget.  There was plenty of help on  the net, but it just didn't seem to work for me for some reason.  A typical example of  the types of curl requests I was sending looked like this:&lt;br /&gt;curl -L -x proxy_details:proxy_port --user username:password --output outuptfile.html &lt;a href="http://testing.biarriworkbench.com/validate_desktop_model"&gt;http://website.com/method&lt;/a&gt; --data "user_info=stuffhere%3Bmorestuffhere%3Bextra_info=morestuffhere"&lt;br /&gt;These command line tools can of course called via scripts as well if required.&lt;br /&gt;&lt;h2&gt;Filddler 2&lt;/h2&gt;&lt;a href="http://www.fiddler2.com/fiddler2/"&gt;http://www.fiddler2.com/fiddler2/&lt;/a&gt;&lt;br /&gt;I  found this tool paricularly useful when diagnosing firewall/proxy  issues as I could see exactly why various requests from curl/wget were,  or were not, working.&lt;br /&gt;&lt;img alias="image2011-10-14 10:42:16.png" class="confluence-embedded-image" height="323" id="2916508" src="https://biarri.onconfluence.com/download/attachments/2752904/image2011-10-14+10%3A42%3A16.png?version=1&amp;amp;modificationDate=1318552935484" title="image2011-10-14 10:42:16.png" type="attachment" url="https://biarri.onconfluence.com" width="640" /&gt;&lt;br /&gt;I'm  certainly not an expert on Fiddler2, and I'm not abou to try and tell  you all the ins and outs of how to use this tool: firstly because I  don't know all of them, secondly because a quick Google search will help  you there.&lt;br /&gt;However, some of the useful features that I have found useful are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It  can monitor traffic from differnt sources.  The "Process" column in the  left pane in the above image shows that curl and firefox traffic has  been detected.&lt;/li&gt;&lt;li&gt;The upper pane on the right shows the request details of the selected item in the left pane:&lt;ul&gt;&lt;li&gt;Headers&lt;/li&gt;&lt;li&gt;TextView&lt;/li&gt;&lt;li&gt;WebForms&lt;/li&gt;&lt;li&gt;HexView&lt;/li&gt;&lt;li&gt;Auth  (useful if want to see how usernames and passwords are being handled)&lt;/li&gt;&lt;li&gt;Raw&lt;/li&gt;&lt;li&gt;XML&lt;/li&gt;&lt;li&gt;JSON&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;The lower pane on the right gives the response details of the selected item in the left pane:&lt;ul&gt;&lt;li&gt;Auth&lt;/li&gt;&lt;li&gt;Caching&lt;/li&gt;&lt;li&gt;Privacy&lt;/li&gt;&lt;li&gt;Raw&lt;/li&gt;&lt;li&gt;XML&lt;/li&gt;&lt;li&gt;JSON&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Another one of the cool features of fiddler2 is that it can be used  to debug encrypted traffic.  It does this by installig a security  certificate on your computer.  Ideally you would only install this  security certificate on a machine for debuggnig purposes and one that  was not passing sensitive information over the internet as it poses a  security risk.  It should be removed from the computer once you have  finished debugging (it's easy enough to put another back in the future  if requred).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-9011690170442198576?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/9011690170442198576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/10/debugging-internet-traffic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/9011690170442198576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/9011690170442198576'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/10/debugging-internet-traffic.html' title='Debugging Internet Traffic'/><author><name>David Philpot</name><uri>http://www.blogger.com/profile/10426874112178844783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1712395984574111782</id><published>2011-10-13T16:08:00.002+11:00</published><updated>2011-10-13T16:15:40.322+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithms'/><title type='text'>Kevin Slavin: How algorithms shape our world</title><content type='html'>&lt;br /&gt;&lt;object width="526" height="374"&gt;&lt;param name="movie" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;param name="bgColor" value="#ffffff"&gt;&lt;/param&gt;&lt;param name="flashvars" value="vu=http://video.ted.com/talk/stream/2011G/Blank/KevinSlavin_2011G-320k.mp4&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/KevinSlavin-2011G.embed_thumbnail.jpg&amp;vw=512&amp;vh=288&amp;ap=0&amp;ti=1194&amp;lang=&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=kevin_slavin_how_algorithms_shape_our_world;year=2011;theme=new_on_ted_com;theme=what_s_next_in_tech;theme=a_taste_of_tedglobal_2011;theme=to_boldly_go;event=TEDGlobal+2011;tag=Technology;tag=complexity;tag=computers;tag=social+change;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" /&gt;&lt;embed src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" pluginspace="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" bgColor="#ffffff" width="526" height="374" allowFullScreen="true" allowScriptAccess="always" flashvars="vu=http://video.ted.com/talk/stream/2011G/Blank/KevinSlavin_2011G-320k.mp4&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/KevinSlavin-2011G.embed_thumbnail.jpg&amp;vw=512&amp;vh=288&amp;ap=0&amp;ti=1194&amp;lang=&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=kevin_slavin_how_algorithms_shape_our_world;year=2011;theme=new_on_ted_com;theme=what_s_next_in_tech;theme=a_taste_of_tedglobal_2011;theme=to_boldly_go;event=TEDGlobal+2011;tag=Technology;tag=complexity;tag=computers;tag=social+change;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1712395984574111782?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1712395984574111782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/10/kevin-slavin-how-algorithms-shape-our.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1712395984574111782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1712395984574111782'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/10/kevin-slavin-how-algorithms-shape-our.html' title='Kevin Slavin: How algorithms shape our world'/><author><name>Joe</name><uri>http://www.blogger.com/profile/12875745156578898029</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-Ahp5frY7EQk/TpY7bm2GcNI/AAAAAAAAAAo/gcnqBIjwXr0/s220/joe-forbes.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1755035371736097832</id><published>2011-09-28T08:59:00.002+10:00</published><updated>2011-09-28T09:09:51.026+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='optimisation'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='workbench'/><category scheme='http://www.blogger.com/atom/ns#' term='pre-emptive optimisation'/><title type='text'>Pre-emptive optimisation; or, how to be deliberately wasteful of server resources</title><content type='html'>For one of our long-standing clients we have been running vehicle routing optimisations on a daily basis.  A file of daily orders is uploaded into our Workbench system, and is split up into several regions, each of which needs to be separately optimised.  A planner works through each region, going through a series of data checks (e.g. location geocode checking), before hitting an “Optimise” button.&lt;br /&gt;&lt;br /&gt;All of the heavy lifting is done on a server (the planner accesses it through a web app via a browser), so it’s possible that the server could silently start up the required optimisations without the planner’s involvement, and in the (fairly common) case where the region does not require any data corrections, when the planner is up to the optimisation stage, the result could be immediately available (as it has already been run, or is in the process of being run).  This idea now been implemented and took only a short amount of Python code.&lt;br /&gt;&lt;br /&gt;Furthermore, it runs in parallel as each optimisation is itself split into a separate child process (running a C++ exe) which Linux distributes across the 8 cores of our server machine.&lt;br /&gt;The pre-emptive optimisations are kicked off using Python’s multiprocessing package, as follows:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;from multiprocessing import Process&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;...&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;p = Process(target=start_preemptive_optimisations, args=(...))&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;p.start()&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Control is returned to the user at this point while the optimisations run in the background.  Results are stored in a folder whose name is stored in a database table; when the planner then comes to press Optimise, the system checks if there have been any data corrections – if so, it runs the optimisation from scratch as usual (the pre-emptive result for that region is thus never referenced); however, if there are no corrections, the system simply uses the stored result from the folder.&lt;br /&gt;&lt;br /&gt;The end result for the user is that in many cases the optimisations appear to run almost instantaneously.  There are really no downsides as we do not pay for our servers on a CPU cycle basis, so we can easily be wasteful of our server CPU time and run these optimisations even if their results are sometimes not needed.&lt;br /&gt;&lt;br /&gt;One “wrinkle” we discovered with this is that we had to make our process checking more robust.  There is Javascript in our browser front end that polls for certain events, such as an optimisation finishing, which is indicated by a process ceasing to exist.  The Python for this is shown below, where “pid” is a process ID.  The function returns True if the given process has finished or not.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;span style="color: #ff7700;font-weight:bold;"&gt;def&lt;/span&gt; check_pid_and_return_whether_process_has_finished&lt;span style="color: black;"&gt;&amp;#40;&lt;/span&gt;pid&lt;span style="color: black;"&gt;&amp;#41;&lt;/span&gt;:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;if&lt;/span&gt; pid &lt;span style="color: #ff7700;font-weight:bold;"&gt;and&lt;/span&gt; pid &lt;span style="color: #66cc66;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #ff4500;"&gt;0&lt;/span&gt;:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; multiprocessing.&lt;span style="color: black;"&gt;active_children&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#41;&lt;/span&gt; &amp;nbsp; &lt;span style="color: #808080; font-style: italic;"&gt;# reap all zombie children first; this also seems to pick up non-children processes&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;try&lt;/span&gt;:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #dc143c;"&gt;os&lt;/span&gt;.&lt;span style="color: black;"&gt;waitpid&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#40;&lt;/span&gt;pid, &lt;span style="color: #dc143c;"&gt;os&lt;/span&gt;.&lt;span style="color: black;"&gt;WNOHANG&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#41;&lt;/span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #808080; font-style: italic;"&gt;# this reaps zombies that are child processes, as it gives these processes a chance to output their final return value to the OS.&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;except&lt;/span&gt; &lt;span style="color: #008000;"&gt;OSError&lt;/span&gt; &lt;span style="color: #ff7700;font-weight:bold;"&gt;as&lt;/span&gt; e:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;int&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#40;&lt;/span&gt;e.&lt;span style="color: #dc143c;"&gt;errno&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span style="color: #ff4500;"&gt;10&lt;/span&gt;: &amp;nbsp;&lt;span style="color: #808080; font-style: italic;"&gt;# the 10 indicates pid is not a child process; in this case we want to do nothing and let os.kill be the function to throw an exception and return True (indicating process is finished).&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;return&lt;/span&gt; &lt;span style="color: #008000;"&gt;True&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;try&lt;/span&gt;:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #dc143c;"&gt;os&lt;/span&gt;.&lt;span style="color: black;"&gt;kill&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#40;&lt;/span&gt;pid, &lt;span style="color: #ff4500;"&gt;0&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#41;&lt;/span&gt; &amp;nbsp; &lt;span style="color: #808080; font-style: italic;"&gt;# doesn't actually kill the process, but raises an OSError if the process pid does not exist; this indicates the process is finished. &amp;nbsp;Applies to all processes, not just children.&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;except&lt;/span&gt; &lt;span style="color: #008000;"&gt;OSError&lt;/span&gt; &lt;span style="color: #ff7700;font-weight:bold;"&gt;as&lt;/span&gt; e:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;return&lt;/span&gt; &lt;span style="color: #008000;"&gt;True&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;else&lt;/span&gt;:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;return&lt;/span&gt; &lt;span style="color: #008000;"&gt;True&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #ff7700;font-weight:bold;"&gt;return&lt;/span&gt; &lt;span style="color: #008000;"&gt;False&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note the “reaping” of zombie processes here, and the complication that arises if a process is not a direct child of the calling Python process (it might be a “child of a child”).  In this case we use a call to the (in this case rather mis-named) function os.kill.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1755035371736097832?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1755035371736097832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/09/pre-emptive-optimisation-or-how-to-be.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1755035371736097832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1755035371736097832'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/09/pre-emptive-optimisation-or-how-to-be.html' title='Pre-emptive optimisation; or, how to be deliberately wasteful of server resources'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-7378725616497038654</id><published>2011-09-05T10:49:00.010+10:00</published><updated>2011-09-05T11:20:44.949+10:00</updated><title type='text'>Spatial Clustering in C++ (post 5 of 5) – The final outputs</title><content type='html'>&lt;br /&gt;In this fifth and final post of the series on Spatial Clustering in C++, we’ll look at some of the final outputs produced and wrap up the discussion of techniques and codes used.&lt;br /&gt;&lt;br /&gt;In the last post I presented some code that can be used to generate an Alpha Shape from a set of points, create it as an OGR Polygon, and output these polygons to MID/MIF files.  I’ve since found that one of the functions used in that code, GetNextRing, is quite inefficient when the polygon has a complex perimeter (many points on its boundary), which happens with very small values for &lt;span style="font-style: italic;"&gt;alpha&lt;/span&gt;.  Still it wouldn't be too hard to speed that code up.&lt;br /&gt;&lt;br /&gt;It’s interesting to generate some different Alpha Shapes with varying of the &lt;span style="font-style: italic;"&gt;alpha &lt;/span&gt;parameter.  Recall that &lt;span style="font-style: italic;"&gt;alpha &lt;/span&gt;corresponds to how tightly the polygon is “shrink wrapped” around the points it encloses; it is actually the radius of circles that define the “bites” taken out around the perimeter of the shape.  If &lt;span style="font-style: italic;"&gt;alpha &lt;/span&gt;is too high, one gets a very approximate shape that starts to approach the convex hull of the points, while if &lt;span style="font-style: italic;"&gt;alpha &lt;/span&gt;is too low, the shape starts to get very “spiky”, and eventually one starts to lose whole parts of the polygon completely.  The good news is that the polygons produced are not too visually dissimilar if you stay within reasonable bounds for &lt;span style="font-style: italic;"&gt;alpha &lt;/span&gt;– that is, they are not overly sensitive to its value.&lt;br /&gt;&lt;br /&gt;Let’s have a look with the San Francisco bay area as our example.  Here I’m using an &lt;span style="font-style: italic;"&gt;eps &lt;/span&gt;in the DBSCAN of 0.009 with &lt;span style="font-style: italic;"&gt;minPts &lt;/span&gt;= 8, which gives the following clusters:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-56tiI8pSNC0/TmQdbspsbRI/AAAAAAAAABw/ILadevtDTZk/s1600/SanFran_points.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 261px;" src="http://1.bp.blogspot.com/-56tiI8pSNC0/TmQdbspsbRI/AAAAAAAAABw/ILadevtDTZk/s400/SanFran_points.png" alt="" id="BLOGGER_PHOTO_ID_5648672194309156114" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And for the Alpha Shapes, an &lt;span style="font-style: italic;"&gt;alpha &lt;/span&gt;of 2500 gives the following:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-OllWyZiqAGY/TmQduFw0x8I/AAAAAAAAAB4/-XauTYwGjwc/s1600/Alpha_2500.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 266px;" src="http://3.bp.blogspot.com/-OllWyZiqAGY/TmQduFw0x8I/AAAAAAAAAB4/-XauTYwGjwc/s400/Alpha_2500.png" alt="" id="BLOGGER_PHOTO_ID_5648672510287595458" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In the next picture you can see how the shapes represent the points (note also the hole in the large green cluster – the Alpha Shapes code we’re using doesn’t allow for actual holes within the shapes produced):&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-Ak8IxDPKPJQ/TmQd_FJz63I/AAAAAAAAACA/m1h3yfLRPw4/s1600/Alpha_2500_with_points.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 261px;" src="http://2.bp.blogspot.com/-Ak8IxDPKPJQ/TmQd_FJz63I/AAAAAAAAACA/m1h3yfLRPw4/s400/Alpha_2500_with_points.png" alt="" id="BLOGGER_PHOTO_ID_5648672802181737330" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here I’ve used Bing Aerial in MapInfoPro to give the shapes produced some spatial context, and I’ve used 33% transparency on the polygon layer (use Layer Properties).  Incidentally you can use Style Overrides to give patterned output as well, such as:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-0IQTgv6lXC4/TmQekkrlVeI/AAAAAAAAACI/fh0BXrb0ZvI/s1600/Alpha_2500_semi_trans.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 288px;" src="http://2.bp.blogspot.com/-0IQTgv6lXC4/TmQekkrlVeI/AAAAAAAAACI/fh0BXrb0ZvI/s400/Alpha_2500_semi_trans.png" alt="" id="BLOGGER_PHOTO_ID_5648673446300046818" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;With alpha 5000, the results are very similar, though some of the “holes” along the polygon boundaries have now been “filled in”:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-e6VXuQ0JSxw/TmQe0oP4R-I/AAAAAAAAACQ/xATqFUi9v3U/s1600/Alpha_5000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 246px;" src="http://1.bp.blogspot.com/-e6VXuQ0JSxw/TmQe0oP4R-I/AAAAAAAAACQ/xATqFUi9v3U/s400/Alpha_5000.png" alt="" id="BLOGGER_PHOTO_ID_5648673722135496674" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The colours of the shapes are different here just because of the funky unique RGB generator function I’m using which depends on the creation index of the polygon; the clusters are the same, only alpha is different.&lt;br /&gt;&lt;br /&gt;Even with alpha = 20000, the shapes are still good visual approximations of the points:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-0c6RW_KQ_dE/TmQfFVmGvCI/AAAAAAAAACY/T812WY4Jy-Y/s1600/Alpha_20000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 259px;" src="http://2.bp.blogspot.com/-0c6RW_KQ_dE/TmQfFVmGvCI/AAAAAAAAACY/T812WY4Jy-Y/s400/Alpha_20000.png" alt="" id="BLOGGER_PHOTO_ID_5648674009186221090" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;With 50000 the shapes are still OK but some big holes have now been filled in:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-mruQaHhe3aU/TmQfMFaIsXI/AAAAAAAAACg/ZuKyriPbel4/s1600/Alpha_50000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 258px;" src="http://3.bp.blogspot.com/-mruQaHhe3aU/TmQfMFaIsXI/AAAAAAAAACg/ZuKyriPbel4/s400/Alpha_50000.png" alt="" id="BLOGGER_PHOTO_ID_5648674125100134770" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And with alpha 5000000 one starts to get nearer to the convex hull:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-3VqFv1_Ka38/TmQfRVl3RPI/AAAAAAAAACo/QuPiF1p4pxE/s1600/Alpha_500000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 270px;" src="http://3.bp.blogspot.com/-3VqFv1_Ka38/TmQfRVl3RPI/AAAAAAAAACo/QuPiF1p4pxE/s400/Alpha_500000.png" alt="" id="BLOGGER_PHOTO_ID_5648674215343637746" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;With smaller values of alpha, such as 1000, the shapes are similar to alpha 2500.  Below that, however, the Alpha Shapes algorithm starts to produce multiple, very spiky (many points defining a complex boundary) polygons for each cluster, such as this example with alpha 500:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-wqYLLvm8hhU/TmQfgftOj_I/AAAAAAAAACw/h_luWZMI1U4/s1600/Alpha_500.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 260px;" src="http://2.bp.blogspot.com/-wqYLLvm8hhU/TmQfgftOj_I/AAAAAAAAACw/h_luWZMI1U4/s400/Alpha_500.png" alt="" id="BLOGGER_PHOTO_ID_5648674475756916722" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;These anemic shapes no longer approximate the points very well.&lt;br /&gt;&lt;br /&gt;With larger data sets just showing the clustered points gets slower, so you could potentially also make a geoset and use zoom levels, with polygons shown at higher zoom levels, then show the clustered points when zoomed in closer.&lt;br /&gt;&lt;br /&gt;In terms of output, I’ve found &lt;a href="http://mitab.maptools.org/"&gt;Tab2tab&lt;/a&gt; is a useful little program to convert between Mid/Mif and Tab formats, though it is not without its problems: older versions have a loss of precision, and current versions appear to lose the colours of the polygons (regions in the parlance).  One could potentially also write out the polygons or clusters using &lt;a href="http://www.gdal.org/ogr/"&gt;OGR&lt;/a&gt; functions directly in the output format desired.  And if you don’t have MapInfoPro, &lt;a href="http://www.qgis.org/"&gt;QGIS&lt;/a&gt; is a good open source alternative.&lt;br /&gt;&lt;br /&gt;If you've made it this far, then I hope you've enjoyed this five part blog post.  I'll leave you with a summary of the tools and algorithms that have been deployed in this exercise:&lt;br /&gt;&lt;table border="1"&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;th&gt;Tool/algorithm&lt;/th&gt;&lt;br /&gt;    &lt;th&gt;What it does&lt;/th&gt;&lt;br /&gt;    &lt;th&gt;Notes/shortcomings&lt;/th&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://www.census.gov/geo/www/tiger/"&gt;TIGER spatial data&lt;/a&gt;&lt;/th&gt;&lt;br /&gt;    &lt;td&gt;Source for free US spatial data&lt;/th&gt;&lt;br /&gt;    &lt;td&gt;In this exercise, used as a data source of points for spatial clustering&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://www.pbinsight.com/products/location-intelligence/applications/mapping-analytical/mapinfo-professional/"&gt;MapInfo&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Display and edit spatial data&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Commercial product, but very good&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Kdtree"&gt;kdtree&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Data structure for storing 2 dimensional points&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Allows fast lookup of nearby points.  Good C++ implementation &lt;a href="http://code.google.com/p/kdtree/"&gt;here&lt;/a&gt;.&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://www.gdal.org/ogr/"&gt;OGR&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Library for computational geometry&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Good utility functions for reading and writing points and polygons&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/DBSCAN"&gt;DBSCAN&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Algorithm for spatial clustering&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Simple to implement; previous blog posts in this series show how to make this run really fast.&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Convex_hull"&gt;Convex Hull&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Shape containing a set of points&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Not a good approximation to spatial clusters, but easy and fast to compute e.g. with OGR functions&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://www.netlib.org/voronoi/hull.html"&gt;Clarkson code for Alpha Shapes&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Old style C code for producing Alpha Shapes (polygons representing sets of points)&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Slightly dodgy code, doesn't produce polygons with holes inside, but runs OK if called as a black box executable.&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;   &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://mitab.maptools.org/"&gt;Tab2Tab&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Map data conversion utility&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Older versions lose precision; new versions lose polygon style/colour information&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;a href="http://www.qgis.org/"&gt;QGIS&lt;/a&gt; (Quantum GIS)&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Open source alternative to MapInfoPro&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;Slower and not as feature rich as MapInfoPro&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-7378725616497038654?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/7378725616497038654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/09/spatial-clustering-in-c-post-5-of-5.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7378725616497038654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7378725616497038654'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/09/spatial-clustering-in-c-post-5-of-5.html' title='Spatial Clustering in C++ (post 5 of 5) – The final outputs'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-56tiI8pSNC0/TmQdbspsbRI/AAAAAAAAABw/ILadevtDTZk/s72-c/SanFran_points.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-4199042152711486993</id><published>2011-08-30T16:30:00.008+10:00</published><updated>2011-08-30T17:08:19.976+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='alpha shapes'/><category scheme='http://www.blogger.com/atom/ns#' term='spatial clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='convex hull'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='ogr'/><title type='text'>Spatial Clustering in C++ (post 4 of 5) – Generating Alpha Shapes</title><content type='html'>In previous posts we saw how to run the &lt;a href="http://en.wikipedia.org/wiki/DBSCAN"&gt;DBSCAN&lt;/a&gt; spatial clustering algorithm over a set of spatial data points: in our example, all block centroids in California.  We also saw how to make it run really quickly.  In this post we’ll investigate a way to turn those clusters into polygons.  These polygons will represent our clusters in an approximate way, but will be fast to display and provide a visually compelling way to appraise the clusters we’ve created.&lt;br /&gt;&lt;br /&gt;One way to get a polygon from a set of points is to form the &lt;a href="http://en.wikipedia.org/wiki/Convex_hull"&gt;Convex Hull&lt;/a&gt;.  However, for our clusters, convex hulls, though easily generated using OGR’s &lt;span style="font-family:courier new;"&gt;ConvexHull()&lt;/span&gt; on a &lt;span style="font-family:courier new;"&gt;MultiPoint&lt;/span&gt; object, do not look so great – they cover over large swathes of what we’d intuitively think of as the “shape” describing the points.  An example from a real cluster produced by DBSCAN is shown below:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-PglciE0_SsE/TlyFDopPNYI/AAAAAAAAABY/Ra5y6o7REpI/s1600/ConvexHullExample_no_hull.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 343px;" src="http://4.bp.blogspot.com/-PglciE0_SsE/TlyFDopPNYI/AAAAAAAAABY/Ra5y6o7REpI/s400/ConvexHullExample_no_hull.png" alt="" id="BLOGGER_PHOTO_ID_5646534330312242562" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In this example, the light green coloured cluster would be badly represented by a convex hull (which is shown in pink):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-pOxY5QDlpp8/TlyFOAwkoII/AAAAAAAAABg/ojbduSrYUok/s1600/ConvexHullExample.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 343px;" src="http://3.bp.blogspot.com/-pOxY5QDlpp8/TlyFOAwkoII/AAAAAAAAABg/ojbduSrYUok/s400/ConvexHullExample.png" alt="" id="BLOGGER_PHOTO_ID_5646534508584149122" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Another example can be found in Part 1 of this blog series, for the largest cluster in the picture.&lt;br /&gt;&lt;br /&gt;Unfortunately there’s no unambiguous way to wrap a set of points in a non-convex polygon (that is, there’s no such thing as a “bounding polygon” – think about it...).  However, we can use something called &lt;span style="font-weight: bold; font-style: italic;"&gt;Alpha Shapes&lt;/span&gt;, which have a parameter (&lt;span style="font-style: italic;"&gt;alpha&lt;/span&gt;) which describes “how concave” we’d like our shape to go (intuitively, how tightly to “shrink wrap” our points).  Good descriptions of Alpha Shapes are provided &lt;a href="http://research.engineering.wustl.edu/%7Epless/546/lectures/lecture22.pdf"&gt;here&lt;/a&gt;, &lt;a href="http://cgm.cs.mcgill.ca/%7Egodfried/teaching/projects97/belair/alpha.html"&gt;here&lt;/a&gt; and &lt;a href="http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Alpha_shapes_2/Chapter_main.html"&gt;here&lt;/a&gt;, and in the context of spatial data, &lt;a href="http://code.flickr.com/blog/2008/10/30/the-shape-of-alpha/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For the above example, with a suitably chosen alpha (in this case, 2500), the alpha shape looks like the following:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-JkOGxrfRVH4/TlyMCOUmnqI/AAAAAAAAABo/dM7QZgh0ehk/s1600/ConvexHullExample_AlphaShape.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 359px;" src="http://1.bp.blogspot.com/-JkOGxrfRVH4/TlyMCOUmnqI/AAAAAAAAABo/dM7QZgh0ehk/s400/ConvexHullExample_AlphaShape.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646542002647899810" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There’s not a lot of Alpha Shape C++ code around and it’s not something you’d probably want to code up yourself unless you’re very interested in computational geometry and have lots of spare time.  One source is &lt;a href="http://www.netlib.org/voronoi/hull.html"&gt;Ken Clarkson’s code&lt;/a&gt;.  This is old-style C code which I initially made the mistake of trying to integrate into my own code as a library, eschewing its command line interface.  Unfortunately this meant making the code (which is full of global variables) re-entrant; it turns out the code contains subtle crashes and can generate unexpected results if repeatedly run over many inputs.  So keeping it as a “black box” and calling it as an exe from my own code seems like the only option – however it does work well in that way, though it is somewhat slower as it has to invoke an exe for every polygon to be created.&lt;br /&gt;&lt;br /&gt;Another shortcoming of this particular code is that the alpha shapes produced do not include any “holes”.&lt;br /&gt;&lt;br /&gt;For my &lt;span style="font-style: italic;"&gt;alpha &lt;/span&gt;I’ve chosen 2500, and I’ve also used a multiplier in the command line to reduce the risk of numerical instability with points that are very close to each other (latitude/longitude coordinates going down to 6 or more decimal places).&lt;br /&gt;&lt;br /&gt;Another minor issue to note is that when your data includes more than one data item “stacked” at the same spatial point (for example if the data has several points representing the distinct addresses within an apartment building or suchlike), then in the worst case if such stacked points are isolated, you can end up with a cluster that only occupies a single point and hence doesn’t get processed as a polygon.&lt;br /&gt;&lt;br /&gt;For very large clusters (bigger than say, 40000 or so) one could potentially also reduce the time for the Alpha Shape calculation by putting a grid over the points and taking only a sample of points in each grid cell.&lt;br /&gt;&lt;br /&gt;In the next post we’ll see the results of running the Alpha Shapes code on our clusters.  For now, here is the code that calls the Clarkson executable.  Note that it contains a Windows-centric function which is not cross-platform, RunExeFromCommandLine.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;ogrsf_frmts.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;set&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;vector&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;iomanip&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;windows.h&amp;gt; &amp;nbsp;// for SHELLEXECUTEINFO etc&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;quot;node.h&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;using&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;namespace&lt;/span&gt; std&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; RunExeWithCommandLine&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;wstring wstrExelocation, wstring wstrCommand&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; SHELLEXECUTEINFO lpExecInfo&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;cbSize&lt;/span&gt; &amp;nbsp;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;sizeof&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;SHELLEXECUTEINFO&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;lpFile&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; wstrExelocation.&lt;span style="color: #007788;"&gt;c_str&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;fMask&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; SEE_MASK_DOENVSUBST &lt;span style="color: #000040;"&gt;|&lt;/span&gt; SEE_MASK_NOCLOSEPROCESS&lt;span style="color: #008080;"&gt;;&lt;/span&gt; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;hwnd&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; &amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;lpVerb&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; L&lt;span style="color: #FF0000;"&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;lpParameters&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; wstrCommand.&lt;span style="color: #007788;"&gt;c_str&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;lpDirectory&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;nShow&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; SW_SHOWMINNOACTIVE&lt;span style="color: #008080;"&gt;;&lt;/span&gt; &amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpExecInfo.&lt;span style="color: #007788;"&gt;hInstApp&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;HINSTANCE&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;SE_ERR_DDEFAIL&lt;span style="color: #008080;"&gt;;&lt;/span&gt; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; BOOL fSuccess &lt;span style="color: #000080;"&gt;=&lt;/span&gt; ShellExecuteEx&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;lpExecInfo&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;lpExecInfo.&lt;span style="color: #007788;"&gt;hProcess&lt;/span&gt; &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;WaitForSingleObject&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;lpExecInfo.&lt;span style="color: #007788;"&gt;hProcess&lt;/span&gt;, INFINITE&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;CloseHandle&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;lpExecInfo.&lt;span style="color: #007788;"&gt;hProcess&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; fSuccess &lt;span style="color: #000080;"&gt;==&lt;/span&gt; TRUE&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;OGRLinearRing&lt;span style="color: #000040;"&gt;*&lt;/span&gt; GetNextRing&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgptsPoly, &lt;span style="color: #0000ff;"&gt;const&lt;/span&gt; vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgpts, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; first, set&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; new_points&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; rgpt_index &lt;span style="color: #000080;"&gt;=&lt;/span&gt; first&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRLinearRing&lt;span style="color: #000040;"&gt;*&lt;/span&gt; ring &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; from &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #000040;"&gt;-&lt;/span&gt;1, to &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; rgptsPoly.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; rgptsPoly.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;first &lt;span style="color: #000080;"&gt;==&lt;/span&gt; rgpt_index&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; from &lt;span style="color: #000080;"&gt;=&lt;/span&gt; it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;first&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; to &lt;span style="color: #000080;"&gt;=&lt;/span&gt; it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;second&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #000040;"&gt;*&lt;/span&gt;it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;1,&lt;span style="color: #000040;"&gt;-&lt;/span&gt;1&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;break&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;second &lt;span style="color: #000080;"&gt;==&lt;/span&gt; rgpt_index&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; from &lt;span style="color: #000080;"&gt;=&lt;/span&gt; it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;second&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; to &lt;span style="color: #000080;"&gt;=&lt;/span&gt; it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;first&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #000040;"&gt;*&lt;/span&gt;it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;1,&lt;span style="color: #000040;"&gt;-&lt;/span&gt;1&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;break&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;from &lt;span style="color: #000080;"&gt;==&lt;/span&gt; &lt;span style="color: #000040;"&gt;-&lt;/span&gt;1&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRPoint point&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgpts&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;from&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;second, rgpts&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;from&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;first&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;ring &lt;span style="color: #000080;"&gt;==&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ring &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;new&lt;/span&gt; OGRLinearRing&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ring&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;addPoint&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;point&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rgpt_index &lt;span style="color: #000080;"&gt;=&lt;/span&gt; to&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; new_points.&lt;span style="color: #007788;"&gt;insert&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;from&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; new_points.&lt;span style="color: #007788;"&gt;insert&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;to&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;to &lt;span style="color: #000080;"&gt;==&lt;/span&gt; first&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;break&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; ring&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; GetFirstNonZero&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgptsPoly&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; rgptsPoly.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; rgptsPoly.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;first &lt;span style="color: #000080;"&gt;&amp;gt;=&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;first&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; GetRings&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgptsPoly, &lt;span style="color: #0000ff;"&gt;const&lt;/span&gt; vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgpts, vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRLinearRing&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rings&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; set&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; setStartingPoints&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; setStartingPoints.&lt;span style="color: #007788;"&gt;insert&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;GetFirstNonZero&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgptsPoly&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;GetFirstNonZero&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgptsPoly&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; rings.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; set&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; new_points&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;set&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; setStartingPoints.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; setStartingPoints.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRLinearRing&lt;span style="color: #000040;"&gt;*&lt;/span&gt; ring &lt;span style="color: #000080;"&gt;=&lt;/span&gt; GetNextRing&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgptsPoly, rgpts, &lt;span style="color: #000040;"&gt;*&lt;/span&gt;it, new_points&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;ring &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt; &lt;span style="color: #000040;"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ring&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getNumPoints&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;=&lt;/span&gt; 3&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rings.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;ring&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;new_points.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;==&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; new_points.&lt;span style="color: #007788;"&gt;insert&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;GetFirstNonZero&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgptsPoly&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;new_points.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;==&lt;/span&gt; 0 &lt;span style="color: #000040;"&gt;||&lt;/span&gt; &lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;new_points.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;break&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; setStartingPoints.&lt;span style="color: #007788;"&gt;clear&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; setStartingPoints.&lt;span style="color: #007788;"&gt;insert&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;new_points.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, new_points.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; rings.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; GetPolygonBoundary&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;const&lt;/span&gt; vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgpts, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; nCluster, vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgNewPolys&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; wstring wstrPathForTempFiles &lt;span style="color: #000080;"&gt;=&lt;/span&gt; L&lt;span style="color: #FF0000;"&gt;&amp;quot;C:/temp/&amp;quot;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; wstring wstrTempFileInput &lt;span style="color: #000080;"&gt;=&lt;/span&gt; wstrPathForTempFiles &lt;span style="color: #000040;"&gt;+&lt;/span&gt; L&lt;span style="color: #FF0000;"&gt;&amp;quot;sites&amp;quot;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; wstring wstrTempFileOutput &lt;span style="color: #000080;"&gt;=&lt;/span&gt; wstrPathForTempFiles &lt;span style="color: #000040;"&gt;+&lt;/span&gt; L&lt;span style="color: #FF0000;"&gt;&amp;quot;sites-alf&amp;quot;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; wstring wstrCommandLineArgs &lt;span style="color: #000080;"&gt;=&lt;/span&gt; L&lt;span style="color: #FF0000;"&gt;&amp;quot;-A -oN -i&amp;quot;&lt;/span&gt; &lt;span style="color: #000040;"&gt;+&lt;/span&gt; wstrTempFileInput &lt;span style="color: #000040;"&gt;+&lt;/span&gt; L&lt;span style="color: #FF0000;"&gt;&amp;quot; -aa2500 -m10000&amp;quot;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ofstream os&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; os.&lt;span style="color: #007788;"&gt;open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;wstrTempFileInput.&lt;span style="color: #007788;"&gt;c_str&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, ios&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;trunc&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;os.&lt;span style="color: #007788;"&gt;is_open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; rgpts.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; rgpts.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; os &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; setprecision&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;9&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;second &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;first &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; os.&lt;span style="color: #007788;"&gt;close&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;RunExeWithCommandLine&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;L&lt;span style="color: #FF0000;"&gt;&amp;quot;C:/Temp/hull/Release/addcl.exe&amp;quot;&lt;/span&gt;, wstrCommandLineArgs&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; rgptsPoly&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ifstream in&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; in.&lt;span style="color: #007788;"&gt;open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;wstrTempFileOutput.&lt;span style="color: #007788;"&gt;c_str&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;in.&lt;span style="color: #007788;"&gt;is_open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;char&lt;/span&gt; blank&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;500&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; in.&lt;span style="color: #007788;"&gt;getline&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;blank, 500&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; &lt;span style="color: #666666;"&gt;// ignore first line&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;while&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;in.&lt;span style="color: #007788;"&gt;eof&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; n1, n2&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; in &lt;span style="color: #000080;"&gt;&amp;gt;&amp;gt;&lt;/span&gt; n1 &lt;span style="color: #000080;"&gt;&amp;gt;&amp;gt;&lt;/span&gt; n2&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rgptsPoly.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;pair&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;n1, n2&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgptsPoly.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;==&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRLinearRing&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; rings&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgptsPoly.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;=&lt;/span&gt; 2&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;GetRings&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgptsPoly, rgpts, rings&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;=&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; nTotalNumberOfPointsInRings &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRLinearRing&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; rings.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; rings.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nTotalNumberOfPointsInRings &lt;span style="color: #000040;"&gt;+&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getNumPoints&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #666666;"&gt;// Note if nTotalNumberOfPointsInRings &amp;lt; (int)rgptsPoly.size(), then GetRing only processed &lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #666666;"&gt;// &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nTotalNumberOfPointsInRings out of rgptsPoly.size() points. &amp;nbsp;This is OK, as sometimes&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #666666;"&gt;// &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; the shape includes a line (polygon with 2 points), which we'll generally ignore.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRLinearRing&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; rings.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; rings.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt; poly &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;new&lt;/span&gt; OGRPolygon&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; poly&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;addRing&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poly&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getExteriorRing&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getNumPoints&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;=&lt;/span&gt; 3&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; poly&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;closeRings&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rgNewPolys.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poly&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; rgNewPolys.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Note that I do not consider the code above to be particularly good; I was still trying to gain an understanding of the output of Clarkson's alpha shape code as I was developing it, and it shows.  Anyhow, it has the useful property of working fairly robustly.&lt;br /&gt;&lt;br /&gt;The above code is called with code like the following:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; rgNewPolys&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;map&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; mapNodesInEachCluster&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; vecNodes.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; vecNodes.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster &lt;span style="color: #000080;"&gt;&amp;gt;=&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mapNodesInEachCluster&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;map&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;, vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; mapNodesInEachCluster.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; mapNodesInEachCluster.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;GetPolygonBoundary&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;second, it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;first, rgNewPolys&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;=&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000dd;"&gt;cout&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;Failure with &amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;second.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot; points&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WritePolygonsToMidMifFile&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt;&amp;quot;C:/Temp/Polygons&amp;quot;&lt;/span&gt;, rgNewPolys&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Where the WritePolygonsToMidMifFile function is:&lt;br /&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; WritePolygonsToMidMifFile&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;string strFileName, vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; polys&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ofstream osFileMid, osFileMif&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;OpenMidMifAndWritePreamble&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;strFileName, osFileMid, osFileMif&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; i &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; polys.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; polys.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;, i&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMid &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;i&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &amp;nbsp;&lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;Region &amp;nbsp;1&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;&amp;nbsp; &amp;nbsp; &amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getExteriorRing&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getNumPoints&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; n &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; n &lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getExteriorRing&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getNumPoints&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; n&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #666666;"&gt;// first and last point are the same&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRPoint pt&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getExteriorRing&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getPoint&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;n, &lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;pt&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; pt.&lt;span style="color: #007788;"&gt;getX&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; pt.&lt;span style="color: #007788;"&gt;getY&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; rgb &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;40 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;i &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 13&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;%&lt;/span&gt; 215&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 255 &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 255 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;40 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;i &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 4573&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;%&lt;/span&gt; 215&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 255 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;40 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;i &lt;span style="color: #000040;"&gt;%&lt;/span&gt; 215&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &amp;nbsp;&lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot; Pen (1,2,0) &amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;&amp;nbsp; &amp;nbsp; Brush (&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;2&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; rgb &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;)&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif.&lt;span style="color: #007788;"&gt;close&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMid.&lt;span style="color: #007788;"&gt;close&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;true&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;We’ll see some of the outputs produced in the next and final post in this series, where we’ll also look at the effect of different values of alpha.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-4199042152711486993?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/4199042152711486993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/08/spatial-clustering-in-c-post-4-of-5.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4199042152711486993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4199042152711486993'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/08/spatial-clustering-in-c-post-4-of-5.html' title='Spatial Clustering in C++ (post 4 of 5) – Generating Alpha Shapes'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-PglciE0_SsE/TlyFDopPNYI/AAAAAAAAABY/Ra5y6o7REpI/s72-c/ConvexHullExample_no_hull.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-7658557750526096922</id><published>2011-08-29T12:02:00.002+10:00</published><updated>2011-08-29T13:51:38.838+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spatial clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='kdtree'/><category scheme='http://www.blogger.com/atom/ns#' term='code performance'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Spatial Clustering in C++ (post 3 of 5) – A Speedier DBSCAN</title><content type='html'>Welcome to part 3 of this 5 part blog post on Spatial Clustering using C++.  In the two previous posts we  read in some map data (Californian census block centroids) and performed some clustering on the points using the DBSCAN algorithm.  In this post we’ll investigate how to make the code run faster.  This is important if you want this type of algorithm to run in reasonable time over a very large data set (e.g. all of the USA), or you want to run it repeatedly (e.g. to investigate different parameters).&lt;br /&gt;&lt;br /&gt;In this investigation I’ll employ some of the techniques for code optimisation that I keep in my mental kit bag, namely: using raw arrays instead of container objects; pre-calculate and cache values wherever possible; use statics to avoid memory overheads; “pool” up frequently re-allocated objects.&lt;br /&gt;&lt;br /&gt;But first, the golden rule: always profile.  The first thing I’ll do is surround the call to DBScan() with a simple time clocking:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;time_t&lt;/span&gt; tmStartTime&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000dd;"&gt;time&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;tmStartTime&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; nClusters &lt;span style="color: #000080;"&gt;=&lt;/span&gt; RunDBScan&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;time_t&lt;/span&gt; lTimeNow&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000dd;"&gt;time&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;lTimeNow&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;time_t&lt;/span&gt; tsDuration &lt;span style="color: #000080;"&gt;=&lt;/span&gt; lTimeNow &lt;span style="color: #000040;"&gt;-&lt;/span&gt; tmStartTime&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000dd;"&gt;cout&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; tsDuration &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot; seconds to run DBScan&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The version of DBSCAN presented in the previous post runs in about 86 seconds, so this is the benchmark where we start from (note that is in the Debug build configuration).&lt;br /&gt;&lt;br /&gt;Next I do my “poor man’s profiling” – in Visual Studio, I just hit Debug / Break when the main algorithm is running.  Breaking a few times gives a picture of where the time is being spent the most. [Incidentally, I love this method of profiling, as it’s just so quick, given that it doesn’t require any external tools or specialised performance builds, yet it still often enables you optimise 90% of the worst bottlenecks in the code].&lt;br /&gt;&lt;br /&gt;In this case I find the majority of time is spent allocating memory when pushing items onto the STL vector &lt;span style="font-family: courier new;"&gt;rgpNeighbourhood2 &lt;/span&gt;inside ExpandCluster / GetNodesInRadius.&lt;br /&gt;&lt;br /&gt;I tried to use vector’s “reserve” function to allocate memory in larger chunks.  However, it’s not clear what the best chunk size to use would be; in fact experimenting with different values can dramatically affect the overall performance.  For my test data set, I found the best value was 25, and this reduced the running time to 60 seconds.&lt;br /&gt;&lt;br /&gt;Another similar strategy when using STL vectors is to use static and clear; replace the declaration of the vector with the following code:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;static&lt;/span&gt; vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; rgpNeighbourhood2&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;rgpNeighbourhood2.&lt;span style="color: #007788;"&gt;clear&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: &lt;br /&gt;&lt;br /&gt;#008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;vector::clear&lt;/span&gt; does not change the vector’s capacity in this version of STL (with MS Visual Studio 8), so the vector is made only once, and it is re-allocated presumably only a handful of times (whenever it's required to get larger than it previously was).  This method is better than using reserve, as it doesn’t require any arguments or parameters, and it is faster too – only 53 seconds.&lt;br /&gt;&lt;br /&gt;Of course one can also fall back on good old raw C arrays instead of using vectors.  I haven’t posted the code for this, but it reduces the time further to 39 seconds.  Using raw C arrays does really impact the readability and maintainability of the code and would need to be wrapped up in some nice class wrapper or suchlike in an industrial strength application.&lt;br /&gt;&lt;br /&gt;Once this is all done, the bottleneck is now inside kdtree, specifically where it allocates and de-allocates its result objects (objects of type kdres).  Looking into the code in this area, I saw the allocation guarded with &lt;span style="font-family: courier new;"&gt;#define&lt;/span&gt;s: &lt;span style="font-family: courier new;"&gt;USE_LIST_NODE_ALLOCATOR&lt;/span&gt;.  Looking at the documentation, it advocates switching this tag on.  In Windows you will also need to define &lt;span style="font-family: courier new;"&gt;NO_PTHREADS&lt;/span&gt; and comment out the line &lt;span style="font-family: courier new;"&gt;#ERROR&lt;/span&gt; that warns about the code no longer being thread-safe.&lt;br /&gt;&lt;br /&gt;Using the list node allocator reduces the time down to an astounding 15 seconds.  Finally, running the code in Release instead of Debug reduces the time down to 4 seconds – not bad considering the first naive version took nearly a minute and a half to run!  Profiling now shows most time is spent inside kdtree functions to return the nearest nodes, and there’s not much we can do about that.&lt;br /&gt;&lt;br /&gt;Summarising what we’ve found:&lt;br /&gt;&lt;br /&gt;86 seconds for the first version of the algorithm&lt;br /&gt;60 seconds with reserve of 25 on rgpNeighbourhood2&lt;br /&gt;53 seconds with static instead of reserve&lt;br /&gt;39 seconds with raw C arrays instead of STL vectors&lt;br /&gt;15 seconds with kdtree &lt;span style="font-family: courier new;"&gt;list_node_allocator &lt;/span&gt;switched on (and raw C arrays)&lt;br /&gt;4 seconds in Release configuration (and raw C arrays)&lt;br /&gt;&lt;br /&gt;And the lessons learnt (as always, it seems) from optimising code:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;always measure timings – bottlenecks are very often not where you’d think they would be&lt;/li&gt;&lt;li&gt;it’s often sufficient to use very simple profiling&lt;/li&gt;&lt;li&gt;it’s frequently surprising how fast you can eventually make the code run&lt;/li&gt;&lt;/ul&gt;Now that we have our DBSCAN running blazingly fast, we'll in the next post see how to create alpha shapes that will give the output more visual appeal.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-7658557750526096922?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/7658557750526096922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/08/spatial-clustering-in-c-post-3-of-5.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7658557750526096922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7658557750526096922'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/08/spatial-clustering-in-c-post-3-of-5.html' title='Spatial Clustering in C++ (post 3 of 5) – A Speedier DBSCAN'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-3075193406342644265</id><published>2011-08-26T12:06:00.011+10:00</published><updated>2011-08-30T16:29:39.977+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='alpha shapes'/><category scheme='http://www.blogger.com/atom/ns#' term='spatial clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='kdtree'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='ogr'/><title type='text'>Spatial Clustering in C++ (post 2 of 5) – Running DBSCAN</title><content type='html'>In the last post in this series I explained how to get and read in some spatial data points for California.  In this post we’ll run the &lt;a href="http://en.wikipedia.org/wiki/DBSCAN"&gt;DBSCAN&lt;/a&gt; algorithm to perform spatial clustering.&lt;br /&gt;&lt;br /&gt;DBSCAN is a well-known algorithm that identifies clusters based on density.  A major advantage of DBSCAN is that it can identify arbitrary shape objects (ie. it does not presuppose the size, shape, or number of clusters in the data, as some other methods do), and it removes noise during the clustering process.  It’s also quite a simple algorithm to implement.&lt;br /&gt;&lt;br /&gt;The two parameters controlling DBSCAN are eps and minPts.  They work together to define how the clusters should “grow”: if more than minPts points are within a radius of eps of a point, then those neighbouring points are also included in the cluster; each point in the expanded cluster is then subjected to the same test.&lt;br /&gt;&lt;br /&gt;Our &lt;a href="http://code.google.com/p/kdtree/"&gt;kdtree&lt;/a&gt; data structure provides just what we need for the “neighbours” test with its kd_nearest_range function.  However as a side note we should observe that our eps (radius) parameter here is expressed in latitude/longitude distance units – in a real application we would likely want to use a more natural unit such as metres or kilometres.  (One can convert, but the conversion is dependent on latitude).  One consequence of using lat/long distance, apart from the its non-intuitiveness, is that the radius will be slightly different depending on the latitude of the point.&lt;br /&gt;&lt;br /&gt;So, we’ll now show the code to get the points in a given radius – the GetNodesInRadius function:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; GetNodesInRadius&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt; pt, &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; dblRadius, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; nMinPts, vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgpNodesFound&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; pos&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;2&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;pt&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetLongitude&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, pt&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetLatitude&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; kdres&lt;span style="color: #000040;"&gt;*&lt;/span&gt; res &lt;span style="color: #000080;"&gt;=&lt;/span&gt; kd_nearest_range&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;kdTree, pos, dblRadius&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; number_near &lt;span style="color: #000080;"&gt;=&lt;/span&gt; kd_res_size&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;res&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;number_near &lt;span style="color: #000080;"&gt;&amp;gt;=&lt;/span&gt; nMinPts&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;while&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;kd_res_end&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;res&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt; ptNear &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;kd_res_item&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;res, pos&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rgpNodesFound.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;ptNear&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; kd_res_next&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;res&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; kd_res_free&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;res&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; number_near &lt;span style="color: #000080;"&gt;&amp;gt;=&lt;/span&gt; nMinPts&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;And this is called by our DBSCAN code, which is as follows.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; ExpandCluster&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; rgp, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; nCluster, &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; dblEpsilon, &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; nMinPts&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; rgpNeighbourhood&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; i &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; i &lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;rgp.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; i&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;rgp&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;i&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_fVisited&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rgp&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;i&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster &lt;span style="color: #000080;"&gt;=&lt;/span&gt; nCluster&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rgp&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;i&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_fVisited &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;true&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rgpNeighbourhood.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgp&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;i&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; i &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; i &lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;rgpNeighbourhood.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; i&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt; pNodeNear &lt;span style="color: #000080;"&gt;=&lt;/span&gt; rgpNeighbourhood&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;i&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; rgpNeighbourhood2&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;GetNodesInRadius&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;pNodeNear, dblEpsilon, nMinPts, rgpNeighbourhood2&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #666666;"&gt;// append to rgpNeighbourhood items in rgpNeighbourhood2 that aren't already in rgpNeighbourhood&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; j &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; j &lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;rgpNeighbourhood2.&lt;span style="color: #007788;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; j&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt; pNode &lt;span style="color: #000080;"&gt;=&lt;/span&gt; rgpNeighbourhood2&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;j&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;pNode&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_fVisited&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pNode&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_fVisited &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;true&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;pNode&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster &lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pNode&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster &lt;span style="color: #000080;"&gt;=&lt;/span&gt; nCluster&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rgpNeighbourhood.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;pNode&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; RunDBScan&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; dblEpsilon &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color:#800080;"&gt;0.0045&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; nCluster &lt;span style="color: #000080;"&gt;=&lt;/span&gt; 0, nMinPts &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;8&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; vecNodes.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; vecNodes.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt; pNode &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;pNode&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_fVisited&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pNode&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_fVisited &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;true&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; rgpNeighbourhood&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;GetNodesInRadius&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;pNode, dblEpsilon, nMinPts, rgpNeighbourhood&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pNode&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster &lt;span style="color: #000080;"&gt;=&lt;/span&gt; nCluster&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pNode&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_fVisited &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;true&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ExpandCluster&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;rgpNeighbourhood, nCluster, dblEpsilon, nMinPts&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nCluster&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; nCluster&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here I’ve implemented a very simple performance improvement over the DBSCAN pseudo-code as it appears in Wikipedia.  I don’t add the point P’ to the current neighbourhood N unless it has no cluster already; this guarantees that subsequent iterations over N will only process unvisited points.  The results are exactly the same but it runs 2-3 times faster (at least with this STL vector-based implementation).&lt;br /&gt;&lt;br /&gt;Even so, this code uses a fairly naive implementation with STL vectors.  We’ll see in the next blog post in this series how to refine this implementation and in the process make it run very fast.&lt;br /&gt;&lt;br /&gt;With this example data set (California census block data) there tend to be many clusters, including many small ones (though, to be sure, there is at least one truly massive cluster – Los Angeles!).  One could obviously cull out the smallest clusters after DBSCAN is run if that is appropriate for your application.&lt;br /&gt;&lt;br /&gt;I'm writing out the cluster points to Mid/Mif files and importing them into Tab using MapInfoPro.  The code to write the points is:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; OpenMidMifAndWritePreamble&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;string strFileName, ofstream&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; osFileMid, ofstream&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt; osFileMif&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMid.&lt;span style="color: #007788;"&gt;open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;strFileName &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;.mid&amp;quot;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;.&lt;span style="color: #007788;"&gt;c_str&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, ios&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;trunc&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;osFileMid.&lt;span style="color: #007788;"&gt;is_open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif.&lt;span style="color: #007788;"&gt;open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;strFileName &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;.mif&amp;quot;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;.&lt;span style="color: #007788;"&gt;c_str&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, ios&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;trunc&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;osFileMif.&lt;span style="color: #007788;"&gt;is_open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMid &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; setprecision&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;20&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;Version 300&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;Charset &lt;span style="color: #000099; font-weight: bold;"&gt;\&amp;quot;&lt;/span&gt;Neutral&lt;span style="color: #000099; font-weight: bold;"&gt;\&amp;quot;&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;Delimiter &lt;span style="color: #000099; font-weight: bold;"&gt;\&amp;quot;&lt;/span&gt;,&lt;span style="color: #000099; font-weight: bold;"&gt;\&amp;quot;&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;CoordSys Earth Projection 1, 0 Bounds (-1000, -1000) (1000, 1000)&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;Columns 1&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot; &amp;nbsp;Cluster Integer&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;Data&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;true&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; WritePoints&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;string strFileName&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ofstream osFileMid, osFileMif&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;OpenMidMifAndWritePreamble&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;strFileName, osFileMid, osFileMif&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;const_iterator&lt;/span&gt; it &lt;span style="color: #000080;"&gt;=&lt;/span&gt; vecNodes.&lt;span style="color: #007788;"&gt;begin&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; vecNodes.&lt;span style="color: #007788;"&gt;end&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; it&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMid &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;Point &amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetLongitude&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetLatitude&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; c &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; rgb &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;40 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;c &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 13&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;%&lt;/span&gt; 215&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 255 &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 255 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;40 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;c &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 4573&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;%&lt;/span&gt; 215&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;*&lt;/span&gt; 255 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;40 &lt;span style="color: #000040;"&gt;+&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;c &lt;span style="color: #000040;"&gt;%&lt;/span&gt; 215&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; size &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster &lt;span style="color: #000080;"&gt;&amp;gt;=&lt;/span&gt; 0 &lt;span style="color: #008080;"&gt;?&lt;/span&gt; 6 &lt;span style="color: #008080;"&gt;:&lt;/span&gt; 2&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;&amp;nbsp; Symbol (34,&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt;it&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;m_nCluster &lt;span style="color: #000080;"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0xFFFFFF&lt;/span&gt; &lt;span style="color: #008080;"&gt;?&lt;/span&gt; rgb &lt;span style="color: #008080;"&gt;:&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;size&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;8&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color: #FF0000;"&gt;&amp;quot;)&amp;quot;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMif.&lt;span style="color: #007788;"&gt;close&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; osFileMid.&lt;span style="color: #007788;"&gt;close&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;true&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Here I've used a cute little one-liner to generate unique colours for each cluster.  Non-clustered points ("noise" in DBSCAN terms) are coloured white (with black outline) and drawn smaller than the clustered points.&lt;br /&gt;&lt;br /&gt;The results with eps set to 0.0045 and minPts = 8 give 3706 clusters, and 488,761 out of the total of 710,146 points end up in a cluster.  Zooming in on the San Francisco area looks like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-r8e-LBv_Voo/TlcP9opEpPI/AAAAAAAAABA/tUhLnuWWC-c/s1600/SanFranArea.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 297px;" src="http://4.bp.blogspot.com/-r8e-LBv_Voo/TlcP9opEpPI/AAAAAAAAABA/tUhLnuWWC-c/s400/SanFranArea.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5644998209488332018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Changing eps to 0.009 gives larger clusters, as you would expect.  This time there are 3473 clusters, and 592,652 points are clustered.  San Francisco looks like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-9O_3VuMwIb4/TlcROCBnPUI/AAAAAAAAABI/_xf2GboxZF4/s1600/SanFranArea2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 290px;" src="http://1.bp.blogspot.com/-9O_3VuMwIb4/TlcROCBnPUI/AAAAAAAAABI/_xf2GboxZF4/s400/SanFranArea2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5644999590691683650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In the next post I'll show how to significantly speed up DBSCAN, and in further posts demonstrate how to get our output to look like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-yBIJYl8BnjM/TlcWvsSCryI/AAAAAAAAABQ/XJPmTMCfNa8/s1600/SanFranArea3_polygons.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 285px;" src="http://2.bp.blogspot.com/-yBIJYl8BnjM/TlcWvsSCryI/AAAAAAAAABQ/XJPmTMCfNa8/s400/SanFranArea3_polygons.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5645005666528702242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-3075193406342644265?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/3075193406342644265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/08/spatial-clustering-in-c-post-2-of-5.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3075193406342644265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3075193406342644265'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/08/spatial-clustering-in-c-post-2-of-5.html' title='Spatial Clustering in C++ (post 2 of 5) – Running DBSCAN'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-r8e-LBv_Voo/TlcP9opEpPI/AAAAAAAAABA/tUhLnuWWC-c/s72-c/SanFranArea.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-6027214638609506729</id><published>2011-08-22T16:29:00.025+10:00</published><updated>2011-08-26T12:03:25.308+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='alpha shapes'/><category scheme='http://www.blogger.com/atom/ns#' term='spatial clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='kdtree'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='ogr'/><title type='text'>Spatial Clustering in C++ (Part 1 of 5)</title><content type='html'>Welcome to the first of a five-part blog post where I work through an end-to-end example of spatial data clustering using C++.  I’ll be using a number of tools and techniques, including:  &lt;p&gt;- processing spatial point data using &lt;a href="http://www.pbinsight.com/products/location-intelligence/applications/mapping-analytical/mapinfo-professional/"&gt;MapInfoPro&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;- storing points in a &lt;a href="http://en.wikipedia.org/wiki/Kdtree"&gt;kdtree&lt;/a&gt; data structure (which will enable fast lookup of nearby points)&lt;/p&gt;  &lt;p&gt;- performing spatial clustering using an implementation of the &lt;a href="http://en.wikipedia.org/wiki/DBSCAN"&gt;DBSCAN&lt;/a&gt; algorithm&lt;/p&gt;  &lt;p&gt;- creating &lt;a href="http://research.engineering.wustl.edu/%7Epless/546/lectures/lecture22.pdf"&gt;Alpha Shapes&lt;/a&gt; (think “shrink-wrapped” polygons) to visualise the output&lt;/p&gt;&lt;p&gt;- using &lt;a href="http://www.gdal.org/ogr/"&gt;OGR&lt;/a&gt; for various miscellaneous geometry tasks&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Aside from the commercial product MapInfoPro (which is optional for this), all of the tools and codes I use are free/open source with permissive licences.  We'll also see (particularly by blog post #3 in this series) that the combination of these tools means our spatial clustering can be blazingly fast to compute.&lt;br /&gt;&lt;/p&gt;  &lt;p&gt;The simple version of spatial data clustering I'll be doing here is to develop code that will automatically figure out groups (clusters) of densely connected points on a map.  A typical application for this might be to automatically find towns or cities from a population map.&lt;/p&gt;&lt;p&gt;The eventual output we'll get looks like the following (and I hope this whets your appetite to follow the entire 5 parts of this blog post):&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-qb_DE_5K2AQ/TlH6qwDmCmI/AAAAAAAAAA4/Ftot7PiCiqc/s1600/intro_pic2.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 271px;" src="http://1.bp.blogspot.com/-qb_DE_5K2AQ/TlH6qwDmCmI/AAAAAAAAAA4/Ftot7PiCiqc/s400/intro_pic2.png" alt="" id="BLOGGER_PHOTO_ID_5643567420433369698" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-style: italic;"&gt;The above picture shows each cluster found in the data, and coloured uniquely&lt;/span&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-Pdns2mG3ivY/TlH6fi2zxNI/AAAAAAAAAAw/eFO_Sre1pHQ/s1600/intro_pic1.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 265px;" src="http://1.bp.blogspot.com/-Pdns2mG3ivY/TlH6fi2zxNI/AAAAAAAAAAw/eFO_Sre1pHQ/s400/intro_pic1.png" alt="" id="BLOGGER_PHOTO_ID_5643567227911521490" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-style: italic;"&gt;The above picture shows the output of running Alpha Shapes to obtain polygons which represent the clusters.&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For this exercise I’ll be using a subset of the &lt;a href="http://www.census.gov/geo/www/tiger/"&gt;US Tiger spatial data&lt;/a&gt;.&lt;span style=""&gt;  &lt;/span&gt;In this case I’m choosing California block data.&lt;span style=""&gt; (I did in fact find it very hard to find a freely available file of spatial data points - e.g. addresses for an entire country - to use as my sample data).  To get this TIGER data, g&lt;/span&gt;o to the TIGER &lt;a href="http://www.census.gov/cgi-bin/geo/shapefiles2010/main"&gt;download site&lt;/a&gt; and &lt;span style="font-style: italic;"&gt;Select Block data, California, All Counties.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;There are at least two easy ways to get points from this data.  The first, and probably quickest (if you have MapInfoPro installed), is to open the block file in MapInfoPro, and go Query / SQL Select, and select &lt;span style="font-family: courier new;"&gt;CentroidX(obj), CentroidY(obj)&lt;/span&gt; from the table, then save this selection as a separate file and export it to MID/MIF format.  The MID file will then contain all the centroid points.  An alternative shown below is to use OGR-computed centroids. &lt;span style=""&gt;  &lt;/span&gt;There are 710,146 points in all.&lt;/p&gt;  &lt;p&gt;Now let’s write some C++ to read in these points, and store them in a 2-dimensional kdtree, as well as in an STL vector of Node objects.&lt;span style=""&gt;  &lt;/span&gt;Our kdtree code here is provided by the excellent implementation hosted at &lt;a href="http://code.google.com/p/kdtree/"&gt;Google Code&lt;/a&gt; (and consists of just two files, kdtree.h and kdtree.cpp).  This code is compiled with Visual Studio but should be relatively cross-platform.&lt;/p&gt;&lt;p&gt;First we define a little helper class to store our points (which we'll call Nodes).  The Visited and Cluster members will be used later for DBSCAN.&lt;/p&gt;&lt;br /&gt;&lt;div class="highlight" &gt;&lt;br /&gt;&lt;code&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;utility&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt; Node &lt;span style="color: #008080;"&gt;:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; std&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;pair&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;double&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #008080;"&gt;:&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Node&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; x, &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; y&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #008080;"&gt;:&lt;/span&gt; std&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;pair&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;double&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;y,x&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; m_fVisited &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; m_nCluster &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; GetLongitude&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;const&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; second&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; GetLatitude&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;const&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; first&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; m_fVisited&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; m_nCluster&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Next is the main code that reads in the points and stores them in both a kdtree (so that we can get nearest nodes later) and a vector.   I've included all the &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;#include&lt;/span&gt;&lt;/span&gt;s that we're going to need in the code of subsequent blog posts.&lt;/p&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;quot;kdtree.h&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;iomanip&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;vector&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;map&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;lt;ogrsf_frmts.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339900;"&gt;#include &amp;quot;node.h&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;using&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;namespace&lt;/span&gt; std&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;kdtree&lt;span style="color: #000040;"&gt;*&lt;/span&gt; kdTree&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;vector&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt; vecNodes&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; ReadInPointsFromFile&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;string strFile&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; ifstream in&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; in.&lt;span style="color: #007788;"&gt;open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;strFile.&lt;span style="color: #007788;"&gt;c_str&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;in.&lt;span style="color: #007788;"&gt;is_open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; kdTree &lt;span style="color: #000080;"&gt;=&lt;/span&gt; kd_create&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;2&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #0000ff;"&gt;while&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;!&lt;/span&gt;in.&lt;span style="color: #007788;"&gt;eof&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; x, y&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;char&lt;/span&gt; comma&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; in &lt;span style="color: #000080;"&gt;&amp;gt;&amp;gt;&lt;/span&gt; x &lt;span style="color: #000080;"&gt;&amp;gt;&amp;gt;&lt;/span&gt; comma &lt;span style="color: #000080;"&gt;&amp;gt;&amp;gt;&lt;/span&gt; y&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt; pt &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;new&lt;/span&gt; Node&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;x, y&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; vecNodes.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;pt&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; xy&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;2&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;x, y&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; kd_insert&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;kdTree, xy, pt&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;true&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; main&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; argc, &lt;span style="color: #0000ff;"&gt;char&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt; argv&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; ReadInPointsFromFile&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt;&amp;quot;C:/Temp/CentroidPoints.MID&amp;quot;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/span&gt;&lt;p&gt;The alternative approach (mentioned above) for getting points from the block data - without needing MapInfoPro - is to read in the shape file data directly and use OGR library functions to calculate the polygon centroids.  This code is shown below.  You'll need to have OGR installed for this - the easiest way is to install the &lt;a href="http://fwtools.maptools.org/"&gt;FWTools&lt;/a&gt; binaries.  You'll then need to make sure your project includes the FWTools Include file, and links with the appropriate lib.&lt;/p&gt;&lt;p&gt;This approach is a little slower to run than using MapInfoPro.  (If you just wanted a fast approximation of the block centroids, however, you could probably just take the centroid of the bounding box of the polygons as they are read in.)&lt;/p&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; ReadInPolygonsFromFile&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;string strFile&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; kdTree &lt;span style="color: #000080;"&gt;=&lt;/span&gt; kd_create&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;2&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; OGRRegisterAll&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; OGRDataSource&lt;span style="color: #000040;"&gt;*&lt;/span&gt; poDS &lt;span style="color: #000080;"&gt;=&lt;/span&gt; OGRSFDriverRegistrar&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;Open&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;strFile.&lt;span style="color: #007788;"&gt;c_str&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poDS &lt;span style="color: #000080;"&gt;==&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt; &lt;span style="color: #000040;"&gt;||&lt;/span&gt; poDS&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetLayerCount&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000080;"&gt;&amp;lt;=&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; OGRLayer&lt;span style="color: #000040;"&gt;*&lt;/span&gt; poLayer &lt;span style="color: #000080;"&gt;=&lt;/span&gt; poDS&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetLayer&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; OGRFeature&lt;span style="color: #000040;"&gt;*&lt;/span&gt; poFeature&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #0000ff;"&gt;while&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poFeature &lt;span style="color: #000080;"&gt;=&lt;/span&gt; poLayer&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetNextFeature&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; OGRGeometry&lt;span style="color: #000040;"&gt;*&lt;/span&gt; poGeometry &lt;span style="color: #000080;"&gt;=&lt;/span&gt; poFeature&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetGeometryRef&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poGeometry &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; OGRwkbGeometryType nType &lt;span style="color: #000080;"&gt;=&lt;/span&gt; wkbFlatten&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poGeometry&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getGeometryType&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; OGRFeatureDefn&lt;span style="color: #000040;"&gt;*&lt;/span&gt; poFDefn &lt;span style="color: #000080;"&gt;=&lt;/span&gt; poLayer&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;GetLayerDefn&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;long&lt;/span&gt; lType &lt;span style="color: #000080;"&gt;=&lt;/span&gt; wkbFlatten&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;nType&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;lType &lt;span style="color: #000080;"&gt;==&lt;/span&gt; wkbPolygon&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;static_cast&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poGeometry&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;get_Area&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRPoint pt&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;static_cast&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poGeometry&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;Centroid&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;pt&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt; node &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;new&lt;/span&gt; Node&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;pt.&lt;span style="color: #007788;"&gt;getX&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, pt.&lt;span style="color: #007788;"&gt;getY&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vecNodes.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;node&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; xy&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;2&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;pt.&lt;span style="color: #007788;"&gt;getX&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, pt.&lt;span style="color: #007788;"&gt;getY&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; kd_insert&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;kdTree, xy, node&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;else&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;lType &lt;span style="color: #000080;"&gt;==&lt;/span&gt; wkbMultiPolygon&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRMultiPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt; pmpg &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;static_cast&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRMultiPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poGeometry&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;clone&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; nPoly &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; nPoly &lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt; pmpg&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getNumGeometries&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt; nPoly&lt;span style="color: #000040;"&gt;++&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRGeometry&lt;span style="color: #000040;"&gt;*&lt;/span&gt; poSubGeometry &lt;span style="color: #000080;"&gt;=&lt;/span&gt; pmpg&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;getGeometryRef&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;nPoly&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poSubGeometry &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt; &lt;span style="color: #000040;"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;static_cast&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poSubGeometry&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;NULL&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;static_cast&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poSubGeometry&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;get_Area&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #000040;"&gt;!&lt;/span&gt;&lt;span style="color: #000080;"&gt;=&lt;/span&gt; 0&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; OGRPoint pt&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;static_cast&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;lt;&lt;/span&gt;OGRPolygon&lt;span style="color: #000040;"&gt;*&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poSubGeometry&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #000040;"&gt;-&lt;/span&gt;&lt;span style="color: #000080;"&gt;&amp;gt;&lt;/span&gt;Centroid&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;pt&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Node&lt;span style="color: #000040;"&gt;*&lt;/span&gt; node &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;new&lt;/span&gt; Node&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;pt.&lt;span style="color: #007788;"&gt;getX&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, pt.&lt;span style="color: #007788;"&gt;getY&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vecNodes.&lt;span style="color: #007788;"&gt;push_back&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;node&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt; xy&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;2&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt; &lt;span style="color: #000080;"&gt;=&lt;/span&gt; &lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;pt.&lt;span style="color: #007788;"&gt;getX&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;, pt.&lt;span style="color: #007788;"&gt;getY&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; kd_insert&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;kdTree, xy, node&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;else&lt;/span&gt; &amp;nbsp;&lt;span style="color: #666666;"&gt;// &amp;nbsp;maybe lType == wkbPoint or wkbLineString ?&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt; &amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; OGRFeature&lt;span style="color: #008080;"&gt;::&lt;/span&gt;&lt;span style="color: #007788;"&gt;DestroyFeature&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;poFeature&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; main&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; argc, &lt;span style="color: #0000ff;"&gt;char&lt;/span&gt;&lt;span style="color: #000040;"&gt;*&lt;/span&gt; argv&lt;span style="color: #008000;"&gt;&amp;#91;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#93;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; ReadInPolygonsFromFile&lt;span style="color: #008000;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt;&amp;quot;C:/Temp/tl_2010_06_tabblock10/tl_2010_06_tabblock10.shp&amp;quot;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;#41;&lt;/span&gt;&lt;span style="color: #008080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/code&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;p&gt;Stay tuned for the next post, where we’ll run the DBSCAN algorithm and start to see some nice outputs!&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-6027214638609506729?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/6027214638609506729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/08/spatial-clustering-in-c-part-1-of-5.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6027214638609506729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6027214638609506729'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/08/spatial-clustering-in-c-part-1-of-5.html' title='Spatial Clustering in C++ (Part 1 of 5)'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-qb_DE_5K2AQ/TlH6qwDmCmI/AAAAAAAAAA4/Ftot7PiCiqc/s72-c/intro_pic2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-936218240532303482</id><published>2011-07-27T16:33:00.005+10:00</published><updated>2011-07-27T16:51:43.179+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='hosted solutions'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='workbench'/><title type='text'>js/css resource serving in python apps with Fanstatic</title><content type='html'>I've just been checking out &lt;a href="http://www.fanstatic.org"&gt;Fanstatic&lt;/a&gt;, a resource publishing/static file serving solution for wsgi python apps. I've been contemplating something like this as our javascript and css dependencies are getting more complex. It would also be useful to have some form of automatic cache invalidation so users don't have to do a special browser refresh when we update our applications. &lt;br /&gt;&lt;br /&gt;It's easy to set up with CherryPy&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="highlight" &gt;&lt;pre&gt;&lt;span style="color: #007020; font-weight: bold"&gt;from&lt;/span&gt; &lt;span style="color: #0e84b5; font-weight: bold"&gt;fanstatic&lt;/span&gt; &lt;span style="color: #007020; font-weight: bold"&gt;import&lt;/span&gt; Fanstatic&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #007020; font-weight: bold"&gt;if&lt;/span&gt; __name__ &lt;span style="color: #666666"&gt;==&lt;/span&gt; &lt;span style="color: #4070a0"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;    app &lt;span style="color: #666666"&gt;=&lt;/span&gt; cherrypy&lt;span style="color: #666666"&gt;.&lt;/span&gt;Application(Root())&lt;br /&gt;    app&lt;span style="color: #666666"&gt;.&lt;/span&gt;wsgiapp&lt;span style="color: #666666"&gt;.&lt;/span&gt;pipeline&lt;span style="color: #666666"&gt;.&lt;/span&gt;append((&lt;span style="color: #4070a0"&gt;&amp;#39;repoze.who&amp;#39;&lt;/span&gt;, setup_auth))&lt;br /&gt;    app&lt;span style="color: #666666"&gt;.&lt;/span&gt;wsgiapp&lt;span style="color: #666666"&gt;.&lt;/span&gt;pipeline&lt;span style="color: #666666"&gt;.&lt;/span&gt;append((&lt;span style="color: #4070a0"&gt;&amp;#39;beaker&amp;#39;&lt;/span&gt;, setup_session_storage))&lt;br /&gt;    app&lt;span style="color: #666666"&gt;.&lt;/span&gt;wsgiapp&lt;span style="color: #666666"&gt;.&lt;/span&gt;pipeline&lt;span style="color: #666666"&gt;.&lt;/span&gt;append((&lt;span style="color: #4070a0"&gt;&amp;#39;fanstatic&amp;#39;&lt;/span&gt;, Fanstatic))&lt;br /&gt;    cherrypy&lt;span style="color: #666666"&gt;.&lt;/span&gt;quickstart(app, config&lt;span style="color: #666666"&gt;=&lt;/span&gt;&lt;span style="color: #4070a0"&gt;&amp;#39;workbench.conf&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;after that is done, you can jquery.need() in the widget/template that needs jquery, and similar for our other dependencies. Has anyone else used fantastic? What are other solutions to dependencies and serving js/css? Is there an easier and better solution? Wrapping new libraries for fanstatic looks like a bit of effort but I haven't explored it much yet.&lt;br /&gt;&lt;br /&gt;Loki&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-936218240532303482?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/936218240532303482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/07/jscss-resource-serving-in-python-apps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/936218240532303482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/936218240532303482'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/07/jscss-resource-serving-in-python-apps.html' title='js/css resource serving in python apps with Fanstatic'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-9015897617304720347</id><published>2011-07-08T15:22:00.002+10:00</published><updated>2011-07-08T15:43:48.748+10:00</updated><title type='text'>Multi-server SSL with CherryPy</title><content type='html'>It's quite hard to see in the CherryPy docs how to support http and https from a single app. It turns out combining a few of the posts on the tools wiki is the way to go.&lt;br /&gt;&lt;br /&gt;Starting the app looks like:&lt;br /&gt;&lt;br /&gt;&lt;div class="highlight" &gt;&lt;pre&gt;&lt;span style="color: #007020; font-weight: bold"&gt;if&lt;/span&gt; __name__ &lt;span style="color: #666666"&gt;==&lt;/span&gt; &lt;span style="color: #4070a0"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #007020; font-weight: bold"&gt;from&lt;/span&gt; &lt;span style="color: #0e84b5; font-weight: bold"&gt;cherrypy&lt;/span&gt; &lt;span style="color: #007020; font-weight: bold"&gt;import&lt;/span&gt; _cpserver&lt;br /&gt;    &lt;span style="color: #007020; font-weight: bold"&gt;from&lt;/span&gt; &lt;span style="color: #0e84b5; font-weight: bold"&gt;cherrypy&lt;/span&gt; &lt;span style="color: #007020; font-weight: bold"&gt;import&lt;/span&gt; _cpwsgi_server&lt;br /&gt;&lt;br /&gt;    secure_server &lt;span style="color: #666666"&gt;=&lt;/span&gt; _cpwsgi_server&lt;span style="color: #666666"&gt;.&lt;/span&gt;CPWSGIServer()&lt;br /&gt;    cherrypy&lt;span style="color: #666666"&gt;.&lt;/span&gt;config&lt;span style="color: #666666"&gt;.&lt;/span&gt;namespaces[&lt;span style="color: #4070a0"&gt;&amp;#39;secure_server&amp;#39;&lt;/span&gt;] &lt;span style="color: #666666"&gt;=&lt;/span&gt; &lt;span style="color: #007020; font-weight: bold"&gt;lambda&lt;/span&gt; k, v: &lt;span style="color: #007020"&gt;setattr&lt;/span&gt;(secure_server, k, v)&lt;br /&gt;    secure_server&lt;span style="color: #666666"&gt;.&lt;/span&gt;bind_addr &lt;span style="color: #666666"&gt;=&lt;/span&gt; (&lt;span style="color: #4070a0"&gt;&amp;#39;0.0.0.0&amp;#39;&lt;/span&gt;, cherrypy&lt;span style="color: #666666"&gt;.&lt;/span&gt;config[&lt;span style="color: #4070a0"&gt;&amp;#39;secure_server.socket_port&amp;#39;&lt;/span&gt;])&lt;br /&gt;&lt;br /&gt;    adapter &lt;span style="color: #666666"&gt;=&lt;/span&gt; _cpserver&lt;span style="color: #666666"&gt;.&lt;/span&gt;ServerAdapter(cherrypy&lt;span style="color: #666666"&gt;.&lt;/span&gt;engine, secure_server, secure_server&lt;span style="color: #666666"&gt;.&lt;/span&gt;bind_addr)&lt;br /&gt;    adapter&lt;span style="color: #666666"&gt;.&lt;/span&gt;subscribe()&lt;br /&gt;&lt;br /&gt;    app &lt;span style="color: #666666"&gt;=&lt;/span&gt; cherrypy&lt;span style="color: #666666"&gt;.&lt;/span&gt;Application(Root())&lt;br /&gt;    app&lt;span style="color: #666666"&gt;.&lt;/span&gt;wsgiapp&lt;span style="color: #666666"&gt;.&lt;/span&gt;pipeline&lt;span style="color: #666666"&gt;.&lt;/span&gt;append((&lt;span style="color: #4070a0"&gt;&amp;#39;repoze.who&amp;#39;&lt;/span&gt;, setup_auth))&lt;br /&gt;    app&lt;span style="color: #666666"&gt;.&lt;/span&gt;wsgiapp&lt;span style="color: #666666"&gt;.&lt;/span&gt;pipeline&lt;span style="color: #666666"&gt;.&lt;/span&gt;append((&lt;span style="color: #4070a0"&gt;&amp;#39;beaker&amp;#39;&lt;/span&gt;, setup_session_storage))&lt;br /&gt;    cherrypy&lt;span style="color: #666666"&gt;.&lt;/span&gt;quickstart(app, config&lt;span style="color: #666666"&gt;=&lt;/span&gt;&lt;span style="color: #4070a0"&gt;&amp;#39;workbench.conf&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And the important config file options are:&lt;br /&gt;&lt;br /&gt;&lt;div class="highlight" &gt;&lt;pre&gt;[&lt;span style="color: #007020; font-weight: bold"&gt;global&lt;/span&gt;]&lt;br /&gt;server&lt;span style="color: #666666"&gt;.&lt;/span&gt;socket_host &lt;span style="color: #666666"&gt;=&lt;/span&gt; &lt;span style="color: #4070a0"&gt;&amp;quot;0.0.0.0&amp;quot;&lt;/span&gt;&lt;br /&gt;server&lt;span style="color: #666666"&gt;.&lt;/span&gt;socket_port &lt;span style="color: #666666"&gt;=&lt;/span&gt; &lt;span style="color: #40a070"&gt;8080&lt;/span&gt;&lt;br /&gt;server&lt;span style="color: #666666"&gt;.&lt;/span&gt;thread_pool &lt;span style="color: #666666"&gt;=&lt;/span&gt; &lt;span style="color: #40a070"&gt;10&lt;/span&gt;&lt;br /&gt;secure_server&lt;span style="color: #666666"&gt;.&lt;/span&gt;socket_port &lt;span style="color: #666666"&gt;=&lt;/span&gt; &lt;span style="color: #40a070"&gt;8443&lt;/span&gt;&lt;br /&gt;secure_server&lt;span style="color: #666666"&gt;.&lt;/span&gt;ssl_certificate &lt;span style="color: #666666"&gt;=&lt;/span&gt; &lt;span style="color: #4070a0"&gt;&amp;quot;certs/self_sign_certificate.crt&amp;quot;&lt;/span&gt;&lt;br /&gt;secure_server&lt;span style="color: #666666"&gt;.&lt;/span&gt;ssl_private_key &lt;span style="color: #666666"&gt;=&lt;/span&gt; &lt;span style="color: #4070a0"&gt;&amp;quot;certs/self_sign.key&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Loki&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-9015897617304720347?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/9015897617304720347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/07/multi-server-ssl-with-cherrypy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/9015897617304720347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/9015897617304720347'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/07/multi-server-ssl-with-cherrypy.html' title='Multi-server SSL with CherryPy'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-7623211284052229107</id><published>2011-06-23T14:49:00.000+10:00</published><updated>2011-06-23T14:49:14.216+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='optimisation'/><category scheme='http://www.blogger.com/atom/ns#' term='operations research'/><category scheme='http://www.blogger.com/atom/ns#' term='fibre'/><title type='text'>Biarri provides Network Design Optimisation to NBN Co.</title><content type='html'>NBN Co today announced that they awarded an 8 year contract to Biarri to&amp;nbsp;supply network design optimisation to support development of efficient, lower cost network construction plans.&lt;br /&gt;&lt;br /&gt;Biarri is to provide optimisation technology to NBN Co for fibre network design optimisation. The optimisation engine quickly generates low-cost fibre network designs based on the requirements of the reference architecture. It can determine optimal fibre area boundaries, the position of fibre hubs, and the layout and route of distribution and local fibre.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;See the&amp;nbsp;&lt;a href="http://www.nbnco.com.au/wps/wcm/connect/main/site-base/main-areas/publications-and-announcements/announcements/NBN-Co-uses-advanced-maths-to-optimise-network-design-reduce-costs.html"&gt;NBN Co site&lt;/a&gt;&amp;nbsp;for more detail.&lt;/div&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-9e9-NpXR5tU/TgLE0rbDwaI/AAAAAAAAAG0/0zw8eCmlGgA/s1600/FOND+Logic.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-9e9-NpXR5tU/TgLE0rbDwaI/AAAAAAAAAG0/0zw8eCmlGgA/s1600/FOND+Logic.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Logic of the Fibre Optic Network Design Tool&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-7623211284052229107?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.nbnco.com.au/wps/wcm/connect/main/site-base/main-areas/publications-and-announcements/announcements/NBN-Co-uses-advanced-maths-to-optimise-network-design-reduce-costs.html' title='Biarri provides Network Design Optimisation to NBN Co.'/><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/7623211284052229107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/06/biarri-provides-network-design.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7623211284052229107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7623211284052229107'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/06/biarri-provides-network-design.html' title='Biarri provides Network Design Optimisation to NBN Co.'/><author><name>www.biarri.com</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_A-i4GK9mCAI/S_82JC2C1aI/AAAAAAAAAEw/JVmeqm1_xVY/S220/Icons-tools.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-9e9-NpXR5tU/TgLE0rbDwaI/AAAAAAAAAG0/0zw8eCmlGgA/s72-c/FOND+Logic.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-7316184018873448573</id><published>2011-06-03T09:59:00.006+10:00</published><updated>2011-06-03T11:06:44.819+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='optimisation'/><category scheme='http://www.blogger.com/atom/ns#' term='operations research'/><category scheme='http://www.blogger.com/atom/ns#' term='vehicle routing'/><title type='text'>Optimisation: Striking the Right Balance</title><content type='html'>One of the guiding principles we use in commercial mathematics is to "Model Conservatively, but Optimise Aggressively".  This means that the problem domain should be modeled with sufficient "fat" in the data to ensure that the results are both legal and robust; but given this, we should then seek to apply the best (fastest and highest quality) solution approach that we can get our hands on.&lt;br /&gt;&lt;br /&gt;Optimising aggressively can sometimes have it's downfalls, though, if taken too literally.  I've been doing a few experiments with numerical weightings of the objective function in a Vehicle Routing problem, where this issue is readily apparent.  (Actually it is a Vehicle Routing problem with time windows, heterogeneous fleet, travel times with peak hours, both volume and weight capacities, and various other side constraints).&lt;br /&gt;&lt;br /&gt;Our Vehicle Routing uses travel times (based on shortest paths through the street network) that are characterised by distance and duration.  Durations can vary due to different road speeds on different types of streets (highways vs suburban roads for example).  This leads to the question of how (on what basis) to optimise the vehicle routes - given that the optimisation has already to some extent minimised the number of vehicles and created well-clustered routes - what is the most desirable outcome for KPIs in terms of duration and distance?&lt;br /&gt;&lt;br /&gt;In one experiment I've tried three different weightings for the duration (cost per hour) while keeping the cost per distance constant.  I've run three values for this cost per hour - low, medium, and high weightings - on real-life delivery problems across two different Australian metropolitan regions.&lt;br /&gt;&lt;br /&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="455"&gt;&lt;col style="width: 92pt;" width="122"&gt;  &lt;col style="width: 84pt;" width="112"&gt;  &lt;col style="width: 76pt;" width="101"&gt;  &lt;col style="width: 90pt;" width="120"&gt;  &lt;tbody&gt;&lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt; width: 92pt;" width="122" height="20"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="width: 84pt;" width="112"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="width: 76pt; font-weight: bold;" width="101"&gt;Region 1&lt;/td&gt;   &lt;td style="width: 90pt;" width="120"&gt;&lt;br /&gt;&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td&gt;Total Duration&lt;/td&gt;   &lt;td&gt;Driving Duration&lt;/td&gt;   &lt;td&gt;Distance&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;Cost/hour&lt;/td&gt;   &lt;td&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td&gt;&lt;br /&gt;&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;Low&lt;/td&gt;   &lt;td align="right"&gt;74:47&lt;/td&gt;   &lt;td align="right"&gt;24:38&lt;/td&gt;   &lt;td align="right"&gt;708&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;Medium&lt;/td&gt;   &lt;td align="right"&gt;72:45&lt;/td&gt;   &lt;td align="right"&gt;23:55&lt;/td&gt;   &lt;td align="right"&gt;712&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;High&lt;/td&gt;   &lt;td align="right"&gt;72:58&lt;/td&gt;   &lt;td align="right"&gt;23:42&lt;/td&gt;   &lt;td align="right"&gt;768&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="455"&gt;&lt;col style="width: 92pt;" width="122"&gt;  &lt;col style="width: 84pt;" width="112"&gt;  &lt;col style="width: 76pt;" width="101"&gt;  &lt;col style="width: 90pt;" width="120"&gt;  &lt;tbody&gt;&lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt; width: 92pt;" width="122" height="20"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="width: 84pt;" width="112"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="width: 76pt; font-weight: bold;" width="101"&gt;Region 2&lt;br /&gt;&lt;/td&gt;   &lt;td style="width: 90pt;" width="120"&gt;&lt;br /&gt;&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td&gt;Total Duration&lt;/td&gt;   &lt;td&gt;Driving Duration&lt;/td&gt;   &lt;td&gt;Distance&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;Cost/hour&lt;/td&gt;   &lt;td&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td&gt;&lt;br /&gt;&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;Low&lt;/td&gt;   &lt;td align="right"&gt;113:54&lt;/td&gt;   &lt;td align="right"&gt;46:44&lt;/td&gt;   &lt;td align="right"&gt;1465&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;Medium&lt;/td&gt;   &lt;td align="right"&gt;107:51&lt;/td&gt;   &lt;td align="right"&gt;41:36&lt;/td&gt;   &lt;td align="right"&gt;1479&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="height: 15pt;" height="20"&gt;High&lt;/td&gt;   &lt;td align="right"&gt;108:51&lt;/td&gt;   &lt;td align="right"&gt;43:49&lt;/td&gt;   &lt;td align="right"&gt;1518&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;From these results, there is a (more-or-less) general correspondence between distance and the driver cost per hour as you would expect.  However, if you push one weighting too far (ie. optimise too aggressively or naively), it will sometimes be to the detriment of &lt;span style="font-weight: bold;"&gt;all the KPIs &lt;/span&gt;as the optimisation will be pushing too strongly in one direction (perhaps it is outside the parameter space for which it was originally tuned, or perhaps it pushes the metaheuristic into search-space regions which are more difficult to escape from).  This is most acutely seen in Region 2 when using the high cost per hour value.  Conversely if you drop the cost per hour to a low value, the (very modest) reduction you get in distance is very badly paid for in terms of much longer durations.  What is most likely happening in this case is that the routes are including much more waiting time (waiting at delivery points for the time windows to "open"), in order to avoid even a short trip (incurring distance) to a nearby delivery point that could be done instead of waiting.&lt;br /&gt;&lt;br /&gt;The problem of striking the right balance is most acute with metaheuristics which can only really be tuned and investigated by being run many times across multiple data sets, in order to get a feel for how the solution "cost curve" looks in response to different input weightings.  In our example, an in-between value for cost per hour seems to strike the best balance to produce the overall most desirable KPI outcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-7316184018873448573?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/7316184018873448573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/06/optimisation-striking-right-balance.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7316184018873448573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7316184018873448573'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/06/optimisation-striking-right-balance.html' title='Optimisation: Striking the Right Balance'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-6665661317362593615</id><published>2011-05-27T15:52:00.000+10:00</published><updated>2011-05-27T15:52:08.295+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='operations research'/><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Successfully Implementing Commercial Mathematics</title><content type='html'>We have grown Biarri based on successfully bringing the power of mathematics to bear on business. We try hard to make operations research easier for business to digest. &amp;nbsp;Over the last few years there are a few things we have learned that are worth pointing out.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Target businesses that need analytical support and know they need it.&lt;/b&gt; Many businesses now have lots of data but that they lack the analytical ability to utilise that data. The businesses we target understand that smart decisions are based on 'results gleaned from algorithmic insight and executed with the confidence that comes from really doing the math'. 'Analytics' is now part of the business improvement conversation however you need to target businesses that have complex problems that are solvable &lt;u&gt;and&lt;/u&gt; need solving. Additionally, we have always had better success when the problem has a clear owner who will benefit directly from solving the problem.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Differentiate your offering.&lt;/b&gt; 'Optimisation' and now 'Analytics' are overused terms. As applied mathematicians we can certainly bring some real science to the table. But this is not enough. What has emerged as very important is our ability to make the mathematics digestible. We have tried hard to deliver 'Accessible Optimisation'. We believe optimisation is only powerful if it is:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Easy to apply to real world operations&lt;/li&gt;&lt;li&gt;Easy to understand (intuitive)&lt;/li&gt;&lt;li&gt;Easy to access (usable)&lt;/li&gt;&lt;li&gt;Affordable with minimum capital spend&lt;/li&gt;&lt;li&gt;Fast and reliable&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;3. Focus on implementation practicalities.&lt;/b&gt; You need to keep your eye on the basics of project management. Some of the key issues for us have been:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Work hard to keep the scope tight by focusing on the 20% of features that deliver 80% of the value.&lt;/li&gt;&lt;li&gt;Use simple frameworks that everyone can understand. All our custom models and tools use a simple linear workflow/logic around a smart engine.&lt;/li&gt;&lt;li&gt;Stay close to your customer and practice the art of no surprises.&lt;/li&gt;&lt;li&gt;Excel is useful for modelling. It is available on every desk top, flexible, familiar, easy to use and accepted by non-technical managers.&lt;/li&gt;&lt;li&gt;Develop and implement prototype models quickly and have a simple way of upgrading them when needed. &amp;nbsp;For example, we always keep our prototype engines separate to the front-end so we can easily port them to different solution frameworks.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-6665661317362593615?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/6665661317362593615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/05/successfully-implementing-commercial.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6665661317362593615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6665661317362593615'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/05/successfully-implementing-commercial.html' title='Successfully Implementing Commercial Mathematics'/><author><name>www.biarri.com</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_A-i4GK9mCAI/S_82JC2C1aI/AAAAAAAAAEw/JVmeqm1_xVY/S220/Icons-tools.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-8167378438687372446</id><published>2011-05-16T10:32:00.004+10:00</published><updated>2011-05-18T10:28:52.388+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='graphs'/><category scheme='http://www.blogger.com/atom/ns#' term='VBA'/><category scheme='http://www.blogger.com/atom/ns#' term='visualisation'/><category scheme='http://www.blogger.com/atom/ns#' term='excel'/><title type='text'>Custom Excel Charts: Scatter Plots</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"&gt;&lt;u&gt;&lt;br /&gt;&lt;/u&gt;&lt;/span&gt;&lt;/div&gt;&lt;p class="MsoNormal"&gt;I am often required to create some very specific charts for clients that are far outside of the capability of regular Excel charting functionality. I use VBA to create these custom charts in a dynamic way to visualise outputs of mathematical modelling. These outputs are important to clients as they allow them to view the complex outputs in simple, familiar ways.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;I have in the past created &lt;span style="color:red"&gt;&lt;a href="http://biarri.blogspot.com/2010/08/l-shaped-excel-graph.html"&gt;L-Shaped Graphs&lt;/a&gt;&lt;/span&gt; for clients that helped optimise the use of space for a dynamic Excel Dashboard that needed to be constrained to an A4 print out.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;More recently, I have been required to create a custom ‘March Chart’ that plots the movements of different work crews over space and time. I received a print out of an old ‘March Chart’ that had been manually created by the client, and was asked to replicate it exactly in Excel so that it could be viewed as an output of a mathematical model.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;THE POWER OF SCATTER PLOTS&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;When creating a custom chart in Excel, you must use one of the existing charts as a template. This template can then be twisted and abused into doing what you need through tricks and manipulation within VBA.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;For the March Chart project, I discovered just how very useful a scatter plot can be as the template for an advanced Excel chart. The scatter plot can be thought of as a blank canvas on to which x,y data points can be plotted. Each data point can then be joined by a line to another data point, creating a straight line. A series of sequential data points with straight lines joining them called a ‘data series’ can be used to create paths and even ‘curves’. With this functionality in mind, you essentially now have a blank canvas that you can draw anything on in Excel with VBA!&lt;/p&gt;  &lt;p class="MsoNormal"&gt;This all seems far too good, so Excel had to put some barriers in our way to make it a little trickier.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoListParagraphCxSpFirst" style="text-indent: -18pt; "&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;span style="font: normal normal normal 7pt/normal 'Times New Roman'; "&gt;        &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;For starters, there is the ever present issue of backward compatibility to Excel 2003. The object model used to create charts was changed from Excel 2003 to Excel 2007, so it is very important to be aware of this, and find out early if your client is using Excel 2003. Fortunately for myself, the client for the ‘March Chart’ had upgraded to at least Excel 2007 so this was not an issue for me. &lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;span style="font: normal normal normal 7pt/normal 'Times New Roman'; "&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;More specific to the advanced use of scatter plots, Excel limits you to 255 data series on a chart. Each sequence of coordinates that join together to make a continuous line are defined as a data series. This means that you can only have 255 distinct continuous lines on your chart.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Each of these data series, can only consist of 255 data points. Unless your chart is extremely big and going to be shown on a very large screen, this is pretty easy to manage. There are two options:&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoListParagraphCxSpFirst" style="margin-left: 72pt; text-indent: -18pt; "&gt;&lt;span style="font-family: 'Courier New'; "&gt;&lt;span&gt;o&lt;span style="font: normal normal normal 7pt/normal 'Times New Roman'; "&gt;       &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Split the data series into multiple data series. If you make the two data series the same colour, and begin the second data series at the last point of the first data series then they will appear to be a continuous line. This is a good option if you are not close to the limit of data series, however can create more issues to overcome as an additional legend entry will be created.&lt;/p&gt;&lt;p class="MsoListParagraphCxSpLast" style="margin-left: 72pt; text-indent: -18pt; "&gt;&lt;span style="font-family: 'Courier New'; "&gt;&lt;span&gt;o &lt;span style="font: normal normal normal 7pt/normal 'Times New Roman'; "&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;For any data series that has more than 255 potential data points, skip over every second, third, etc. depending on the actual number so that the number of data points implemented to the actual plotted data series remains under 255. This is my preferred method as no additional work is required in fixing the legend and is in my opinion neater.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;The following is an example output of the March Chart showing different colours for different work crew types. You can track the geographic location over time of each work crew very simply with this visualisation.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;a href="http://1.bp.blogspot.com/-fGdGx9gLqJw/TdBzXU8ZjoI/AAAAAAAAAMA/pGCP75vbIKQ/s1600/blog_5.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img src="http://1.bp.blogspot.com/-fGdGx9gLqJw/TdBzXU8ZjoI/AAAAAAAAAMA/pGCP75vbIKQ/s400/blog_5.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5607108380672495234" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 393px; " /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoListParagraphCxSpLast" style="text-align: left;margin-left: 72pt; text-indent: -18pt; "&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-8167378438687372446?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/8167378438687372446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/05/custom-excel-charts-scatter-plots.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8167378438687372446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8167378438687372446'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/05/custom-excel-charts-scatter-plots.html' title='Custom Excel Charts: Scatter Plots'/><author><name>Steven</name><uri>http://www.blogger.com/profile/04508368748951926559</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-fGdGx9gLqJw/TdBzXU8ZjoI/AAAAAAAAAMA/pGCP75vbIKQ/s72-c/blog_5.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1954907813145656056</id><published>2011-05-16T09:42:00.006+10:00</published><updated>2011-05-16T10:01:05.616+10:00</updated><title type='text'>Excel 2D Data Lookup using INDEX with MATCH</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://1.bp.blogspot.com/-7KokUYEva3w/TdBnNJlaC1I/AAAAAAAAAL4/TEpaY6npGuo/s1600/blog_4.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;/a&gt;&lt;a href="http://1.bp.blogspot.com/-R70SI8w1IyM/TdBm6DliSNI/AAAAAAAAALw/esSRvfj5TXU/s1600/blog_3.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;/a&gt;&lt;div&gt;&lt;div&gt;INDEX with MATCH enables lookup of a cell in with an unknown reference in a matrix with row and column labels.&lt;/div&gt;&lt;p class="MsoNormal"&gt;The two formulas:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;INDEX&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Syntax: &lt;i&gt;INDEX(array, row_num, [column_num])&lt;/i&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Index is very simple and the syntax is fairly self explanatory.&lt;/p&gt;&lt;p class="MsoNormal"&gt;INDEX takes an array of data as the first parameter, a row number as the second and a column number as the third. The function then return the value in the array referenced by the row and column specified.&lt;/p&gt;&lt;p class="MsoNormal"&gt;An example array in Excel:&lt;/p&gt;&lt;/div&gt;&lt;a href="http://2.bp.blogspot.com/-aMkYrbwKMzg/TdBmXbVqPeI/AAAAAAAAALg/YdvXs0ZZTpI/s1600/blog_1.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 346px; height: 110px;" src="http://2.bp.blogspot.com/-aMkYrbwKMzg/TdBmXbVqPeI/AAAAAAAAALg/YdvXs0ZZTpI/s400/blog_1.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5607094088737897954" /&gt;&lt;/a&gt;&lt;div&gt;&lt;p class="MsoNormal"&gt;To return ‘Black’ using the INDEX function use the formula:&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;i&gt;=INDEX(B2:D4,3,2)&lt;/i&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Note that the second parameter refers to the 3&lt;sup&gt;rd&lt;/sup&gt; row in the array B2:D4 and not the 3&lt;sup&gt;rd&lt;/sup&gt; row of the spreadsheet. This applies for the column reference also.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;When used like this, INDEX appears to be fairly limited in its practical applications, as if you already know the row and column number of a cell in the array, you can generally reference the cell directly.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;However, when used with MATCH, INDEX becomes one of the most powerful and useful functions in Excel.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;MATCH&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Syntax: &lt;i&gt;MATCH(lookup_value, lookup_array, [match_type])&lt;/i&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;MATCH is again quite simple on its own however requires a little more consideration and care than INDEX. &lt;/p&gt;  &lt;p class="MsoNormal"&gt;MATCH takes a lookup value as its first parameter and a lookup array as the second. For our purposes the lookup array needs to be a single dimension. This can be row wise or column wise. &lt;/p&gt;  &lt;p class="MsoNormal"&gt;MATCH then returns the index of the lookup value if it is found in the lookup array.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;However false positives are easy, as the third parameter of MATCH is the [match_type] which takes one of three values:&lt;/p&gt;&lt;/div&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "&gt;&lt;img src="http://4.bp.blogspot.com/-fSPIMPyl3DY/TdBmuNMp7qI/AAAAAAAAALo/IdDEE8fYLcI/s400/blog_2.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5607094480079023778" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 123px; height: 57px; " /&gt;&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="-webkit-text-decorations-in-effect: underline; "&gt;&lt;p class="MsoNormal"&gt;The default value is 1, and this can cause issues as if you forget to add this optional parameter then you could very easily get incorrect lookups occurring that are hard to notice. This is because the lookup will still return a value even if it can not find what you are looking for. MATCH will return some value that is ‘Less than’ the lookup value, which is very rarely what you actually want. It is important when using MATCH with INDEX for matrix lookups to &lt;b&gt;remember to set match_type parameter equal to 0.&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;An example array in Excel:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;a href="http://1.bp.blogspot.com/-R70SI8w1IyM/TdBm6DliSNI/AAAAAAAAALw/esSRvfj5TXU/s1600/blog_3.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img src="http://1.bp.blogspot.com/-R70SI8w1IyM/TdBm6DliSNI/AAAAAAAAALw/esSRvfj5TXU/s400/blog_3.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5607094683657455826" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 101px; height: 105px; " /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="text-align: left;"&gt;&lt;p class="MsoNormal"&gt;To return the row index of the array for the value “Colour 2”:&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;i&gt;=MATCH("Colour 2",A2:A4,0)&lt;/i&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;This will return: 2&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Note that this is the row number of the lookup value “Colour 2” in the lookup array and not in the worksheet.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;INDEX with MATCH&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;MATCH is used to provide logic to the row_num and column_num parameters of INDEX.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;If a matrix in Excel has labels for both the rows and columns, then INDEX with MATCH can lookup a specific cell in the matrix with ease.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;An example of such a matrix:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "&gt;&lt;img src="http://1.bp.blogspot.com/-7KokUYEva3w/TdBnNJlaC1I/AAAAAAAAAL4/TEpaY6npGuo/s400/blog_4.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5607095011685043026" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 346px; height: 108px; " /&gt;&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="-webkit-text-decorations-in-effect: underline; "&gt;&lt;p class="MsoNormal"&gt;INDEX with MATCH can be used with this matrix to answer questions such as ‘What is Colour 2 of Group 3?&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Repeating from above, the syntax for INDEX is:&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;i&gt;INDEX(array, row_num, [column_num])&lt;/i&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The input array for this example is B2:D4.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The row_num and column_num parameters need to be found using MATCH as shown above.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;row_num: &lt;i&gt;MATCH("Colour 2",A2:A4,0)&lt;/i&gt; will return 2&lt;/p&gt;  &lt;p class="MsoNormal"&gt;col_num: &lt;i&gt;MATCH("Group 3",B1:D1,0)&lt;/i&gt; will return 3&lt;/p&gt;  &lt;p class="MsoNormal"&gt;These can then be put into INDEX to create our formula:&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;i&gt;=INDEX(B2:D4,MATCH("Colour 2",A2:A4,0),MATCH("Group 3",B1:D1,0))&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;This will return pink.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;I now use INDEX with MATCH nearly every time I do data analysis and manipulation in Excel. Clients often have data in 2D Matrices, and it is no longer a hurdle for me to use this data with ease.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1954907813145656056?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1954907813145656056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/05/excel-2d-data-lookup-using-index-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1954907813145656056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1954907813145656056'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/05/excel-2d-data-lookup-using-index-with.html' title='Excel 2D Data Lookup using INDEX with MATCH'/><author><name>Steven</name><uri>http://www.blogger.com/profile/04508368748951926559</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-aMkYrbwKMzg/TdBmXbVqPeI/AAAAAAAAALg/YdvXs0ZZTpI/s72-c/blog_1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-532772919591221805</id><published>2011-05-05T10:27:00.004+10:00</published><updated>2011-05-06T13:28:27.143+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QGIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sqlite'/><category scheme='http://www.blogger.com/atom/ns#' term='shapefiles'/><title type='text'>Editing vector layers with Quantum GIS</title><content type='html'>I've been looking around for an open source alternative to the excellent Desktop GIS Mapping Application &lt;a href="http://www.pbinsight.com/products/location-intelligence/applications/mapping-analytical/mapinfo-professional/"&gt;MapInfo Pro&lt;/a&gt;.  I've installed and played with both &lt;a href="http://www.qgis.org/"&gt;Quantum GIS (QGIS)&lt;/a&gt; and &lt;a href="http://www.mapwindow.org/"&gt;MapWindow&lt;/a&gt;.  The latter is a little bare bones and does not seem to include any geometry editing, so I've been focussing instead on QGIS.&lt;br /&gt;&lt;br /&gt;QGIS is a &lt;a href="http://giscoder.blogspot.com/2008/04/quantum-gis-first-impressions.html"&gt;great application&lt;/a&gt;, though it is quite noticably slower to render very large mapping layers than MapInfo Pro.  However - and this is, strangely, not very well known or documented - QGIS &lt;span style="font-weight: bold;"&gt;will only let you edit layers which are &lt;a href="http://en.wikipedia.org/wiki/Shapefiles"&gt;Shapefiles&lt;/a&gt;&lt;/span&gt;.   There is no documentation that I can find which says why the "Toggle Editing" function is always disabled for other files - this is very confusing/frustrating if you don't know about this Shapefile limitation.&lt;br /&gt;&lt;br /&gt;There is a converter within QGIS (which is really just a UI on &lt;a href="http://www.gdal.org/ogr2ogr.html"&gt;ogr2ogr&lt;/a&gt;) to convert between TAB and SHP formats, but Shapefile layers are rather limited because you can't mix geometries within a layer - both nodes (points), and lines, for example.  This is rather a problem because the map data I have has both points and lines - the points are needed to style the line endpoints and allow for data attributes on them.  Separating points and lines into different layers in this context is a bit of a pain.  Shapefiles also have various other limitations - for example, field names can be no longer than 10 characters.&lt;br /&gt;&lt;br /&gt;Perhaps hooking up QGIS to an &lt;a href="http://www.sqlite.org/"&gt;SQLite&lt;/a&gt; database with &lt;a href="http://www.gaia-gis.it/spatialite/"&gt;Spatialite&lt;/a&gt; extension might make managing the map data layers more streamlined - one for a rainy day...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-532772919591221805?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/532772919591221805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/05/editing-vector-layers-with-quantum-gis.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/532772919591221805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/532772919591221805'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/05/editing-vector-layers-with-quantum-gis.html' title='Editing vector layers with Quantum GIS'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-5447353146523807440</id><published>2011-05-05T09:38:00.002+10:00</published><updated>2011-05-06T13:28:40.658+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='COIN-OR'/><category scheme='http://www.blogger.com/atom/ns#' term='cplex'/><category scheme='http://www.blogger.com/atom/ns#' term='installing'/><category scheme='http://www.blogger.com/atom/ns#' term='OSI'/><title type='text'>Installing Cplex in Linux Ubuntu</title><content type='html'>I've been trying to install ILOG's &lt;a href="http://www-01.ibm.com/software/integration/optimization/cplex-optimizer/"&gt;Cplex&lt;/a&gt; product on a 64 bit Ubuntu machine.  There are a few small hiccups I encountered.&lt;br /&gt;&lt;br /&gt;First, try to install as root with&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;./cplex_studio122.linux-x86.bin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;On my machine I'm installing to /opt/ILOG/CPLEX_Studio122.  If you get an error like "jre/bin/java: not found" then you need the "32 bit libs" package:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;apt-get install ia32-libs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(You may also need to set the path with LD_LIBRARY_PATH=/usr/lib32).  The 32 bit libraries seem to be required only for the installer (at least, they are not needed for programs that just link with the static Cplex libs).&lt;br /&gt;&lt;br /&gt;After installing, you may get a build error (running as a non-root user) that it can't find the cplex header files.  Try &lt;span style="font-family:courier new;"&gt;ls /opt/ILOG/CPLEX_Studio122 &lt;/span&gt;and see if there are permission denied messages - the installation seems to screw up some permissions on this folder, however this is easily fixed with &lt;span style="font-family:courier new;"&gt;chmod +r /opt/ILOG/CPLEX_Studio122&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;If you are using &lt;a href="http://www.coin-or.org/"&gt;COIN-OR&lt;/a&gt;'s &lt;a href="https://projects.coin-or.org/Osi/"&gt;Osi&lt;/a&gt; class OsiCpxSolverInterface you will also need the following at the top of your OsiCpxSolverInterface.cpp file:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#include "/opt/ILOG/CPLEX_Studio122/cplex/include/ilcplex/cplex.h"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A typical Makefile snippet which includes Cplex and COIN/Osi might then look like:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;my_objects = YourFile.o OsiCbcSolverInterface.o OsiCpxSolverInterface.o&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;CPPFLAGS = -fPIC -I/usr/include -I/usr/include/coin -DNDEBUG -I/opt/ILOG/CPLEX_Studio122/cplex/include/ilcplex&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;LIBFLAGS = &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;-l:libCbc.so -l:libCbcSolver.so -l:libCoinUtils.so -l:libOsi.so -l:libOsiClp.so -l:libClp.so &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;-l:/opt/ILOG/CPLEX_Studio122/cplex/lib/x86-64_sles10_4.1/static_pic/libcplex.a -l:/opt/ILOG/CPLEX_Studio122/cplex/lib/x86-64_sles10_4.1/static_pic/libilocplex.a &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;my_program : $(&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;my_objects&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    g++ -Wall -fPIC -shared -o &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;my_program&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt; $(&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;my_objects&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;.PHONY : clean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;clean :&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    rm &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;*.o&lt;/span&gt;&lt;/span&gt; &lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;my_program&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-5447353146523807440?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/5447353146523807440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/05/installing-cplex-in-linux-ubuntu.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5447353146523807440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5447353146523807440'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/05/installing-cplex-in-linux-ubuntu.html' title='Installing Cplex in Linux Ubuntu'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-4409012690501409650</id><published>2011-03-18T11:49:00.011+11:00</published><updated>2011-03-18T12:55:48.021+11:00</updated><title type='text'>Function within a Function in C++ - Everything In Its Right Place</title><content type='html'>I have been coding in C++ for a number of years. Only recently did I find out that there is an indirect way to write a function within a function. I have found myself using this little workaround more and more recently. When coupled with the use of a static variable within a function, the ability to have "Everything In Its Right Place" i.e. avoid unnecessary functions and variables in the global namespace, is particularly appealing to my inner code nazi.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;The below code snippet shows an example...&lt;br /&gt;&lt;br /&gt;Note &lt;div&gt;- I have only tested the code snippet below for compilation using Visual Studio&lt;/div&gt;&lt;div&gt;- Visual Studio's debugger does not allow you to "watch" spndI when execution is inside the function NodeIsOfSameTypeAsIButNotI&lt;/div&gt;- I have formatted the code for the narrow width afforded this blog! So the example looks more verbose than it would otherwise be, and the blogger may mangle some of the code when it is posted (causing me to re edit the post over and over until google gets it right)&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;struct CNode&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;// shell struct to enable code compilation&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;double GetLongitude() const {return 0;}&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;double GetLatitude() const {return 0;}&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;double GetType() const {return 0;}&lt;/div&gt;&lt;div&gt;};&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;template&lt;class&gt; class CSomeClassHoldingNodesForFastFinding&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;public:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;b&gt;typedef bool(*NodeCanBeClosest)(const T*);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;template&lt;class&gt; inline T* FindClosest&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;(&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;double dblLongitude, &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;double dblLatitude, &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;&lt;b&gt;NodeCanBeClosest pNodeCanBeClosest&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;)&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;{&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;return NULL; // Really return a T* not Null&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;};&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;void FindClosestNodePairsAndDoSomethingWithThem&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;(&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;vector&lt;cnode*&gt;&amp;amp; rgpnd, &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;CSomeClassHoldingNodesForFastFinding&lt;cnode&gt;* pFastFindNodes&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;)&lt;/div&gt;&lt;div&gt;{&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;b&gt;static CNode* spndI = NULL;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;for (size_t nNodeI = 0; nNodeI != rgpnd.size(); nNodeI++)&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;{&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;&lt;b&gt;spndI = rgpnd[nNodeI];&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;struct Func&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;{&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;static bool NodeIsOfSameTypeAsIButNotI(const CNode* pnd) &lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;{&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;return &lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;     &lt;/span&gt;pnd != spndI &lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;     &lt;/span&gt;&amp;amp;&amp;amp; &lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;     &lt;/span&gt;pnd-&gt;GetType() == spndI-&gt;GetType();&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;}&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;};&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;CNode* pndJ = pFastFindNodes-&gt;FindClosest&lt;cnode&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;(&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;spndI-&gt;GetLongitude(), &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;spndI-&gt;GetLatitude(), &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;&lt;b&gt;&amp;amp;Func::NodeIsOfSameTypeAsIButNotI&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;);&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;// .. Do something with spndI and pndJ&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-4409012690501409650?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/4409012690501409650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/03/function-within-function-in-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4409012690501409650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4409012690501409650'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/03/function-within-function-in-c.html' title='Function within a Function in C++ - Everything In Its Right Place'/><author><name>Ben</name><uri>http://www.blogger.com/profile/05874593951999827643</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-7957208757133493650</id><published>2011-02-08T21:56:00.002+11:00</published><updated>2011-02-08T22:03:41.525+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='people'/><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>The business of Biarri</title><content type='html'>&lt;p class="MsoNormal"&gt;At Biarri we build mathematical optimisation products and models and we have also been building up the business over the past two years from very humble beginnings.  Below are a few more of the business lessons we have learnt growing a tech start up in Australia.&lt;/p&gt;  &lt;p class="MsoListParagraphCxSpFirst" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"&gt;&lt;span style="mso-list:Ignore"&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;       &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;Get some rhythm&lt;/b&gt; – we have used the Rockefeller Habits checklist from Verne Harnish – it gives each day, week, month, quarter and year a target and keeps the team accountable for key actions. It also means we are always watching the cash burn.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;To quote Verne “cash is oxygen”.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;This is important as we were also told very early that costs have a way of taking care of themselves if not very closely watched – this is true.&lt;/p&gt;  &lt;p class="MsoListParagraphCxSpMiddle" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"&gt;&lt;span style="mso-list:Ignore"&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;       &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;Meet your competition &lt;/b&gt;– how else will you really know how to differentiate and where their weaknesses are? &lt;span style="mso-spacerun:yes"&gt; &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoListParagraphCxSpMiddle" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"&gt;&lt;span style="mso-list:Ignore"&gt;3.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;       &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;Give people space to deliver&lt;/b&gt; – give good people the space to deliver and they almost always will.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;People don’t need rules or process – they need a challenges and support.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;We have been amazed at the great work our super smart university students produce on our projects. Our customers also love it.&lt;span style="mso-spacerun:yes"&gt;   &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoListParagraphCxSpMiddle" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"&gt;&lt;span style="mso-list:Ignore"&gt;4.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;       &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;Keep low cost&lt;/b&gt; – we have had many big corporate guys come to our offices and comment on the poor paint job, old carpet or our back alley address.&lt;span style="mso-spacerun:yes"&gt;    &lt;/span&gt;They don’t seem to get it.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;You don’t need to be on level 24 to produce a great product and you can certainly sell it cheaper if you are not.&lt;/p&gt;  &lt;p class="MsoListParagraphCxSpLast" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"&gt;&lt;span style="mso-list:Ignore"&gt;5.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;       &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;Stay close to customers &lt;/b&gt;– make the calls every day to stay close to people and opportunities arise.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;We find that you need to be out speaking to people, catching up for coffee and on the phone to grow a business like ours.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-7957208757133493650?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/7957208757133493650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2011/02/business-of-biarri.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7957208757133493650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7957208757133493650'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2011/02/business-of-biarri.html' title='The business of Biarri'/><author><name>Ash Nelson</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-8344741676938420646</id><published>2010-12-30T15:46:00.005+11:00</published><updated>2011-02-01T12:25:25.454+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='curl'/><category scheme='http://www.blogger.com/atom/ns#' term='hosted solutions'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><title type='text'>Using libCurl to make web requests from a C++ program</title><content type='html'>This blog post is to share how to make a C++ program using the &lt;a href="http://curl.haxx.se/libcurl/c/"&gt;libcurl C interface&lt;/a&gt; under Windows/Visual Studio, as it is a little non-trivial.&lt;br /&gt;&lt;br /&gt;The libcurl API lets you transfer files to a server and call exposed functions outside of a browser context.  Because we are using CherryPy with &lt;a href="http://en.wikipedia.org/wiki/Basic_access_authentication"&gt;basic user authentication&lt;/a&gt; as our web platform, I needed to be able to call various functions such as the one I'm using in this example: "get_result".  The equivalent Linux curl command line would be:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;curl --user user:password  "httpss://www.insertyourURLhere.com/get_result?id=30417&amp;amp;task=9332"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;where obviously you'd change "insertyourURLhere", use the appropriate user name and password, and I've assumed "get_result" takes two arguments, "id" and "task".&lt;br /&gt;&lt;br /&gt;On Windows with Visual Studio, after downloading the libcurl source, you need to first build the libcurl lib.  To achieve this, you need to change the C++ Preprocessor definitions by removing "_USRDLL", and adding instead "CURL_STATICLIB".&lt;br /&gt;&lt;br /&gt;Now, in your own program, add the C++ preprocessor definition "CURL_STATICLIB", link with libcurl.lib as well as with ws2_32.lib, winmm.lib and wldap32.lib.  This will avoid link errors.&lt;br /&gt;&lt;br /&gt;The following C++ code shows how to make requests to the web server "get_result" function, using HTTP POST.  It demonstrates using a callback function (to retrieve the text of the server's response), passing the URL encoded arguments (encoded using curl_easy_escape), authenticating using basic authentication, and gathering timing diagnostics.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;#include "curl.h"&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;#define YOUR_URL "https://www.insertyourURLhere.com/"&lt;br /&gt;#define USER_AND_PWD "user:password"&lt;br /&gt;&lt;br /&gt;static string gs_strLastResponse;&lt;br /&gt;&lt;br /&gt;// Callback to gather the response from the server.  Comes in chunks (typically 16384 characters at a time), so needs to be stitched together.&lt;br /&gt;size_t function_pt(void *ptr, size_t size, size_t nmemb, void * /*stream*/)&lt;br /&gt;{&lt;br /&gt; gs_strLastResponse += (const char*)ptr;&lt;br /&gt; return size * nmemb;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool CallServerWithCurl(string strData1, strData2, string&amp;amp; strErrorDescription)&lt;br /&gt;{&lt;br /&gt; CURL* curl = curl_easy_init();&lt;br /&gt; if (curl == NULL)&lt;br /&gt; {&lt;br /&gt;     strErrorDescription = "Unable to initialise Curl";&lt;br /&gt;     return false;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; curl_easy_setopt(curl, CURLOPT_URL, (YOUR_URL + "get_result").c_str());&lt;br /&gt; curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);&lt;br /&gt; curl_easy_setopt(curl, CURLOPT_USERPWD, MY_USER_AND_PWD);    // set user name and password for the authentication&lt;br /&gt;&lt;br /&gt; char* data1 = curl_easy_escape(curl, strData1.c_str(), 0);&lt;br /&gt; char* data2 = curl_easy_escape(curl, strData2.c_str(), 0);&lt;br /&gt; string strArguments = "id=" + data1 + "&amp;amp;task=" + data2;&lt;br /&gt; const char* my_data = strArguments.c_str();&lt;br /&gt;&lt;br /&gt; curl_easy_setopt(curl, CURLOPT_POSTFIELDS, my_data);&lt;br /&gt; curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(my_data));   // if we don't provide POSTFIELDSIZE, libcurl will strlen() by itself&lt;br /&gt;&lt;br /&gt; curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);     // enable verbose for easier tracing&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;  gs_strLastResponse = "";&lt;br /&gt;&lt;/code&gt;&lt;code&gt;  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_pt);        // set a callback to capture the server's response&lt;br /&gt;&lt;br /&gt; CURLcode res = curl_easy_perform(curl);&lt;br /&gt;&lt;br /&gt; // we have to call twice, first call authenticates, second call does the work&lt;br /&gt; res = curl_easy_perform(curl);&lt;br /&gt;&lt;br /&gt; if (res != CURLE_OK)&lt;br /&gt; {&lt;br /&gt;     strErrorDescription = "Curl call to server failed";&lt;br /&gt;     return false;&lt;br /&gt; }&lt;br /&gt; if (!DoSomethingWithServerResponse(gs_strLastResponse))&lt;br /&gt; {&lt;br /&gt;     strErrorDescription = "Curl call to server returned an unexpected response";&lt;br /&gt;     return false;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // extract some transfer info&lt;br /&gt; double speed_upload, total_time;&lt;br /&gt; curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &amp;amp;speed_upload);&lt;br /&gt; curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &amp;amp;total_time);&lt;br /&gt; fprintf(stderr, "Speed: %.3f bytes/sec during %.3f seconds\n", speed_upload, total_time);&lt;br /&gt;&lt;br /&gt; curl_easy_cleanup(curl);&lt;br /&gt;&lt;br /&gt; return true;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Libcurl building and linking tips were found at &lt;a href="http://curl.haxx.se/mail/lib-2007-04/0120.html"&gt;http://curl.haxx.se/mail/lib-2007-04/0120.html&lt;/a&gt; and elsewhere.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-8344741676938420646?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/8344741676938420646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/12/using-libcurl-to-make-web-requests-from.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8344741676938420646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8344741676938420646'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/12/using-libcurl-to-make-web-requests-from.html' title='Using libCurl to make web requests from a C++ program'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-6201966435489878471</id><published>2010-12-23T16:17:00.005+11:00</published><updated>2010-12-23T16:37:16.460+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computer science'/><title type='text'>Computer Science Journal Recommendations</title><content type='html'>I was just contemplating this last night and I think my slightly before new years resolution is to read one journal paper a week as part of my "Biarri Day learning." :)&lt;br /&gt;&lt;br /&gt;I'm going to start with &lt;a href="http://www.jair.org/contents.html"&gt;The Journal of AI Research&lt;/a&gt;  and &lt;a href="http://www.kybernetika.cz/content.html"&gt;Kybernetika&lt;/a&gt;  because they publish everything for free online and are reputable / &lt;a href="http://www.cs.iit.edu/~xli/CSJournalsRanking.htm"&gt; well ranked&lt;/a&gt;. Well... and maybe because Kybernetika has a fantastic sounding name. :)&lt;br /&gt;&lt;br /&gt;If anyone else can recommend a useful and readable Computer Science / AI related journal please comment! &lt;br /&gt;&lt;br /&gt;Loki&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-6201966435489878471?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/6201966435489878471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/12/computer-science-journal.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6201966435489878471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6201966435489878471'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/12/computer-science-journal.html' title='Computer Science Journal Recommendations'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1313631931080225304</id><published>2010-12-23T12:02:00.002+11:00</published><updated>2010-12-23T12:10:29.063+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mapinfo'/><title type='text'>MapInfo tips</title><content type='html'>I've had reason to manipulate some spatial data recently using &lt;a href="http://www.pbinsight.com/products/location-intelligence/applications/mapping-analytical/mapinfo-professional/"&gt;MapInfo Professional&lt;/a&gt;, and picked up a few tips that I thought might be useful to someone else one day:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Some good tips for using SQL Select can be found here: &lt;a href="http://www.sgsi.com/MIUserGroup/SGSI_SQLSelect.htm"&gt;http://www.sgsi.com/MIUserGroup/SGSI_SQLSelect.htm&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;You can use SQL conditions that select objects by their spatial properties.  Use syntax like: Str$(obj) = "line", and Str$(obj) = "point", Str$(obj) = "region" etc.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;To change the projection, use File / Save Copy As and click the Projection button.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Get used to using the arrow keys to pan around the map, and the mousewheel to zoom in and out - this saves having to switch to the Grabber tool all the time to move around.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Press "S" to go into "Snap" mode.  This is very useful when creating lines, to make sure they attach to nodes (note the nodes don't have to be in the same layer when your lines snap).  When in Snap mode you will see the text "SNAP" in the status bar at the bottom of the MapInfo main window.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;The menu item Map / Change View is useful to go straight to a given lat/long coordinate.  (It centres the view on your entered coordinate).  You will need to be careful however if you have multiple layers open that have different coordinates or projections.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;To merge two different layers:&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;                 * First, the tables have to have the same structure.  Use Table / Maintenance / Table Structure to add and remove fields as required.&lt;br /&gt;                 * Then use either Table / Update Column or Table / Append Rows To Table.  If using Update Column on node/arc layers (to copy data from the node or arc objects of one table to the corresponding objects on another), I found using Join with Intersects worked best.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;To separate a single layer that contains nodes and arcs into two layers:&lt;/li&gt;&lt;/ul&gt;                * Run an SQL Select query with the condition Str$(obj) = "line" - this will select only the arcs. &lt;br /&gt;               * Then Save the selection to a separate file (which will be the arcs layer), and delete the selected arcs from your original layer (leaving only the nodes).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1313631931080225304?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1313631931080225304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/12/mapinfo-tips.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1313631931080225304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1313631931080225304'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/12/mapinfo-tips.html' title='MapInfo tips'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-698564251345910946</id><published>2010-12-07T12:14:00.003+11:00</published><updated>2010-12-07T14:53:25.691+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='postgis'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Database vs pure python performance</title><content type='html'>I was just looking through some of our common code and noticed some maths code in python that I knew could be replaced by a function in our geo-database, Postgis. However I wondered what the performance difference between calling out to some C code via the database and doing a simple bit of maths in python would be. The code has no loops, is simple and should be very fast. &lt;br /&gt;&lt;br /&gt;It turns out the database approach is around 100X slower... &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; timeit.Timer(&amp;#39;common.lat_long_distance_db(db_wrap, 144.865906, 144.865237, -37.836183, -37.831359 random.random())&amp;#39;, &lt;br /&gt;         &amp;quot;from __main__ import common, db_wrap, random&amp;quot;).timeit(10000)&lt;br /&gt;2.001802921295166&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; timeit.Timer(&amp;#39;common.lat_long_distance(144.865906, 144.865237, -37.836183, -37.831359 random.random())&amp;#39;, &lt;br /&gt;         &amp;quot;from __main__ import common, random, db_wrap&amp;quot;).timeit(10000)&lt;br /&gt;0.02936482429504394&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I would suggest this isn't the right way to use the DB! :) &lt;br /&gt;&lt;br /&gt;If we write a function where we just select a constant value from the database we can find the call over head of the database calls and remove the postgis process and parsing cost.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;timeit.Timer(&amp;#39;lat_long_distance_db_just_select(db_wrap, 144.865906, 144.865237, -37.836183, -37.831359 random.random())&amp;#39;, &lt;br /&gt;         &amp;quot;from __main__ import db_wrap, random, lat_long_distance_db_just_select&amp;quot;).timeit(10000)&lt;br /&gt;1.4460480213165283&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Large percentage of overhead. &lt;br /&gt;&lt;br /&gt;Seems to suggest that I should look into the difference between selecting out the data, apply the python function then updating the db with results. I suspect apply the postgis functions to data that is already in the db instead of looping in python will be best, but empirical data is enlightening!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-698564251345910946?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/698564251345910946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/12/datebase-vs-pure-python-performance.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/698564251345910946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/698564251345910946'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/12/datebase-vs-pure-python-performance.html' title='Database vs pure python performance'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-5383892902454176203</id><published>2010-12-03T16:39:00.002+11:00</published><updated>2010-12-03T16:45:44.335+11:00</updated><title type='text'>Cherrypy and coping with Internet Exporer Cache issues</title><content type='html'>Ahh, IE caches Ajax requests. This is rather confusing when you call a function and expect it to execute something on the server but instead it immediately returns. Luckily, it's very simple to fix when using cherrypy. Just add the following code to your .conf file for the functions you don't want to cache, or apply it globally.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;tools.response_headers.on = True&lt;br /&gt;tools.response_headers.headers = [('Expires', 'Sun, 19 Nov 1985 05:00:00 GMT'),&lt;br /&gt;('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'),&lt;br /&gt;('Pragma', 'no-cache')]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Loki&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-5383892902454176203?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/5383892902454176203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/12/cherrypy-and-coping-with-internet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5383892902454176203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5383892902454176203'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/12/cherrypy-and-coping-with-internet.html' title='Cherrypy and coping with Internet Exporer Cache issues'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-7727704768580781909</id><published>2010-12-03T16:12:00.003+11:00</published><updated>2010-12-03T16:35:59.638+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Array Comparison in PostgreSQL</title><content type='html'>I just had an input table, where I wanted to map multiple items to a single code. &lt;br /&gt;&lt;br /&gt;I had foo and bar which I wanted to map to baz. They could be in any order though, (bar and foo) so I couldn't just aggregate a string and compare those. &lt;br /&gt;&lt;br /&gt;Instead I used array_agg and array_sort&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;select i.id, m.type from &lt;br /&gt;    (select id_mot1 AS id, array_sort(array_agg(annoying_types)) AS input_type, &lt;br /&gt;        from &lt;br /&gt;        (select m.* from import_temp as m order by m.id_input, m.id asc) AS t &lt;br /&gt;        group by id_input) as i, &lt;br /&gt;type_map as m where i.input_type = array_sort(m.input_type) ;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I create an array of the grouped values using array_agg, sort it using array_sort and then compare it to the sorted mapping. Sorting on insert into the mapping would make more sense though.&lt;br /&gt;&lt;br /&gt;array_sort is from the post by David Fetter at &lt;a href="http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks#General_array_sort"&gt; PostgreSQL SQL Tricks.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Loki&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-7727704768580781909?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/7727704768580781909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/12/arrays-comparison-in-postgresql.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7727704768580781909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7727704768580781909'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/12/arrays-comparison-in-postgresql.html' title='Array Comparison in PostgreSQL'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-4086294253870298757</id><published>2010-11-18T18:10:00.006+11:00</published><updated>2010-11-18T18:54:21.998+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEs'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='shortcuts'/><title type='text'>Some Linux IDEs for C++</title><content type='html'>I recently went on a short excursion looking for good, lightweight IDEs for C++ in Linux, similar to my adventures with &lt;a href="http://biarri.blogspot.com/2010/07/ide-for-python.html"&gt;Python IDEs&lt;/a&gt;.  My (modest) needs are similar to my Python IDE needs, specifically however I want very good step-through debugging support, and in terms of a lightweight solution, would like a tool that doesn't have a big project/workspace overhead with the IDE creating many of it's own files (our C++ programs all have simple makefiles, with debugging info turned on and code optimisation suppressed by compiling with the -g and -O0 flags).&lt;br /&gt;&lt;br /&gt;Here is what I found:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.gnu.org/software/gdb/"&gt;GDB&lt;/a&gt; is the GNU debugger used by GCC and actually has a text interface for step-through debugging that is actually usable - if you are very patient.  There is also a graphical interface called &lt;a href="http://www.gnu.org/software/ddd/"&gt;DDD&lt;/a&gt;, however I did not try this. &lt;/li&gt;&lt;li&gt;&lt;a href="http://projects.gnome.org/anjuta/"&gt;Anjuta DevStudio&lt;/a&gt; is an IDE for GNOME.  Debugging is activated with a plugin found under Edit/Preferences/Installed Plugins.  This IDE worked OK for me in 32 bit Linux, but failed (shutting itself down) when trying to debug under 64 bit Linux.&lt;/li&gt;&lt;li&gt;&lt;a href="http://codelite.org/"&gt;CodeLite&lt;/a&gt; is a cross-platform IDE, that seemed to work well at first, however I could not get it to respect my program's command line arguments.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.geany.org/"&gt;Geany&lt;/a&gt; is an IDE with a clean presentation that I have used in the past just to look at C++ code; debugging is supposedly achieved with a &lt;a href="http://plugins.geany.org/geanygdb.html"&gt;plug-in&lt;/a&gt; called GeanyGDB, however I did not try it.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.codeblocks.org/"&gt;Code::Blocks&lt;/a&gt; is a very mature IDE that is a little chunky-looking in appearance (though it's download size suggests it is more lightweight than the IDEs listed above), and seemingly requires you to make various project files (at least that seemed the easiest way to get it to a point where I could use it for debugging).  However, the debugging does work rather well (and it even supports the &lt;a href="http://biarri.blogspot.com/2010/04/mighty-middle-click.html"&gt;Mighty Middle Click&lt;/a&gt;).  Though it does not seem to show variable internals for more complex variables (dereferencing STL iterators would be nice, but maybe I'm missing something there), this will be my IDE of choice in Linux for a little while at least, I think.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Trying out these IDEs in Linux has, if nothing else, emphasised to me just how impressive, powerful and usable Microsoft's &lt;a href="http://www.microsoft.com/visualstudio/en-us/"&gt;Visual Studio&lt;/a&gt; is (for Windows only, of course).  I have used Visual Studio in it's various incarnations since 1996, and it keeps upping the bar even with the 2010 version with awesome debugging features like "Pin to source", which lets you make little variable watch windows right alongside the line of code that it is relevant for.  It offers so much at a glance (local variable values, current stack, etc) in an elegant way, and one quickly becomes used to being able to look deep into the internals of STL data types, change the line of execution or a variable's value while debugging, and the like.&lt;br /&gt;&lt;br /&gt;One thing that would be really good is if all these IDEs standardised their debugging hotkeys; as the table below shows (where I have also included Eric and Firebug), they are generally all different.  I think Eric's scheme is the best, as it seems logical and doesn't require any contortions with Shift and Control keys.&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt;&lt;br /&gt;&lt;/th&gt;&lt;th&gt;Start&lt;/th&gt;&lt;th&gt;Continue&lt;/th&gt;&lt;th&gt;Step&lt;/th&gt;&lt;th&gt;Step into&lt;/th&gt;&lt;th&gt;Step out&lt;/th&gt;&lt;th&gt;Stop&lt;/th&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Anjuta&lt;/td&gt;&lt;td&gt;F4&lt;/td&gt;&lt;td&gt;F4&lt;/td&gt;&lt;td&gt;F6&lt;/td&gt;&lt;td&gt;F5&lt;/td&gt;&lt;td&gt;Shift-F5&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Codeblocks&lt;/td&gt;&lt;td&gt;F8&lt;/td&gt;&lt;td&gt;Ctrl-F7&lt;/td&gt;&lt;td&gt;F7&lt;/td&gt;&lt;td&gt;Shift-F7&lt;/td&gt;&lt;td&gt;Ctrl-Shift-F7&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Visual Studio and CodeLite&lt;/td&gt;&lt;td&gt;F5&lt;/td&gt;&lt;td&gt;F5&lt;/td&gt;&lt;td&gt;F10&lt;/td&gt;&lt;td&gt;F11&lt;/td&gt;&lt;td&gt;Shift-F11&lt;/td&gt;&lt;td&gt;Shift-F5&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Eric&lt;/td&gt;&lt;td&gt;F5&lt;/td&gt;&lt;td&gt;F6&lt;/td&gt;&lt;td&gt;F7&lt;/td&gt;&lt;td&gt;F8&lt;/td&gt;&lt;td&gt;F9&lt;/td&gt;&lt;td&gt;F10&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Firebug&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;F8&lt;/td&gt;&lt;td&gt;F10&lt;/td&gt;&lt;td&gt;F11&lt;/td&gt;&lt;td&gt;Shift-F11&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-4086294253870298757?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/4086294253870298757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/11/some-linux-ides-for-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4086294253870298757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4086294253870298757'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/11/some-linux-ides-for-c.html' title='Some Linux IDEs for C++'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-179685625599039522</id><published>2010-10-11T16:22:00.004+11:00</published><updated>2010-10-22T10:01:12.865+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Tech Start Up Business Lessons</title><content type='html'>Biarri commenced as a commercial maths start up almost two years ago. In this time we have learnt a lot.&lt;br /&gt;We focus hard on deploying optimisation and quantitative analytics in accessible ways to deliver the power of mathematics quickly and cheaply. Our just launched workbench (&lt;a href="http://www.biarriworkbench.com"&gt;www.biarriworkbench.com&lt;/a&gt;) is a great example of this – providing monthly low cost rental of powerful maths engines available over a browser.&lt;br /&gt;&lt;br /&gt;While we have been building products and models we have also been building a business and have learnt a few things along the way. Below are a few of the business lessons we have learnt growing a tech start up in Australia.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Be in the cloud – because we were delivering our optimisation workbench using the cloud, we sought out cloud services for our internal business needs. Our accounting software, CRM, email and timesheets are all rented from Software as a Service companies. We learnt a lot about what makes a good web app by using these services and we saved a lot of capital cost upfront. Specifically let me say that SAASU (www.saasu.com.au) is a really good accounting system for a small business – much easier to use than MYOB or quicken in my view.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Always push back against one-sided contract terms from big corporates – we find almost always you will get at least what you ask for. In house lawyers and legal departments will always try it on, especially when they are dealing with a small business – push back hard there is always some flex&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Not all phone companies are the same – one large Australian telco sells conference calling enabled handsets while their network does not support conference (e.g. 3 way) calling. This is not disclosed up front- we found out when we tried our first conf call. Ask the question, be wary of penguins and remember Skype is your friend.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Hope these few thoughts help. There is more we are learning each day so will stick up some more thoughts soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-179685625599039522?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/179685625599039522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/10/tech-start-up-business-lessons.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/179685625599039522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/179685625599039522'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/10/tech-start-up-business-lessons.html' title='Tech Start Up Business Lessons'/><author><name>Ash Nelson</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-6668253106795608663</id><published>2010-10-04T11:36:00.003+11:00</published><updated>2010-10-04T11:57:38.274+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='cross-platform'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><title type='text'>Cross-platform development</title><content type='html'>During the course of developing Biarri’s flagship Workbench product, we’ve taken pains to ensure that our (GUI-less) optimisation “engines” work well under both Windows and Linux operating systems (so-called &lt;a href="http://en.wikipedia.org/wiki/Cross-platform"&gt;cross-platform&lt;/a&gt;).  This turns out to be relatively easy as long as you stay away from the big OS-specific frameworks (e.g. Microsoft’s MFC/COM/ATL etc).  We’ve picked up some handy tips along the way, particularly applicable to C++ development, which are worth sharing here.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Be aware of differences in &lt;span style="font-weight: bold;"&gt;line endings&lt;/span&gt; - Windows uses carriage return and line feed &lt;span style="font-weight: bold;"&gt;\r\n&lt;/span&gt;, while Linux/Unix uses just line feed &lt;span style="font-weight: bold;"&gt;\n&lt;/span&gt;. (Note that Visual Studio will show files with Linux line feeds correctly, but Notepad won't - this is one way to tell what line endings your file has in Windows).  This can be particularly important when importing data e.g. into databases where the file originates from another OS.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Always use &lt;span style="font-weight: bold;"&gt;forward slashes&lt;/span&gt; for file paths, not backslashes.  Also, file names and folder paths are &lt;span style="font-weight: bold;"&gt;case sensitive &lt;/span&gt;under Linux but not under Windows.  And don't assume there is a C: or D: drive!&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;You may have to be careful writing to &lt;span style="font-weight: bold;"&gt;temporary files and folders&lt;/span&gt;.  In Linux /tmp is often used; in Windows /[user]/AppData/local/temp (location of the TEMP environment variable – e.g. type “%TEMP%” into the start menu or Windows Explorer).  For Linux, it is sometimes necessary to manipulate a folder’s “&lt;a href="http://en.wikipedia.org/wiki/Sticky_bit"&gt;sticky bit&lt;/a&gt;” to ensure that the folder is accessible by other users (e.g. a Postgres database user) – e.g. in Python:&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-family:courier new;"&gt;os.chmod(temp_dir_name, os.stat(temp_dir_name).st_mode | stat.S_ISVTX | stat.S_IRGRP | stat.S_IROTH | stat.S_IWGRP | stat.S_IXOTH)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Be aware of the differences in&lt;span style="font-weight: bold;"&gt; file permissions&lt;/span&gt; in Windows and Linux.  In Linux files have  an “executable” bit.  &lt;span style="font-family:courier new;"&gt;chmod a+x [file] &lt;/span&gt;makes a file an exe, which can then be run with “./filename”.&lt;/li&gt;&lt;/ul&gt;For C++ development:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Name all cpp and h files in &lt;span style="font-weight: bold;"&gt;lower case&lt;/span&gt; if possible.  Files are case sensitive in Linux and this includes &lt;span style="font-family:courier new;"&gt;#include&lt;/span&gt;'s!&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;For compiling with GCC under Linux, the last line in a C++ file &lt;span style="font-weight: bold;"&gt;must be blank&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;In Linux C++ programs, general &lt;span style="font-weight: bold;"&gt;exception handling&lt;/span&gt; with &lt;span style="font-family:courier new;"&gt;catch(...) &lt;/span&gt;does not work.  You can use &lt;a href="http://www.alexonlinux.com/signal-handling-in-linux"&gt;sighandlers&lt;/a&gt; instead (see this for example), though it's not as good – it is more equivalent to an exit(), with a chance to clean up.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Beware &lt;span style="font-weight: bold;"&gt;doubles comparisons&lt;/span&gt; and inequality checking, at least in C++ programs.  Always use a delta i.e. A == B may not be the case in both Windows and Linux if they are essentially the same number so use fabs(A - B) &lt; delta, where delta is some suitably small number.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Build tips for Linux: Type "make" when you are in the directory to build the project.  This will search for a file called "Makefile" and run it. (Use "make -f filename" to make from a different makefile).  To force a recompile you can "touch" a file using "touch filename".&lt;br /&gt;To clean out all object files type "make clean" (as long as your make file defines what cleaning does...).   Use "make -j4" to run make with for concurrent jobs, to take advantage of multicore.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;In bash, to get a recursive line count of .cpp/.h files: &lt;span style="font-family:courier new;"&gt;find &lt;span style="font-style: italic;"&gt;[directory]&lt;/span&gt; -type f -name *.cpp -exec wc -l {} \; | awk '{total += $1} END{print total}'&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Differences for GCC 4.3 compiler (e.g. compared to version 4.2.4): &lt;a href="http://gcc.gnu.org/gcc-4.3/porting_to.html"&gt;http://gcc.gnu.org/gcc-4.3/porting_to.html&lt;/a&gt;. (To check your version of GCC, type gcc -v).&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-6668253106795608663?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/6668253106795608663/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/10/cross-platform-development.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6668253106795608663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6668253106795608663'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/10/cross-platform-development.html' title='Cross-platform development'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-3136862685154254264</id><published>2010-09-29T21:21:00.002+10:00</published><updated>2010-09-29T21:33:14.070+10:00</updated><title type='text'>Operations Research - Cloud Computing – The impending launch of Biarri’s WorkBench</title><content type='html'>With the impending launch of Biarri’s workbench and our ongoing close relationship with Schweppes for the daily routing of soft drink deliveries (an application of perhaps the most well known &lt;a href="http://en.wikipedia.org/wiki/Operations_research"&gt;operations research&lt;/a&gt; problem: &lt;a href="http://en.wikipedia.org/wiki/Vehicle_routing_problem"&gt;the vehicle routing problem&lt;/a&gt;), I thought that the following excerpt from a journal article submitted to the &lt;a href="http://www.worldscinet.com/apjor/"&gt;Asia Pacific Journal of Operations Research&lt;/a&gt; would be a very timely blog post. &lt;br /&gt;&lt;br /&gt;The journal article is entitled “Real-Life Vehicle Routing with Time Windows for Visual Attractiveness and Operational Robustness” and it describes the vehicle routing algorithm we have implemented for Schweppes.&lt;br /&gt;&lt;br /&gt;The excerpt details a specific example encompassing two things we are very passionate about at Biarri. First “Commercial Mathematics” – that is making OR (well not strictly just OR) work in the real world. And second, the revolutionary capabilities that the advent of &lt;a href="http://en.wikipedia.org/wiki/Cloud_computing"&gt;cloud computing&lt;/a&gt; has for the delivery of software. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;“Vehicle routing problems manifest in a remarkably wide range of commercial and non-commercial enterprises. From: industrial waste collection to grocery delivery; underground mining crew replenishment to postal and courier collection and delivery; inbound manufacturing component transportation to finished car distribution; in-home primary health care delivery to pathology specimen clearances from surgeries for analysis; and from coal seam gas field equipment maintenance to beverage distribution, to name but a few.&lt;br /&gt;&lt;br /&gt;Automated planning systems used by industry at present are predominantly client-server or desktop based applications. Such systems are often: expensive, requiring a large upfront capital investment; accompanied by a large software deployment project requiring initial and ongoing IT department cooperation; customisable to a particular organisations requirements, however commonly retain a large amount of exposed functionality due to the breadth of the existing client base; and require substantial user training as the workflow is usually not restricted in a linear fashion .... Each of these characteristics constitutes a barrier to adoption of automated planning systems, and for most small to medium enterprises these barriers prove insurmountable.&lt;br /&gt;&lt;br /&gt;With the advent of &lt;a href="http://en.wikipedia.org/wiki/Cloud_computing"&gt;cloud computing&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Software_as_a_service"&gt;software as a service (SaaS)&lt;/a&gt; these barriers are being removed. SaaS: embodies a different commercial model; has essentially no IT footprint; mandates (as vendors may never directly interact with potential clients) simple intuitive linear workflows; and involves almost no end user training beyond perhaps an optional demonstration video.&lt;br /&gt;&lt;br /&gt;The emergence of this new avenue for the delivery of optimisation based planning systems heralds, a heretofore, unparalleled opportunity for operations research practitioners to engage with a wider potential consumer base than ever before. However, the nature of the delivery mechanism requires the algorithms developed: to be robust and flexible (within their domain of application they must be capable to dealing with a wide range of input data); to have very short run times (the user base is more likely to be under time pressure than ever before); to produce high quality solutions (noting the inherent trade off between run time and  solution quality); to be wrapped in a simple linear workflow (meaning it is always obvious what the next step in the planning process is); but above all, be able to produce real-life, practically implementable solutions, without the need for user training and/or experience. &lt;br /&gt;&lt;br /&gt;For pure delivery, or pure pick up vehicle routing applications, real-life, practically implementable solutions are often synonymous with geographically compact, non-overlapping routes with little or no intra-route cross over. There are numerous reasons why such solutions are preferred .... If a customer cannot be serviced at the preferred time (e.g. the vehicle cannot get access, the customer is closed, another delivery is taking place, the customer is too busy), because the route stays in the same geographical area, it is easy to return to the customer at a later time. During busy traffic periods drivers are loathe to exit and re-enter a motorway to service individual customers. Even though such customers may be enroute to the&lt;br /&gt;bulk of the customers the route services, thus incurring a minimum of additional kilometres, they may nevertheless be far from the majority of the customers the route services. If there is severe traffic disruption, it is easier to use local alternate routes between customers in a route that is geographically compact to ensure that pick-ups or deliveries can still be made. Third party transport providers, which prefer routes to be as simple as possible, may exert some influence over the planning process. Finally ... it is easier to maintain customer relationships by assigning drivers to routes that routinely service a similar geographical area. In summary, solutions which are more visually attractive are more robust, and thus more likely to actually deliver the full extent of the cost savings that should flow from the use of automated planning systems.&lt;br /&gt;&lt;br /&gt;This paper describes an algorithm for the vehicle routing problem with time windows, …. The algorithm is: robust and flexible; fast; wrapped in a user interface utilising a simple linear workflow and so requires no user training or experience; and produces high quality, visually attractive and practically implementable solutions.”&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-3136862685154254264?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/3136862685154254264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/09/operations-research-cloud-computing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3136862685154254264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3136862685154254264'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/09/operations-research-cloud-computing.html' title='Operations Research - Cloud Computing – The impending launch of Biarri’s WorkBench'/><author><name>Ben</name><uri>http://www.blogger.com/profile/05874593951999827643</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-3367125025123304117</id><published>2010-08-30T09:11:00.006+10:00</published><updated>2010-08-30T09:56:27.192+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hosted solutions'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='workbench'/><title type='text'>Our technology stack</title><content type='html'>&lt;p&gt;&lt;br /&gt;Over the course of developing our Workbench solution we've adopted a powerful set of interconnecting components.  It’s worth mentioning what these are and how they fit together.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;  Almost all the components of the stack are free and/or open source. We want to be as platform independent as possible and not get too locked in to one technology paradigm.  This means that as much as possible, parts should be as “hot swappable” as possible - which also helps encourage strong componentisation.  Using components with mature and open/standardised interfaces is very necessary when you're crossing language boundaries (most notably, Javascript-Python and Python-C++) and client/server boundaries; otherwise you risk re-inventing the wheel.  Ideally each component we use should also still be in active development (in the IT world - with the odd highly venerable exception - if software is not growing and evolving, it's usually either dying, already in it's death throes, or extinct).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;    There’s an art to using the right tool for the job, and we’ve made mistakes.  We over-used Mako (see Loki’s &lt;a href="http://biarri.blogspot.com/2010/07/choosing-web-framework-and-what-to-do.html"&gt;blog post&lt;/a&gt;) and also originally used a slightly inferior lib for the C++ xmlrpc back end; both these mis-steps were fairly easily rectified.  Arguably, we probably still use too much C++ and not enough Python – the C++ line count dwarfs the Python line count by a considerable margin.  One last interesting point is that, at the moment, we're still eschewing use of an &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;ORM&lt;/a&gt; (Object Relational Mapping layer - such as &lt;a href="http://www.sqlalchemy.org/"&gt;SQL Alchemy&lt;/a&gt;) - time will tell whether that is a good idea or not.&lt;br /&gt;&lt;/p&gt;&lt;table style="border: medium none ; border-collapse: collapse; width: 634px; height: 512px;" border="1" cellpadding="0" cellspacing="0"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr style="height: 99pt;"&gt;&lt;br /&gt;&lt;td style="border: 1pt inset rgb(136, 136, 136); padding: 0.75pt; width: 279.75pt; height: 99pt;" width="373"&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;              Server:&lt;br /&gt;      &lt;/b&gt;&lt;br /&gt;      &lt;b&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fwww.python.org%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzduC6yrgARTk7kwHrn1J-3iFgLERA"&gt;Python&lt;/a&gt;&lt;br /&gt;      &lt;/b&gt;- language&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fwww.cherrypy.org%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzcwSTDxR4l3WX9acZbGMy4TQFqBow"&gt;&lt;b&gt;CherryPy&lt;/b&gt;&lt;br /&gt;      &lt;/a&gt;   - Python-based web app framework&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fwww.postgresql.org%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzcx6aoK3ewah2Idq4XQoO278O8A6Q"&gt;PostgreSQL&lt;/a&gt;&lt;br /&gt;      &lt;/b&gt;   - open source RDBMS&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Finitd.org%2Fpsycopg%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzfKfGqHHqxM2RDRJev2YqmkI7kTJQ"&gt;PsycoPg2&lt;/a&gt;&lt;br /&gt;      &lt;/b&gt;   - database adaptor for PostgreSQL/Python&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fdocs.python.org%2Flibrary%2Fxmlrpclib.html&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzfeML3rp-dE1RXSbKKaEJASjeubCA"&gt;&lt;b&gt;XmlRPCLib&lt;/b&gt;&lt;br /&gt;      &lt;/a&gt;   - XML RPC (used to communicate with some of the engines)&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fwww.makotemplates.org%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzcDey7kOU63YYzLhrY-i0Mq5B1KcQ"&gt;&lt;b&gt;Mako&lt;/b&gt;&lt;br /&gt;      &lt;/a&gt;   - Python template library&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Frepoze.org%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzcDSdOe_gIoRCAhUmrfypIvAHUoVw"&gt;&lt;b&gt;Repoze&lt;/b&gt;&lt;br /&gt;      &lt;/a&gt;   - Zope/WSGI Python middleware (for authentication)&lt;br /&gt;    &lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td style="border-style: inset inset inset none; border-color: rgb(136, 136, 136) rgb(136, 136, 136) rgb(136, 136, 136) -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0.75pt; width: 270.75pt; height: 99pt;" width="361"&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;Client:&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;        &lt;a href="http://www.google.com/url?q=https%3A%2F%2Fdeveloper.mozilla.org%2Fen%2FJavaScript&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzc3Jp3M1AqDrZtda8oH8xfycLq3Iw"&gt;JavaScript&lt;/a&gt;&lt;br /&gt;      &lt;/b&gt;   - client-side browser language&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;        &lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fjquery.com%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzdK4pcUKOy2xaTaw4Slh3BECp-M_w"&gt;              j&lt;b&gt;Query&lt;/b&gt;&lt;br /&gt;      &lt;/a&gt;&lt;b&gt;   &lt;/b&gt;- JavaScript library for event handling and more&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fcloudmade.com%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzeANnplHE9jpBDHWhoZxEXw1jsiLQ"&gt;&lt;b&gt;Cloudmade&lt;/b&gt;&lt;br /&gt;      &lt;/a&gt;   - OSM map provider/server&lt;br /&gt;    &lt;/span&gt;&lt;/p&gt;&lt;p  style="font-family:times new roman;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  style="font-family:times new roman;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Data Interchange:&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  style="font-family:times new roman;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt; &lt;a href="http://www.google.com/url?q=http%3A%2F%2Fwww.json.org%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzcFe31sFT_1KgYX6z0EdqYkMW3Ijg"&gt;&lt;b&gt;JSON&lt;/b&gt;&lt;/a&gt; - JavaScript Object Notation&lt;/span&gt;&lt;/p&gt;&lt;p  style="font-family:times new roman;"&gt;&lt;span style="font-size:100%;"&gt; &lt;a href="http://www.google.com/url?q=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FXML&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzcleBprrnejzRyheYbOkKg7Mptl2g"&gt;&lt;b&gt;XML&lt;/b&gt;&lt;/a&gt; - eXtensible Markup Language&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style="border-style: inset inset inset none; border-color: rgb(136, 136, 136) rgb(136, 136, 136) rgb(136, 136, 136) -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0.75pt; width: 361.5pt; height: 99pt;" width="482"&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;Mathematical Engines:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;      Mostly in C++ using &lt;/span&gt;&lt;span style="font-size:85%;"&gt;STL&lt;/span&gt;&lt;br /&gt;  &lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fsourceforge.net%2Fapps%2Fmediawiki%2Fcppunit%2Findex.php%3Ftitle%3DMain_Page&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzfUVEgxk0Q7XkY6y6owEhAfxOif4g"&gt;CppUnit&lt;/a&gt;&lt;br /&gt;      &lt;/b&gt;- C++ library for unit testing&lt;/span&gt;&lt;br /&gt;  &lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fwww.gdal.org%2Fogr%2F&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzdzfaDN3JINhsIq3xMg96e5xlrvnQ"&gt;OGR&lt;/a&gt;&lt;br /&gt;      &lt;/b&gt;   - map data library, part of GDAL - used to read map data&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://xmlrpc-c.sourceforge.net/"&gt;Libxmlrpc-c&lt;/a&gt;&lt;br /&gt;      &lt;/b&gt;   - C++ back end for XMLRPC - used by a running process to communicate   with the front end via Python&lt;br /&gt;    &lt;/span&gt;&lt;br /&gt;  &lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:85%;"  &gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-3367125025123304117?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/3367125025123304117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/08/our-technology-stack.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3367125025123304117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3367125025123304117'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/08/our-technology-stack.html' title='Our technology stack'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1508807286728941337</id><published>2010-08-09T14:59:00.006+10:00</published><updated>2011-02-08T16:19:25.940+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design - Open up a World'/><title type='text'>Logos</title><content type='html'>&lt;span style="font-weight: bold;"&gt;The word that explains&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cXnXH4SDQSQ/TF-aFtdqDnI/AAAAAAAAACo/wA-Gim_udqA/s1600/bia-curves.png"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 134px;" src="http://2.bp.blogspot.com/_cXnXH4SDQSQ/TF-aFtdqDnI/AAAAAAAAACo/wA-Gim_udqA/s200/bia-curves.png" alt="" id="BLOGGER_PHOTO_ID_5503286692564045426" border="0" /&gt;&lt;/a&gt;Logos (&lt;span style="font-weight: bold;"&gt;λὀγοσ&lt;/span&gt;) is a Greek word that can be translated as "&lt;span style="font-weight: bold;"&gt;the word that explains&lt;/span&gt;”. Logo, as we have come to understand it means to produce meaning and which unifies a concept with a visual design. In ancient Greece, for Philosopher &lt;span style="font-weight: bold;"&gt;Heraclitus&lt;/span&gt; "Logos" was the place where the universal belongs. The universe can be seeing as chaos, as a river that flows constantly and never repeats the same pattern. But if we all head towards the "logos" we would achieve a universal way to understand the world. In order to see things in the same common way, we should "homo-logate" (&lt;span style="font-weight: bold;"&gt;ὁμολουεῖν&lt;/span&gt;) become one to the logos (homogeneous). &lt;br /&gt;&lt;br /&gt;In post-industrial times, Logo is the word that unifies a group of people working in a project under a name, usually represented through an icon, which is easy to identify. &lt;br /&gt;Heraclitus was worried about &lt;span style="font-weight: bold;"&gt;each one having its own logo &lt;/span&gt;so as to avoid chaos. In modern times, a business, a company, a project requires the same unification or "homogenisation" in order to ensure that all the people involve are on the same boat.  For a project to run properly, it needs "Logos".&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cXnXH4SDQSQ/TF-aNvNjPsI/AAAAAAAAACw/97MPOIBfwsw/s1600/biarry-buterfly.png"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 164px;" src="http://3.bp.blogspot.com/_cXnXH4SDQSQ/TF-aNvNjPsI/AAAAAAAAACw/97MPOIBfwsw/s200/biarry-buterfly.png" alt="" id="BLOGGER_PHOTO_ID_5503286830472314562" border="0" /&gt;&lt;/a&gt;When a graphic designer creates a logo, is not simply doing a nice drawing to promote a company; instead, it is discovering that universal symbol that belong to everyone involve in the project and unifies the project it self. There is nothing about aesthetics or make up; instead, it is the ultimate creative process, the beginning of the universal value that produces identification or "homogenisation" for the group. For this reason, an assembly line would never fit into an artistic conception; as in nature and life, there is no order in what should be first or second, instead, everything works and belong to a coherent collaborative process: The artist discovers the symbol that drives us all towards the universal and in this light it is where everyone can see themselves as belonging to the same thing.&lt;br /&gt;&lt;br /&gt;  Another linguistic particularity is the word “project”, commonly used in our times. “Pro-eject” means to head towards something. If “logo” is the symbol that identifies the group, a “project” should be coherent with the logo, with its symbol. For example: an olive tree can identify a company that produces olive oil. There is a direct correlation in what this company does and its symbol. But we do not always find this obvious and direct relationship; usually, logos and promotional images are based on the concept of manipulation, distortion of the reality and many companies use their logo as an aesthetic camouflage. A very clear case of this is commonly identifiable in Petrol companies, most of them use green flowers or vivid environmental colours to mislead consumers into thinking their products are environmentally sound.&lt;br /&gt;&lt;br /&gt;The idea of manipulation thought images evolved with the time responding to consumer’s expectations. Few decades ago, petrol companies where identified with symbols of power/energy while these days the new black is green.&lt;br /&gt;&lt;br /&gt;Beyond moral, a designer is a communicator, not a manipulator. When Heraclitus invokes Greeks to follow the Logos (λὀγοσ) I guess he was hoping for a more creative world. A true artist should be a demiurge, someone capable of finding creativity between two worlds: the fluent chaotic river and universal beauty of the tree on the other side of the river.&lt;br /&gt;That is what we become when we advocate to a pro-eject.&lt;br /&gt;&lt;br /&gt;read more at: &lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://sebastianbourges.com/"&gt;sebastianbourges.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1508807286728941337?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1508807286728941337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/08/logos.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1508807286728941337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1508807286728941337'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/08/logos.html' title='Logos'/><author><name>Sebastian Bourges</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://1.bp.blogspot.com/_cXnXH4SDQSQ/TAhUIEPG4wI/AAAAAAAAAAU/2MEG5NdVr58/S220/sebastian-bourges-profile.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cXnXH4SDQSQ/TF-aFtdqDnI/AAAAAAAAACo/wA-Gim_udqA/s72-c/bia-curves.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-4574615853749838464</id><published>2010-08-06T10:44:00.007+10:00</published><updated>2010-08-06T10:56:10.905+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='graphs'/><category scheme='http://www.blogger.com/atom/ns#' term='excel'/><title type='text'>The 'L' Shaped Excel Graph</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="color:#0000EE;"&gt;&lt;u&gt;&lt;br /&gt;&lt;/u&gt;&lt;/span&gt;&lt;/div&gt;I recently had to develop a graphical report in Excel that was required to fit perfectly on a single A4 page for printing purposes. A lot of information was supposed to fit on this page, so using the space well was very important. After the initial formatting was reviewed it was decided that one graph in particular needed to be bigger and clearer. With a bit of reshuffling the final space available for this graph was a big ‘L’ shape at the bottom of the page.&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_JwmWYDvt8gc/TFtblfAF6DI/AAAAAAAAAKw/lPW_q-HkEY4/s1600/LSpace.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 242px; height: 156px;" src="http://4.bp.blogspot.com/_JwmWYDvt8gc/TFtblfAF6DI/AAAAAAAAAKw/lPW_q-HkEY4/s320/LSpace.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5502092069298366514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;A perfect amount of space but unfortunately part of the ‘L’ would have to go to waste – unless some sort of ‘L’ shaped graph could be created…&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;The ‘L’ Shaped Graph:&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;a href="http://1.bp.blogspot.com/_JwmWYDvt8gc/TFtb-cZKKTI/AAAAAAAAALA/pBVAb1O9nWA/s1600/LGraph.jpg"&gt;&lt;img src="http://1.bp.blogspot.com/_JwmWYDvt8gc/TFtb-cZKKTI/AAAAAAAAALA/pBVAb1O9nWA/s400/LGraph.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5502092498094926130" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 169px; " /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p class="MsoNormal"&gt;The ‘L’ shaped graph utilises the extra space by moving the title and legend away from the actual data. This results in the data having space to expand and become more readable (very important with this detailed ‘Clustered-Stacked Column Graph’). It is important to note that once created, it is very difficult to edit this graph and it should most likely be treated as read only.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;How it is done:&lt;/p&gt;  &lt;p class="MsoListParagraphCxSpFirst" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Finalise the data for your chart. (The legend will no longer update to reflect changes in the data once we are done)&lt;/li&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Create a copy of the chart&lt;/li&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Delete all axis labels and gridlines on the copy.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;      &lt;p class="MsoNormal" style="margin-left:18.0pt"&gt;Now comes the trick – removing the data without affecting the legend:&lt;/p&gt;  &lt;p class="MsoListParagraphCxSpFirst" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;To do this, select each data point on the copy (not data series) and right-click: Format data point. When you first click a data point it most likely selects the entire series, so click again to target just the data point. If you were to do this for the series then the legend would update to reflect the change, which we don’t want.&lt;/li&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Select No-fill in the Fill tab. This will white out that data point. Do this for all the data points until just the legend and title remain on the copy.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;      &lt;p class="MsoNormal"&gt;Now to fix up the original chart:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Select the legend and title of the original chart and delete&lt;/li&gt;&lt;li&gt;Resize to utilise the space&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;The rest is just simple formatting to customise the graph to your needs. Here are some of the things I did:&lt;/p&gt;  &lt;p class="MsoListParagraphCxSpFirst" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Select the legend of the copy and right-click: Format legend&lt;/li&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;In Legend Options: Legend Position select ‘Top’.&lt;/li&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Now resize the legend of the copied chart to whatever you like. You may notice that the chart area, although blank, is still selectable and may be an annoyance while resizing other aspects of the copy. This can not be deleted however you can resize it to be very tiny in one of the corners of that graph.&lt;/li&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Remove the borders of both the original graph and the copy. Right-click: Format Chart area: Border Colour: No line.&lt;/li&gt;&lt;li&gt;&lt;span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri; mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"&gt;&lt;span style="mso-list:Ignore"&gt;&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Now create borders to surround the ‘L’ shaped chart on the spreadsheet itself to make it appear like the original and the copy are joined.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The process of whiting out each data point can be very tedious. In practice I created this graph with VBA to automate the process. There are some more tricks required if using VBA for the whole graph however I won’t go into them here. Like all VBA, heavy use of the macro recorder, trial and error, a little blind luck and a lot of patience go a long way.&lt;/p&gt;&lt;/div&gt;&lt;p class="MsoNormal"&gt; &lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-4574615853749838464?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/4574615853749838464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/08/l-shaped-excel-graph.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4574615853749838464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4574615853749838464'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/08/l-shaped-excel-graph.html' title='The &apos;L&apos; Shaped Excel Graph'/><author><name>Steven</name><uri>http://www.blogger.com/profile/04508368748951926559</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_JwmWYDvt8gc/TFtblfAF6DI/AAAAAAAAAKw/lPW_q-HkEY4/s72-c/LSpace.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-6821432193208011781</id><published>2010-07-27T11:44:00.004+10:00</published><updated>2010-08-02T09:27:43.027+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEs'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>An IDE for Python</title><content type='html'>For some time now I have been trying to find a decent IDE with step-through debugging support for Python.  I've wanted it for Linux, but Windows support would also be a bonus.&lt;br /&gt;&lt;br /&gt;There’s &lt;a href="http://stackoverflow.com/questions/126753/is-there-a-good-free-python-ide-for-windows"&gt;some debate&lt;/a&gt; about the need for an IDE for Python, which (as a veteran of C++ development with Visual Studio) I am still pondering.  I get that Python is a higher level language (umm, that’s why I’m using it), but the central problem of ironing out the kinks in the business/engine logic of my code is never going to go away.  It really makes me wonder what size and types of code bases the IDE/debugger naysayers are building.&lt;br /&gt;&lt;br /&gt;People also talk about &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; with &lt;a href="http://wiki.python.org/moin/IntegratedDevelopmentEnvironments"&gt;PyDev&lt;/a&gt;, but I’m deterred by the reputedly formidable learning curve, the reportedly sluggish performance, and the &lt;a href="http://www.protocolostomy.com/2010/05/13/python-ide-frustration/"&gt;apparent bloat&lt;/a&gt; of it.  I wanted something lighter, but still free.  And I didn’t want something that would require a big project hierarchy, settings tweakings etc, just to run a small Python script.  I don’t think my needs are outlandish: easy thing should be easy, hard things should be possible...&lt;br /&gt;&lt;br /&gt;This &lt;a href="http://spyced.blogspot.com/2005/09/review-of-6-python-ides.html"&gt;comparison of Python IDEs&lt;/a&gt; – the first hit on Google – seems good but is 5 years old (ancient in software development terms).  And the &lt;a href="http://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments#Python"&gt;Wikipedia comparison table&lt;/a&gt; is just the basic facts, ma’am.  The &lt;a href="http://wiki.python.org/moin/IntegratedDevelopmentEnvironments"&gt;Python.org list of IDEs&lt;/a&gt; is better, but without some sort of detail or commentary it's difficult to figure out what's best for your needs, and parts of it are out of date.  Mile long feature lists are all well and good, but how well do the features do what they're supposed to do?&lt;br /&gt;&lt;br /&gt;So I embarked on a trial of a few of the free IDEs out there.  First stop was &lt;a href="http://sourceforge.net/projects/spe/"&gt;SPE&lt;/a&gt; – “Stani’s Python Editor”... which I couldn’t get installing.  I know, I know, in Linux Land you’ve got to be prepared to tinker in the innards with spanner in hand... but a frustrating hour or two later, no go.  Perhaps because this tool doesn’t seem to be actively developed any more (as I found out afterwards).  Next I tried &lt;a href="http://boa-constructor.sourceforge.net/"&gt;Boa Constructor&lt;/a&gt;.  It installed, and first impressions were cautiously positive, though it felt like beta software to me.  Sure enough after trying to use it in anger the pain points came – I couldn’t figure out the rhyme or reason why it wouldn’t just run the Python script I had open, I had to constantly restart, breakpoints weren’t always respected, etc.  Overall it seems more aimed at GUI building than running scripts.&lt;br /&gt;&lt;br /&gt;Next was the &lt;a href="http://eric-ide.python-projects.org/"&gt;Eric IDE&lt;/a&gt;.  Eric installs with just a simple “apt-get install eric”.  The Python file you have open runs with “Start/Debug Script...”  Breakpoints and stepping through just work (in fact, debugging is an absolute breeze).  Lines with Python parse errors get a little bug icon on them in the editor margin (cute, but also handy).  It’s not perfect by any means – it takes a while to start up, it occasionally automatically breaks at places where you have no breakpoints, etc etc.  It’s GUI is formidable at first glance, but it’s set out logically and should seem familiar to those like me steeped in Visual Studio.  It's also still being very actively developed.&lt;br /&gt;&lt;br /&gt;One interesting aspect of Eric's editor is that it uses rich text with proportionally spaced fonts, in contrast to the plain monospaced font that most code editors sport.  This might seem sacrilegious to some, but it seems to work fine for me, and in fact lets me see more code on the screen.  It's not so good for &lt;a href="http://en.wikipedia.org/wiki/ASCII_art"&gt;ASCII art&lt;/a&gt; though.&lt;br /&gt;&lt;br /&gt;Obviously I haven’t tried trials of the commercial IDEs out there – Komodo Edit, WingWare, etc, and I’d be curious what "killer features" (that work out of the box!) they have that Eric doesn’t.  But for now, the journey’s over, with a clear winner.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-6821432193208011781?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/6821432193208011781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/07/ide-for-python.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6821432193208011781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6821432193208011781'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/07/ide-for-python.html' title='An IDE for Python'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-5892674880742703716</id><published>2010-07-06T15:50:00.003+10:00</published><updated>2010-07-06T17:10:27.724+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='workbench'/><title type='text'>Choosing a web framework and what to do about templates</title><content type='html'>In the ongoing evolution of the workbench I've solved some interesting problems and found some hard ones I haven't solved yet. I also made some poor choices and later found more elegant solutions. All this is a learning process and I'd like to share some of those findings in this series. I'll cover templates, web framework choices and making your own widgets. &lt;br /&gt;&lt;br /&gt;Templates:&lt;br /&gt;&lt;br /&gt;Originally I searched for the most elegant and expressive templating language for what I needed to do and found &lt;a href="http://www.makotemplates.org/"&gt;Mako&lt;/a&gt;. It's fast, good for simple interpolation and some basic control structures. However, after trying to write even one of our basic workflows in it, I was less enthused. I needed a range of slightly dodgy hacks to get what I wanted out. &lt;br /&gt;&lt;br /&gt;For instance, I wanted to have a mako function put a piece of text (javascript) in a buffer and output it later (in the head section). I found a way of doing this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%!&lt;br /&gt;    def string_buffer(fn, target_buffer=&amp;#39;html_buf&amp;#39;):&lt;br /&gt;        def decorate(context, *args, **kw):&lt;br /&gt;            context[&amp;#39;attributes&amp;#39;][target_buffer]  = runtime.capture(context, fn, *args, **kw)&lt;br /&gt;            return &amp;#39;&amp;#39;        &lt;br /&gt;        return decorate&lt;br /&gt;%&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%def name=&amp;quot;doc_ready_js()&amp;quot; decorator=&amp;quot;partial(string_buffer, target_buffer=&amp;#39;doc_ready_buf&amp;#39;)&amp;quot;&amp;gt;&lt;br /&gt;    ${caller.body()}&lt;br /&gt;&amp;lt;/%def&amp;gt;&lt;br /&gt;&amp;lt;%def name=&amp;quot;main_js()&amp;quot; decorator=&amp;quot;partial(string_buffer, target_buffer=&amp;#39;main_js_buf&amp;#39;)&amp;quot;&amp;gt;&lt;br /&gt;    ${caller.body()}&lt;br /&gt;&amp;lt;/%def&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Needing to use decorators, partial function application and weird context/global variable magic for quite simple features freaked me out enough and convinced me to hunt for a better solution. I wanted the simple to be easy and the hard to be possible. The template was making the the simple hard. I looked at a pile of templating languages and I still liked Mako the most out of them, but decided after reading &lt;a href="http://bitbucket.org/tavisrudd/throw-out-your-templates/src/tip/throw_out_your_templates.py"&gt; this wonderful rant by by Tavis Rudd&lt;/a&gt; that the solution is obvious: Do simple stuff with templates if you need to, but mostly avoid them. &lt;br /&gt;&lt;br /&gt;The clearest way to demonstrate the advantages of a pure python solution is with code, both sections of code generate the same simplified workflow: &lt;br /&gt;&lt;br /&gt;The Mako:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%namespace name=&amp;quot;zui&amp;quot; file=&amp;quot;zui.mako&amp;quot;/&amp;gt;&lt;br /&gt;&amp;lt;%namespace name=&amp;quot;importer&amp;quot; file=&amp;quot;importer.mako&amp;quot;/&amp;gt;&lt;br /&gt;&amp;lt;%namespace name=&amp;quot;widgets&amp;quot; file=&amp;quot;widgets.mako&amp;quot;/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%inherit file=&amp;quot;workflow_wrapper.mako&amp;quot;/&amp;gt;&lt;br /&gt;&amp;lt;%def name=&amp;quot;workflow()&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;%&lt;br /&gt;        current_workflow_id = attributes[&amp;#39;get_new_id&amp;#39;]()&lt;br /&gt;        attributes[&amp;#39;workflow_steps&amp;#39;][current_workflow_id] = [[],[],[]]&lt;br /&gt;        grid = attributes[&amp;#39;get_new_id&amp;#39;]()&lt;br /&gt;        map = attributes[&amp;#39;get_new_id&amp;#39;]()&lt;br /&gt;    %&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;%call expr=&amp;quot;importer.importer({&amp;#39;name&amp;#39;:&amp;#39;text&amp;#39;, &amp;#39;address&amp;#39;:&amp;#39;text&amp;#39;}, [&amp;#39;name&amp;#39;, &amp;#39;address&amp;#39;], r&amp;#39;&amp;#39;&amp;#39;&lt;br /&gt;    Here you need to select a CSV file with address and a name for the locations&lt;br /&gt;    you want to geocode. Names have to be unique.&amp;#39;&amp;#39;&amp;#39;, table_name,  &amp;#39;import_done()&amp;#39;)&amp;quot;&amp;gt;&amp;lt;/%call&amp;gt;&lt;br /&gt;&lt;br /&gt;    ## events are run on the client side so are javascript&lt;br /&gt;    &amp;lt;%call expr=&amp;quot;widgets.run_engine_step(&amp;#39;Geocode&amp;#39;,&lt;br /&gt;                                         {&amp;#39;onclick&amp;#39;:&amp;#39;&amp;#39;&amp;#39;calculate_button(&amp;#39;geocode_addresses&amp;#39;,&lt;br /&gt;                                         geocode_results);&amp;#39;&amp;#39;&amp;#39;},&lt;br /&gt;                                         workflow_icon=&amp;#39;geocode&amp;#39;)&amp;quot;&amp;gt;&amp;lt;/%call&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;%call expr=&amp;quot;zui.workflow_step(&amp;#39;output&amp;#39;, &amp;#39;View Results&amp;#39;)&amp;quot;&amp;gt;&lt;br /&gt;        ${widgets.grid_holder(table_name, grid)}&lt;br /&gt;        ${widgets.map_holder(map)}&lt;br /&gt;    &amp;lt;/%call&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;%zui:main_js&amp;gt;&lt;br /&gt;        function import_done(){&lt;br /&gt;            console.log(&amp;quot;run when import is finished&amp;quot;);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        function geocode_results(){&lt;br /&gt;            ${widgets.grid_init(grid, table_name, &amp;#39;&amp;#39;)}&lt;br /&gt;        }&lt;br /&gt;    &amp;lt;/%zui:main_js&amp;gt;&lt;br /&gt;&amp;lt;/%def&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The Python:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;import zui, widgets, importer, layout&lt;br /&gt;&lt;br /&gt;class Geocoder(zui.Workflow):&lt;br /&gt;    def __init__(self, the_zui, table):&lt;br /&gt;        zui.Workflow.__init__(self, the_zui, table)&lt;br /&gt;        importer.Importer(self, {'name':'text', 'address':'text'}, ['name', 'address'], r'''&lt;br /&gt;            Here you need to select a CSV file with address and a name for the locations&lt;br /&gt;            you want to geocode. Names have to be unique.''', self.table_name,&lt;br /&gt;            'Geocoder.import_done()')&lt;br /&gt;&lt;br /&gt;        ## events are run on the client side so are javascript&lt;br /&gt;        widgets.RunEngineStep(self, 'Geocode',&lt;br /&gt;                {'onclick':'''calculate_button('geocode_addresses',&lt;br /&gt;                    Geocoder.geocode_results);'''}, workflow_icon='geocode')&lt;br /&gt;&lt;br /&gt;        grid = widgets.Grid(self.table_name)&lt;br /&gt;        cm_map = widgets.Map()&lt;br /&gt;&lt;br /&gt;        self.workflow_step('output', 'View Results', container_size = "container-results1", body =&lt;br /&gt;                layout.multi_column('', grid, cm_map))&lt;br /&gt;&lt;br /&gt;        self.main_js(&lt;br /&gt;            '''&lt;br /&gt;            function import_done(){&lt;br /&gt;                console.log("run when import is finished");&lt;br /&gt;            }&lt;br /&gt;            function geocode_results(){&lt;br /&gt;                '''+grid.load()+'''&lt;br /&gt;            }&lt;br /&gt;            ''')&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It is so much easier to be expressive and elegant when you minimise the usage of templates. You can clean things up by using some of the expressive power of a multi-paradigm language and not have to do anything too strange. I still see the use for templates when you need to interpolate a few variables into a long piece of HTML. The built in python template function seems fine for this. In my next post I'll over web frameworks and what I think about widgets. You should be able to see from today's bit of code that I think they are important and hard to do with templates.&lt;br /&gt;&lt;br /&gt;Loki&lt;br /&gt;&lt;br /&gt;p.s.&lt;br /&gt;&lt;br /&gt;If you feel like relaxing after reading this, &lt;a href="http://www.youtube.com/user/MrLokiMissSeraphim"&gt;check out my band's YouTube channel.&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-5892674880742703716?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/5892674880742703716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/07/choosing-web-framework-and-what-to-do.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5892674880742703716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5892674880742703716'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/07/choosing-web-framework-and-what-to-do.html' title='Choosing a web framework and what to do about templates'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-5923352677757590465</id><published>2010-07-02T15:22:00.004+10:00</published><updated>2010-07-05T14:01:48.153+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><title type='text'>Javascript: It's actually pretty decent.</title><content type='html'>I admit it, the 'Java' in the word JavaScript has previously put me off. However, it turns out it really is rather nice and with some searching you can find some good documentation! &lt;br /&gt;&lt;br /&gt;In our midst we have a language with more in common with scheme and lisp than Java or VB! And, it's wonderful features are eloquently explained by Douglas Crockford covering &lt;a href="http://javascript.crockford.com/private.html"&gt; how to use encapsulation &lt;/a&gt; and a great series of slides by John Resig explaining  &lt;a href="http://ejohn.org/apps/learn/"&gt; closures and prototype based inheritance. &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Douglas Crockford mentions a JavaScript gotcha that bit me - "this" which you use like self in python but is implicit, is set incorrectly for inner functions. It's simple to get around though, just set a var, i.e "that" to it's value before your inner functions. &lt;br /&gt;&lt;br /&gt;I'm planning, and I admit this plan may be impeded by other more pressing concerns, to write a series of posts explaining my recent investigation of python (and some non-python) web frameworks. I also want to discuss my quest to write a application framework based on the principles of simplicity, elegance and power, for users and developers. &lt;br /&gt;&lt;br /&gt;Despite JavaScript's positives the idea of a python to JS complier like &lt;a href="http://pyjs.org/"&gt;Pyjamas&lt;/a&gt; does seem enticing. I'd be really interested in hearing comments from anyone who's used it. Python to me is still far more elegant. :)&lt;br /&gt;&lt;br /&gt;Loki&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-5923352677757590465?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/5923352677757590465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/07/javascript-its-actually-pretty-decent.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5923352677757590465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5923352677757590465'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/07/javascript-its-actually-pretty-decent.html' title='Javascript: It&apos;s actually pretty decent.'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-6197003235782998311</id><published>2010-06-28T14:36:00.002+10:00</published><updated>2010-06-28T14:53:19.136+10:00</updated><title type='text'>Merging PostScript (.ps) files</title><content type='html'>I recently had to merge the output of a bunch of academic papers I had written in Latex. Each file uses a document class from a range of academic journals (has its own title, abstract, bibliography etc). &lt;br /&gt;&lt;br /&gt;I could have made a single Latex file and &lt;span style="font-style:italic;"&gt;shoe horned&lt;/span&gt; each individual file into it, but I knew there had to be a better (less labour intensive) way.&lt;br /&gt;&lt;br /&gt;Using Latex you can create pdf (using dvipdfm) or ps (using dvips) files. There are various ways to merge pdf files (pdfsam) and ps files (using ghostscript). &lt;br /&gt;&lt;br /&gt;However the quality of the merged file I produced was always very poor. Eventually (after much googling) I found a solution&lt;br /&gt;&lt;br /&gt;gswin32c.exe -dNOCACHE -dNOPAUSE -sDEVICE=pswrite -dBATCH -sOutputFile=Output.ps Input1.ps Input2.ps Input3.ps Input4.ps&lt;br /&gt;&lt;br /&gt;The "-dNOCACHE" option preserves the quality of the output file. The output file however is very large. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;To ensure the page numbers in the merged document are continuous you can use the Latex command "\setcounter{page}{X}"&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-6197003235782998311?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/6197003235782998311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/06/merging-postscript-ps-files.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6197003235782998311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6197003235782998311'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/06/merging-postscript-ps-files.html' title='Merging PostScript (.ps) files'/><author><name>Ben</name><uri>http://www.blogger.com/profile/05874593951999827643</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-4140195439432592458</id><published>2010-06-28T11:33:00.002+10:00</published><updated>2010-06-28T11:36:11.996+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hosted solutions'/><category scheme='http://www.blogger.com/atom/ns#' term='workbench'/><category scheme='http://www.blogger.com/atom/ns#' term='point solutions'/><title type='text'>Thoughts on Point Solutions</title><content type='html'>Lately I have been thinking a bit about the advantages of small, tightly focussed web apps (so-called “point solutions”) that scratch a single little itch, versus larger, more powerful and general web apps that tend to deliver more of a total body rub.  This question is of utmost importance to a company like Biarri that needs to place its development time and effort into the best channels.&lt;br /&gt;&lt;br /&gt;The question was highlighted by a real-world problem a colleague posed recently: how to assign foursomes in rounds of Golf so that all of the players got to play with each other player at least once.  It is not trivial to construct such a solution (if one even exists) by hand, if the constraints are “tight” enough (for example, 20 players and 8 rounds). &lt;br /&gt;&lt;br /&gt;Small point solutions that solve a small but non-trivial problem like this might be fairly quick to develop and deploy on the web.  But it doesn’t take much feature creep before you get a pile of extra “features” (particular requirements for some players, minimising the number of repeated pairings, right through to printing out score cards etc); before you know it (or more precisely, after months or years of hard coding) you’d have a full-blown Golf Tournament Scheduler.  Such a web app might sell for much more, but would probably attract many less customers.  And what happened to the poor casual golfer or golf tournament organiser on a shoestring budget who just wanted to solve his or her original golf player assignment problem?&lt;br /&gt;&lt;br /&gt;In the spirit of acknowledging that the future is impossible to predict, I think Biarri must address more wide-ranging, lightweight “point solutions”, particularly at our fledgling stage.  More mini-apps with a wider potential customer base will allow us to gauge which itches need the most scratching; more complex apps, as every seasoned developer knows, seem to always cause issues and problems – in short, sheer complexity – quite out of scale with the larger code line count; not to mention being harder to use and understand for users (more buttons!)&lt;br /&gt;&lt;br /&gt;Those who have test-driven our Workbench solution will also know that, to some extent, we’re trying to have our cake and eat it to, by allowing these smaller “point” solutions to exist as workflows (standalone web apps) in their own right, whilst also being “nestable” – that is, able to be composited in a larger, more powerful workflow.  Look out for Geocoding as a sub-workflow inside Travel Time Calculation, coming to the Workbench very soon.  And who knows if the Biarri Golf Tournament Organiser will ever eventuate!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-4140195439432592458?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/4140195439432592458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/06/thoughts-on-point-solutions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4140195439432592458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4140195439432592458'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/06/thoughts-on-point-solutions.html' title='Thoughts on Point Solutions'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1647654679058971716</id><published>2010-06-24T12:28:00.007+10:00</published><updated>2010-06-28T11:36:46.452+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='COIN-OR'/><category scheme='http://www.blogger.com/atom/ns#' term='operations research'/><category scheme='http://www.blogger.com/atom/ns#' term='Linear Programming'/><title type='text'>Re-solving Linear Programs with COIN-OR</title><content type='html'>I recently had to go from solving a Linear Program (LP) once only, to modifying the problem and re-solving it multiple times.  I was using the excellent open source &lt;a href="http://www.coin-or.org/"&gt;COIN-OR&lt;/a&gt; libraries as my interface (OSI) and solver (CLP).&lt;br /&gt;&lt;br /&gt;I found that you will get obscure-looking crashes (though, to be sure, I am using the downloaded binaries, not building COIN from source) inside OSI/COIN if you do not keep around the matrix and vector objects that you use to build your LP.  It&lt;span style="font-weight: bold;"&gt; is &lt;/span&gt;safe to delete these objects if you are solving the problem once only, even before you have called &lt;span style="font-family: courier new;font-size:85%;" &gt;initialSolve()&lt;/span&gt;.  But it is &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; safe if you have to re-solve the LP!&lt;br /&gt;&lt;br /&gt;A simple generic little helper class I used for this is:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;class LPObjects&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;nbsp;  public:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;nbsp; &amp;nbsp;    CoinPackedMatrix* m_matrix;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;nbsp; &amp;nbsp;    double* m_objective, * m_col_lb, * m_col_ub, * m_rowrhs, *    m_rowsen;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;nbsp;    LPObjects()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; &amp;nbsp;   {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  &amp;nbsp; &amp;nbsp;      m_objective = NULL;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   &amp;nbsp;&amp;nbsp;     m_col_lb = m_col_ub = NULL;   &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   &amp;nbsp;&amp;nbsp;     m_rowrhs = m_rowsen = NULL;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  &amp;nbsp; &amp;nbsp;      m_matrix = NULL;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  &amp;nbsp;  }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  &amp;nbsp;  void Create(int n_cols, int n_rows, double dblInfinity)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  &amp;nbsp;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     &amp;nbsp; &amp;nbsp;   m_objective = new double[n_cols]; //the objective coefficients&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    &amp;nbsp; &amp;nbsp;    m_col_lb    = new double[n_cols]; //the column lower bounds&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     &amp;nbsp;&amp;nbsp;   m_col_ub    = new double[n_cols]; //the column upper bounds&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     &amp;nbsp; &amp;nbsp;   m_rowrhs = new double[n_rows]; //the row rhs&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    &amp;nbsp; &amp;nbsp;    m_rowsen = new char[n_rows]; //the row sense&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    &amp;nbsp; &amp;nbsp;    for (int i = 0; i &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    &amp;nbsp; &amp;nbsp; &amp;nbsp;        m_objective[i] = 0.0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    &amp;nbsp; &amp;nbsp;    for (int i = 0; i &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     &amp;nbsp; &amp;nbsp;   {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     &amp;nbsp; &amp;nbsp; &amp;nbsp;       m_col_lb[i] = 0.0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    &amp;nbsp; &amp;nbsp; &amp;nbsp;        m_col_ub[i] = dblInfinity;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    &amp;nbsp; &amp;nbsp;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   &amp;nbsp; &amp;nbsp;     m_matrix =  new CoinPackedMatrix(false, 0, 0);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     &amp;nbsp; &amp;nbsp;   m_matrix-&gt;setDimensions(0, n_cols);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  &amp;nbsp;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;si&lt;/span&gt;&lt;/span&gt; is your &lt;span style="font-family: courier new;font-size:85%;" &gt;OsiXxxSolverInterface &lt;/span&gt;object, and &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;g_LP&lt;/span&gt;&lt;/span&gt; is a static pointer to an instance of &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;LPObjects&lt;/span&gt;&lt;/span&gt;, then &lt;span style="font-size:85%;"&gt;g_LP&lt;/span&gt; can be initialised with:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-size:85%;" &gt;  &amp;nbsp;  if (g_LP == NULL)&lt;br /&gt;   &amp;nbsp; {&lt;br /&gt;     &amp;nbsp; &amp;nbsp;   g_LP = new LPObjects;&lt;br /&gt;    &amp;nbsp; &amp;nbsp;   g_LP-&gt;Create(n_cols, n_rows, si-&gt;getInfinity());&lt;br /&gt;  &amp;nbsp;  }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Create your problem representation by filling out rowrhs, rowsen, etc, and be sure to use &lt;span style="font-family: courier new;font-size:85%;" &gt;CoinPackedMatrix&lt;/span&gt;’s &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;appendRows&lt;/span&gt;&lt;/span&gt; to populate your matrix coefficients in bulk rather than using multiple calls to &lt;span style="font-family: courier new;font-size:85%;" &gt;appendRow&lt;/span&gt; (which is much much slower for larger LPs).&lt;br /&gt;&lt;br /&gt;Then load your problem into OSI with:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;si-&gt;loadProblem(*g_LP-&gt;m_matrix, g_LP-&gt;m_col_lb, g_LP-&gt;m_col_ub, g_LP-&gt;m_objective, g_LP-&gt;m_rowsen, g_LP-&gt;m_rowrhs, NULL);&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and solve with &lt;span style="font-family: courier new;font-size:85%;" &gt;si-&gt;initialSolve()&lt;/span&gt;.  Now you change the LP using the usual methods such as &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;si-&gt;setColUpper()&lt;/span&gt;&lt;/span&gt;, and re-solve with &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;si-&gt;resolve()&lt;/span&gt;&lt;/span&gt;.  Note your call to &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;si-&gt;setColUpper()&lt;/span&gt;&lt;/span&gt; (or whatever) does not directly reference the matrix or vectors of g_LP, but those objects must remain in memory! &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;&lt;span style="font-style: italic;"&gt;Code used with binary distribution “CoinAll-1.2.0-win32-msvc9” under Windows Vista / Visual C++ Express 2008.&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1647654679058971716?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1647654679058971716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/06/re-solving-linear-programs-with-coin-or.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1647654679058971716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1647654679058971716'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/06/re-solving-linear-programs-with-coin-or.html' title='Re-solving Linear Programs with COIN-OR'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-5870891840125401119</id><published>2010-06-18T22:37:00.011+10:00</published><updated>2010-06-23T09:12:46.412+10:00</updated><title type='text'>Animating the trajectory of a vehicle routing optimisation algorithm</title><content type='html'>I recently wanted to view an animation of a vehicle routing optimisation algorithm I have been working on. &lt;br /&gt;&lt;br /&gt;The algorithm uses a two phase optimisation approach. The first phase is a construction heuristic. The second phase is guided local search meta heuristic. The algorithms primary focus is to produce a visually attractive solution. Visually attractive solutions are usually synonymous with compact, non-overlapping routes with little or no intra-route cross over.&lt;br /&gt;&lt;br /&gt;A colleague suggested I have a look at &lt;a href="http://www.pygame.org/news.html"&gt;pygame&lt;/a&gt;. I hunted around to try and find an existing script that did something similar to what I wanted and found the &lt;a href="http://www.pygame.org/project-Fracture+Simulator-1298-.html"&gt;fracture simulator&lt;/a&gt;. It is always easier to modify something than to start from scratch!&lt;br /&gt;&lt;br /&gt;I was pleasantly surprised at how easy it turned out to be. I am very much a python novice, and had never heard of pygame before, but have been programming for a number of years. I was able to get the basics of my animation up and running in one evening! This far exceeded my expectations!&lt;br /&gt;&lt;br /&gt;&lt;object height="385" width="480"&gt;&lt;param name="movie" value="http://www.youtube.com/v/QbppXKGanMw&amp;hl=en_US&amp;fs=1&amp;color1=0x3a3a3a&amp;color2=0x999999"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/QbppXKGanMw&amp;hl=en_US&amp;fs=1&amp;color1=0x3a3a3a&amp;color2=0x999999" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;The python script can be viewed &lt;a href="http://docs.google.com/View?id=ddqvf66s_0cjfqm6fk"&gt;here&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;The input file used to create the uploaded animation can be viewed &lt;a href="http://docs.google.com/View?id=ddqvf66s_1ddg6pqgf"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-5870891840125401119?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/5870891840125401119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/06/part-1-animating-trajectory-of-vehicle.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5870891840125401119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5870891840125401119'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/06/part-1-animating-trajectory-of-vehicle.html' title='Animating the trajectory of a vehicle routing optimisation algorithm'/><author><name>Ben</name><uri>http://www.blogger.com/profile/05874593951999827643</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1783483121483007593</id><published>2010-06-04T11:18:00.014+10:00</published><updated>2011-02-08T16:20:31.945+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design - Open up a World'/><title type='text'>Open up a World</title><content type='html'>&lt;span&gt;This post is the start of a new series about design. There will be a new post every few days explaining the Biarri approach to design.  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;  The role of designers in modern times.&lt;/span&gt;  &lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cXnXH4SDQSQ/TAhbzML2CyI/AAAAAAAAABQ/xEYrPmi7ifc/s1600/coke-santa360.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 151px;" src="http://1.bp.blogspot.com/_cXnXH4SDQSQ/TAhbzML2CyI/AAAAAAAAABQ/xEYrPmi7ifc/s200/coke-santa360.jpg" alt="" id="BLOGGER_PHOTO_ID_5478729881698568994" border="0" /&gt;&lt;/a&gt;&lt;span&gt;The idea of graphic design is usually associated with aesthetics, the make up that’s put on top of an already developed product or concept in order to improve its image and sales. Under this point of view, design is just a part of production, an extra adjustment in the assembly line to achieve the final goal: increase sales with a more seductive image. &lt;br /&gt;&lt;br /&gt; A designer is a person with creative sensibility, often with an artistic background; and good skills in generating visual ideas. But the most important point: A designer is someone who understands the creative process from the beginning to bring things into being, into existence.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cXnXH4SDQSQ/TF-KfahiwDI/AAAAAAAAACQ/IaGixYiZYew/s1600/da-vinchi-01.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 198px;" src="http://1.bp.blogspot.com/_cXnXH4SDQSQ/TF-KfahiwDI/AAAAAAAAACQ/IaGixYiZYew/s200/da-vinchi-01.jpg" alt="" id="BLOGGER_PHOTO_ID_5503269541970624562" border="0" /&gt;&lt;/a&gt;&lt;span&gt;In the times of Leonardo da Vinci, it wouldn't be surprising to find an artist capable of painting canvas and conceive helicopters, or a sculptor who was at the same time an expert in anatomy. A designer needs to have a holistic approach as a creator, inspired by the discovery of the beauty and harmony present in every creative process.&lt;br /&gt;&lt;br /&gt;Since the times of the industrial revolution the process of art has been displaced from being an independent conceptual process itself to become just a part of an assembly line. As industries grow, the role of the designer has become more and more specific. Currently we can find fashion designers, interior designers, industrial designers, graphic designers, communication designers, interface designers, light designers, set designers, etcetera; and within each category they can even become more specialised: there are designers specifically for typography, branding, packaging, magazines, print industries, concept artists, art directors, illustrators, 2D and 3D artists and so on.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cXnXH4SDQSQ/TAhclyUGSJI/AAAAAAAAABw/sKCCU_UF2-s/s1600/charlie_chaplin02.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 168px;" src="http://4.bp.blogspot.com/_cXnXH4SDQSQ/TAhclyUGSJI/AAAAAAAAABw/sKCCU_UF2-s/s200/charlie_chaplin02.jpg" alt="" id="BLOGGER_PHOTO_ID_5478730750927194258" border="0" /&gt;&lt;/a&gt;&lt;span&gt;The artist is still responsible for the idea generation but now from a specific position. Their work is no longer to bring something into existence; instead it is limited to bringing only the aesthetic into existence. The product or concept has already been determined, in many cases, by a business group that works closely with the financial and marketing department.  This changing role has serious implications in terms of the way we value the artistic process. The main issue is the frustration for the artist in loosing their creative autonomy, which is by nature a holistic process, ecstatic.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Vertigo and Ecstasy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cXnXH4SDQSQ/TF-HTJtcxsI/AAAAAAAAAB4/1SRTSYmT_FY/s1600/ecstasy+experience.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 160px;" src="http://2.bp.blogspot.com/_cXnXH4SDQSQ/TF-HTJtcxsI/AAAAAAAAAB4/1SRTSYmT_FY/s200/ecstasy+experience.jpg" alt="" id="BLOGGER_PHOTO_ID_5503266032763848386" border="0" /&gt;&lt;/a&gt;&lt;span&gt;Any creative person will be sensitive to experiences of “ecstasy”, from the Greek “existanai” which means: “drive out of one’s mind”, something that comes from inside to outside. Ecstasy is an experience that born to be share.&lt;br /&gt;People consciously share ecstatic experiences during creative processes of any type. The result always opens up a new world of possibilities. Creativity then is a constant starting point to new possibilities.&lt;br /&gt;&lt;br /&gt;On the other hand, we have experiences of “vertigo”. From Latin “vertere” originally used to represent the whirling movement of liquids.  An experience of Vertigo opposes to the experience of ecstasy: “vertigo” is something that comes from outside to inside and is experimented individually. An experience of vertigo will not open up a world or any possibilities. It’s just a pleasant short moment, a feeling that ends up when the stimulus is not present or relevant anymore.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cXnXH4SDQSQ/TF-KVl0p1-I/AAAAAAAAACI/ysK6qqyVWr8/s1600/vertigo.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 151px;" src="http://1.bp.blogspot.com/_cXnXH4SDQSQ/TF-KVl0p1-I/AAAAAAAAACI/ysK6qqyVWr8/s200/vertigo.jpg" alt="" id="BLOGGER_PHOTO_ID_5503269373204879330" border="0" /&gt;&lt;/a&gt;&lt;span&gt;From the consumer point of view, an element of consume is an experience of vertigo. As its name indicates: consume, it extinguish it self once the short satisfaction is reached.&lt;br /&gt;From the designer point of view, creativity applied to process of vertigo is destiny to die like most of the pages of a shallow magazine.&lt;br /&gt;&lt;br /&gt;A real design should focus in open up possibilities for new creations. It is vital for all artist and people in general to create experiences of ecstasy in order to survive in time.&lt;br /&gt;&lt;br /&gt;Ecstatic collaborative processes are the key to success&lt;span style="font-weight: bold;"&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;Read more at: &lt;a href="http://sebastianbourges.com/"&gt;sebastianbourges.com&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1783483121483007593?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1783483121483007593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/06/role-of-designer-in-modern-times_04.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1783483121483007593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1783483121483007593'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/06/role-of-designer-in-modern-times_04.html' title='Open up a World'/><author><name>Sebastian Bourges</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://1.bp.blogspot.com/_cXnXH4SDQSQ/TAhUIEPG4wI/AAAAAAAAAAU/2MEG5NdVr58/S220/sebastian-bourges-profile.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cXnXH4SDQSQ/TAhbzML2CyI/AAAAAAAAABQ/xEYrPmi7ifc/s72-c/coke-santa360.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1294097658048308947</id><published>2010-05-14T17:01:00.003+10:00</published><updated>2010-06-01T10:50:36.510+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='excel'/><category scheme='http://www.blogger.com/atom/ns#' term='sqlite'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>SQLite</title><content type='html'>I recently needed to organise and filter a heap of data from a new client.  I didn't want to deal with the overhead of a full-blown database and decided to try sqlite3.  As it turns out, it was really easy to work with since the bindings are included with Python2.6.  All I needed to do was read a bit on how to interface Python with sqlite here: &lt;a href="http://www.blogger.com/I%20recently%20needed%20to%20organise%20and%20filter%20a%20heap%20of%20data%20from%20a%20new%20client.%20%20I%20didn%27t%20want%20to%20deal%20with%20a%20full-blown%20database%20and%20decided%20to%20try%20sqlite3.%20%20It%20was%20easy%20to%20work%20with%20since%20I%20already%20have%20Python2.6.%20%20All%20I%20needed%20to%20do%20was%20read%20a%20bit%20on%20how%20to%20interface%20Python%20with%20sqlite%20here:%20http://docs.python.org/library/sqlite3.html#module-sqlite3%20and%20I%20was%20good%20to%20go%21"&gt;http://docs.python.org/library/sqlite3.html#module-sqlite3&lt;/a&gt; and I was good to go!  I also installed a nice database management utility called SQLite Database Browser v2.0b 1 which you can get here: &lt;a href="http://sqlitebrowser.sourceforge.net/"&gt;http://sqlitebrowser.sourceforge.net&lt;/a&gt;.  It makes managing the structure of the database a bit easier than working in a windows command prompt and you can write SQL on-the-fly if you're having some problems with your Python.  I find that it is pretty stable (though some of my poorly written SQL queries do send it into a tizzy and I need to kill it and reopen).&lt;br /&gt;&lt;br /&gt;Now, I've decided to create a sqlite database and integrate it with the Excel front-end for one of our solvers (used when clients require desktop deployment).  I anticipated that integration with an SQL database would greatly simplify and speed-up the reporting (with the added bonus of a significant reduction in the need for me to write complex vba code). Initially I banged around getting really frustrated with Excel, and DAO (even after I installed the ODBC driver available here: &lt;a href="http://www.ch-werner.de/sqliteodbc/"&gt;http://www.ch-werner.de/sqliteodbc/&lt;/a&gt;).  Then I discovered SQLite for Excel here: &lt;a href="http://sqliteforexcel.codeplex.com/"&gt;http://sqliteforexcel.codeplex.com/&lt;/a&gt;.  Whew!  So far, I have found it very easy to work with and I am busy completing my reporting tool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1294097658048308947?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1294097658048308947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/05/i-recently-needed-to-organise-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1294097658048308947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1294097658048308947'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/05/i-recently-needed-to-organise-and.html' title='SQLite'/><author><name>Bonnie Douglas</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-3398401906609207126</id><published>2010-04-23T10:42:00.002+10:00</published><updated>2010-04-23T10:48:09.884+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='shortcuts'/><title type='text'>The Mighty Middle Click</title><content type='html'>I recently discovered a nice set of shortcuts that use the middle mouse button click:&lt;br /&gt;&lt;br /&gt;•    In &lt;a href="http://support.mozilla.com/en-US/kb/Mouse+shortcuts"&gt;Firefox &lt;/a&gt;or &lt;a href="http://www.microsoft.com/windows/products/winfamily/ie/ie7/quickref.mspx"&gt;Internet Explorer&lt;/a&gt;, middle-clicking on a link will open that link in a new tab.&lt;br /&gt;•    In Firefox or Internet Explorer, middle-clicking on a tab will close that tab.  This also works to close files in Visual Studio.&lt;br /&gt;&lt;br /&gt;I’ve started to use these and find myself using them all the time.  Apparently middle-click is useful in &lt;a href="http://www.pcmech.com/article/middle-click-shortcuts-in-windows-7/"&gt;Windows 7&lt;/a&gt; as well.&lt;br /&gt;&lt;br /&gt;For more juicy &lt;a href="http://support.mozilla.com/en-US/kb/Mouse+shortcuts"&gt;&lt;/a&gt;&lt;a href="http://support.mozilla.com/en-US/kb/Keyboard+shortcuts"&gt;Firefox shortcuts&lt;/a&gt;:&lt;br /&gt;•    Ctrl-T for a new tab&lt;br /&gt;•    Ctrl-W to close the currently active tab&lt;br /&gt;•    Space and Shift-space to page up/down&lt;br /&gt;•    Ctrl-F to find&lt;br /&gt;•    Ctrl-Tab/Ctrl-Shift-Tab to go forward/back one tab&lt;br /&gt;&lt;br /&gt;And my two best Windows shortcuts, which I can't live without:&lt;br /&gt;•    Ctrl-Shift-Esc – bring up Task Manager&lt;br /&gt;•    F2 in Explorer – rename a file&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-size:78%;" &gt;Thanks also to &lt;a href="http://www.knowledgesutra.com/index.php/15-firefox-tricks_t49240.html"&gt;http://www.knowledgesutra.com/index.php/15-firefox-tricks_t49240.html&lt;/a&gt; for some nice tips.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-3398401906609207126?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/3398401906609207126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/04/mighty-middle-click.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3398401906609207126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3398401906609207126'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/04/mighty-middle-click.html' title='The Mighty Middle Click'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1619497589773503135</id><published>2010-03-23T12:04:00.002+11:00</published><updated>2010-03-23T12:10:43.794+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lxml'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='xslt'/><title type='text'>XSLT vs Python/LXML</title><content type='html'>I recently had to adapt some old &lt;a href="http://www.w3.org/TR/xslt"&gt;XLST&lt;/a&gt; which read in an XML document and did some transformations to turn it into CSV data.  For those who don’t know what &lt;a href="http://en.wikipedia.org/wiki/XSLT"&gt;XSLT&lt;/a&gt; is (consider yourself lucky!), it is a declarative, XML-based transformation language usually used for transforming a source XML into destination XML. &lt;br /&gt;&lt;br /&gt;Now the XSLT I was dealing with also had some Javascript and VBScript functions inside it, and after struggling with it for a while I eventually realised – to my horror, as I needed it to run cross-platform on both Windows and Linux – that it also incorporated some Microsoft-specific extensions.   So I ditched the XSLT and switched to writing it from scratch in Python with the &lt;a href="http://codespeak.net/lxml/"&gt;LXML&lt;/a&gt; library instead.  Less than 2 hours later, to do the exact same task – including thorough error checking – the Python turned out to be 205 lines, while the XSLT was 714 lines.&lt;br /&gt;&lt;br /&gt;For a long time I wondered if it was just me, that I was too much of a procedural, C++ thinker, and just didn’t “get” XLST.   XSLT is supposed to be a purpose-built tool for the job, right?  Well, I'll say now what I've always secretly thought, namely that  XSLT is obtuse and horrible and I’ll steer clear of it forever.  And evidently &lt;a href="http://www.martinfowler.com/bliki/MovingAwayFromXslt.html"&gt;I’m&lt;/a&gt; &lt;a href="http://mail.python.org/pipermail/baypiggies/2008-May/003435.html"&gt;not&lt;/a&gt; &lt;a href="http://java.dzone.com/news/death-xslt-web-frameworks"&gt;alone&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1619497589773503135?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1619497589773503135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/03/xslt-vs-pythonlxml.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1619497589773503135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1619497589773503135'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/03/xslt-vs-pythonlxml.html' title='XSLT vs Python/LXML'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1355601349080486889</id><published>2010-02-02T15:52:00.004+11:00</published><updated>2010-02-02T17:57:35.096+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SimPy'/><category scheme='http://www.blogger.com/atom/ns#' term='discrete-event simulation'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Using Simpy and Python</title><content type='html'>I recently completed a discrete-event simulation model using &lt;a href="http://www.mcs.vuw.ac.nz/cgi-bin/wiki/SimPy?SimPy"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;SimPy&lt;/span&gt;&lt;/a&gt;.  This was my first foray into Python programming and the first time I used a non-graphical discrete-event simulation package (most of my previous experience was using Witness).  &lt;br /&gt;&lt;br /&gt;The model  tracks the utilisation of wagons on trains.  Key constraints include availability of staff, availability of a path through the network for movement of trains and wagons, and availability of a spare locomotive to make ancillary wagon movements.  Maintenance activities are simulated as are wagon faults and repairs. &lt;br /&gt;&lt;br /&gt;The rail network is represented using a &lt;a href="http://en.wikipedia.org/wiki/DOT_language"&gt;.dot&lt;/a&gt; file; our brilliant computer scientist, Loki, devised a mechanism to find a path through the network using the &lt;a href="http://www.linux.ime.usp.br/%7Ematiello/python-graph/docs/pygraph-module.html"&gt;pygraph minmax module&lt;/a&gt; (&lt;a href="http://dkbza.org/pydot.html"&gt;pydot&lt;/a&gt; is used to parse the .dot file). &lt;br /&gt;&lt;br /&gt;Although the learning curve was quite steep for me, I found that I really enjoy working with both Python and SimPy.  It was liberating not fiddling with graphics which must be placed precisely on the screen or manipulated to get element iteractions to work perfectly.  The use of a .dot file to represent the rail network means that it can be changed at will without requiring a vast amount of re-work to fix graphics (the initial network is a high-level representation of the actual network which will be refined in the future).  As an added bonus,  &lt;a href="http://www.graphviz.org/"&gt;Graphviz&lt;/a&gt; can be used to view and modify the .dot files.  SimPy doesn't come loaded with pre-configured entities (like machines, staff, tracks, forklifts, etc.).  However, you can create any entity you desire and define it's behaviour using the Python programming language.  Since SimPy is open source all code is freely available and can be modified to provide further functionality.  This provides far greater flexibility than I've experienced with other packages since I was not limited by behaviours defined by the package developers and the use of a package-specific macro language.  As with other simulation packages I've used, I created variables to track important information and then created both .txt and .csv output files on which extensive analysis can be performed. &lt;br /&gt;&lt;br /&gt;While the cost of using Python and SimPy was a significant learning curve (for me) I feel that it was definitely worth it.  We'll be looking to use SimPy on future projects!&lt;br /&gt;&lt;br /&gt;Special thanks to Klaus Muller for his patience in answering my questions and assistance!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1355601349080486889?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1355601349080486889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/02/using-simpy-and-python.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1355601349080486889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1355601349080486889'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/02/using-simpy-and-python.html' title='Using Simpy and Python'/><author><name>Bonnie Douglas</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-5855320328537951970</id><published>2010-01-28T11:24:00.004+11:00</published><updated>2010-01-28T18:32:04.334+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hosted solutions'/><category scheme='http://www.blogger.com/atom/ns#' term='gis'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='geocoding'/><title type='text'>Lightweight Geocoding</title><content type='html'>At Biarri we're always on the look out for inexpensive, light tools that we can integrate with and pass on the value to our Workbench customers.  We've been hunting for quite a while but haven't yet found a good free &lt;a href="http://en.wikipedia.org/wiki/Geocoder"&gt;Geocoder &lt;/a&gt;that is suitable for possibly intensive commercial use (and preferably worldwide!).  Geocoders turn addresses into latitude/longitude coordinates; &lt;a href="http://en.wikipedia.org/wiki/Reverse_geocoding"&gt;reverse geocoding&lt;/a&gt;, which is also sometimes useful, finds the closest valid address given a coordinate.&lt;br /&gt;&lt;br /&gt;Any geocoder worth its salt needs to be able to do a good job at fuzzy string matching because addresses are frequently given incorrectly (e.g. "Road" instead of "Street", multiple names for highways - "Hume Highway" vs "M31", common misspellings, ambiguity at suburb boundaries, confusion over locality names, etc).  It's the quality of this matching in combination with the correctness and up-to-date-ness of the underlying map data that sets different geocoders apart.&lt;br /&gt;&lt;br /&gt;I recently tried out &lt;a href="http://tinygeocoder.com/"&gt;TinyGeocoder&lt;/a&gt;.  It has a simple API which appears to work quite well.  It doesn't give you any direct information about what it matched to or how well it matched, though you can use the reverse geocoding function to get an idea.  Though I'm finding the results a little bit patchy and fickle (some well known streets just inexplicably won't geocode, for example), and not particularly fast, overall it is a reasonable tool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-5855320328537951970?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/5855320328537951970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/01/lightweight-geocoding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5855320328537951970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/5855320328537951970'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/01/lightweight-geocoding.html' title='Lightweight Geocoding'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-7280239979527569888</id><published>2010-01-27T17:25:00.004+11:00</published><updated>2010-01-28T12:07:25.614+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><title type='text'>Generic Geometry Library</title><content type='html'>To anyone who is trying to download the &lt;a href="http://geometrylibrary.geodan.nl/"&gt;Generic Geometry Library&lt;/a&gt; (which was recently accepted by Boost) - you need to use the following subversion command line&lt;br /&gt;&lt;br /&gt;svn co https://svn.boost.org/svn/boost/sandbox/ggl geometry&lt;br /&gt;&lt;br /&gt;and not the one that is currently advertised&lt;br /&gt;&lt;br /&gt;svn co https://svn.boost.org/svn/boost/sandbox/geometry geometry&lt;br /&gt;&lt;br /&gt;We plan to use this library to compute convex hulls, and area of intersection of polygons, within our engines that are written in c++&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-7280239979527569888?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://geometrylibrary.geodan.nl/' title='Generic Geometry Library'/><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/7280239979527569888/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/01/generic-geometry-library.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7280239979527569888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7280239979527569888'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/01/generic-geometry-library.html' title='Generic Geometry Library'/><author><name>Ben</name><uri>http://www.blogger.com/profile/05874593951999827643</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-4481344143692651241</id><published>2010-01-05T13:27:00.000+11:00</published><updated>2010-01-05T13:27:54.266+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Biarri Turns One</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_A-i4GK9mCAI/S0KjLeEjuII/AAAAAAAAAEo/Tj6xmIODlQg/s1600-h/179600_ep06_ev.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_A-i4GK9mCAI/S0KjLeEjuII/AAAAAAAAAEo/Tj6xmIODlQg/s200/179600_ep06_ev.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Today is Biarri's Birthday! We started trading as a business on 5 January 2009. &amp;nbsp;We have had a great first year and we would like to thank everyone that have supported us. &amp;nbsp;We look forward to building on our success and delivering smart optimisation tools in 2010 and beyond.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-4481344143692651241?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/4481344143692651241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/01/biarri-turns-one.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4481344143692651241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/4481344143692651241'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/01/biarri-turns-one.html' title='Biarri Turns One'/><author><name>www.biarri.com</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_A-i4GK9mCAI/S_82JC2C1aI/AAAAAAAAAEw/JVmeqm1_xVY/S220/Icons-tools.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_A-i4GK9mCAI/S0KjLeEjuII/AAAAAAAAAEo/Tj6xmIODlQg/s72-c/179600_ep06_ev.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-8213080849792542319</id><published>2010-01-05T13:19:00.000+11:00</published><updated>2010-01-05T13:19:27.625+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='operations research'/><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Designing Distribution Networks for Utilities</title><content type='html'>Many utilities face the problem of designing distribution networks. &amp;nbsp;These networks need to reach all (or nearly all) households to distribute (or collect) the commodity supplied by the utility. &amp;nbsp;This may be electricity, gas, water, data (cable or optical fibre) or sewerage.&lt;br /&gt;&lt;br /&gt;Typically these distribution networks are built as a subset of some underlying network. &amp;nbsp;Most commonly this is the street network. &amp;nbsp;The reason for this is obvious – the street network connects all households and businesses – which are the final demand points of utilities. &amp;nbsp;Some networks may piggyback on existing networks. &amp;nbsp;For example an optical fibre rollout may be done using existing power poles.&lt;br /&gt;&lt;br /&gt;From a mathematical point of view we can consider the underlying points of demand (households or small collections of households) as nodes in a graph. &amp;nbsp;The potential connections between these nodes are arcs. &amp;nbsp;We refer to this network of potential connections as the underlying network. &amp;nbsp;If the distribution network can be represented as a tree (and this is often the case) then the problem of determining the best distribution network is similar to the minimum spanning tree problem solved on the underlying network (&lt;a href="http://en.wikipedia.org/wiki/Minimum_spanning_tree"&gt;http://en.wikipedia.org/wiki/Minimum_spanning_tree&lt;/a&gt;). &amp;nbsp;This problem is straightforward to solve with an algorithm that is relatively easy to understand. &amp;nbsp;The main information required is the cost of the candidate arcs. &amp;nbsp;For example, it may be relatively cheap to string new cable between existing poles (for electricity or data networks), but much more expensive to dig a trench to install cable underground in an area with no overhead poles.&lt;br /&gt;&lt;br /&gt;The problem faced by a utility will however have many practical considerations that cannot be handled by the classical minimum spanning tree algorithm. &amp;nbsp;These will include:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The problem is really one of building several spanning trees, each of which can handle a maximum demand. &amp;nbsp;This arises because of underlying technical restrictions such as transformer capacity; the need to have pumping stations for water, gas and sewerage; the maximum number of optical fibre connections to a hub; etc.&lt;/li&gt;&lt;li&gt;The cost of arcs in the tree depends on the downstream demand. &amp;nbsp;This arises because the pipes or cables need to get bigger as the tree collects more downstream demand.&lt;/li&gt;&lt;li&gt;Splitting nodes in the tree may be expensive. &amp;nbsp;This can occur because of splicing costs (in optical fibre networks) or the need to distribute pressure evenly.&lt;/li&gt;&lt;li&gt;The spanning trees will themselves need to be connected back to the “mains” network. &amp;nbsp;Indeed the problem of designing the mains network may need to be considered as part of the overall problem, though typically most of the cost will be in the feeder network due to the sheer number of connections required.&lt;/li&gt;&lt;li&gt;The maximum network length from the mains to a node is limited due to pressure/voltage losses.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Recently Biarri has undertaken a Proof of Concept project with a utility to look at designing a distribution network. &amp;nbsp;We have formulated and solved an optimisation based approach to give solutions guaranteed to be within a very small margin of the optimal solution. &amp;nbsp;On a sample network covering around 2000 households we were able to achieve:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;An optimal solution in two minutes on standard PC’s&lt;/li&gt;&lt;li&gt;6% reduction in equipment costs&lt;/li&gt;&lt;li&gt;Huge reduction in planning effort – it took many man weeks to design the same area by hand&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The speed of the solution process frees up the network designer to consider higher level issues that are not part of the optimisation model, such as the possible saving from using different technical approaches. &amp;nbsp;These choices can be modelled as a series of “What if…?” scenarios.&lt;br /&gt;&lt;br /&gt;We plan to extend the work done so far to cover even more of the practical issues faced by utilities. &amp;nbsp;A technical paper covering the work will be prepared in 2010.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-8213080849792542319?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/8213080849792542319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2010/01/designing-distribution-networks-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8213080849792542319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8213080849792542319'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2010/01/designing-distribution-networks-for.html' title='Designing Distribution Networks for Utilities'/><author><name>www.biarri.com</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_A-i4GK9mCAI/S_82JC2C1aI/AAAAAAAAAEw/JVmeqm1_xVY/S220/Icons-tools.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-1741897671318420959</id><published>2009-12-29T12:30:00.004+11:00</published><updated>2009-12-29T13:36:49.852+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gis'/><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>generating kml thematic maps with python and postgis</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_zE8s-Jl6u8w/SzlrFtCxc5I/AAAAAAAAAAM/mxFt_TGlHY4/s1600-h/thematic_map.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;" src="http://3.bp.blogspot.com/_zE8s-Jl6u8w/SzlrFtCxc5I/AAAAAAAAAAM/mxFt_TGlHY4/s400/thematic_map.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5420481372251845522" /&gt;&lt;/a&gt;&lt;br /&gt;The &lt;a href="http://biarriworkbench.com"&gt;Biarri workbench&lt;/a&gt; now has a tool for showing the frequency of an event per postcode. The colourised map (funkier name &lt;a href="http://en.wikipedia.org/wiki/Choropleth_map"&gt;Choropleth map&lt;/a&gt;) is generated as KML from postcode regions that are stored in a postgis database. This just requires a little bit of sql and python:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;dict_cur.execute("select p.gid, p.poa_2006, ST_AsKML(the_geom) as \&lt;br /&gt;                  polygon, frequency, (frequency - stats.min) / (stats.max - \&lt;br /&gt;                  stats.min)::float as scaled_frequency from "+table+" c, \&lt;br /&gt;                  postcode_regions p, (select max(frequency), min(frequency) \&lt;br /&gt;                  from "+table+") as stats where p.poa_2006 = c.postcode")&lt;br /&gt;return my_lookup.get_template("thematic_kml.mako").render(rows=dict_cur.fetchall())&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The sql just normalises the column we want as our colour intensity and returns the KML for each postcode region.&lt;br /&gt;&lt;br /&gt;The mako template:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;&amp;lt;kml xmlns=&amp;quot;http://earth.google.com/kml/2.2&amp;quot; xmlns:atom=&amp;quot;http://www.w3.org/2005/Atom/&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Document&amp;gt;&lt;br /&gt;    &amp;lt;name&amp;gt;Thematic Map&amp;lt;/name&amp;gt;&lt;br /&gt;        &amp;lt;description&amp;gt;generated with the Biarri workbench&amp;lt;/description&amp;gt;&lt;br /&gt;    % for row in rows:&lt;br /&gt;    &amp;lt;Style id=&amp;quot;${row[&amp;#39;gid&amp;#39;]}&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;LineStyle&amp;gt;&lt;br /&gt;          &amp;lt;color&amp;gt;40000000&amp;lt;/color&amp;gt;&lt;br /&gt;          &amp;lt;width&amp;gt;3&amp;lt;/width&amp;gt;&lt;br /&gt;        &amp;lt;/LineStyle&amp;gt;&lt;br /&gt;        &amp;lt;PolyStyle&amp;gt;&lt;br /&gt;            &amp;lt;color&amp;gt;${intensity(row[&amp;#39;scaled_frequency&amp;#39;])}&amp;lt;/color&amp;gt;&lt;br /&gt;            &amp;lt;fill&amp;gt;1&amp;lt;/fill&amp;gt;&lt;br /&gt;            &amp;lt;outline&amp;gt;1&amp;lt;/outline&amp;gt;&lt;br /&gt;        &amp;lt;/PolyStyle&amp;gt;&lt;br /&gt;      &amp;lt;/Style&amp;gt;&lt;br /&gt;      &amp;lt;Placemark&amp;gt;&lt;br /&gt;        &amp;lt;name&amp;gt;${row[&amp;#39;poa_2006&amp;#39;]}&amp;lt;/name&amp;gt;&lt;br /&gt;        &amp;lt;description&amp;gt;&lt;br /&gt;        ${row[&amp;#39;frequency&amp;#39;]}&lt;br /&gt;        &amp;lt;/description&amp;gt;&lt;br /&gt;        &amp;lt;styleUrl&amp;gt;#${row[&amp;#39;gid&amp;#39;]}&amp;lt;/styleUrl&amp;gt;&lt;br /&gt;        ${row[&amp;#39;polygon&amp;#39;].replace(&amp;quot; &amp;quot;, &amp;#39;\n&amp;#39;)}&lt;br /&gt;      &amp;lt;/Placemark&amp;gt;&lt;br /&gt;    % endfor&lt;br /&gt;      &amp;lt;/Document&amp;gt;&lt;br /&gt;&amp;lt;/kml&amp;gt;&lt;br /&gt;&amp;lt;%!&lt;br /&gt;import webcolors&lt;br /&gt;import colorsys&lt;br /&gt;&lt;br /&gt;def intensity(frequency):&lt;br /&gt;#frequencies are already scaled between 0 and 1&lt;br /&gt;    return &amp;#39;cc&amp;#39; webcolors.rgb_to_hex(tuple((int(a * 256) for a in colorsys.hsv_to_rgb(0.134, frequency, 0.90)))).strip(&amp;#39;#&amp;#39;)&lt;br /&gt;%&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The mako template is quite easy to read if you notice the % sections are actually python code. The only challenge I had was that ST_AsKML produces kml with the co-ordinates space separated. Google earth is fine with this but the kml viewer we're using, web map lite, only likes them newline separated. My colour function just changes the intensity of the colour. A gradient between blue and red would probably be more appropriate.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Loki&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-1741897671318420959?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/1741897671318420959/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2009/12/generating-kml-thematic-maps-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1741897671318420959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/1741897671318420959'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2009/12/generating-kml-thematic-maps-with.html' title='generating kml thematic maps with python and postgis'/><author><name>Loki Davison</name><uri>http://www.blogger.com/profile/00025294022151791528</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_zE8s-Jl6u8w/SzlrFtCxc5I/AAAAAAAAAAM/mxFt_TGlHY4/s72-c/thematic_map.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-8543799001608808719</id><published>2009-12-08T15:53:00.002+11:00</published><updated>2009-12-08T16:00:39.089+11:00</updated><title type='text'>Biarri's first Open Source contribution</title><content type='html'>Today Biarri &lt;a href="http://en.wikipedia.org/wiki/Open_source"&gt;open sourced&lt;/a&gt; its first code.  We've used Google Code hosting with an MIT License to open source a small program called osm2mif that converts &lt;a href="http://www.openstreetmap.org/"&gt;Open Street Map&lt;/a&gt; data (OSM) to &lt;a href="http://en.wikipedia.org/wiki/MapInfo_Interchange_Format"&gt;MapInfo Interchange Format&lt;/a&gt; (MID/MIF).&lt;br /&gt;&lt;br /&gt;From the &lt;a href="http://code.google.com/p/osm2mif/"&gt;Google Code project homepage for osm2mif&lt;/a&gt;:&lt;br /&gt;&lt;div id="wikicontent" style="padding: 0pt 3em 1.2em 0pt; font-style: italic;"&gt;  &lt;p&gt;Converts an Open Street Map file (.OSM) to mid/mif output, creating a topology for routing (that is, breaking up the OSM ways at intersection points, and also processing "no right turn" restriction relations). &lt;/p&gt;&lt;p&gt;Can use filtering to convert only within a given coordinate bounding box; also can convert only a subset of features (e.g. just roads, or just coastlines and lakes/rivers, or some given mixture); can also transform tag values to given strings, and use particular MIF styles (pen style, polyline vs region etc) based on the given tag values. &lt;/p&gt;&lt;p&gt;The program is written in C++ and contains only one file, with less than 1000 lines, and no external dependencies apart from the standard library. Compiles under both Windows (Visual Studio) and Linux (GCC). Runs pretty quickly for OSM files under a Gigabyte, but does use up lots of RAM when running. &lt;/p&gt;  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-8543799001608808719?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/8543799001608808719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2009/12/biarris-first-open-source-contribution.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8543799001608808719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8543799001608808719'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2009/12/biarris-first-open-source-contribution.html' title='Biarri&apos;s first Open Source contribution'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-3719597229398862172</id><published>2009-11-29T15:41:00.000+11:00</published><updated>2009-11-29T15:41:30.162+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='people'/><title type='text'>Sebastian Joins The Team</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_A-i4GK9mCAI/SxH7TLZQoYI/AAAAAAAAAEg/OrNGWWEqL-4/s1600/SebastianBourges+Photo.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_A-i4GK9mCAI/SxH7TLZQoYI/AAAAAAAAAEg/OrNGWWEqL-4/s200/SebastianBourges+Photo.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;We welcome Sebastian Bourges to Biarri as our new Artistic Director. His focus will be the design of the website and the usability of our optimisation tools. &amp;nbsp;He will drive the online look and feel of the business.&lt;br /&gt;&lt;br /&gt;Sebsatian is originally from Argentina where he studied Industrial Design at the National University of Cordoba. He has had a range of design roles including running his own graphic and multimedia design business. He migrated to Australia in 2006 and worked for Katana Productions which later merged with The Feds, where he developed a variety of multimedia projects and websites for film directors. Recently he has been working as an independent multimedia designer.&lt;br /&gt;&lt;br /&gt;Sebastian is married, lives in Melbourne and is a keen photographer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-3719597229398862172?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/3719597229398862172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2009/11/sebastian-joins-team.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3719597229398862172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3719597229398862172'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2009/11/sebastian-joins-team.html' title='Sebastian Joins The Team'/><author><name>www.biarri.com</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_A-i4GK9mCAI/S_82JC2C1aI/AAAAAAAAAEw/JVmeqm1_xVY/S220/Icons-tools.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_A-i4GK9mCAI/SxH7TLZQoYI/AAAAAAAAAEg/OrNGWWEqL-4/s72-c/SebastianBourges+Photo.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-8857981993926798895</id><published>2009-11-27T23:01:00.004+11:00</published><updated>2009-11-27T23:08:21.427+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSM'/><title type='text'>Using Open Street Map data for Australia</title><content type='html'>I’ve been using &lt;a href="http://www.openstreetmap.org/"&gt;Open Street Map&lt;/a&gt; (OSM) data for Australia for generating matrices of travel times and distances that are suitable for input to truck routing optimisation problems.  OSM is a world-wide map data set that anyone can edit and is impressively comprehensive.&lt;br /&gt;&lt;br /&gt;Some of the resources I’ve used are &lt;a href="http://www.osmaustralia.org"&gt;www.osmaustralia.org&lt;/a&gt;, which does a regular batch job to extract country by country OSM data, and&lt;a href="http://keepright.x10hosting.com/"&gt; http://keepright.x10hosting.com/&lt;/a&gt; which keeps an up to date list of map data errors.  These types of errors are important to know about when producing routable data from OSM, in particular dead end one way streets and “almost junctions”.&lt;br /&gt;&lt;br /&gt;I’ve been using Quantum GIS (&lt;a href="http://www.qgis.org/"&gt;QGIS&lt;/a&gt;) to look at the data after converting it to MID/MIF format.  I can get it to label the lines that are one way streets, but unfortunately there is no way to show the line direction in QGIS, which is a major pain.  (Actually there is a way but you have to get a source code branch from their repo and build it all etc etc).  [Now that I think of it, a silly cheat way to do it would also be to produce another field in the map data, say a letter which represents whether the arc is "D" for down or "L" for left etc (based on the difference in the lat/longs of the start and end nodes of each arc), and label that way.]&lt;br /&gt;&lt;br /&gt;I also found that the performance of QGIS is quite different depending on whether the data is opened as TAB or MIDMIF format.  TAB format is fairly fast (just zooming, panning etc) but MIDMIF is quite noticeably slower.  You'd think it wouldn't make a difference as it would be using the same internal data representation, but obviously not.&lt;br /&gt;&lt;br /&gt;I’m using some extra layers to show some of the processed data (picture below).  For example, I have a layer which just shows the arcs involved in restricted turns, which I can layer on top of the street network and use a thicker line style for.  I also use dots in another layer which I have produced based on my "island" processing.  The dots represent "orphaned" nodes which are not on the main "island" of map data (which is connected in the sense that all nodes can reach all other nodes).  These orphaned nodes will be ignored by the travel time calculation.  There are around 9600 of these nodes in the entire set of Australia OSM routable data I’m using (which has 620042 nodes and 1503668 arcs in total).  This filtered subset of OSM data I am using includes only street segments with a “highway” tag – this will exclude cycleways, pathways, hiking trails, ferry routes, ski slopes, building outlines, administrative boundaries, waterways etc.&lt;br /&gt;&lt;br /&gt;Some observations on the OSM data (for Australia):&lt;br /&gt;•    One way information seems quite complete.&lt;br /&gt;•    Only 12% of the streets have road speed information (“max_speed” tag).  This is an issue as vehicle routing needs highways to have a faster speed otherwise they won't be used (and there will be lots of rat-running for example).  In longer routes (e.g. interstate) the travel time will also be grossly overestimated.  A couple of things we could do here: search for all segments with "highway", "motorway", or "freeway" in their names and assume some sort of speed like 80km/h on these segments.  Or, with a bit more coding effort, if there are chains of segments where one has a speed and the others with the same street name don't, assume that speed on all of those segments.&lt;br /&gt;•    About 70% of the road segments have street names.  Some of the unnamed segments are bits of roundabout, service roads, motorway on/off-ramps etc.  But, there are also a lot of streets which are classified (by their "highway" tag) as "secondary", "tertiary", "unclassified" and even "residential" which are not named.  This is an issue when vehicle routing needs to produce driver directions or verbose path information.&lt;br /&gt;•    There's only several hundred instances of streets which have restricted manoeuvre information (banned right hand turns being the prime example).  Most of these instances are in Sydney.  In reality this number should be in the thousands or tens of thousands.  This will likely be the biggest issue from a routing quality point of view - it will mean you can do many illegal right turns.&lt;br /&gt;•    I found a weird character or two at the end of the file, which causes both Python and C++ file reading functions to get confused and read blanks forever.  Weird, but easily avoided.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vh86hLMiUXg/Sw-_vnMVK4I/AAAAAAAAAAM/K9S3ty8CIuw/s1600/QGIS_OSM_Sydney.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 676px; height: 354px;" src="http://1.bp.blogspot.com/_vh86hLMiUXg/Sw-_vnMVK4I/AAAAAAAAAAM/K9S3ty8CIuw/s320/QGIS_OSM_Sydney.png" alt="" id="BLOGGER_PHOTO_ID_5408752502190713730" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-8857981993926798895?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/8857981993926798895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2009/11/using-open-street-map-data-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8857981993926798895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/8857981993926798895'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2009/11/using-open-street-map-data-for.html' title='Using Open Street Map data for Australia'/><author><name>Andrew Grenfell</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_vh86hLMiUXg/Sw-_vnMVK4I/AAAAAAAAAAM/K9S3ty8CIuw/s72-c/QGIS_OSM_Sydney.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-3947460297212098593</id><published>2009-11-18T11:15:00.002+11:00</published><updated>2009-11-18T11:54:04.114+11:00</updated><title type='text'>Drawing figures for scientific publications: XFig and MS Windows</title><content type='html'>I recently had to modify a picture (figure) as part of a resubmission to an academic journal.&lt;br /&gt;&lt;br /&gt;The picture was created using &lt;a href="http://www.xfig.org/"&gt;XFig&lt;/a&gt; some time ago. XFig is one of the most widely used applications for creating figures for academic publications, and easily the best application I have used for this purpose. Its ability to incorporate &lt;a href="http://www.latex-project.org/"&gt;Latex&lt;/a&gt; scientific formulas (use "xfig -specialtext -latexfonts -startlatexFont default" when launching XFig) and fonts, means that figures can be easily and beautifully integrated into Latex documents.&lt;br /&gt;&lt;br /&gt;As I now have a windows machine, and am definitely no expert on linux (I am slowly trying to remedy this) I was dreading having to jump through the hoops to get XFig working on my new windows box (See &lt;a href="http://www.cs.usask.ca/%7Ewew036/latex/xfig.html"&gt;http://www.cs.usask.ca/~wew036/latex/xfig.html&lt;/a&gt;). Part of the process involves installing &lt;a href="http://www.cygwin.com/"&gt;Cygwin&lt;/a&gt; (a Linux-like environment for Windows). Not being familiar with linux this process seems quite convoluted (and I have been down this path before).&lt;br /&gt;&lt;br /&gt;Googling XFig also brings up &lt;a href="http://www.schmidt-web-berlin.de/winfig/"&gt;WinFig&lt;/a&gt;. Which is supposed to be very similar to XFig but runs on MS Windows. After downloading WinFig I quickly found out that you can only save figures with 15 or less objects in them without paying for the full version (making the free version not very useful). Something that the homepage neglects to mention.&lt;br /&gt;&lt;br /&gt;I soon realised that because I had already installed &lt;a href="http://moxiefoxtrot.com/2009/04/23/installing-ubuntu-904-in-virtualbox-202/"&gt;virtual box&lt;/a&gt; and installed &lt;a href="http://www.ubuntu.com/getubuntu/download"&gt;ubuntu&lt;/a&gt; (the process was very pain free) I should definitely try to use XFig within Ubuntu. Installing XFig within Ubuntu is what one my colleagues would call &lt;span style="font-style: italic;"&gt;automagical&lt;/span&gt; - with a terminal inside Ubuntu type "sudo apt-get install xfig", then as mentioned before type "xfig -specialtext -latexfonts -startlatexFont default" and I was cooking straight away.&lt;br /&gt;&lt;br /&gt;In order to open my file in XFig in Ubuntu I was hoping to be able to share some folders with MSWindows, and then mount them inside Ubuntu. Alas, despite all my efforts I have still not been able to get this to work. Email to the rescue, emailed them to myself, opened my gmail in ubuntu, saved the file and the problem was solved.&lt;br /&gt;&lt;br /&gt;The moral of the story (well this blog) is that if you are trying to get XFig working on windows, - don't. Use the power that virtual box gives you and run XFig in Ubuntu within virtual box on your Windows machine! Now to move back to the Latex editing applications in linux and away from those I have been using with MS Windows!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-3947460297212098593?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/3947460297212098593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2009/11/drawing-figures-for-scientific.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3947460297212098593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/3947460297212098593'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2009/11/drawing-figures-for-scientific.html' title='Drawing figures for scientific publications: XFig and MS Windows'/><author><name>Ben</name><uri>http://www.blogger.com/profile/05874593951999827643</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-6286867687473693866</id><published>2009-11-17T14:00:00.001+11:00</published><updated>2009-11-17T14:00:38.721+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='operations research'/><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Well Done Nick and Daryl - Maths Prize Winners</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_A-i4GK9mCAI/SwIRdmPdyjI/AAAAAAAAAEY/lNpxTbdZLAs/s1600/obgpol8mt5lz.gif" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_A-i4GK9mCAI/SwIRdmPdyjI/AAAAAAAAAEY/lNpxTbdZLAs/s320/obgpol8mt5lz.gif" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Daryl Bruce and Nick Vaskrsic both won awards at the recent RMIT Mathematical Sciences Awards Night. &amp;nbsp;Daryl won the Operations Research Prize and Nick won the Mathematics Rising Star Prize. &amp;nbsp;Both of them currently work as part-time business analysts and route optimisation planners for Biarri. &lt;br /&gt;&lt;br /&gt;It is great to see the guys doing so well in their studies. All the best to everyone in the Biarri team who are currently in the midst of exams - good luck!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-6286867687473693866?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/6286867687473693866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2009/11/well-done-nick-and-daryl-maths-prize.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6286867687473693866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/6286867687473693866'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2009/11/well-done-nick-and-daryl-maths-prize.html' title='Well Done Nick and Daryl - Maths Prize Winners'/><author><name>www.biarri.com</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_A-i4GK9mCAI/S_82JC2C1aI/AAAAAAAAAEw/JVmeqm1_xVY/S220/Icons-tools.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_A-i4GK9mCAI/SwIRdmPdyjI/AAAAAAAAAEY/lNpxTbdZLAs/s72-c/obgpol8mt5lz.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-7820362653793605257</id><published>2009-11-07T09:21:00.002+11:00</published><updated>2009-11-07T09:24:56.052+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Web Applications Designer</title><content type='html'>We are making great progress with the Smart Optimisation Tools we are building for the Workbench.  But we now need to pump up our web and application design capability so we can speed up development and polish the products.  We are looking to hire a web application designer.  &lt;br /&gt;&lt;br /&gt;The job is based in Melbourne and we need someone who can design the 'look and feel' of our web applications, website and brand. &amp;nbsp;This is a chance to get someone in on the ground floor to be the creative force behind our online style and usability. They will be Biarri's design guru. &amp;nbsp;As a creative designer, they will have:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A strong visual eye and understanding of web usability&lt;/li&gt;&lt;li&gt;Creative flair that they use to build clean and appealing interfaces&lt;/li&gt;&lt;li&gt;The ability to drive the design process&lt;/li&gt;&lt;li&gt;End-to-end design skills, from sketches and wireframes to HTML/CSS integration&lt;/li&gt;&lt;/ul&gt;The job is also on Seek&amp;nbsp;&lt;span style="border-collapse: collapse; font-family: arial, sans-serif, 'Arial Unicode MS'; font-size: 13px;"&gt;&lt;a href="http://www.seek.com.au/job/industrial-web-applications-designer/melbourne/16207367/23/1/" style="color: #0000cc;" target="_blank"&gt;http://www.seek.com.au/job/&lt;wbr&gt;&lt;/wbr&gt;industrial-web-applications-&lt;wbr&gt;&lt;/wbr&gt;designer/melbourne/16207367/&lt;wbr&gt;&lt;/wbr&gt;23/1/&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3523038529731701286-7820362653793605257?l=biarri.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.seek.com.au/job/industrial-web-applications-designer/melbourne/16207367/23/1/' title='Web Applications Designer'/><link rel='replies' type='application/atom+xml' href='http://biarri.blogspot.com/feeds/7820362653793605257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://biarri.blogspot.com/2009/11/web-applications-designer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7820362653793605257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3523038529731701286/posts/default/7820362653793605257'/><link rel='alternate' type='text/html' href='http://biarri.blogspot.com/2009/11/web-applications-designer.html' title='Web Applications Designer'/><author><name>www.biarri.com</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_A-i4GK9mCAI/S_82JC2C1aI/AAAAAAAAAEw/JVmeqm1_xVY/S220/Icons-tools.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3523038529731701286.post-728607907549783571</id><published>2009-10-12T22:22:00.003+11:00</published><updated>2009-10-12T22:35:24.789+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='developers'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>The Wonders of Python</title><content type='html'>I recently wrote a little code generator in Python that takes in a schema file in XML format and expands out specially marked up tags inside C++ code. It was my first real industrial strength use of Python and (for this C++ veteran at least) I was amazed at how much I could accomplish in just 300 lines of code. In particular I liked:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Not having to compile!&lt;/li&gt;&lt;li&gt;List comprehensions&lt;/li&gt;&lt;li&gt;String slicing and dicing&lt;/li&gt;&lt;li&gt;Returning multiple arguments from a function&lt;/li&gt;&lt;li&gt;Some really nice constructs:&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;return "True" if (self.Type not in self.VariableTypes) else "False"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;       This one sure does flow like natural language.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Dynamic typing sometimes feels like a free for all, but I’ll gladly pay that price for the many powerful features it enables. I sure am writing “self” a lot though :-)&lt;br /&gt;&lt;br /&gt;I think the real epiphany moment was realising that there is essentially no real complexity inherent in the language – this is very liberating compared to C++ where you have to constantly steer clear of C++’s many dark corners (about which entire books have been written, e.g. &lt;a href="http://semantics.org/cpp_gotchas/index.html"&gt;&lt;span style="font-style: italic;"&gt;C++ Gotchas &lt;/span&gt;by Stephen Dewhurst&lt;/a&gt;).   Programming really does become less of a struggle.&lt;br /&gt;&lt;br /&gt;A somewhat tangential link musing over Python vs C++ in the context of unit testing is &lt;a href="http://www.gigamonkeys.com/blog/2009/10/05/coders-unit-testing.html"&gt;this blog post&lt;/a&gt;, which describes approaching bu
