[GRASS5] Vector Calculator for Grass
Christoph Simon
ciccio at kiosknet.com.br
Wed Aug 7 10:03:56 EDT 2002
I've started to program a vector calculator program for Grass,
inspired by r.mapcalc, wich is available at
http://freegis.org/cgi-bin/viewcvs.cgi/grass51/vector/v.mapcalc/
Right now, I need to take a break working on it for professional
reasons, as I am involved in a bigger project of which I do not know
how long it will last.
I'll try to summarize and comment here on what has been done, what it
is useful for and what still needs to be done.
It's much more complicated to deal with vector maps than with raster
maps. Particularly, there are several levels on which we might want to
deal with a vector map. For this reason the design of v.mapcalc is
that of a skeleton with plugins: A parser will interpret statements
and call the appropriate functions it finds in dynamically loaded
plugins.
The syntax should be able to deal with four different types:
- numbers
- points
- point lists
- maps
Nummeric expressions should do what everybody would expect. There are
some dozens of builtin functions from the math library. Points and
point lists are meant in the mathematical sense: A point is a set of
two or three numbers, representing the coordinate. All points have
three components, but the third, if missing has the value of
sqrt(-1). An expression will yield a 3D result if all arguments a
3D. There is a set of basic builtin operations like dot and cross
product. Point lists are meant for polygons, lines, areas, etc. Points
and point lists have no categories or attributes. And finally, of
course, v.mapcalc deals with map expressions.
For numbers, the infix operators do the obvious. For other types, the
parser will translate them to function calls with predefined
names. Some samples are set and can be replaced by something useful.
The plugins are designed to be as simple as possible. There is one
example which actually doesn't do anything but shows how it can be
called. Such a plugin needs three global functions: One which can be
called to find out the name the user must type to use the function,
one which returns a string denoting the return type and the type and
number of arguments, and finally the function itself.
There are two more types which are somewhat special: One is type
`argument' which can be any of the basic types. The parser will accept
anything to be the argument to a function call, but the mechanism to
actually call that function will check if the types match the
prototype. The second special type `any' is sort of a backdoor: If
something new comes up, it can be treated as type any, and it will be
responsibility of the plugin to verify that it's the correct type. One
case where the any-type can be useful is for SQL statement-pieces or
other constructs when dealing with attributes, which can be literally
of "any" type.
There is one problem with this approach within v.mapcalc, which is
calling a function with a variable list of arguments. This is a bit
complicated, and before thinking of easy solutions, I need to
recommend reading the code. Just before calling it, v.mapcalc has a
pointer to that functions and a linked list of structures which hold
the argument types and values. It would be nice to be able to
construct such a call argument by argument, but there is no portable
way to do so: First assembly would be needed, and second, the way a
stack frame is built for a particular compiler/architecture can vary.
The solution is to maintain a list of typedef'd prototypes and call
them in a switch. This means, if someone needs a new function and
writes a plugin, either he finds a typedef which matches this
prototype, or he needs to add the typedef and a case in the switch.
It makes only limited sense to mix arguments of different types: three
at the power of map-A doesn't seem to be useful. So, the basic
strategy is accept expressions only of the same type, while mixing
types is always possible within the arguments to a function call.
There is a file listing some example expressions. I hope that it is
what one could expect. Adding a few plugins should allow for very
complex expressions and operations.
What still needs to be done:
- The lexical scanner. At this point, there is a very simple and
limited scanner. My plan was to provide 4 methods of input:
+ from the command line
+ from stdin, interactively, using GNU readline and history
+ from stdin by IO redirection like in "script | v.mapcalc"
+ from a file, like in "v.mapcalc -i statementfile"
Of course, this should be done with Flex, with the input selection
as needed for all methods, as well as support for Bison to indicate
the position of a parse error.
- There should be several builtin commands allowing to:
+ include a file with statements
+ document the meaning of a variable or function
+ attaching documentaton to a variable or function
+ saving certain things in a readible script like documentation or
constant values.
+ a command to terminate the program (right now, only with Ctrl-D)
- There is not yet any support for loops and conditionals. These do
not seem to be of much use with maps, but can prove powerful on
points and point lists.
- There are certain operations which need to be performed always, like
opening a map. For now, they need to be done in the plugin, but
should definitively move to v.mapcalc.
- Point lists are not working yet, though much of the basic
infrastructure is already done.
- There seems to be a bug in memory management which can cause the
program to crash. Probably there are many more than that.
I plan to continue work on v.mapcalc as soon as my time allows. In the
meanwhile, I'd be happy if others advance on this (the core of
v.mapcalc and/or plugins), and I'll do everything to answer questions
someone might have trying to do so.
--
Christoph Simon
ciccio at kiosknet.com.br
---
^X^C
q
quit
:q
^C
end
x
exit
ZZ
^D
?
help
.
More information about the grass-dev
mailing list