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

Robert Lagacé lagace at echo.grr.ulaval.ca
Sat Mar 10 10:55:34 EST 2001


strobe anarkhos wrote:
> 

I like your proposition.

> 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.
>

This is very interesting.
 
> 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).
>

Name : ri_draw_line(x1,y1,x2,y2) or draw_line_ri(x1,y1,x2,y2) ??

As a user, I prefer the second form.

As a programmer, I prefer the first form. 
 
> 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.

-- 
Robert Lagacé, professeur
Pavillon Comtois
Université Laval
Ste-Foy, Québec, G1K 7P4
tel : (418)-656-2131#2276
Fax : (418)-656-3723
E-mail : lagace at grr.ulaval.ca

---------------------------------------- 
If you want to unsubscribe from GRASS Development Team mailing list write to:
minordomo at geog.uni-hannover.de with
subject 'unsubscribe grass5'



More information about the grass-dev mailing list