During the summer and early fall of 1982, I was working furiously on AutoCAD-80, the CP/M-80 version of AutoCAD. At the same time, Dan Drake and Greg Lutz were working on AutoCAD-86 for the IBM (Greg) and the Victor 9000 (Dan). Because AutoCAD-80 started to work earlier, largely because it used intelligent display devices and didn't require the extensive low-level drivers that the IBM and Victor needed (and still need), AutoCAD-80 took the lead on feature implementation through the introduction of the package at COMDEX in November of 1982 and into early 1983.
What follows are excerpts from the extensive development log that chronicled AutoCAD's earliest formative stages. I've tried to select sections that show the first appearance of key facets of AutoCAD, foreshadow features implemented much later, and give a general flavour of the initial development of the package. You can see that from the very start a major theme in AutoCAD development was figuring out how to make it fit in memory. The version described below had to run in a machine with a total memory of 64K bytes, of which only 52K was free for user programs.
The log was begun in July of 1982. The practice of dating entries did not begin until late August.
When you specify a length (e.g., circle radius, size for text), GDATA/GEDIT should allow you to specify two points (if the first arg was a point, it would ask for a second. Then it would take DIST of the two points and use that for the length. If the second point were null, it would use the origin of the object being entered (center of circle, base of text, etc.)). Installed in GEDIT 8/19/82. Could also do the same thing in GORIENT for angles, but it's a lot less frequently used and I don't feel like doing it at the moment.
Text and shape sizes should be specified in terms of the basic size of the drawing, not as a scale factor.
To compress the redraw file: if start point of current coordinates is same as end point of last, just output (X2+10000, Y2).
Group designation. When you're asked to “digitise entities”, you should be able (somehow) to specify one or more boxes, as for the SOLID entity. Then every item which has a vector within that box (or is totally within the box [which??]) should be selected. This will let you grab a group of stuff in a drawing and move it somewhere else, or delete a section. Current point selection is a special case of this.
Speed up regen—for every entity we should be able to calculate an “enclosing box”. This is a conservatively larger box which we know to contain all vectors generated by the entity. If the box is totally off the screen, we can skip regen of the entity entirely and avoid all the calls on CLIP. If the box maps into one pixel, just draw a dot and forget it. This should make large, complex, drawings viewed in small pieces much more efficient.
We need an interactive shape editor.
All versions of MicroCAD should be able to write an “entity interchange format” file. The utility which does this may not be actually in the main package, or may be called as an overlay. All versions of MicroCAD, regardless of internal file representation, will be able to interchange drawings this way. Installed in MicroCAD-80.
Design change: Made DBLIST quit list and return to command mode if you type Control C. Fixed to also pause on Control S. Document this & pass on to C version.
Can we use a better algorithm for FILL? Maybe we should have an entry in the display driver for FILL, as some displays have that capability. In fact, maybe we want to totally rework the interface between the display driver and MCAD: displays are getting smarter and smarter, even the Microangelo can draw circles, and the NEC can do arbitrary arcs as well as fill. Maybe the display should be passed an entity clipped and scaled to screen coordinates. The display driver could either do it itself, or buck it back to a vectoriser mechanism which would call the display again with individual lines as at present. Note that this would seriously mess up the REDRAW file interface and in particular VRTST, which would now have to test any kind of entity the device can draw.
Dimensioning drawings—one should be able to specify a default scale for the drawing, e.g., feet, angstroms, kiloparsecs, and have all MCAD communications in that scale. MCAD should come with a units database, so if the user appends a unit name to a number input, it will perform the conversion to the drawing scale. You should be able to have a drawing rescaled to different units, or just ask for any output (DIST, AREA) in other units (for example, your design is metric but you need to know how many square feet of aluminum plate to buy).
At some point we're going to have to put in some kinds of macro command facility. It might be wise to do this sooner rather than later, since we might avoid lots of custom coding and application specific stuff we'd otherwise get asked for. Obviously, the boundaries between shapes, INSERTs, and command macros are fuzzy. Here's an example of a request from an architect which I'd like to write a macro for. After finishing a floor plan, they want to put in those little dimension lines that look like:
and they'd very much like to do that just by designating the two end points of the dimension and where the legend was supposed to go. Try working out this example in your head, and you'll see that some form of “entity variable” is required in the macro facility as well as control structures.
Digitiser menu. We should supply preprinted digitiser menu overlays that the user could Xerox & write in the legends for his menu. When you install the program, you would tape the menu to the digitiser & digitise the two corner points. MCAD would then figure out where it was & therefore where the subdivisions were. We might also put the number of vertical & horizontal divisions in the configuration file, so you could make as crowded or open menu as you liked. We might want to provide the option of a screen menu as well. This would be essential for use with a light pen, and might make the digitiser menu work better as well (wouldn't have to take your eyes off the screen). Maybe this could be cleanly integrated with the split-screen work we'll have to do to support one-screen systems. If you have a large digitiser, you could have a small digitiser menu you could move to the area you were working on. Any designation within the menu would indicate the menu. To hit a drawing point there, just move the menu first. I installed a position sense and auto-scale in MCAD-80. When you specify a MENU file, it looks for the file MCADMENU.CFG. If this file is present, the digitiser menu lower left corner & upper right corner are taken from it, along with the default menu file. The menu is then automatically loaded. If the file does not exist, the user is asked to digitise the menu corners and to specify the menu file name.
Terminology change: SHIFT has been renamed PAN.
Terminology change: ARRAY is now REPEAT. REPEAT is now ENDREP.
Terminology change: ORIGIN (for INSERT) has been renamed BASE. The BASE command now sets it, and it is called the “Insertion base” in the STATUS display.
Terminology change: SNAP is now RESOLUTION (which may be abbreviated to RES). It works just like it used to, but defaults ON at the start of a new drawing. The status display was changed to call it “Resolution”.
Implemented a new option on the GRID command. You can now say GRID 5X for example, and set the grid to 5 times the resolution (formerly snap value). You can still specify a number without the X and set the grid to anything you like. Should we have grids with different X & Y increments?
Installed the new LIMITS facility. Drawing limits may be changed by the new LIMITS command. GPOINT will reject any point outside the defined drawing limits. Extents have been redefined to be the corners of a box enclosing the actual data in the drawing. They are recomputed on every REGEN (note special handling in REGEN for aborted REGENs). In STATUS they are displayed, flagged if the drawing runs outside the limits. ZOOM ALL was changed to display the drawing limits, or the extents, whichever is larger.
The LIMITS facility has repercussions that run through MCAD. ZOOM ALL was rewritten again to hopefully do what we want. It gives you a display with the lower left corner aligned at the X and Y coordinates of the left lower drawing limit or extent, whichever is less. The extents were changed again to be reset based on generation only for a ZOOM ALL which runs to a normal completion. That means that if you delete something which reduces the used space extents, they won't be updated until you do another ZOOM ALL. Any other approach I can think of has disastrous implications on any attempt we might make to optimise generation of entities. See the comments in DSCMDS and CSCALE which explain this change.
Removed the CENTER command. It has been superseded by the ZOOM C option.
Installed the ZOOM L option. This allows setting the screen window by the lower left corner point and the side width.
Made the LAYER command accept COLOUR as well as COLOR for our friends across the Atlantic. Note that since we've replaced CENTER with ZOOM C, center/centre is no longer a problem. I may just change LAYER to look at the first 2 characters of the command, but I haven't yet.
Added the OOPS command. Now whenever ERASE is erasing entities, it makes a list called OOPSLIST which records the entity database file location of each entity erased. OOPSLIST is cleared at the start of an ERASE command, so following an ERASE, OOPSLIST represents the entities deleted by the most recent ERASE. The OOPS command scans OOPSLIST and goes through the entity database “un-erasing” all the entities on the list (this is easy because we erase simply by negating the TCODE of the entity, to bring back, just negate again).
The problem of REPEAT/ENDREP accumulation in files could be eliminated by detecting an REPEAT immediately followed by a ENDREP and deleting both on the fly. Then if you delete all the items within the pair, the REPEAT block would go away as well. Not hard to do on a REGEN.
Might we want to install a MODIFY command? It would work just like a LIST, but would give you the chance to change entity properties. Or is the ability to edit the drawing interchange file enough (I vote no). Any suggestions on how to specify a MODIFY of an ENDREP?
I went at the digitiser interface with a chainsaw on 8/26/82. The changes are major in concept and scope, and will be described below:
First, to allow greater resolution for larger digitisers, the scale of coordinates returned by DGDRV was changed from 0–1023 to 0–20479. This twentyfold multiplication of scale allows us to lose no resolution on a digitiser which resolves 200 points per inch and has a longest dimension of 100 inches. So much for large digitisers.
Second, I changed the way DIG smooths samples from the digitiser. Previously, it waited until it had two samples and averaged them. I changed this to use an exponentially smoothed moving average with smoothing constant .10 (it can be changed in DIG [parameter SMOOTH]). This technique (used to smooth radar samples when computing trajectories) enormously reduces the jitter caused by single random samples, and imparts a “buttery smooth” motion to the cursor on the screen regardless of how jerky the digitiser sampling rate or motion is. It also avoids the overflow which would result from adding two FIXED(15) numbers in the 20000 range.
Third, I installed a totally new mode where the digitiser is used as a true digitiser rather than a screen pointing device. When you enter MCAD-80, the digitiser works just as it does in INTERACT. If you enter the TABLET ON command, MCAD-80 asks you to digitise two points on the drawing on the digitiser and enter their drawing coordinates. From the digitiser coordinates and the coordinates entered, MCAD-80 computes the scaling, translation, and rotation of the coordinate system of the digitiser with respect to that of the drawing, and saves these parameters. It turns on TABLET mode. In TABLET mode, whenever GDATA processes a digitised point, it will transform the digitiser coordinates into the drawing coordinates. This allows dimensioned material to be entered and the actual drawing coordinates to be stored in the entity database.
This is completely general: the full resolution of the digitiser is used in the calculation, and the drawing may be placed on the digitiser in any orientation; may have any desired coordinates (we assume the coordinates are rectangular), and any two points may be digitised to establish the transformation to digitiser space. Thus a small drawing may be placed anywhere on the digitiser, and a large drawing may be digitised in pieces.
When in TABLET mode (which is indicated on the status display), points from the drawing are mapped into drawing space without regard to what the screen displays. Points may be entered which are off the screen, and the screen resolution is of no import. In TABLET mode, the cursor on the screen will track the digitiser cursor as before, but the relationship between where it points on the screen and the drawing points is broken (see below for why this done). The menu may continue to be used while in TABLET mode. Entities entered will be displayed windowed to whatever the screen window is.
Those commands which use entity designation rather than coordinate specification (such as ERASE, MOVE, and LIST), may be used while in TABLET mode, as long as the entity being specified is on the screen. In this case the cursor is used to point to the item on the screen. (That's why it displays in screen coordinates even though TABLET mode is on). The normal mode one would use when entering data in TABLET mode is to set up the TABLET, then do a ZOOM W to put the area being entered on the screen (just point to the drawing areas, TABLET mode will worry about internal coordinates). I think this is reasonable, but it isn't hard to make the cursor track the drawing coordinates rather than the screen if that seems better. I just didn't want to give up the ease of entity designation while in TABLET mode for the common case of deleting a bad entity just entered. My feeling is that the cursor position doesn't matter in TABLET mode because the user is looking at the digitiser, not the cursor on the screen.
The TABLET command has other subcommands. TABLET OFF turns off TABLET mode and restores normal digitiser operation. A subsequent TABLET ON command will turn TABLET mode back on with the same coordinate transformations as before. TABLET CAL (for CALIBRATE), forces a recalibration of the tablet, in case the drawing is moved. TABLET CAL turns on TABLET mode if completed successfully.
Changed the extension and nomenclature for interchange files. Previously they were “Entity Interchange Files”, .EIF. Now they are “Drawing Interchange Files”, .DIF. There's a hundred people who know what a drawing is for every one who knows what an “entity” is.
On 8/27/82 I installed the following optimisation for text generation. If the text is less than 4 dots and more than 2 dots high, I just draw a dot for each character centered vertically in the text height, with each character using .6 of the text box width (who knows?). If the text is less than 2 dots high, I just draw a line where the text would go with length equal to 0.6 * txsize * length_of_text_string. If the text start point is above the top of the screen or to the right of the screen, all generation is skipped. If the start Y coordinate plus the size of the text is below the bottom of the screen, we skip generation. Also if the start X coordinate plus the string length times the height is less than the left of the screen. The rules for skipping generation entirely are pretty conservative and shouldn't lose text unless you're doing something funny. See EREGEN for full details on the horrors arbitrary text rotation introduce in implementing these tests.
Here's an idea. We've all come up with the idea to optimise regen by calculating an “enclosing box” for every entity. The problem is how to calculate the bounds of the box for shapes and text (arcs don't come cheap either). 'Spose, however, that we add 4 cells to each entity record. When we EREGEN the entity the first time, we have CLIP calculate an entity extents & save them in the entity item. Once calculated, we can instantly see whether an entity is on the screen or not. The disadvantage of this is that it makes the entity file bigger by 4 reals per entity; this is significant, and I don't know enough to say whether the speed is worth the space. It wouldn't be horrible to “have it both ways” I guess. Note that this scheme also gives you a very cheap test for whether the entity contains enough detail to bother generating.
As you know, I have great plans for INSERTs. One of the dilemmas with INSERT is that it can be used both for combining drawings done in pieces and as a user-defined part facility. When combining drawings, you want the layer information in the INSERT to be preserved (which is what INTERACT currently does), but when you use an INSERT as a part from a library, you want the INSERTed entity to go onto the current drawing layer. Rather than muck things up with modes and commands, I have installed the following logic: entity layers are copied on an INSERT unless the layer number from the insert file is 127. Layer 127 will be replaced by the current layer of the drawing. Thus, you can have it either way you like, and you define how the INSERT works when you create it (which is probably the time that makes most sense).
Further work on INSERT. When you load an INSERT, I now allow you to specify an arbitrary rotation, X size, and Y size. The X size and Y size are divided by difference in the high limit and low limit, respectively of the X and Y dimensions of the drawing being inserted, resulting in X and Y scale factors to be applied to the drawing inserted. The rotation is used to rotate the inserted entities around the insertion base of the drawing being inserted. The resulting transformed entities are then inserted in the working drawing as before, with the insertion base of the inserted drawing aligned above the insertion point designated. If the X and Y scale do not result in a rectangular coordinate system for the inserted drawing, the following restrictions apply:
Note that everything works correctly as long as the X and Y scale are equal. I envision the installation of a new entity called a SCALE FACTOR which handles aspect ratio changes and scaling at the CLIP level. Then an INSERT can just generate this item if required. That's why I didn't go to great lengths here. As long as the drawing contains only lines, points, and traces, it may be changed in aspect ratio without restriction. Anything may be rotated without restrictions. Note that you can rotate your whole drawing by starting a new drawing and INSERTing the old one with a rotation specified and unity scale factor.
I also threw some effort into civilising the LAYER command. Now when you say LAYER, it prompts you with “Layer (Layer no./ON/OFF/COLOR): ”. If you say ON or OFF, it prompts you for the list of layers (see LAYRCM.PLI for exact messages). The LAYER command previously did a REDRAW on normal exit, because it may have changed the visibility or colour of the lines on the screen. If LAYER exited in error (for example because a bad number were entered after an ON, this REDRAW would be skipped). I changed it so that whenever you leave LAYER, you get a redraw regardless of what you've done. Thus if you say: LAYER ON 1,2 OFF 19 FOOEY, the screen gets updated to reflect the changes you've made before the error.
Installation of the menu driver and associated sicknesses: now MCAD.COM is the program you call to enter MicroCAD. You can optionally specify a drawing name on the call. If you do, that will be the default drawing name for menu selections. LPROG was changed to accept an extension, and all the other actual main programs (MCADE, MCADP, etc.) were given extensions of “.OVL”, which will prevent some gonzo calling them directly from the console. MCADE always works on a .$$$ work file. This file is prepared for it by MCAD, and is converted back into a .DWG file or discarded after MCADE returns with its completion code in the command tail. I added a PLOT command in MCADE. This chains to the plotter driver, which produces a plot of the current state of the .$$$ drawing file, and chains back to MCADE right where you left off. This is very handy for interim views of the drawing.
On 9/6/82 GEDIT was enhanced to allow you to specify two points when an angle (GORIENT) is required. It takes the angle between the first and second point and uses that for the orientation. That way, you can “show it” which way you want to text etc. to run.
As suggested by Richard Handyside, I made entering just an “@” when a point is expected return the same point as last entered. This works out as a logical default, since @x,y is the relative point specification.
Totally re-did the INSERT mechanism. These changes supersede the INSERT enhancements mentioned above, offering all the capabilities with none of the restrictions (the previous INSERT was done as a test vehicle for parts of this implementation). Three new entity types have been added. Type 12 is “Block definition start” and has a name, and X and Y base as attributes. Type 13 is “Block end” and has no attributes. Type 14 is “Block reference” and has attributes of block name, X and Y position, X and Y scale, and rotation.
When you do an INSERT, MCAD asks you for a block name. If this block is not already used in the drawing, it loads the block from a file with the same name (a different name may be used by saying blockname=filename). Drive specifiers will be stripped from the file name if it is used as the default block name. A block definition start entity will be placed in the file, with X and Y base drawn from the master record of the drawing being INSERTed (old terminology, origin). Then all the nondeleted entities will be copied into the current drawing, followed by a block end entity. Unlike the old insert, the coordinates of the drawing being loaded are not translated as the entities are loaded. They remain in their host coordinates forever. All transformations are done when the block is elaborated as a result of a block reference entity.
Regardless of whether the block was previously defined or just loaded, a reference to it will then be generated, with the user being prompted for insertion position, X and Y scale, and rotation. As X and Y scale default to 1, and rotation 0, the effect of the command defaults to the operation of the old INSERT.
After entering the entities, PREGEN is called as before to process them. EREGEN contains almost all the support for the new entities. A block definition not previously seen causes the block to be scanned to the matching end (oh yes, blocks can be nested without limit other than memory space). The block is then defined on the in-memory list, with the start and end entity locations saved. If a block definition is seen for a block already known, the block is immediately skipped by the expedient of plugging the already stored end entity location into the entity scan address. This means that having lots of long block definitions in your drawing doesn't slow you up on REGENs.
When EREGEN sees a block reference entity, it makes a logical subroutine call in the entity file, pushing the return entity address and continuing with the first entity of the block referenced. Based on the attributes of the block reference item, a transformation descriptor is constructed and stacked so that CXFORM will correctly map the internal coordinates of the block being elaborated into the location, scale, and orientation desired by the user. Since both the return and coordinate transformation items are stacked, block calls may be nested without bound. EREGEN will always treat the regen of a block reference item as primitive. Hence one call on EREGEN may actually draw hundreds of entities. NOTE that as a result, the entity in the entity record when you come back from EREGEN may not be the same one as when you called it. Hence, people like MOVE, and OOPS had better do their MODDR before, not after, the call on EREGEN.
When CLIP is drawing vectors and writing them in the refresh file, it tests whether any block elaboration is underway. If so, all the vectors in the refresh file are tagged with the entity location of the OUTERMOST block being elaborated at the time. Why outermost? Because if you INSERT a part with complex internal structure, and you happen to point to an internal part, you still want the whole thing to move (be deleted, etc.). This very simple trick makes INSERTed entities primitive to all MCAD operations.
But why, you ask, copy the INSERTed entities into the drawing? Why not just save the block name as a file reference? I decided to copy them for reasons of efficiency and maintainability. CP/M file opening is extremely slow—we cannot tolerate a file open for every block reference, so we'd have to open the files and leave them open—not attractive from the standpoint of buffer space! Also, I feel that it's a valuable feature that a drawing be self-contained. If INSERTs stored references to other files, the user couldn't just copy the drawing and be confident he had everything. It would also make user programs which process .DIF files much more complicated. If the user wants to change the definition of the part, we can easily provide him the option when the temp copy of the drawing is made (in the menu driver) to replace one or more INSERT blocks in the drawing with new versions in files. Thus, after long thought, it seems to me that the way I put it in is the correct way from a design standpoint, not considering implementation at all. It certainly would have been easier to make each INSERT scan a file! Also, the way I did it allows us to let the user define his own blocks in the drawing independent of INSERT files. This might be handy in certain drawing environments.
Hence, with these changes to INSERT, the art of coding SHAPEs will become much less necessary for most users. This gives us every capability in accessing stored drawings that Robocom has, and more (as their system cannot store parts which contain other parts).
Here's a point of contention: should a GRID be drawn by setting the grid points on, or by inverting them? If you had a drawing with lots of SOLIDs, the grid might be hard to see. On the other hand, grid points would seem to break lines into separate segments. I've left it as always turning the points on, but I'd like comments on which it should do.
Freeze for stabilisation declared on 9/14/82 04:30. No additional features to be added until release of level 1.0. Only discrepancy resolution form changes will be made.
DRF#1 9/15/82 1:17 Arcs and circles don't always regen if part of a block which has been scaled. Corrected by applying all scale factors to a point centerX+radius,centerY+radius, taking DIST of that, and using that for the test for on-screen. Some extremely bizarre cases may still fail, but no realistic ones. For example, X scale=20, Y scale=.1, angle=90. Is it worth calling CXFORM 4 times to fix this?
DRF#2 9/18/82 2:09 No way to configure a system without digitiser without accessing I/O ports. Output ready mask for digitiser (otherwise unused) was defined as “digitiser present flag”. If nonzero, digitiser port will be polled. If zero, digitiser read routine always returns “no sample” and no I/O port accesses will be made.
DRF#3 9/18/82 2:12 Bad test for drawing limits in GEDIT. Fixed.
DRF#4 9/18/82 2:04 Can't set high drawing limits to large (>600) value. If an overflow happened in CVDTS in attempt to BLIP point, coordinates weren't returned. Changed in GEDIT to ignore overflows in attempt to BLIP (since it's off screen, BLIP wouldn't do anything anyway).
DRF#5 9/18/82 13:28 Setting resolution to zero in MICROCAD doesn't turn off resolution snap mode as documented. Changed to do so. Also, if resolution is set to zero, default GRID value to X limit/10 to avoid confusion if GRID ON is done.
DRF#6 9/18/82 13:26 Mike Riddle points out that “.DIF” is used for VisiCalc interchange files. Changed drawing interchange file extension to “.DXF” to keep some gonzo from trying to load one into VisiCalc.
DRF#7 9/20/82 16:16 Shape compiler wasn't closing output file before chaining back to the main menu. This caused the last block not be written out. Changed to close output file in every case. (Reported by Jamal Munshi).
On 10/10/82, I changed ERASE and MOVE to remove the old item by drawing over it with dark vectors. This eliminates the pesky and time-consuming REDRAW which used to follow every ERASE or MOVE, and makes things run immensely faster. The routine UNDRAW in REDRAW accomplishes the magic. Note that if you have overlapped entities, the process of undrawing an entity may turn off bits which should be set by other entities. If this happens, and you really need to see a cleaned-up screen, you can just type REDRAW and everything will be correct. As with the use of FLOOD, my feeling is that this is the correct choice as the full REDRAW was just intolerable for complex drawings. This code has been integrated with the flood code for TRACE and SOLID entities, so that completely filled TRACEs and SOLIDs will be flooded with zeroes to turn them off. The Microangelo provides no way to turn off a pattern-flooded area, so such an area will remain on the screen until you do a REDRAW (its boundary lines will be turned off, making it clear the entity has been deleted).
I went through the whole thing and changed it to AutoCAD. This took about 6 hours because all the MCAD segment names buried in more than half of the modules had to be changed, and the modules recompiled. I sure hope this is the last time! You now start it up with ACAD, and all the file names which previously contained MCAD now use ACAD instead.
DRF#17 10/11/82 19:53 Some people thought PAN worked backward, so it was changed to work backwards. (Reported by Keith Marcelius).
I revised the interaction of INSERTs and layers. Previously, INSERTed entities retained their original layer, except entities on layer 127 were statically moved to the current layer at original transcription time. This was not very useful. I changed it so that an INSERT's layers are preserved, except that any entity in a block with layer of 127 will be drawn on the layer of the outermost block active at the time the entity is drawn. This lets you define an insert and put it (or parts of it) on any desired layer at the time it is used.
All the new features contributed to memory growth which blew off our goal of running in a 52K user space. To free up more memory, EACQ, which was the longest overlay, was split up into two separate overlays (ACAD9=EACQ1, ACAD10=EACQ2). SHAPE, TEXT, TRACE, and SOLID acquisition were moved to EACQ2, and COMMAND was changed to call the correct overlay based on which entity type is being entered.
On 10/29/82 I installed light pen support code. There are two new configuration variables for the Microangelo associated with the light pen. The first is called LPUSED, and should be set to 0FF if the light pen is used and zero otherwise. The second is called LPDELAY, which controls the light pen selection logic. When the light pen is enabled, the screen is run in reverse video so that the tracking cross may be seen better. To designate a point with the light pen, you “pick up” the tracking cross, move it to the desired point, and let go of the tracking cross (by removing pressure from the light pen or taking your finger off the end region). After the delay specified by LPDELAY, the point will be selected. Be careful not to move the light pen too fast across dark regions of the screen, or you'll lose the tracking cross and incorrectly designate a point within that region. Both a light pen and digitiser may be used on the same system, but only one at time. If both are connected, the digitiser has priority; to use the light pen, just remove the digitiser cursor from the tablet (or otherwise make it stop sending samples).
On 10/30/82 I installed code by Greg Lutz to correct a bug he found in the interaction between INSERTs and REPEAT/ENDREP loops. If an INSERT was invoked inside a REPEAT loop, the coordinates of the block invocation entity were transformed by ETRANS to the loop instance coordinates. When the contents of the block were read, ETRANS transformed them again, resulting in (in the simplest case) double translation of the entities. The new code makes block invocation push AXTRANS and AYTRANS and set them to zero before a block is elaborated. At the end of the block, they are restored from the block execution (BX_) item. This should make all combinations of blocks and repeats work correctly.
Corrected a bug in TRACE entry reported by Richard Handyside. While entering a continued TRACE, if a point outside the drawing limits is inadvertently entered, a bizarre last leg of the trace was drawn. The TRACE entry code was assuming that when GPOINT returns an NVALID result, the X and Y coordinates were unchanged. In the case of an out of limits point, this is untrue (so that ID can be used on out of limits points). As it turned out, TRACE had already copied the last point to separate variables, so all that was needed was to use them. Now entering an out of limits point will terminate a trace just like hitting the space bar (that is, putting a right angle end on the last segment of the trace).
If the drawing editor crashed while editing a drawing, all changes made in the editing session would be lost beyond hope of recovery. This is because CP/M only updates the file directory item for a file on the disc when the file is closed, and even though we were faithfully writing out the new entities and refreshing the drawing header on every REGEN, all this new information would be lost if the normal closeout code were not executed. I changed REGEN to close and re-open the drawing file at the end of every REGEN. This means that if ACAD crashes, all you have to do to get back to the point of the last REGEN (ZOOM, PAN, ENDREP, or anything else that causes a REGEN) is rename the .DWG file to .BAK and the .$$$ file to .DWG. The $$$ file thus contains a valid drawing as of the last REGEN. If you're doing a long editing session and want to make sure you're protected, just do an explicit REGEN every now and then. In normal use of the package, the user will probably be doing enough REGEN inducing operations that loss in a crash will be minimised.
On 11/1/82 I made the ZOOM and PAN commands in DSCMDS an overlay (ACAD11). This freed up about 1600 bytes of memory to waste on other features.
On 11/17/82 I installed an on-screen menu for the light pen. This works the following way: if configured, the right border of the screen is dedicated to a menu, with one line for each of the 40 menu items. When you point at a menu item, it flashes. You may move up and down the menu area and the flashing will follow you to confirm the location. When you get to the desired menu item and release the light pen, the menu item will go to reverse video as it is executed. It will be restored to normal when the light pen is next pointed into the menu area. When the light pen menu is used, the aspect ratio of the screen is changed and XDAR and YDAR are adjusted to accommodate the space removed from the right of the screen.
On 11/18/82, as requested by Lars Moureau and Keith Marcelius, I added a feature to INSERT which allows old-style pure transcription of the file being loaded, rather than copying it into a block. You select this mode by preceding the file name with an asterisk. You may insert a file previously loaded as a block without any duplication or error. The block is ETRANS relocated to the desired insert point based on its insertion base, but scaling and rotation are not allowed and the prompts for them are not issued.
To allow clearer and more concise labeling of MENU items displayed on the on-screen menu, I added a “menu label” field to the menu file. If the first character of a line in the .MNU file is “[”, the text between the “[” and the next “]” will be displayed on the screen menu. The actual text sent to the input processor when that item is selected will be the text that follows the “]”.
Often one wants to specify high-level commands using the menu facility but is thwarted by the inability to allow user-specified parameters in the midst of a canned input stream. No more. I installed a “menu macro” facility which allows the interpretation of the menu text to be suspended, a user input to be accepted (from the keyboard, digitiser, light pen, etc.), and then the menu text interpretation to be resumed. As the menu text is scanned, if a “\” character is hit, the next user input is accepted via GDATA(0) (that is, terminated by space, semicolon, or return), and logically inserted in the menu string at that point. After the user entry is processed, the scan of the menu text resumes after the “\”.
For example, suppose we've defined an INSERT file called NANDGATE and we want to be able to insert it at 1x1 scale with no rotation simply by pointing to the location. We would define a menu item as follows:
[NAND]insert nandgate \1 1 0
This would do the INSERT command and supply the file name. Then a user input would be requested to supply the insertion location. The scale and rotation queries would be supplied by the menu text automatically. If that's not esoteric enough, define an insert called BOX which is a square with side of 1. You can then define a menu item as follows:
[BOX]insert box \@ \@ \0 Obsolete—see below.
To use this menu item, you select it, and then digitise the location you want the box to go. Then the “@” forces a “2 points” entry form for the X scale. You supply the second point from the digitiser which sets the X scale to make the box as wide as the distance from the box origin to the second digitise. The second “@” forces “2 points” for the Y scale also, and you enter the second point specifying the height. Since the box has side of 1, the scaling makes it as big as the lengths you've specified. The angle is forced to zero. Thus you point to BOX, point to where you want it to go, point to where you want the right edge to go, and point to where you want the top to go, and there's your box. And all without adding any new entities to ACAD! Yes, I know it would be nicer to just point to the upper right of the box, and I'm working on that.
Note that in defining these menu items, the placement of spaces to force execution of commands is critical. I'm downright embarrassed at how little code it took to put this in. It's all in GDATA and it's not much.
On 11/19/82 I added the ability to specify both the X and Y scale factors of an INSERT by simply entering one point. If you respond to the “X scale factor” query for an INSERT with “CORNER” (“C” is enough), then it prompts you for the “upper right corner”. You digitise a point, and the abs(delta X) becomes the X scale factor and the abs(delta Y) becomes the Y scale factor. Thus if you've defined the INSERT to be 1 by 1 you can insert it and scale it to the screen just by digitising two points.
Thus, with the changes made today, the BOX macro defined above becomes:
[Box]insert box \center \0
To use it, you just point to the BOX menu item, the left lower corner of the box, and the upper right corner point. A box is then inserted to the scale you selected. To make the rotation variable, replace the last “0” with a “\”, and you'll then be able to point to the angle you want the box to go on.
On 11/20/82 I finally got around to installing a buffering routine in LOAD. This cut the time needed to load the text shapes (TXT.SHP) by a factor of four. This reduces the annoying delay during the initial drawing of a picture while AutoCAD loads the text definition. I also cleaned up the carriage return/line feed logic of error messages in LOAD, which had a bad case of conceptual acne.
I made some minor changes in the format of the on-screen menu which allow the menu to be overwritten with a new menu without confusing the light pen logic. This lets you have items in your main menu which select subsidiary menus. (Previously if you did this, it confused the logic which inverted the last-selected item, and you wound up with two items inverted. These fixes correct this bug.)
As suggested by Mike Ford, I changed the “Digitise entities” message to “Select objects”.
I installed the long-awaited “window designation” facility to EID. The EID prompt message was further changed to “Select objects or window:”, and EID was changed to recognise the letter “W” as a response before the first point is entered. Upon receiving the “W” it prompts for a left lower corner point and a right upper corner point (actually, you can enter them in any order). It then scans the refresh file and selects all entities which have at least one visible vector within the window, and from those only the ones which have no visible vectors outside the window. Read that over again and think about it for a while; it's not easy to comprehend, but it's easy to use and meets the most logical user assumption, I think.
If you're using a light pen, often you want to move the tracking cross somewhere else on the screen to unclutter an area you're examining. Since the tracking cross only moves when the light pen is selected, and deselecting it designates a point, this generated an error message when the point was input to the command prompt. I changed COMMAND to just ignore points input at the command prompt, so you can move the tracking cross at will. Yes, I know, but this is the kind of little thing that users appreciate.
I added a “Last entity” selection option in EID. If you reply to the EID “Select objects” prompt with “L”, EID will choose the most recently entity (whether visible or not). This is very, very handy especially for deleting the last thing you entered by mistake. Note that with ERASE you can step back through the file entity by entity by entering multiple ERASE L commands.
I installed Dan Drake's analytically correct code for calculating the number of segments to draw in a circle. This makes small circles smoother and big circles faster. It also optimises circles too small to see into a dot, speeding up REGEN of circles when you've zoomed way out. Note to myself: Dan's code uses ACOS, which pulled in 500 bytes of library. I must change it and define ACOS in terms of ATAN which ANG already pulls in. If you don't see a note below which says I did it, please remind me.
On 11/21/82 I looked up ACOS and redefined my own in EREGEN in terms of ATAN and SQRT. It gets the same answer as the one in the library and gets rid of 500 bytes (n.b., I wonder how much more can be saved with tricks like this-look at the library some time).
I installed a new BLOCK command. This command lets you create a block “on the fly” from parts of an existing drawing. This makes for more spontaneity while drawing, as you don't have to define all your parts ahead of time so you can insert them from files. When you enter the BLOCK command, you will first be asked “Insertion base:”. Supply the point which is to become the insertion base of the new part (point to it on the screen). This has exactly the same effect as the BASE command when making an INSERT file. Next the standard “Select objects” prompt will appear, and you may use any of the entity designation options to choose the entities which are to make up the new part. To confirm that the entities you've selected are the right ones, they will disappear from the screen. Next the prompt “Block name:” will appear. Simply enter the name you want the new block to have (as no file name is relevant here, no equal sign should appear in the prompt). AutoCAD will then construct a block with that name containing the designated entities with the specified insertion base. You may then immediately use that block just like it was INSERTed from a file. The entities which were placed into the block are deleted from the drawing. If you don't want them to be deleted, just say “OOPS” after the BLOCK command finishes, and they will be restored to the drawing.
I installed a CHANGE command. This command is not the same as Mike Riddle's, and I don't know whether it is what we want. It is what I wanted to clean up drawings, and I'm convinced that something like it is a valuable addition to AutoCAD. I'm equally sure that what we really want isn't exactly this command, so maybe we don't want to document it until we come up with a final design. It is, however, awfully doggone handy. But on to the facts. When you say CHANGE, the first thing that appears is the standard “Select objects” prompt. You designate the objects that you want to change. Only lines and circles can be changed. Any other objects pointed to will not be changed (but they will disappear from the screen, only to reappear on the next regen—this is what we call “el buggo”). Assuming you've selected one or more entities, you will next be asked for an “Intersection point”. If the object is a line, its endpoint closest to the intersection point will be changed to meet the intersection point. If ORTHO mode is on, the line's new coordinate in the direction of its longest run will be forced to the value of the corresponding coordinate of the other end. Thus, in ORTHO mode, only orthogonal lines will result from a CHANGE (this sounds clunky, but just wait until you use it to make a horizontal line meet a circle while zoomed way in, then you'll stand up and applaud). If the entity being changed is a circle, its radius will be adjusted so that the circumference of the circle passes through the intersection point. We all know that we need a much more general EDIT command which can talk about any property of an entity, plus modify entities based on properties of other entities (e.g., “Run this line in this direction until it hits that arc” or “Make this circle pass through the endpoint of that line”, and so on), but until we get one, this thing makes cleaning up perspective drawings and hybrid digitised stuff like the shuttle drawing about ten times faster than before.
On 11/23/82 I fixed a bug in EREGEN. If we were generating a circle or arc which was very large with respect to the screen, the code which calculated the number of segments to draw could divide by zero. Since in this case we want to restrict the number of segments to the maximum anyway, I just changed it to catch the ON condition and set the number of segments to the maximum, which is shorter in code and less complex than testing for zero everywhere in this fairly involved code.
The code which decides how many segments to use to approximate an arc or circle was basing the number of segments drawn on the relative sizes of circle and screen, but did not reduce the number of segments when drawing an arc. Hence, a 5° arc would be drawn with as many segments as a 360° circle. This made for very beautiful arcs, but very slow drawing! I changed it to first calculate the number of segments it would be drawing were the circle complete, then reduce the count by the expression max(2,NS*TINCR/2*Pi), which guarantees that no arc will be compressed to a straight line, but proportionally decreases the sector count for arcs.
I made another speedup change in EREGEN: previously I drew text as dots if it was too small to read and just as a line if it was smaller than a dot. I changed this to always draw text too small to read as a line the approximate length of the generated text. This makes display of small text about 5 times faster, as only one entity is generated per text entity rather than one per character. I find the result just as aesthetic. Comments are welcome.
COMDEX 1982
“Strange memories on this nervous night in Las Vegas. It seems like a lifetime, or at least a Main Era—the kind of peak that never comes again. Maybe it meant something. Maybe not in the long run…but no explanation, no mix of words or music or memories can touch that sense of knowing that you were there and alive in that corner of time and the world. Whatever it meant….
“There was madness in any direction, at any hour. You could strike sparks anywhere. There was a fantastic universal sense that whatever we were doing was right, that we were winning.
“That, I think, was the handle—that sense of inevitable victory over the forces of Old and Evil. Not in any mean or military sense; we didn't need that. Our energy would simply prevail. There was no sense in fighting—on our side or theirs. We had all the momentum; we were riding the crest of a high and beautiful wave.”
— Hunter S. Thompson, Fear and Loathing in Las Vegas
On 12/16/82 I installed a centered text option in EACQ2. When the “Insertion point” prompt is issued, you may now enter “C”. This will cause a “Center point” prompt to appear—a point is supplied as for the insertion point, but the text will be centered both vertically and horizontally around this point. This is accomplished by making a dummy run through SHDRAW for the text with a new flag set which causes SHDRAW simply to update a max and min X and Y area used by the text. This area is then used to adjust the insertion point so that the text will be centered around it. Implementation note: we assume in this code that the text font has already been loaded before the first text entity is entered. Because earlier logic only loaded the text font the first time EREGEN encountered a text entity, this assumption was not always true. As a result, COMMAND was fixed to check whether the text font was loaded when a TEXT entity command is encountered. If it is not (TXGRID=0), then LOAD is called to load TXT.SHP before EACQ2 is called. This guarantees that EACQ will be able to calculate the size of the text if required for centering. The centered text is very handy for labeling macros for things such as flowcharting packages, and will play an important part in the dimensioning facility.
The centered text mode is “remembered” and if more text is entered by just pressing return at the next command prompt, subsequent lines will be centered under (in the logical sense, depending on orientation) the original line.
On 12/19/82 I completed the installation of “simple dimensioning”. This is a form of automatic dimensioning derived from a description of how Computervision does it as described by Jamal Munshi. Some changes and additional features were added in this implementation. The facility is controlled by the DIM command. The entire facility is in an overlay, and if the feature is not purchased with the package, the overlay can simply be deleted from the release disc. COMMAND will catch the overlay not found error and print the message “Optional feature not installed.” and return to the command prompt.
First some background and terminology: a dimension consists of two “extension lines” (referred to as “witness lines” in some texts) which lead from the points being dimensioned to the specification of the dimension, a “dimension line” which has arrows on the end and which points to the extension lines, and the “dimension text”, which gives the actual dimension between the two extension lines. If there is sufficient room between the extension lines, the dimension line will be within the extension lines, as in:
If there isn't room between the extension lines, the dimension line will be split and point to the extension lines from outside, as in:
In my implementation, dimension lines always run either horizontally or vertically. You can dimension a diagonal with a horizontal or vertical dimension line simply by running the extension lines to the ends of the diagonal line. To create a dimension, enter the DIM command. The first prompt to appear will be “First extension line origin:”. You should designate the point near the item being dimensioned where you want the first extension line to appear. Next the prompt “Dimension line intersection:” will be given. You should then designate where the dimension line should be placed relative to the first extension line point (i.e., where the arrow will hit the first extension line). If the line between the first extension line origin and the dimension line intersection is more horizontal than vertical, the dimension line will run vertically, if more vertical, the dimension line will run horizontally. (Draw a couple and you'll understand.) Finally, you will be asked “Second extension line origin:” which requests you to designate the point near the object where the other extension line is to go. Before moving on to the rest of the command and its action, let me explain how these three points are used to define the dimension.
The first extension line will always start at the point designated for the first extension line origin. It will run either vertically or horizontally depending on the predominant direction between the origin point and the dimension line intersection. Any displacement of the dimension line intersection point from a true vertical or horizontal is ignored—it supplies only the direction and distance between the extension line end and the dimension line (or in other words, the dimension is taken from the extension line, not the dimension line, which is what you want). The second extension line is then drawn from the second extension line origin point, in the same direction as the first extension line, as far out as the first extension line went (note that the ends of the extension line at the dimension line always line up, but the ends nearest the item being dimensioned may appear anywhere, to accommodate strangely shaped objects). The dimension line will then be run either vertically or horizontally from the first extension line to the second.
There is a value called “arrow size” which influences many parts of dimensioning. The ANSI drafting standard specifies that drawn arrows should be 1/8 inch in size. Since we don't know the scale of the final drawing, we don't initially know how big to make the arrows. Thus we have a variable called arrow size which controls this. If no arrow size is specified, we will guess and use 1/64'th of the smallest dimension of the drawing. The arrow size controls the size of the arrows themselves, which are drawn with solid fill at the ANSI-specified aspect ratio of 1 to 3. It also controls how far the extension lines extend past the dimension line (1 arrow length), how much spacing will be placed between the dimension text and the dimension lines (1 arrow length), and the initial size of the dimension text (1.5 arrow length). Further, if the arrows must be moved outside the extension lines, their shafts will have a length of one arrow length. The arrow size can be explicitly specified by the “DIM A” command, and will be saved in the drawing header. ANSI specifies that all arrows in a drawing shall have the same size.
Now we come to the matter of the text that specifies the dimension. The user will be prompted with “Dimension text:”. If just a carriage return is given as the response, the distance in the direction of the dimension line will be measured and edited as a decimal number with four significant digits. Trailing zeroes and decimal points will be suppressed. If text is entered, the text will be used as-is. Since the text is terminated by a carriage return, spaces may be used within it.
Now that all of the components of the dimension have been acquired, the dimension is assembled on the screen. The first test is whether the dimension lines should be drawn inside or outside the extension lines. Our criterion for this decision is that if we have less than 8 times the arrow size between the lines, we'll draw the arrows outside, otherwise we'll try them inside. The text within the dimension is always drawn with angle 0 (that is, horizontally). This is in conformance with the ANSI standard, which specifies “unidirectional” dimensioning as the preferable technique. As a result, there are two cases depending on whether the dimension line runs horizontally or vertically. If it runs horizontally, we have to squeeze the text between the arrows so that the arrows run from the first and last characters of text. If it runs vertically, the lines run from the top and bottom of the letter area. In the horizontal case it's obvious that the length of the text is an important consideration in composing the dimension. In the vertical case we might just ignore the length (as only the height matters in fitting the arrows), but this isn't wise as we might overlay the object being dimensioned with the text. Consequently, for both the horizontal and vertical dimension line cases we compute a length in which the dimension text must be forced to fit; if horizontal, this is the total dimension line less 6 arrow lengths (2 for arrows, 2 for minimum length dimension lines, 2 for clearance between text and lines). If vertical, the fit length is two times the least distance between the dimension line and the extension line origin (this guarantees that the text won't overlap a straight figure; if the figure is convex, it may still overlap, and the user will have to move the dimension line further out).
Now that we know the space we have to work with for the text, we calculate the actual size needed to draw the text with its initial size of 1.5 * Arrow_size (taken by measuring characters in ANSI-standard drawings). If the text fits at that size, it is drawn centered in the dimension line, and the lines extend to within 1 arrow size of the text. If the text doesn't fit, it will be reduced in size until it just fits in the space available. In the case where the arrows are drawn outside the extension lines and the dimension line runs horizontal, the text will be fit within 8 arrow lengths.
The extension lines and dimension line may have any geometrical relationship you desire; you may draw vertical dimensions top to bottom, bottom to top, and with the dimension line to the left or right of the extension line origins, and of course the equivalent for horizontal dimensions. The order you specify the ends makes a difference only when the arrows are drawn outside the extension lines, as the text will always be placed on the end of the second-specified dimension line (affording user control of placement), and when continuing dimensions.
At the point the “First extension line origin:” prompt appears, you may enter “B” or “C” to continue the last dimension. Either reply immediately advances you to the “Second extension line origin:” prompt, and draws a new dimension based on the last one. “B” adds a dimension relative to the first point of the last dimension, drawing the dimension above (or whatever) the last one. This is what you do when you want a set of dimensions all relative to the same base line. Multiple “B” DIM commands will all reference the same base line. The “C” response draws a dimension relative to the second extension line of the last dimension, with the dimension line colinear with the last one drawn (unless the last one was outside the extension lines, in which case the new dimension line will be moved to clear it). This is what you do when you could care less about cumulative tolerances and want all the dimensions in a chain.
All the items that make up the dimension (lines, solids, text) are drawn as primitive entities, so they may be manipulated individually. The dimension facility is simply a tool to make these entities for the user, there is no special support in AutoCAD for dimensioning per se. The dimension code is split between DIM1 and DIM2 so as not to constitute the largest overlay and hence consume more memory—for logical purposes you can consider the two to be one piece of code.
On 12/24/82 I fixed a bug in ERASE reported by Jamal Munshi. This is one of the more humorous bugs I've seen so far in AutoCAD. Suppose you had a REPEAT/ENDREP loop with more than 1 entity in it. If you did an ERASE W and pointed to the entire bounds of the array elaboration, the scan of the refresh file would find each entity once for every array instance. Since there was more than one item in the array, the refresh file will contain a new entity header for each instance in the array. If the operation was an ERASE, and the total number of array items was even, ERASE which just inverts the entity type to delete the entity, would flip the sign an even number of times, leaving the entity not deleted. Since the UNDRAW was driven from the REDRAW file, the items would disappear on the screen, but come back on the next REGEN. I fixed this by making ERASE test whether the entity it's about to delete is already deleted. If so, it just leaves it alone. It's then also necessary to fix OOPS, since OOPS will also see duplicate entities and may re-delete something it shouldn't. Note that other entity designation commands can still be messed up by this case. I think that the real solution is to make EID scan the select list as it chooses each entity and guarantee that any given entity is selected only once. Maybe I'll change it to do that someday.
On 12/25/82 I installed support alternate forms of cursors, as available in the Aurora 1000 board, whose driver I am finishing up. The Aurora 1000 offers a software-selectable set of cursor types. I installed code in various places to support them, if available in a display device, in a device-independent manner. If the display device handles multiple cursor types, it should reference the external fixed(7) variable CURSEL. When DSMARK is called, if CURSEL is 0, the normal cursor should be displayed. If 1, then a box or window cursor should be displayed. If 2, a rubberband cursor should be displayed (i.e. crosshairs “pulling” a line). If CURSEL is nonzero, the other point (other box corner, origin of rubberband line) is given by the external fixed variables CURSLX and CURSLY. These variables are set to the screen coordinates of the last point returned normally by DIG—thus they are normally set to the origin point of the last point entered. Commands may set them (remember to use screen coordinates!) to other points if desired. Code installed to use this new feature is: EID uses a box cursor for the “W” form of designation; DSCMDS uses a box cursor for ZOOM W selection; EACQ1 uses a rubberband cursor for LINE acquisition, and EACQ2 uses a rubberband for TRACE acquisition. Note that if the display device doesn't support alternate cursor types, it may just ignore CURSEL, CURSLX, and CURSLY.
I decided to go ahead and fix the multiple designation bug mentioned above correctly. I removed the kludge code installed yesterday in EDIT for the ERASE and OOPS commands. Then I installed code in EID which, for every point selected, scans the list of already selected entities and if it finds that the designated entity is already on the list, doesn't add it. Instead, it adds the entity to a duplicate selection list, DUPLST. This is necessary because if EID is going to delete the found entities from the refresh file (as for an ERASE or MOVE), it has to save all refresh file finds, even if for duplicate entities. After preparing the unique list and the duplicate list, if UNDRAW is requested, it undraws all refresh file entries in both lists. Otherwise, it just flushes the duplicate list and returns the unique list. This fixes all confusions known to exist when selecting entities within REPEAT/ENDREP loops.
On 1/1/83 I went back to work on the DataType 150 driver. First some words about the design and history of this unfortunate device. It attempts to emulate a Tektronix 4010, but since its internal resolution is only 512×250, it translates the Tektronix coordinate space of 1024×780 into this raster matrix. This has a number of painful side effects. First, of course, the resolution is low to start with (vertical is the bad direction). Next, since we have to send Tektronix coordinates to the beast, AutoCAD believes that it has more resolution than is really available, so it draws things (text and circles) which aren't really visible on the screen. This makes things runs a lot slower than if the terminal were “honest”. Since the Tektronix is a direct view storage tube, there were no commands defined in its command set for erase. Data Type extended the command set to include a dark vector, but did not include a complement vector. This has a horrible impact on the digitiser support, to be discussed below.
The DT150 driver, as currently implemented, uses the top 21 lines of alphanumeric space on the screen for the graphics display. The bottom 3 lines are used as a scrolling region for communication of commands. This is achieved by using the Televideo lock line command for the blank lines that overlay the graphics area, and leaving the bottom lines as a scrolling text area. Thus, the addressable graphics area is 1024×656. The terminal lacks any kind of area fill, so this is done with vectors as the AutoCAD default. Since there is no complement draw, implementing the screen cursor is basically impossible. I fixed it to draw a 3×3 (in Tek coordinates) cross. It draws this cross, then erases it whenever it moves and redraws it at the new location. Since there's no complement screen function, this means that the cross erases whatever it passes over! This means that as you use the digitiser, you slowly wipe the screen, until you're forced to do an explicit REDRAW to see where you are. I made the cursor small deliberately so that it wipes as little as possible.
Another offshoot of supporting terminals which “lie” about their resolution is that the BLIPs drawn for selected points may not look right. In the case of the DT150, they are so small that sometimes they look like “T”s. (Sometimes because it depends on where the center point maps into the modularity of the logical and physical resolution.) I made the variable in BLIP which determines the size of blip external and named it BLIPPO. A display driver is now free to redefine the size of the BLIP in its initialisation routine to be whatever displays correctly on the screen (n.b., should we change the closeness criterion in EID to equal BLIPPO? I think so, but I haven't done so).
In the process of working on the DT150 driver I discovered a “facet” of PL/I which I should warn other potential ploners about. Suppose you have a procedure which you want to pass different text strings for processing. You might declare that procedure as:
ZONK: PROCEDURE(PSTR); DECLARE PSTR CHARACTER(128) VARYING;
then call it as ZONK('Booga'). Be warned, the strong typing rules will force all the string constants you use as arguments to be 128 characters long, with the first as the length flag. Of course it will work fine, and the only way you'll notice you've been had is when you wonder where 30K of memory went. The most obvious way out is to make PSTR a global variable and assign the strings to it. Assignment doesn't force conformance on the right side, so the right side string will retain its attribute of CHARACTER(n), and be converted to the variable string on the left hand side. This little change knocked 2K of wasted data space out of the DT150 driver, and I suspect that I can find similar savings throughout AutoCAD (in particular the PROMPT routine).
On 1/5/83 I “completed” the driver for the DataType 150. This terminal is such a pig that should we really wish to sell AutoCAD on it, a literally endless amount of work can be poured into its gullet without yielding a usable product. What I ended up with was a driver with no on-screen menu, a graphics area at the top, and a 3 line scrolling region at the bottom. Several days were wasted trying to get an on screen menu to work using the cursor positioning keys to make the menu selection. I abandoned this after it became clear that there were fatal flaws in the firmware in the terminal which precluded using this strategy. In order to implement the separate scrolling region and graphics area, I take advantage of the fact that the graphics and alphanumeric displays are separate and logically ORed to create the CRT drive. I use the Televideo lock line function to make the top 21 lines not scroll. Since they are cleared to blanks and don't scroll, they don't interfere with the graphics drawn in the same space. The bottom lines, being unlocked, scroll. I attempted to put a menu on the right side of the screen, but discovered that the cursor address function refuses to go to a line that's locked. It will only address lines in the scrolling region. To circumvent this, I tried unlocking the screen, updating the menu, then locking it again. Because of the way the line lock command works, this takes about 60 characters to do, so moving the cursor up and down the menu took an extremely long time to do. Furthermore, when running this sequence, the terminal would randomly get confused about its scrolling and insert blank lines in the menu area, transpose lines from the bottom 3 into the middle of the screen, and even scroll up the status line from the bottom of the screen. As this behaviour was completely random and not related to XON-XOFF handshaking what was previously checked out, I just decided to pitch the whole idea of an on screen menu and let this porker trot along without.
That left the issue of how to handle commands with lengthy output, such as STATUS and DBLIST. I installed a new procedure in the terminal driver, called DSLONG. (This was put in all the other drivers, but is null in them, as they are two screen versions.) Any command which generates lengthy output should call DSLONG(TRUE) before the first line of the output and DSLONG(FALSE) at the end. It must not exit without calling DSLONG(FALSE). The DT150 DSLONG procedure, on TRUE, clears the graphics and alphanumeric screens and unlocks the scrolling region so the whole screen can scroll. On FALSE, it displays the prompt “Press any key to continue:” and waits for an input character. When it gets one, it clears the screen, re-locks the graphics area, and calls REDRAW to put the picture back up. This kind of trick should work on any reasonable graphics terminal (I hope). The commands which activate DSLONG are STATUS, DBLIST, LAYER ?, and LIST.
On 1/7/83 I fixed some bugs in the shape compiler. First, SHCOMP was failing to test whether the shape number was between 0 and 255. Since the shape number is used to subscript a number of arrays, a bad shape number could lead to disaster. I installed an error message and made the compiler terminate with a syntax error. (Reported by Lars Moureau).
On 1/14/83 I installed code to aid in the use of devices whose support of colors is truly heroic (such as the Vectrix 384). The LAYER COLOR subcommand now accepts “*” as an argument. LAYER COLOR * will set all layers colors equal to their layer numbers (layer 1 color=1,…layer 127 color=127). Thus, drawings with many colors may be created simply by assigning the layer number equal to the desired color.
On 2/12/83 I completed support of the Hitachi “Tiger Tablet”, HDG-1111. This is an RS-232 tablet very similar in general specifications to the HI-PAD from Houston Instrument. It offers either a 12 button cursor or a stylus as the digitising instrument. The driver, in file DSDRVTG, is very similar to the HI-PAD driver. The Tiger Tablet offers many protocol options, and the modes in which I chose to run it were chosen for similarity to the HI-PAD. Should we choose to recommend this device, we can switch to the more efficient and faster-to-track binary mode.
The stylus works like the cursor on the HI-PAD. Moving it on the tablet moves the crosshairs, and pressing it down selects a point. The 12 button cursor is implemented in the following way: moving the cursor on the pad moves the crosshairs. The zero button selects a point. Buttons 1 through 9 select the first 9 menu items immediately, regardless of the position of the cursor. Thus, very commonly used menu items may be set up for instant access through the cursor. Note that with either the stylus or the cursor, conventional menu selections may be made either by pointing to the screen menu and doing a point select (stylus press or zero button), or by making a point select within the digitiser menu.
On 2/21/83 I implemented a driver for the USI Optomouse. This is a four button optical mouse which talks a protocol very close to the Summagraphics Bit Pad. The Optomouse driver (in file DGDRVOM) replaces the digitiser driver in AutoCAD. Assuming that the “tail” of the mouse is at the top, the buttons are numbered with the top row 2-1 and the bottom row 3-4. (The buttons are activated by pressing one end or the other of a bar on the mouse.) Button 1 is the “hit” button and selects a pointed to menu item or a point on the screen. Buttons 2 through 4 select the first 3 menu items regardless of the position of the mouse, and thus may be used for very frequently used commands, obviating the need to move the mouse to point at the main menu. (Note: if this doesn't work for you, it's because whoever generated ACAD forgot to turn on the KEYPAD compile time variable in DIG-just a word to the perplexed.) The Optomouse can be configured by output commands for various modes. Currently, the only configuration done is to program it for 10 ms between samples in order to speed up sampling rate and smooth cursor motion. Note that this driver was developed and tested with a prototype Optomouse and will have to be modified when the production mice with auto-baud rate sensing are delivered. Note that the mouse driver differs from a standard digitiser driver in that DGACOR isn't enabled, and that the output coordinates are clipped to prevent returning a sample in the digitiser menu area, which we can't use with a relative positioning device like a mouse.
On 2/23/83 I blind-implemented a driver for the Summagraphics Bit Pad to solve a customer requirement. The driver was created by modifying the Optomouse driver and tested with the Optomouse. It differs from the Optomouse driver only in that it doesn't send the command string to send sample rate, it turns on DGACOR, and enables the digitiser menu as for the Hi-Pad and Tiger Tablet. The driver was tested with the Optomouse and works, but customer comment will be required before the driver can be considered operational.
On 3/11/83 I completed a complete rewrite of the plotter driver, encompassing both the device-independent part and the Houston Instrument driver. The rewritten driver is now compatible with the version in AutoCAD-86, the offshoot of the Plotter Integrity Project. The changes between the old and new drivers are massive, and will be discussed in something approaching order of importance.
First, there is now a plot configuration file which saves all the parameters for the plot. ACADPLOT.CFG is written and updated by the plot driver, being created the first time a plot is made. It contains the plotter manufacturer name, the plot paper size (either a standard ANSI or DIN size, or a custom size specified by the user in inches or millimeters) the units the plot is in (again Inches or Millimeters, also selecting ANSI or DIN sheet size nomenclature), and the pen width (of the narrowest pen), which is used to calculate the number of vectors needed to FILL a solid and the accuracy required for true circles and arcs.
The file also contains a driver specific configuration section. For the Houston Instrument driver, this specifies the model number (DMP-?), the assignments of pens, line types, and velocities to each color in the drawing.
The plotter driver is now organised so that one master driver can be supplied which runs all plotters we support. The code has been written so that drivers for each manufacturer can be overlays, so there will be no limit on the number of different plotter protocols we can support in one driver.
Once the standards for a plot are specified, they need not be entered again unless the user wants to change the standards. If a change is desired, the user can go through the items, changing only those desired. A null entry to any configuration query leaves the old value unchanged. An interactive entry dialogue is provided in the HI driver to set up the assignment to drawing colors. “X” ends the dialogue. If the parameters are changed, they may be used in the changed form for just this plot or for all future plots, at the user's option.
Handling of scale and windowing the plot onto the paper is totally different. If the SCALE query is answered with a null reply, what is plotted will be identical to the screen contents, nothing more and nothing less. The paper size will be adjusted automatically to accomplish this (and a message will inform the user of the adjustment). Scale may now be answered with a number (specifying a scale greater than 1 to 1 (optionally followed by an “X”)), or by a scale less than 1 in the form “1:n” or “1/n”. This scale will map the drawing units to physical units on the paper according to the units in effect. If the plot is in English units, a scale of 1 will map 1 drawing unit to 1 inch. If metric, 1 drawing unit will become 1 millimeter on the paper. A scale of 2 will make things twice as big on the paper, and a scale of 1:10 or 1/10 will make things ten times smaller.
All input to the plot driver is now handled with a data input routine like that in the drawing editor. Thus space, CR, or “;” may now be used to terminate input, and ^H and ^X work as local editing keys normally. ^C will now abort the plot during configuration, not return the user back to CP/M unexpectedly.
The Houston Instrument driver supports only 15 logical colors (1 to 15). Colors greater than 15 will be wrapped around modulo 15 (e.g., color 16 becomes 1, 17 becomes 2, etc.). This corrects a previous bug where out of range colors would result in the ridiculous action of faithfully drawing with no pen.
On 3/13/83 I made a large number of changes in the main menu module, AUTOCAD. If ACAD is serialised with dealer number 97, our code for an evaluation version, the main menu will now print “EVALUATION VERSION—NOT FOR SALE” in the drawing header for all displays.
I fixed a bug in ZOOM W. A null or line window would cause ACAD to ZOOM into hyperspace. I fixed it to reject a window without area. (Reported by Greg Lutz).
Aaaaah yes, the HI-Pad…. Well, the scum also rises, and it's time to resolve the issue of Hi-Pad jitter once and for all. I spent about 2 hours looking at the character stream sent by the HI-Pad as I subjected it to various “stimuli” such as static electricity (thanks to a cooperative (?) cat), magnets, and proximity to the RGB designs “Big Mutha” monitor and a Hazeltine terminal. Except in cases of extreme and unreasonable abuse (25 KV kitty dragged across the pad), the jitter consisted of a random ± 10 in the Hi-PAD sample. This jitter was completely random, exhibiting no periodicity or pattern that old “Random” Walker could detect. Run lengths varied randomly from 1 to 100! There is no smoothing technique which can compensate for this. The only answer is resolution reduction. So I fixed DGDRVHI to check the sample about to be returned against the last sample returned. If the absolute value of the difference between the current sample and the last sample is 10 or less, the last sample is returned. This results in a pad which is highly responsive to fast moves (as the JITTER averaging code can be disabled), but which settles to rock-steady stability when the cursor stops. But where's the catch? Well, it's very simple. Ignoring ± 10 excursions from the pad makes only movements of 20 points or more meaningful. With a pad resolution of 11000 in X and Y, this means that the pad can't address every pixel in a display with more than 512 dots in any direction. But then, with its jitter it would never succeed if it were to try! So, the HI-Pad has been bashed into acceptable performance for those applications for which it is usable.
I further changed the HI-Pad driver to automatically re-sync if synchronisation has been lost with the data stream. This prevents cursor flashing if an exogenous delay causes loss of sync with the data from the pad (such as a long cursor draw time).
I also changed the HI-Pad driver to lock its output coordinates within the 0 to 22000 limits by forcing out of range coordinates to the extreme limits rather than rejecting samples outside the range. This makes it much easier to select menu items and points near the edges of the screen. This mode is clearly preferable and will be the standard for all digitiser drivers in the future.
On 3/15/83 I hunted down the “8080/8085” bug and installed a workaround in ACAD. For certain values of X, Y and Z, the expression: (X+Y)<Z yields incorrect logical values on an 8080 or 8085 processor, but the correct value on a Z-80 processor. In general, it appears that the use of an expression as an argument to a relational operator can lead to the ambiguity. This caused circles, arcs, text, and traces/solids not to generate in certain cases. The basic bug is in PL/I-80 and an 8 line program was prepared which gets different answers on a Z-80 and 8085. A bug report was submitted to Digital Research. By “Captain Empirical” techniques, it was determined that assigning the expression part of the relational to a temporary variable eliminated the error in evaluation of the relational expression. The code which used such expressions for the off-screen tests in EREGEN (ARC, CIRCLE, and TEXT), and FILL (TRACE, SOLID) was rewritten to bypass the bug until DR supplies a fix.
On 3/23/83 I was foolish enough to try to implement a driver for the Mouse Systems M-1 mouse. I'm not sure if “mouse” is the correct designation for the position of this little bugger within Rodentia. The main problem is that, unlike the USI mouse, the MSC mouse only sends data to the host when something changes. This means that motion of the mouse when the computer is off doing something else is lost, since the samples just pile up in the UART and get lost. Worse, the sample format is 5 bytes per sample, without parity, and with no unique synchronisation code for the first byte (it's a pattern “unlikely” to be used in the 4 binary data bytes which follow). So, you can fix it to time out when out of sync and know that it will re-sync on the next sample, and you can put up with not being able to move the cursor except when the computer is tracking, because that's the way most mice work anyway. But, now for the catch: when you push a button, if the mouse isn't moving, it sends just one sample on the push and one on the release. If you happen to miss the push because you're out of sync or off updating the cursor or checking the console, then the button push is lost forever. I consider this device only to be useful if supported with an interrupt driven driver. Since that's not practical in AutoCAD-80 with its universal configuration requirements, I don't consider this mouse to be usable. And it's a damn pity. The thing has a microcomputer in it, and could have been programmed to work reasonably.
On 3/25/83 I implemented a driver for the Strobe model 100 plotter. This is a small A size plotter which talks a subset of the Hewlett-Packard protocol. The driver was added to the universal plot driver and is selected by answering STROBE to the manufacturer query. As this is a single pen plotter with no dashed line or variable speed support, there is no plotter-specific configuration at all. The plotter works magnificently, and no programming nor mechanical quirks were encountered in bringing it up or developing the driver for it. Since this is an RS-232 device, the port is configured in INSTALL exactly as for the Houston Instrument plotter.
I also took Richard Handyside's HP driver and created a universal HP driver and installed it in the plotter driver. I suspect that it will do something vaguely reasonable, but won't work right until I understand a bit more about the family of HP plotters. It is accessed with the HP manufacturer specification, and has a configuration dialogue almost identical to the HI plotters. Configuration at the INSTALL level is identical, as the HP plotters are RS-232.
On 4/1/83 I installed a CHANGE LAYER command. This command works on any entity type, and allows objects to be easily moved from layer to layer. To use it, give the CHANGE command. The usual prompt to select objects will be given. Then designate the objects to be moved between layers by any of the standard methods. When the prompt “New location” is given, answer “LAYER” (actually, anything beginning with “L” is OK). The prompt “New layer:” will then be issued, and you should respond with the new layer number. The selected objects will then be redrawn on the new layer (if visible).
I extended the CHANGE command to work on TEXT. The location, size, angle, and content of text may now be modified by CHANGE. A null response to any of the queries will cause the selected modification to be ignored.
On 4/19/83 I installed code to allow a demo version of AutoCAD-80 to be generated. The demo version is identical to the regular version, except that it will not write out an output file, nor will it make a plot from within the drawing editor (plots from the main menu are OK). This results in the user being able to try all commands on the sample drawings supplied with the package, and to make new drawings, but since no output may be saved on disc, no real work can be done.
On 1/12/84 I installed a gimmick in DSDRVAUR to provide support for the A-1030 colour mapping board. This option provides a user-loadable palette which can map any of the 16 color numbers generated by the A-1000 into any arbitrary analogue RGB value. Since if this board is present, the colour assignments are up to the user, we do not want AutoCAD's normal colour translation before the codes are sent to the A-1000. The configuration variable LPUSED, previously not used for the A-1000 (it is the light pen present flag for the Scion), is used as the A-1030 present flag. If zero (the default value if not specified) the A-1030 is assumed not to be present and colours are translated into the standard values as before. If LPUSED is set to 0FF in the .INP file, then the A-1030 will be assumed to be configured and colours will be sent to the A-1000 without translation (modulo 16, of course). Thus, the user can set up any mapping he wishes by loading the translation tables in the A-1030 and AutoCAD will not stand in the way.
This electronic schematic drawing and all of its constituents, appeared on the original sample drawings disc. It was the first sample drawing originated on AutoCAD-86.