For a long time I've been meaning to add to RCLIB
http://www.cs.bham.ac.uk/research/poplog/rclib/help/rclib
an interactive polygon-drawing program in the spirit of rc_mouse_draw
described in TEACH RC_GRAPHIC and HELP RC_GRAPHIC
Someone has just asked me for this, so I wrote a first draft, appended
below (note: the actual procedure is just 30 lines of code (including
about 10 blank lines!).
It has been installed here
http://www.cs.bham.ac.uk/research/poplog/rclib/auto/rc_drawlines_interactive.p
but so far it is not in rclib.tar.gz nor in the main rclib
documentation.
The question I am asking is whether I should generalise the procedure
in various ways.
At present this:
rc_draw_lines_interactive(win_obj, colour, width, closed) -> points;
lets you draw in the window corresponding to win_obj, a set of connected
lines of colour specified (current foreground colour if false), using
linewidth width, with the final gap closed up if the last argument is
true, and it returns a list of the points (pairs of numbers) at which
you clicked. Selecting points uses button 1, and lines are drawn as you
click. When done click button 3 and the procedure exits.
Some questions:
Should the result be a list of N points (each currently created using
conspair) if N points are selected, or should it be a list of 2*N
numbers representing the coordinates? The current version makes it
easier to select, e.g. the third point in the list.
What about these possible changes/generalisations:
1. Take an extra argument specifying line style i.e. one of
LineSolid
LineOnOffDash
LineDoubleDash
See HELP rc_graphic
2. Take an extra argument specifying join style, i.e. one of
JoinMiter, JoinRound, JoinBevel
(See REF XpwPixmap)
3. Take an extra argument specifying whether to return the list of
points or not.
4. Take an argument specifying whether to create a list of line
picture objects and return them instead of the corner coordinates,
5. Take an argument specifying whether to show a temporary moving line
from the last selected point to the current mouse cursor
6. Take an argument specifying whether to 'fill' the polygon
at the end.
7. Instead of having all those additional arguments, have an optional
list argument where the contents of list is interpreted as specifying
the above, e.g.
[style 'LineOnOffDash' joinstyle 'JoinBevel' ... ]
8. Make the mouse pointer warp to the window as soon as the procedure
starts.
9. Should the procedure disable all interactions in other windows while
it is running?
etc....
My current feeling is that options 1 and 2 will rarely be used, and can
in any case be set temporarily for the window by a procedure that
invokes rc_draw_lines_interactive.
Likewise someone who cares enough about efficiency to want not to have
the list created would probably know enough about sys_grbg_destpair and
sys_grbg_list to return all the list links to free store anyway.
Efficiency can't be a huge consideration given that this program's
behaviour is restricted by human interaction speeds.
I expect options 4 is best left to people who want to copy and
edit the definition of rc_draw_lines_interactive and then edit the
procedure so as to make he nested procedure next_point do something
different (the whole point of the procedure rc_app_mouse was to make
such things easy to do.)
Option 5 would be doable, but I am not sure how useful it is.
It could be confusing as regards the final step, when clicking button 3
terminates the process without using the location of the mouse to add
another line.
Option 6 could be left to the user to do using the existing
rc_draw_lines_filled, giving it the list returned by
rc_drawlines_interactive to create the list of numbers required.
I suspect automatic warping would irritate some people. Programmers
can always invoke rc_warp_to first.
Comments?
First draft code appended.
[It took longer to write this message!]
Aaron
=======================================================================
/* --- Copyright University of Birmingham 2003. All rights reserved. ------
> File: $local/rclib/auto/rc_drawlines_interactive.p
> Purpose: Interactively draw a collection of connected lines
> Author: Aaron Sloman, Mar 8 2003
> Documentation: HELP RCLIB
> Related Files:
*/
/*
HELP RC_DRAWLINES_INTERACTIVE
rc_draw_lines_interactive(win_obj, colour, width, closed) -> points;
This method can be used to draw lines interactively, using the mouse, on
a window object created using rc_new_window_object. When the procedure
is invoked, pop11 suspends activity waiting for mouse events. Each time
you press mouse button 1 on the specified window it selects a new point
and draws a line from the previously selected point (if there was one)
to the selected point. This continues until button 3 is pressed, in
which case the process terminates and a list of points is returned,
where each point is represented by a pair of numbers.
The arguments are as follows
win_obj
The window, an instance of rc_window_object
colour
A string, specifying the colour, e.g. 'red' or false, in which case
the current foreground colour for the window will be used.
width
An integer specifying the width of the lines to be drawn.
(0 and 1 are equivalent).
closed
If this is false then an open polygon is drawn. If it is true then
a closed polygon, i.e. the last point selected is joined up to
the first point.
EXAMPLES:
;;; create a window
vars win1 = rc_new_window_object("right", "top", 400, 350, true, 'win1');
rc_kill_window_object( win1);
;;; create an open polygon of red lines of width 2
rc_draw_lines_interactive(win1, 'red', 2, false) =>
;;; create a closed polygon of blue lines of width 3
rc_draw_lines_interactive(win1, 'blue', 3, true) =>
;;; create a closed polygon of blue lines of width 3
rc_draw_lines_interactive(win1, 'pink', 6, true) =>
;;; create a closed polygon of lines of width 3
rc_draw_lines_interactive(win1, false, 3, true) =>
;;; create a closed polygon of lines of width 0
rc_draw_lines_interactive(win1, false, 0, true) =>
In the last two cases the default foreground colour of the window
is used, namely black.
;;; kill the window
rc_kill_window_object(win1);
*/
section;
uses rclib
uses rc_linepic
uses rc_mousepic
uses rc_app_mouse
define :method rc_draw_lines_interactive(win_obj:rc_window_object, colour, width, closed) -> points;
dlocal rc_current_window_object = win_obj;
;;; make sure the window is button sensitive
rc_mousepic(win_obj, [button]);
lvars lastx,lasty;
define next_point(x,y) -> point;
conspair(x,y) -> point;
if isnumber(lastx) then
rc_draw_coloured_line(lastx, lasty, x, y, colour, width);
else
rc_draw_blob(x, y, 0, colour);
endif;
x -> lastx, y -> lasty
enddefine;
false ->> lastx -> lasty;
;;; draw repeatedly using button 1, and stop with button 3.
[% rc_app_mouse(next_point, 3) %] -> points;
if closed then
rc_draw_coloured_line(lastx, lasty, destpair(front(points)), colour, width);
endif;
enddefine;
endsection;
|