[GRASS5] Architectural difficulty with grass5 port: display driver function set changes (please read)

strobe anarkhos anarkhos at mac.com
Fri Mar 9 05:54:34 EST 2001


Hello,
	I'm attempting to port GRASS and have hit roadblocks 
specifically dealing with grass5 display drivers. To make what I 
consider a proper port possible I plan to extend the function set of 
the display driver then make small changes to the display command 
set. It has been brought to my attention that the larger grass 
community has already been experimenting in this area and I would 
like to find out if it's possible to avoid a split in the project 
(which I'm sure everybody involved would prefer). This has become 
especially important since I've learned there is a developmental 
d.layers command which I was also planning to implement (although not 
likely with similar results). If the larger grass community extends 
the display driver command set in a different manner than I do (like 
adding layer support) then things are going to get very hairy.

	I'll try to summarize everything which has brought be to the 
decision of extending the display driver function set for my port. 
Then I hope we can understand each other's goals for grass. I've 
taken the time to make myself as clear as possible, so please excuse 
the size of this email.

	I would first like to say I think GRASS is a fantastic GIS 
system with the exception of 2D graphics which I feel is it's weakest 
feature by far. Every display function I planned to add can probably 
be made backwards compatible (see step 4) although I didn't 
originally plan on doing so.

	I'm planning to first port GRASS to OS X then eventually 
GNUStep. OS X is Apple's new operating system while GNUStep is an 
open source implementation of the OpenStep API which runs on any 
*.nix running the X11 display server. OS X supports an API called 
Cocoa which is nearly identical to OpenStep.

	There are two reasons I'm using this API. OpenStep is a 
platform-neutral API which has a high level of abstraction, including 
graphics. Thus complex graphics applications can be written in 
OpenStep and recompiled to various platforms without re-writing the 
drawing code. Secondly OpenStep's graphics abstraction is resolution 
independent meaning images rendered to your screen or postscript 
printers are only representative of the actual image and are 
implicitly scaled when necessary. Thus we get benefits such as 
sub-pixel anti-aliased vector maps, 32bit RGBA or CMYKA layers, 
WYSIWYG printing, small print/PDF/EPS files, live zooming, accurate 
rulers, etc. basically for free.

	The obvious problem is grass display drivers use resolution 
dependent graphics, meaning functions like draw_line() accept values 
in pixel units. I have been toying with various ideas to get around 
this problem and I think I've found a good solution. This is my 
current planned course of development:

1) Develop a simple traditional display driver, adding layer support.

This can be thought of compatibility mode. Here is basically where I 
implement layers. Each group of layers belong to a specific map (and 
projection) so they align correctly. For this reason layer creation 
will also have to use a new display driver function like 
set_map(name, region). If a different map is set a new group of 
layers will be automatically created for the user, probably with the 
title being the map name. I'll make this more clear later.

The user will have to explicitly create a new layer (d.layers?) which 
creates a new drawing canvas. Unfortunately grass5 display drivers do 
not understand the concept of grouping, but rather have a series if 
inline functions like draw_line() thus the user has to explicitly 
make a new layer. This brings up the interesting question of how to 
handle a series of draw_line() and Raster_int() functions. What 
happens in all other grass5 display drivers is one overwrites the 
other (they don't make separate drawing objects). I do this in Cocoa 
using the NSImage command compositeToPoint. Thus if the user isn't 
creating new layers, 'classic' drawing functions will overwrite each 
other.

Obviously my "specialized" interface (grass 5 dev. manual term) will 
automatically create new layers before executing drawing commands 
thus calling multiple commands. If the user doesn't create new 
layers, new commands will overwrite old ones just like it currently 
does in grass5. Thus if the user is using the command line instead of 
my specialized interface, drawing commands will essentially behave 
exactly like grass5 for X11 currently does.

So at this point the only change to the display driver API is adding 
simple layer management functions. The simplest implementation would 
be creating a layer, destroying a layer, and drawing to a specific 
layer. Changing the ordering/hiding of layers doesn't need 
programmatic interfaces in the driver API, the display driver can 
offer graphical interfaces to do this (in order to keep the display 
driver function set small). So long the first three are implemented I 
don't really care, I don't think every single graphical change need 
have a command associated with it.

There is an implicit hierarchy where layers are grouped into the 
map:projection they belong to. This is implicit because the display 
driver automatically does this based on the set_map() function. 
Basically if a map is set which doesn't match the current 
map:projection a new layer is created in that category (which is 
automatically created if the map:projection doesn't exist). The 
projection is obviously part of the region, however you can draw maps 
in the same map:projection even if the regions do not match so long 
the projections do. Thus I can draw two maps with d.vect which have 
the same projection but draw on two different areas of that 
projection. If this conflicts with the current map organization 
internal to GRASS I think it's worth changing, it wouldn't break 
backwards compatibility.

Graphically the display driver can do whatever it wants to switch 
between map:projections. It can use separate windows, tabs, 
page-flippers, whatever. So long it knows the map and region of every 
layer it has all the information required to composite everything 
correctly.

I'm going to now explain how I will implement my display driver just 
to serve your curiosity. The X11 or whatever implementation will 
likely be very different, which in my book is fine so long the result 
of the functions called have an analogous result.

My display driver will allow the user to select the virtual 
dimensions of the drawing area. The default will be 72dpi but easily 
changed to say 300dpi. I'll probably call this the 'compatibility' 
resolution (if you can think of a better term let me know) and is the 
resolution used for grass display driver functions like mouse 
functions, panel functions, etc. I will likely have a zoom window 
which will show where the cursor is in this resolution, thus the 
mouse may move slower when hovering over a map if it's in mouse 
tracking mode (perhaps 2x slower if the compatibility resolution is 
twice the visible one). Or it may run faster if the compatibility 
resolution is smaller than the visible one. Vector functions like 
draw_line and Polygon_abs will likely use NSBezierPath and remain as 
resolution indepedent paths until implicitly composited to the 
compatibility resolution when drawing to screen, saving panels, etc. 
Panels (as defined in the grass5 dev. manual) will likely remain as 
bitmaps, although I have toyed with the idea of using non-bitmap 
panels.

I will only add that set_map() is an ad-hoc function name to explain 
an idea. What I will probably do instead is integrate map setting and 
layer creation by making a functions like:

layer new_layer(map region)
layer set_map(map region)
layer select_layer(layer)
layer select_top_layer(map region)

where the returned layer is the current drawing layer and nil if it 
couldn't be created/selected.

At this point all d.* commands will function without recompilation, 
you just have to edit the monitorcap file to use our new driver 
instead of the old XDRIVER (or whatever).

The default behavior will be almost exactly the same as grass5 in X11 
is currently.

2) Extend the display command set.

The next step will be to add simple resolution independent functions 
to the function set. The syntax will be very simple. 
draw_line(x1,y1,x2,y2) is the resolution dependent vector drawing 
function, the resolution independent function may be 
ri_draw_line(x1,y1,x2,y2) where the units and limits are appropriate 
for the map's region. This function could only logically be used by 
map drawing commands like d.vect. Before using ri_* functions, a map 
drawing command has to set the map using set_map() to assure correct 
alignment (and assure it's only composited with other layers with the 
same map:projection).

All d.* commands will work like before.

3) Edit d.vect to use our new resolution independent functions

d.vect will now use the resolution independent commands and we 
magically get a bunch of extra functionality. The code for using 
ri_draw_line() are actually simpler because no scaling is involved. 
You just pass the region then start using ri_draw_line() and 
ri_Polygon_abs(). Theoretically this is the easiest step.

At first it may appear the updated d.vect command is no different 
than the old one, however the new one has anchor points in floating 
units thus the difference will easily be seen when zooming or 
printing.

Repeating step 2 and 3 for raster is analogous. You set the region 
then use ri_Raster_int() which will pass the raster image without 
scaling. The display driver does the scaling.

Thus only *small* changes need to be made to d.vect, d.area, d.rast, 
and any other map drawing commands in order to gain all the leet 
features I've mentioned.

4) Implement backwards compatibility so new commands work with old displays

By moving the scaling code used in d.rast and d.vect into the X11 
display driver it should be possible to have some form of backwards 
compatibility. In theory the same base set of drawing functions will 
be necessary to create the new display drivers (draw_line(), 
Polygon_abs(), mousing functions, panels, etc.). The most difficult 
may be layers.

We could create a new color definition which is RGBA instead of RGB 
then create a new set of functions which can draw vector and raster 
images in RGBA. If we do, we should also allow an 8-bit mask to be 
attached to a layer. I plan to do this anyway, but it would be great 
if we implemented this in the new display driver API. If you do not 
add RGBA into the general display driver function set any emulation 
will have to use internal RGBA composition then convert to RGB 
'layers' (although I hesitate to ask what on earth are layers good 
for without masks).

I hope we can implement the same set of display functions even if the 
X11 implementation doesn't gain all the features I mentioned.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: text/enriched
Size: 10819 bytes
Desc: not available
Url : http://lists.osgeo.org/pipermail/grass-dev/attachments/20010309/030d6916/attachment.bin


More information about the grass-dev mailing list