[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