/* DRAW_LINES.P */ section $-draw_lines => ved_point ved_draw; /* SPECIFICATION ------------- This module defines routines for drawing lines in Ved. They can be used to draw worlds or retinal images. PUBLIC ved_point(): This defines the Ved command 'point'. The command can take the following forms: point point x y The no-argument form "marks" the current point. The two-argument form "marks" the point at column x on the specified line, and moves the cursor thereto. PUBLIC ved_draw(): This defines the Ved command 'draw'. The command can take the following forms: draw draw char draw x y draw char x y This draws a line from the "marked" point to the character at (x,y). If char is omitted, it defaults to *. If (x,y) are omitted, they default to the cursor position; if present, Ved jumps thereto before drawing the line. */ /* IMPLEMENTATION -------------- ved_point notes the mark position, and stores it in point_x, point_y. ved_draw establishes its end position, and draws there a line to from point_x, point_y. To do this, it calls drawanyline. drawanyline depends on procanyline(x1,y1,x2,y2,proc). This procedure constructs a set of integral points (x,y) which plot the best approximation to a line from (x1,y1) to (x2,y2), and calls proc(x,y) on each point. For drawanyline, proc is something which puts a character at (x,y). The code inside procanyline comes from the image-processing routines in Ramsay and Barrett's book "AI in Practice". */ needs utils; vars point_x, point_y; define global ved_point(); lvars args, len; if vedargument = '' then vedjumpto( vedline, vedcolumn ) else getvedargs( [2] ) -> args -> len; vedjumpto( args(2), args(1) ) endif; vedcolumn -> point_x; vedline -> point_y; enddefine; vars drawanyline;/*forward*/ define global ved_draw(); lvars args, len, char, x, y; if vedargument = '' then vedcolumn -> x; vedline -> y; `*` -> char; else getvedargs( [1,2,3] ) -> args -> len; if len = 2 then `*` -> char; args(1) -> x; args(2) -> y; elseif len = 1 then args(1)(1) -> char; vedcolumn -> x; vedline -> y; else args(3)(1) -> char; args(1) -> x; args(2) -> y; endif; endif; drawanyline( char, point_x, point_y, vedcolumn, vedline ); vedjumpto( y, x ); vedcolumn -> point_x; vedline -> point_y; enddefine; vars procanyline;/*forward*/ /* drawanyline(c, x1, y1, x2, y2): Draw a line of c characters between x1,y1 and x2,y2 inclusive. */ define drawanyline(c, x1, y1, x2, y2); procanyline( x1, y1, x2, y2, procedure( x, y, c ); vedjumpto( y.round, x.round ); c -> vedcurrentchar(); endprocedure(% c %) ); enddefine; /* procanyline(x1, y1, x2, y2, proc): Call proc on each x,y value between x1,y1 and x2,y2 inclusive. These values are interpolated to be suitable for Ved or turtle plotting. They may be reals, and not integers. */ define procanyline(x1, y1, x2, y2, proc); lvars x1, y1, x2, y2, proc; lvars inc, dx, dy, stepx; x2 - x1 -> dx; y2 - y1 -> dy; if round(dx) == 0 and round(dy) == 0 then proc(x2,y2); return endif; unless abs(dx) > abs(dy) ->> stepx then x1, y1 -> x1 -> y1; x2, y2 -> x2 -> y2; dx, dy -> dx -> dy; endunless; dy / abs(dx) -> inc; sign(dx) -> dx; for x1 from x1 by dx to x2 - (0.1 * dx) do proc(if stepx then x1, y1 else y1, x1 endif); y1 + inc -> y1; endfor; proc(if stepx then x2, y2 else y2, x2 endif); enddefine; endsection;