&routine addtic &rem **** add tics from a text file &rem **** with line format: ID X Y &define coo -11 &var &define temp -19 &var &define winrtn 1 &var WIN FILE 1 * 'Tic Input File' &if &eq "x[winrtn]" "x" &do &return CANCEL &end &open [winrtn] error EDITF TIC SHOW COORDINATE [coo] COO KEY ADD &while &do &read [temp] [break] &if &ne "x[temp]" "x" &do &extract 1 [temp] -1 &extract 2 [temp] -2 &extract 3 [temp] -3 3 0 0 %-1 1 %-2 %-3 &end &end 9 0 0 &close COO [coo] &return OK &label error &type "ERROR: Cannot open [winrtn]" &return ERRORHowever, if a routine is to handle coordinates provided by a mouse or digitizer, &getxym values must be collected before setting COO KEY, a task which cannot be performed during an ADD session. Thus if one were to develop a GUI to add arcs, all coordinates would need to be collected prior to ADDing each arc, which could severely limit the practicality of such a routine[2].
Out of sheer determination I came up with the following example, in which vertices are plotted and/or removed using 3.5's MARKER command[3]. I'm going to try to make it more digestible by breaking it into sections. The first section creates and initializes the dialog box:
&routine addarc &rem **** define variables &define i -8 &var &define numv -9 &var &define resp -10 &var &define wksp -11 &var &define arct -12 &var &define sd1 -13 &var &define sd2 -14 &var &define coo -15 &var &define node -16 &var &define weed -17 &var &define temp -19 &var &define winrtn 1 &var &rem **** initialize dialog box EDITF ARC &value [wksp] WKSP SHOW ARCTYPE [arct] SHOW SETDRAWSYM [sd1] [sd2] SHOW COORDINATE [coo] SHOW WEED [weed] SETD OFF &openw [wksp]t$add.dlg &write "BEGIN 0 5.00 5.00 6.75 17.00 v Add Arc(s)" &write "PBUT -101 0.00 0.00 1.50 8.50 v New" &write "GBOX 0 1.50 0.00 5.00 8.50 v Type" &write "RBUT -102 3.00 1.00 1.00 7.00 v Line" &write "RBUT -103 4.00 1.00 1.00 7.00 v Box" &write "RBUT -104 5.00 1.00 1.00 7.00 v Circle" &write "PBUT -105 0.00 8.50 1.50 8.50 v Attach" &write "PBUT -106 2.00 9.00 1.50 8.00 v Back" &write "PBUT -107 3.50 9.00 1.50 8.00 v Clear" &write "PBUT -108 5.00 9.00 1.50 8.00 v Resume" &write "END" &write "G 105" &write "G 106" &write "G 107" &write "G 108" &if &eq [arct] LINE &do &write "C 102" &elseif &eq [arct] BOX &do &write "C 103" &else &write "C 104" &end &closew WIN DB C [wksp]t$add.dlg & DEL [wksp]t$add.dlg
Because simultaneous input from the coordinate device and dialog box is not possible, the routine uses the <1> key (or left mouse button) to enter coordinates and the <2> key (or right mouse button) to "escape" back to the dialog box. Coordinate entry begins when the NEW (return 101) or ATTACH (return 105) button is pressed. When the dialog box is closed (return value -1), the NEW or ATTACH button is pressed, or the ARCTYPE changed (return values 102-104), any stored coordinates (ARCTYPE LINE) are supplied to the ADD command:
&rem **** process responses &sv [numv] 0 &sv [resp] 0 &while &ne [resp] -1 &do WIN DB R [wksp]t$add.cmd &sv [resp] [winrtn] &if &eq [resp] -1 &or &rn [resp] 101 105 &do &rem **** check for existing arc to process &if &eq %<[numv] max 2> [numv] &do &rem **** ADD IT!!!! SETD 7 &value [temp] %<[numv] + 1000> MARKER [temp] SETD 1 COO KEY GRAPHIC OFF ADD &sv [i] 1 &while &rn [i] 1 [numv] &do &value [temp] %<[i] + 1000> &if &eq [i] 1 &or &eq [i] [numv] &do 2 [temp] &else 1 [temp] &end &inc [i] &end 9 0 0 GRAPHIC ON DRAWSELECT COO [coo] &value [node] %<[numv] + 1000> &sv [numv] 0 &end &endCoordinates are collected by storing them in SML variables 1001 and above:
&if &eq [resp] 101 &or &eq [resp] 105 &do &sv [numv] 0 &rem **** if attach, add starting node &if &eq [resp] 105 &do &sv [numv] 1 &value 1001 [node] &end &rem **** collect coordinates for new arc &if &eq [arct] LINE &do &getxym -1 -2 -3 &if &eq [resp] 101 &do SETD 7 &else SETD 5 &end &while &ne %-3 2 &do &sv -6 TRUE &if &ne [numv] 0 &do &rem **** check if < WEED &extract -4 %<[numv] + 1000> 1 &extract -5 %<[numv] + 1000> 2 &cv -4 %-4 - %-1 &cv -5 %-5 - %-2 &cv [temp] ( ( %-4 * %-4 ) + ( %-5 * %-5 ) ) ** 0.5 &if &eq %<[temp] min [weed]> [temp] &do &sv -6 FALSE &end &end &if &eq %-6 TRUE &do &inc [numv] &sv %<[numv] + 1000> "%-1 %-2" MARKER %-1 %-2 &else &type "Last vertex within weed tolerance" &end &if &eq [numv] 1 &do SETD 5 &end &getxym -1 -2 -3 &end &else &rem **** add until cancel &getxym -1 -2 -3 SETD 1 &while &ne %-3 2 &do &if &eq [arct] BOX &do &rem **** box r.band for BOX &getxym -4 -5 -6 2 &else &rem **** line r.band for RADIUS &getxym -4 -5 -6 1 &end &if &ne %-6 2 &do &rem **** ADD IT!!!! GRAPHIC OFF COO KEY ADD 2 %-1 %-2 2 %-4 %-5 9 0 0 GRAPHIC ON COO [coo] DRAWSELECT &getxym -1 -2 -3 &else &sv -3 2 &end &end &endThe difference between NEW and ATTACH is that ATTACH uses the to_node of the previous arc as the from_node of the new one; the user simply adds vertices until the <2> key is pressed. As points are digitized, the MARKER command highlights the potential vertices.
A critical consideration in creating front ends to key menus is obeying the law of WYDIWYG (What You Digitize Is What You Get)! For that reason, each coordinate input after the first node is checked against the WEED tolerance: if it fails the test, it's not added to the coordinate list.
Note that boxes and circles are added immediately, allowing multiple ADDs before escaping to the dialog box. Coordinates are stored for lines so that the user may backup, clear, and/or redirect the potential arc. As will be shown shortly, if a point set for a line exists upon returning to the dialog box, the ATTACH and edit buttons are enabled:
Changing the ARCTYPE is simple enough:
&elseif &eq [resp] 102 &do ARCTYPE LINE &elseif &eq [resp] 103 &do ARCTYPE BOX &elseif &eq [resp] 104 &do ARCTYPE CIRCLEThe BACK button decrements the point list and masks the corresponding markers with a dark color:
&elseif &eq [resp] 106 &do &rem **** mask last point and decrement point list SETD 12 &value [temp] %<[numv] + 1000> MARKER [temp] &dec [numv] SETD 7Before:
After pressing twice:
The CLEAR button masks the entire point list and sets the counter to zero:
&elseif &eq [resp] 107 &do &rem **** mask all points and clear point list SETD 12 &sv [i] [numv] &while &rn [i] 1 [numv] &do &value [temp] %<[i] + 1000> MARKER [temp] &dec [i] &end &sv [numv] 0 SETD 7The RESUME button allows the user to continue adding points, e.g. after backing up:
&elseif &eq [resp] 108 &do &rem **** resume adding points SETD 5 &getxym -1 -2 -3 &while &ne %-3 2 &do &inc [numv] &sv %<[numv] + 1000> "%-1 %-2" MARKER %-1 %-2 &getxym -1 -2 -3 &end &endBefore returning to WIN DB R, the line widgets are enabled or grayed as appropriate[4]:
SHOW ARCTYPE [arct] &rem **** set LINE related widgets &openw [wksp]t$add.cmd &if &eq [arct] LINE &do &if &eq %<[numv] max 2> [numv] &do &write "E 105" &write "E 106" &write "E 107" &write "E 108" &elseif &eq %<[numv] max 1> [numv] &do &write "G 105" &write "E 106" &write "E 107" &write "E 108" &else &write "G 105" &write "G 106" &write "G 107" &write "G 108" &end &else &write "G 105" &write "G 106" &write "G 107" &write "G 108" &end &closew &endFinally, the routine cleans up and restores SETD settings before exiting:
&if &fn [wksp]t$add.cmd &do & DEL [wksp]t$add.cmd &end SETD [sd1] SETD [sd2] &if &eq [sd2] ON &do DRAWS &end &returnOne nice feature of the routine is that it automatically adds the current point list when you quit (how many of us have forgotten to terminate an arc before hitting the <9> key?). Also, if you're supplying coordinates via a digitizer, you can watch the arc grow as you add vertices (one feature of 3.4D+ that I really miss).
Just as examining the WEED tolerance is important to maintain WYDIWYG when adding lines, examining the EDITDISTANCE is critical when manipulating vertices in a VERTEX key menu. In the following section of code, taken from an arc extend routine, the distance to the vertex next to the endpoint is compared to the edit distanceif necessary, the EDITD is altered before the endpoint is moved:
SHOW ARC %[arc_f] VERTEX %[nod_t] [x1] [y1] SHOW ARC %[arc_f] VERTEX %<[nod_t] - 1> [x2] [y2] &cv [x2] [x2] - [x1] &cv [y2] [y2] - [y1] &cv [temp] ( ( [x2] * [x2] ) + ( [y2] * [y2] ) ) ** 0.5 &cv [temp] [temp] / 2 &if &eq %<[editd] min [temp]> [temp] &do EDITD [temp] &sv [temp] TRUE &else &sv [temp] FALSE &end V MOVE 1 [x1] [y1] 1 [x1] [y1] 1 [int_t] 9 0 0 &if &eq [temp] TRUE &do EDITD [editd] &end
&routine record &define outfile -1 &var &define inrec -2 &var &define outrec -3 &var &define wksp -4 &var &define temp -9 &var &rem **** create watch file WIN FILE 2 SML 'Output SML File' &if &eq "x%1" "x" &do &return &end &value -1 1 &value [wksp] WKSP &if &fn [wksp]t$wat.wat &do & DEL [wksp]t$wat.wat &end &type "********************************" &type "Begin entering ARCPLOT commands." &type "Enter '&return' when finished." &type "********************************" &echo &watch [wksp]t$wat.wat &tty &echo &watch &echo &off &rem **** convert watch file to SML &open [wksp]t$wat.wat error &openw [outfile] &while &do &read [inrec] [break] &extract [temp] [inrec] 2 &if &eq "[temp]" "|>CIRCLE" &and &cn "[inrec]" "*" &do &value [temp] [inrec] &read [inrec] [break] &read [inrec] [break] &read [inrec] [break] &r ltrim "|>*" "[inrec]" &rv [inrec] &r rtrim "*<|" "[inrec]" &rv [outrec] &extract -11 [outrec] 1 &extract -12 [outrec] 2 &if &cn "[temp]" "*<|" &do &read [inrec] [break] &read [inrec] [break] &read [inrec] [break] &r ltrim "|>*" "[inrec]" &rv [inrec] &r rtrim "*<|" "[inrec]" &rv [outrec] &extract -13 [outrec] 1 &extract -14 [outrec] 2 &cv -13 %-13 - %-11 &cv -14 %-14 - %-12 &cv -13 ( ( %-13 * %-13 ) + ( %-14 * %-14 ) ) ** 0.5 &else &r ltrim "*" "[temp]" &rv [inrec] &r rtrim "<|" "[inrec]" &rv -13 &end &write " " &write "CIRCLE %-11 %-12 %-13" &elseif &cn "[inrec]" "|>*" &do &r ltrim "|>*" "[inrec]" &rv [inrec] &r rtrim "*<|" "[inrec]" &rv [outrec] &write "[outrec] |" &elseif &cn "[inrec]" "|>" &do &write " " &r ltrim "|>" "[inrec]" &rv [inrec] &if &cn "[inrec]" "*<|" &do &r rtrim "*<|" "[inrec]" &rv [outrec] &write "[outrec] |" &else &r rtrim "<|" "[inrec]" &rv [outrec] &write "[outrec]" &end &end &end &close &closew &rem & DEL [wksp]t$wat.wat &return &label error &type "I/O Error" &return &routine ltrim &value -3 -2 %<fpos "%-1" "%-2" + len "%-1"> &return "%-3" &routine rtrim &value -3 -2 1 %<lpos "%-1" "%-2" - 1> &return "%-3"Note the special handling of the CIRCLE command, which requires the input of a coordinate and radius value. The actions that created the following graphics:
are converted by the routine into the following macro:
CLEAR LINE | 1.202362 2.128740 | 2.246063 3.569685 | 3.329134 2.181496 | 4.240945 3.649213 | PATCH | 1.598425 2.115354 | 2.933071 2.512205 | CIRCLE 3.289764 3.173229 0.407759 MOVE | 1.651575 3.807874 | TEXT 'Naked Lunch' &returnThere are some obvious limitations to this approach:
1) Any line in the watch file longer than 80 characters will be truncated and most likely mishandled.
2) LINE or SHADE coordinate input is limited to a total of (I believe) around 120 characters. Thus more complex objects will be truncated.
3) You can't "freeze" statements involving SML variable substitutions. For example:
WIN EXEC 9 TEXTFONT %1will be recorded verbatim in the watch file:
: |>WIN EXEC 9<| : |>TEXTFONT %1<|
[2]I am, at this time, unable to test SML's ability to capture stream mode coordinates.
[3]Assuming that COLOR.MRK, or some suitable alternate, is the current markerset.
[4]The logic could be improved slightly by not building the dialog command file when [resp] equals -1.