README 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. The code was written by Christoph Simon <ciccio@kiosknet.com.br>.
  2. DESCRIPTION
  3. From ciccio@kiosknet.com.br Wed Aug 7 16:03:56 2002
  4. From: Christoph Simon <ciccio@kiosknet.com.br>
  5. To: grass5@grass.itc.it
  6. I've started to program a vector calculator program for Grass,
  7. inspired by r.mapcalc, wich is available at
  8. http://freegis.org/cgi-bin/viewcvs.cgi/grass51/vector/v.mapcalc/
  9. Right now, I need to take a break working on it for professional
  10. reasons, as I am involved in a bigger project of which I do not know
  11. how long it will last.
  12. I'll try to summarize and comment here on what has been done, what it
  13. is useful for and what still needs to be done.
  14. It's much more complicated to deal with vector maps than with raster
  15. maps. Particularly, there are several levels on which we might want to
  16. deal with a vector map. For this reason the design of v.mapcalc is
  17. that of a skeleton with plugins: A parser will interpret statements
  18. and call the appropriate functions it finds in dynamically loaded
  19. plugins.
  20. The syntax should be able to deal with four different types:
  21. - numbers
  22. - points
  23. - point lists
  24. - maps
  25. Nummeric expressions should do what everybody would expect. There are
  26. some dozens of builtin functions from the math library. Points and
  27. point lists are meant in the mathematical sense: A point is a set of
  28. two or three numbers, representing the coordinate. All points have
  29. three components, but the third, if missing has the value of
  30. sqrt(-1). An expression will yield a 3D result if all arguments a
  31. 3D. There is a set of basic builtin operations like dot and cross
  32. product. Point lists are meant for polygons, lines, areas, etc. Points
  33. and point lists have no categories or attributes. And finally, of
  34. course, v.mapcalc deals with map expressions.
  35. For numbers, the infix operators do the obvious. For other types, the
  36. parser will translate them to function calls with predefined
  37. names. Some samples are set and can be replaced by something useful.
  38. The plugins are designed to be as simple as possible. There is one
  39. example which actually doesn't do anything but shows how it can be
  40. called. Such a plugin needs three global functions: One which can be
  41. called to find out the name the user must type to use the function,
  42. one which returns a string denoting the return type and the type and
  43. number of arguments, and finally the function itself.
  44. There are two more types which are somewhat special: One is type
  45. `argument' which can be any of the basic types. The parser will accept
  46. anything to be the argument to a function call, but the mechanism to
  47. actually call that function will check if the types match the
  48. prototype. The second special type `any' is sort of a backdoor: If
  49. something new comes up, it can be treated as type any, and it will be
  50. responsibility of the plugin to verify that it's the correct type. One
  51. case where the any-type can be useful is for SQL statement-pieces or
  52. other constructs when dealing with attributes, which can be literally
  53. of "any" type.
  54. There is one problem with this approach within v.mapcalc, which is
  55. calling a function with a variable list of arguments. This is a bit
  56. complicated, and before thinking of easy solutions, I need to
  57. recommend reading the code. Just before calling it, v.mapcalc has a
  58. pointer to that functions and a linked list of structures which hold
  59. the argument types and values. It would be nice to be able to
  60. construct such a call argument by argument, but there is no portable
  61. way to do so: First assembly would be needed, and second, the way a
  62. stack frame is built for a particular compiler/architecture can vary.
  63. The solution is to maintain a list of typedef'd prototypes and call
  64. them in a switch. This means, if someone needs a new function and
  65. writes a plugin, either he finds a typedef which matches this
  66. prototype, or he needs to add the typedef and a case in the switch.
  67. It makes only limited sense to mix arguments of different types: three
  68. at the power of map-A doesn't seem to be useful. So, the basic
  69. strategy is accept expressions only of the same type, while mixing
  70. types is always possible within the arguments to a function call.
  71. There is a file listing some example expressions. I hope that it is
  72. what one could expect. Adding a few plugins should allow for very
  73. complex expressions and operations.
  74. What still needs to be done:
  75. - The lexical scanner. At this point, there is a very simple and
  76. limited scanner. My plan was to provide 4 methods of input:
  77. + from the command line
  78. + from stdin, interactively, using GNU readline and history
  79. + from stdin by IO redirection like in "script | v.mapcalc"
  80. + from a file, like in "v.mapcalc -i statementfile"
  81. Of course, this should be done with Flex, with the input selection
  82. as needed for all methods, as well as support for Bison to indicate
  83. the position of a parse error.
  84. - There should be several builtin commands allowing to:
  85. + include a file with statements
  86. + document the meaning of a variable or function
  87. + attaching documentaton to a variable or function
  88. + saving certain things in a readible script like documentation or
  89. constant values.
  90. + a command to terminate the program (right now, only with Ctrl-D)
  91. - There is not yet any support for loops and conditionals. These do
  92. not seem to be of much use with maps, but can prove powerful on
  93. points and point lists.
  94. - There are certain operations which need to be performed always, like
  95. opening a map. For now, they need to be done in the plugin, but
  96. should definitively move to v.mapcalc.
  97. - Point lists are not working yet, though much of the basic
  98. infrastructure is already done.
  99. - There seems to be a bug in memory management which can cause the
  100. program to crash. Probably there are many more than that.
  101. I plan to continue work on v.mapcalc as soon as my time allows. In the
  102. meanwhile, I'd be happy if others advance on this (the core of
  103. v.mapcalc and/or plugins), and I'll do everything to answer questions
  104. someone might have trying to do so.
  105. --
  106. Christoph Simon
  107. ciccio@kiosknet.com.br
  108. ---------------------------------------------------------------------------
  109. EXAMPLES:
  110. Some examples of what is working now:
  111. This is an empty statement, which is legal
  112. ;
  113. Some builtin constants:
  114. 12;
  115. e;
  116. pi;
  117. pnt_o;
  118. pnt_i;
  119. pnt_j;
  120. pnt_k;
  121. rivers;
  122. The last one isn't really a constant, as it depends on what if found
  123. at startup, but it behaves just the like.
  124. a;
  125. This gives an error. "a", which is (not yet) defined, is handled as a
  126. string. There is no operation associated, so this gives a parse error.
  127. Next some simple assignments. Also here, the name of the variable is
  128. initially not more than a string, but after performing the assignment,
  129. they take the type of the expressionL:
  130. num = 10.3;
  131. pnt = (0,0);
  132. map = rivers;
  133. any = mkstring (hallo);
  134. The last is only a backdoor for cases when exceptional things are
  135. needed. The function mkstring is a sample implementation of type
  136. ANY. For now, only one word could be passed, but when flex is being
  137. used a quoted string might contain just anything.
  138. Next, I overwrite these variables. This is somewhat tricky. If you say
  139. "map = rivers", what should happen? In theory, we should actually
  140. duplicate this map, which could imply gigabytes on disk. This is not
  141. done, but if the map is changed, it must not change the former
  142. `value'. I hope it's doing now, what everybody would expect (including
  143. to free eventually the allocated memory).
  144. num = 3.1;
  145. pnt = (1,1);
  146. map = cities;
  147. any = mkstring (hello);
  148. The pure nummeric operations aren't new, beside that I'm trying to
  149. catch illegal operations:
  150. sqrt(e);
  151. num = cos (pi/4);
  152. num = -num + 3 * num - sqrt (num^2);
  153. 3.3 + 4.4;
  154. 2.2 - 1.1;
  155. 5 * 7;
  156. 21 / 0;
  157. 21 / 2;
  158. -21 / 7;
  159. -6.6 ^ 1.2;
  160. 6.6 ^ 1.2;
  161. 12.5 % 3.6;
  162. 2 * (3.1 + 0.9);
  163. Next are points. Note that 2D and 3D are dealt with identically; in
  164. case of 2D, the z-value is sqrt(-1) (NaN, "Not a Number"). This should
  165. be pretty portable. Generally, if at least one point is 2D, the result
  166. of a point operation will be 2D even if 3D points are involved too,
  167. ignoring the third dimension. I've defined some infix operations a bit
  168. arbitrarily. Of course, this could be changed. The double () in case
  169. of a single function argument are surely ugly, but not avoidable.
  170. origin2d = (0,0);
  171. p1 = (1,1);
  172. p2 = p1;
  173. p2 = v_copy (p1);
  174. v_add ((1,0), (0,1));
  175. (1,0) + (0,1);
  176. v_sub ((1,1), (0,1));
  177. (1,1) - (0,1);
  178. v_abs ((-2, -1));
  179. v_neg ((2, 1));
  180. -(2,1);
  181. v_mul ((2,4), 3.3);
  182. (2,4) * 3.3;
  183. 3.3 * (2,4);
  184. v_div ((6.6, 13.2), 3.3);
  185. (6.6, 13.2) / 3.3;
  186. v_unit ((12, 8));
  187. v_cross ((1,2), (4,5));
  188. v_cross ((1,2,3), (4,5,6));
  189. (1,2,3) ^ (4,5,6);
  190. v_val ((3,3));
  191. v_dot ((1,2), (3,4));
  192. (1,2) % (3,4);
  193. v_dot ((1,2,3), (4,5,6));
  194. (1,2,3) % (4,5,6);
  195. v_area ((1,2,3), (4,5,6));
  196. v_eq ((1,2), (1, 2));
  197. v_eq ((1,2), (1.0001, 2.0001));
  198. epsilon = (1e-3, 1e-3);
  199. v_eq_epsilon ((1,2), (1.0001, 2.0001), epsilon);
  200. v_isortho ((0,1), (1,0));
  201. v_ispara ((0, 1), (0, -1));
  202. v_isacute ((0, 1), (0, 0.5));
  203. 3 * (pnt + (2,2));
  204. This is planned, but doesn't work yet:
  205. line = ((1,1), (2,1));
  206. triangle = (line, (1.5, 2));
  207. And finally the map operations, which also aren't new, beside some
  208. internal details (freeing memory, not duplicating, etc.). I think that
  209. there is no map-operation which makes sense if it is not assigned to a
  210. variable. So all map expressions need to follow a variable and an
  211. equal sign. The very first expression, hence, will give an error:
  212. rivers + cities;
  213. map = rivers;
  214. map;
  215. map = rivers + cities;
  216. map = testmap (rivers);
  217. map = test2map (rivers, cities);
  218. map = dltest (rivers, cities);