Monday, December 11, 2006

I'll come back to learning python but thought I would toss in a little Vr as well. Had a situation where a colleague wanted to perform a fairly simple and repetitive task. When it came right down to it Vr already had most of the tools he needed, I thought about stringing it together into a macro for him, but realized that some conditional statements would add a little zip to the solution. In the end the solution is a good example of just using python as an extended macro language. Nothing earth shattering, just using basic Vr commands, but putting a little of the power of python behind them.

The situation was that he wanted to be able to quickly and visually throw points into a file in a random pattern using the mouse. Then to make these same points part of a valid 3d data set he wanted to have the instrument drive back to the points, pause for the dot to be placed on the ground, set the elevation of the symbol to the current instrument position, then go on to the next point without having to issue any command other than ending the id process.

The outline of the solution goes as follows.

  1. Digitize the symbols in a layer that makes them unique.
  2. Capture the xyz locations of those symbols by looping over the points in the file.
  3. Loop over the locations with a process that
    1. Pauses to digitize a new z at each location
    2. Set the symbol to that elevation.
    3. Drive to the next point.
  4. When all done globally change the symbols to make them part of the normal data set.
I'll address a couple of the redundant or wasteful portions of the solution later, but to some extent this will also expose that fact that sometimes I write ugly code just to get something out for testing in a fairly short time, I regularly go back when things are slow and tighten up procedures. This one definitely qualifies as one of the ugly ones, but it's still a good example. Keep in mind that to this point I haven't found a way to make the proper indentation persistant in this blog so until further notice I'll use periods to fill the space where indentation belongs. Lets look at the code line by line...

Gui = PyVrGui()

Gui.PushKeyin ("py drv2lay")
Gui.PushKeyin ("digxyz")
while stat==0:
..Gui.PushKeyin ("dri")
..stat, x, y, z = Gui.GetCoord ('Select Coordinate')
..if stat==0:
....Gui.PushKeyin ("chaele")
....Gui.PushKeyin ("sealin=0")
....Gui.PushKeyin ("seasym=1")
....Gui.PushKeyin ("b1")
....Gui.PushKeyin ("b1")
....Gui.PushKeyin ("b#")

Gui = PyVrGui()
This one just imports the appropriate library that will do most of the work in this script.

The routine used to grab the current instrument position returns a list which includes the process status to evaluate whether the used in fact digitized a point or just hit end.

Gui.PushKeyin ("py drv2lay")
This is the most obscure part of the code. I already have a script that asks the user for a layer number (or number line), creates a drive file containing a drive point for every symbol in that layer, then opens the drive file. I will discuss that program in a later post but for now any function that grabs the xyz values for every symbol in a pre-determined layer would be fine. I chose to go the drive route so the values would be stored temporarily, and I could just use the Vr "dri" function later. "PushKeyin" just sends the string in quotes to the Vr command line as if the user had typed it

Gui.PushKeyin ("digxyz")
Because the first time someone used it, they started the program while still set to the mouse which had been used to digitize the symbol locations, as well they should. Just need a toggle it over if it hasn't already been done.

while stat==0:
Python flow control is fairly standard, In this case if the user hits "End" rather than digitizing the new elevation at the symbol position the routine would return a 1, so if this happens "game over".

Gui.PushKeyin ("dri")
In the actual work part of the loop the first thing we want to do is drive to the next valid coordinate position, remember that there is already a drive file open with all the positions I want because of the other python program I called earlier.

stat, x, y, z = Gui.GetCoord ('Select Coordinate')
Once we get to the position, pause and wait for the operator to put the dot on the ground and hit the button sending a status code and especially important the new Z.

if stat==0:
There is probably a more elegant way of doing this, but the fact is that after the user digitizes a point I needed to know if they had hit "End" and if so just skip the rest. If they digitized a new z location I want to do the following using the keyin routine.
chaele - start chaele because that's what I actually want to do.
sealin=0 - make sure that line search is off.
seasym=1 - make sure symbol search is on.
b1 - hit button 1 to identify the symbol at the location where the instrument is sitting.
b1 - hit button 1 to release the point.
b# - hit the # to end chaele and resume the loop which then drives to the next point.

So in this example I'm just using python to create the drive list, and the control flow to loop over it. I could also turn off any layers that aren't necessary to make sure that nothing errant gets identified. It could also have been done in one step without the second loop by not creating the drive file, but simply making a go to xyz statement part of the first loop which identifies the proper points.

No comments:

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.