Wednesday, September 13, 2017

Musings on being a senior programmer

In some context's the title would mean being an experienced, admired, authoritative person.  Alas for me it just means being old, and in retrospect using the word programmer is a bit of a stretch.  Maybe it is harder to remember things because every day I have so much more important information to pack away for later retrieval, or maybe it is just harder to remember.  As we evolve as a company I find myself adding layer names and function keys that I know I'll use again but not often enough that I'll probably remember them.  Gone are the days when a function was one of 120 three digit numbers (which of course I still remember because I've been using most of them for 30 years). I quit trying to remember things I can Google long ago so why not treat the new layers and functions the same, after all if I expose myself to them often enough I'll eventually remember, and if I don't then searching is easy enough.  Enter sealay and seafk.  Now if I forget what the layer number is, but remember that it had the word "Wall" in the name I can just
sealay wall
and like magic I am presented with a list of options which when selected issues a lay= command.

  Likewise if I forget a function key and don't want the entire funkey command list I can just...
seafk odot
and all the appropriate function keys are presented.

It must be nice to have a limitless unhindered storage capacity, but for those of us who have more useful years in the past than in the future, search is our friend.

They both essentially work the same, just one searches the layer names and one searches the function keys.  Here is an example but you get the idea.

print 'seafky.py modified 9:11 AM 7/27/2017'# Display FKeys matching search string
'''
Copyright 2017 Dennis Shimer
Vr Mapping copyright Cardinal Systems, LLC
No warranties as to safety or usability expressed or implied.
Free to use, copy, modify, distribute with author credit.

Prompts user for Fkey name (or any part) then displays Fkey
'''

def lines2lists(AListOfDataLines):
    DataList=[]
    for Line in AListOfDataLines:
        DataList.append(Line.split())
    return DataList

PrintList=[]

if VrArgs:
    SearchText=VrArgs[0]
else:
    SearchText=PyVrGui().InputDialog ('Search String', 'Partial Funkey Name')[1]

FunKeyFile = open(VrCfg().GetFkeyFileName() , 'r')
FunkeyData = FunKeyFile.readlines()
FunKeyFile.close()
DataList = lines2lists(FunkeyData)

for DataLine in DataList :
    if len(DataLine) == 3 :
        if DataLine[1]=='KeyName':
            if DataLine[2].upper().count(SearchText.upper()):
                PrintList.append(DataLine[2])

if PrintList:
    PromBox = VrPromBox ("Run Fkey", 60, 1)
    PromBox.AddList ("Function Key", 40, len(PrintList)+1, 0)
    for FkeyItem in PrintList:
        PromBox.AddListItem (FkeyItem)
    if (PromBox.Display(0) == 0):
        RunFkey = PromBox.GetListByPrompt ("Function Key")
    else: RunFkey=0
    if RunFkey : PyVrGui().PushKeyin(RunFkey)
    else: PyVrGui().MsgBox('No Match to {:s}'.format(SearchText), 'Matching Layers')

Tuesday, September 20, 2016

Going from Zero to "How did I ever get along before that" in three minutes

The other day I heard about a little indicator app ( aka bookmarks-indicator ) for Ubuntu that sits nicely on the task bar and allows you to drill down through the disk hierarchy by simply mousing over the icon.  It displays the folder names as you move through the system, auto expanding as you pause over a file name, showing individual files in each folder and opening them when you click.  One minute I didn't even know I wanted this ability and three minutes later I wondered how I ever survived without it.  The fact that is was just a couple dozen easy to read lines of python was even funner.  

Jump ahead to this morning and I came across a bunch of lines that just needed to have one particular point removed from them.  Long story, but on this particular job it happens on a fairly regular basis.  Well I've always had a program to straighten a line, removing all points between to identified locations, but I just needed to delete one point, and doing it with a single click would just be that much easier.  Granted EditVertex set to delete is 95% of the way to what I want but honestly sometimes you just need to step outside for a break to grab that last 5% especially if you can do so with a few lines of code.  And let's be honest it's funner than working anyway.

Hence dellpt.py

print 'dellpt.py modified 9:06 AM 9/20/2016'
# Delete Line Point
'''
Copyright 2016 Dennis Shimer
Vr Mapping copyright Cardinal Systems, LLC
No warranties as to safety or usability expressed or implied.
Free to use, copy, modify, distribute with author credit.

Deletes a single point identified on a line.
'''

Ws=PyVrWs()
Line=PyVrLine()
while Line.Id() != -1:
    Ws.UndoBegin(WsNum,"dellpt")
    PntNum=Line.GetIdPoint ()
    Line.DelPoint (PntNum)
    Line.ReRec()
    Line.Plot()
    PyVrGr().Replot()
    Ws.UndoEnd(WsNum)

Thursday, June 09, 2016

Simple tools for simple tasks (an appreciation for....)

Maybe because I am fairly simple minded, I have always had a deep appreciation for "The Unix Philosophy" which to my thinking involves the idea that if you just need to solve a simple little problem quickly you just throw together a simple little tool to do it but at the same time make sure that there is a way to chain these little tools together in a way that can make the aggregate a truly useful and maybe powerful solution. The integration of this idea into the programs I interact with minute by minute all day every day (and the fact that the first versions were on Unix) make Mike Kitaif one of my heroes.  Yes almost every function, option, toolset has an easy, GUI, comprehensive way of dealing with it but at the same time almost all have a simple command equivalent with arguments that can be built upon using function keys, macros, or incredibly the python interpreter. When you combine this with the fact that rather than a monolithic database for hanging on to all the settings they are usually stored in tiny easily accessible (sometimes even text) files you get the opportunity to make the system do almost anything you can dream.

A great example of all this came up recently when I realized that under certain conditions I wanted to under certain conditions be able to view a particular vertical slice of LiDAR data and set the coloring based on elevation sub-slices.  There is of course a way to do this using the GUI for the poidis command.

There are also fairly straightforward ways to set all these things from the command line.
http://www.vrmapping.net/help5/index.html?point_display.htm

However, what I really wanted was the ability to input a minimal amount of information (base elevation and total slice thickness) and then have it display exactly what I wanted with the colors set to the sub slices (thickness divided by total number of available slices, or 20 currently) and here is where the python comes in. Granted the programming is about at the level of an 8 year old with a Raspberry Pi but you get the idea.

print 'viewsl.py modified 6:06 AM 5/6/2016'
# Views a slice of lidar with color by slice elevation.
'''
Copyright 2016 Dennis Shimer
Vr Mapping copyright Cardinal Systems, LLC
No warranties as to safety or usability expressed or implied.
Free to use, copy, modify, distribute with author credit.

A little more user friendly option to the Vr alternative which uses an
external parameter file which can be referenced by other programs
like bumvsl

'''
import os
import man
Ws=PyVrWs()
WsNum=Ws.Aws()
Gui=PyVrGui()

MinZ = Ws.GetMinMax (WsNum)[2]
MaxZ = Ws.GetMinMax (WsNum)[5]
AverageZ = (MaxZ+MinZ)/2.0

#In case the parameter file was never created before or can't be read for some reason
BaseZ=AverageZ
DelZMin=MinZ-AverageZ
DelZMax=MaxZ-AverageZ
Thickness=MaxZ-MinZ

ParFileName=VrCfg().GetVrHomeDir()+'/hostdir/viewslice.par'
if not os.path.isfile(ParFileName):
     open(ParFileName,'w').write('{:.2f} {:.2f} {:.2f} {:.2f}'.format(BaseZ,DelZMin,DelZMax,Thickness))
elif not os.path.getsize(ParFileName):
     open(ParFileName,'w').write('{:.2f} {:.2f} {:.2f} {:.2f}'.format(BaseZ,DelZMin,DelZMax,Thickness))
Params=open(ParFileName,'r').read().split()
BaseZ=float(Params[0])
Thickness=float(Params[3])

#In case the user passes in the numbers from the command line.
if VrArgs:
      BaseZ=float(VrArgs[0])
      Thickness=float(VrArgs[1])

PromBox = VrPromBox ("Set Z Slice", 30, 1)
PromBox.SetFocus()
PromBox.AddDouble('BaseZ',BaseZ,2)
PromBox.AddDouble('Thickness',Thickness,2)

if not VrArgs:
      if PromBox.Display(1)==0:
          BaseZ=PromBox.GetDoubleByPrompt('BaseZ')
          Thickness=PromBox.GetDoubleByPrompt('Thickness')
open(ParFileName,'w').write('{:.2f} {:.2f} {:.2f} {:.2f}'.format(BaseZ,DelZMin,DelZMax,Thickness))

#Just use the numbers to pass along arguments to the built in commands.
print BaseZ,DelZMin,DelZMax,Thickness
Gui.PushKeyin ('PoiFilZsl  On')
Gui.PushKeyin ('PoiFilZsl  BasZ {:.2f}'.format(BaseZ))
Gui.PushKeyin ('PoiFilZsl  MinDel {:.2f}'.format(0))
Gui.PushKeyin ('PoiFilZsl  MaxDel {:.2f}'.format(Thickness))

NumberOfSlices=20
SliceThickness = Thickness*1.08/NumberOfSlices #1.08 because it minimizes the top white slice.
print MinZ,MaxZ,SliceThickness,NumberOfSlices
Gui.PushKeyin ('PoiColSli  On')
Gui.PushKeyin ('PoiColSli  ResZ')
Gui.PushKeyin ('PoiColSli SliZ {:d} {:.2f} {:.2f}'.format(1,0,BaseZ))
CurrentElevation=BaseZ
for CurrentSliceNumber in range(2,NumberOfSlices):
    Gui.PushKeyin ('PoiColSli SliZ {:d} {:.2f} {:.2f}'.format(CurrentSliceNumber,CurrentElevation,CurrentElevation+SliceThickness))
    CurrentElevation+=SliceThickness
Gui.PushKeyin ('PoiColSli SliZ {:d} {:.2f} {:.2f}'.format(NumberOfSlices,CurrentElevation,1000000))

PyVrGr().Replot()

*Read the Wikipedia article if for no other reason than to better appreciate some of the men who helped make this all possible.

Wednesday, December 16, 2015

30 Second Functions

When is it faster to write the function than to even find out how to do it in the help.  Well ok, I did actually search and didn't find out how, but here is what would have been faster.

I use handwheels,  I wanted an easy way to switch the z input from the footdisk to the right handwheel and back.  There is probably a way to pass an argument into a macro but I couldn't find it so enter....

zhand.py

print 'z handwheel'
VrCfg().SetHwLocZ (2)
The beauty of VrCfg is that it modifies the environment in real time just like calling any of the functions that would do the same thing via a dialog box.

Saying anything else would just not have a point, except, always be thinking of ways to extend the usefulness of existing processes.

Tuesday, December 15, 2015

I Get By With A Little Help From My Friends

Talking to a friend the other day it occurred to me how fantastic it would be if Vr could import and display OpenStreetMap data.  Nothing fancy mind you but maybe create an image that you could use as a background for a quick check of the surrounding area or even flight prep.  Wow that sounds like a lot of work unless of course someone else has already done it.  One of the many beauties of Python is the number of fantastic libraries out there if you just spend a little time tracking them down.  If you take that a step farther and are willing to pass a little of the responsibility outside python using system calls or batch files the possibilities are nearly endless.  Let's just say I can now display an OpenStreetMap map image in Vr and it only took about 90 lines of python.  Here are a few of the major helpers besides the map site which is so worthy of support, contribution, and praise.

I know I have mentioned it before but I can't say enough about pyproj which I use to convert my local coordinates to geographic for sending out to various places.

Once I have the corners in Lat / Long the rest will be done by a batch file which is about the only thing my python script creates.  It could be done in other ways but I liked the idea of creating something that could stick around and be easily modified for use again.  So the batch file next makes a call to the openstreetmap.org API for grabbing the map data.

Once the OSM file is in house it will be converted to a bitmap using Maperitive.  I only use such a tiny fraction of the capabilities of this amazing program, but for my purposes using it's command line version with a custom generated script will fit the bill perfectly.

The original bitmap is created in Web Mercator and can also throw in a TFW and KML file for generic use or display by anybody if you want to send them along.  I however want to display it behind my map in a local coordinate system in whatever system I choose so the last step is to re-project the image using GDAL.

Is this the most advanced, professional, elegant way of doing it?  Of course not, you obviously don't know me very well.  As usual it is something you can hack together in just a short time with minimal duplication of effort that gets the job done.  Hooray for real programmers!!!

Don't forget to support your favorite projects with contributions or cash when possible.


For anyone interested in trying VrPython for the first time or if you are early in the game, I suggest going to the earliest posts and working forward. I use VrPython every day for many wonderful things, needless to say it will change and could potentially damage a file. Any risk associated with using VrPython or any code or scripts mentioned here lies solely with the end user.

The "Personal VrPython page" in the link section will contain many code examples and an organized table of contents to this blog in a fairly un-attractive (for now) form.