Wednesday, February 24, 2010

SDI and MDI

SDI and MDI


 

When an application has the ability to open more than one document in a single session, this is known as multiple document interface. When developing an application for a MDI environment, special consideration must be taken, or the application may not function properly or it may interfere with other applications. To prevent applications from affecting one another, Autodesk has developed the concept of NameSpace. A NameSpace is a LISP environment that contains an isolated set of symbols (variables and functions). Each open drawing has it own unique NameSpace. Variables and functions defined in one NameSpace are isolated from variables and functions defined in another. When an AutoLISP application is loaded, the function is only accessible to the drawing where it was loaded. If the application is needed for multiple documents, then its contents can be automatically loaded by either appending the application to the Acaddoc.LSP or by using the VL-VLOAD-ALL function. When an AutoLISP application is compiled into a Visual LISP executable, the developer is given the choice of creating a separate NameSpace for the application. When the developer chooses this option, upon loading the application creates its own NameSpace separate from the NameSpace of the document where that the application was loaded. This guarantees that the variables used in the application will not be accidentally overwritten. Each time a compiled Visual LISP application is loaded in a different document, a new NameSpace is created to maintain the variables and functions associated with that application. When an application is compiled using the separate NameSpace option, by default that application's functions are not exposed to the document where the application is launched. The functions must be exported to the document using the VL-DOC-EXPORT function. To make an application accessible to the document and any other documents where the application is loaded, the VL-DOC-EXPORT function must be used. To determine which applications have defined separate NameSpaces and which of their functions have been exposed to the current document's NameSpace, the VL-LIST-LOADED-VLS and VL-LIST-EXPOSED-FUNCTIONS functions can be used. Once an application has been exposed using the VL-DOC-EXPORT function, its functions can be made available to other applications using the VL-DOC-EXPORT function. Variables contained within applications that define their own NameSpace are not known to the document's NameSpace where the application was loaded. Variables contained within a document's NameSpace may be accessed by a VLX application by using the VL-DOC-REF, VL-DOC-SET or VL-PROPAGATE functions.

The Value of a variable can be transferred from one document's NameSpace to another document's NameSpace using the Visual LISP Blackboard. A blackboard is a NameSpace that is separate from documents and VLX applications. Its purpose is to provide documents with a means of sharing data from one NameSpace to another.

Currently AutoLISP is limited to working with one document at a time. An AutoLISP application cannot issue any entity creation or modification functions in a NameSpace different from the one where the application is currently running.

Windows 95, 98 and NT Registry, Loading and Executing VBA applications

Windows 95, 98 and NT Registry, Loading and Executing VBA applications


 

Traditionally DOS and early versions of Windows (3.X) applications stored essential startup information in initialization (.INI) files. Initialization files are ASCII based text files that are limited in length to 64K. This created a problem; because these files were ASCII text files they were considered low security and could be edited using any text editor. It wasn't until the introduction of Windows NT that Microsoft began addressing these problems by developing a system of database files (collective known as the registry). These files are stored in a centralized location house important startup information used by Windows and other Windows based applications. The registry is a system of proprietary binary database files who's primary purpose is to ensure the integrity of the computer's operating system and applications. The registry uses a hierarchical structure to store information. The structure is comprised of six main components called subtrees (HKEY_LOCAL_MACHINE, HKEY_CLASS_ROOT, HKEY_CURRENT_USER, HKEY_USERS and HKEY_DYN_DATA). Each subtree is made up of subkeys. The subkeys contained in each subtree may also contain subkeys or they may contain active keys. It is the active keys that store the actual values associated with a particular application.

Out of the six subtrees located in the Windows registry, just two contain 90% of the data used by the registry (HKEY_LOCAL_MACHINE and HKEY_USER). The remaining subtrees (with the exception of the HKEY_DYN_DATA) are actually aliases that contain a copy of the contents of the other two keys. All information stored in the registry by an AutoLISP application should be done so in either the HKEY_LOCAL_MACHINE or HKEY_USER.

In addition to the Visual LISP IDE integrated into the AutoCAD environment, Autodesk has also provided the AutoCAD application developer with a second IDE (VBA) for developing applications. Although, AutoLISP is a powerful programming language for developing AutoCAD applications, VBA has the ability to create GUI interfaces much easier and faster than DCL. Because of Visual LISP's ability to incorporate other programming languages, the developer can create the GUI portion of an application with VBA and exchange data between VBA and AutoLISP components.

VL02.lsp

;;;********************************************************************

;;;

;;;    Program Name: VL02.lsp

;;;

;;;    Program Purpose: This program allows the user to calculate the ;;;                necessary bend allowances for soft steel. The

;;;                program uses formulas based on the formulas

;;;                found in the Machinery's Handbook 24th edition.

;;;    

;;;    Program Date: 12/31/98

;;;

;;;    Written By: James Kevin Standiford

;;;

;;;********************************************************************

;;;********************************************************************

;;;

;;;            Main Program

;;;

;;;********************************************************************

(defun c:bend (/ thickness radius_of_bend bend_angle allowance)

(setq    thickness (getreal "\nEnter Material Thickness : ")

    radius_of_bend (getreal "\nEnter Bend Radius : ")

    bend_angle (getreal "\nEnter Bend Angle : ")

)

(setq    allowance

     (* (+ (* 0.64 thickness) (* (* 0.5 3.14) radius_of_bend))

     (/ bend_angle 90)

     )

)

(princ (rtos allowance))

(princ)

)

(princ)

CAM.lsp

;;;********************************************************************

;;;

;;;    Program Name: CAM.lsp

;;;    Program Purpose: Create a Simple harmonic motion cam displacement

;;;             diagram and cam profile

;;;    Program Written By: James Kevin Standiford

;;;    Program Date : 01-31-99

;;;

;;;********************************************************************

;;;

;;;    Main Program

;;;

;;;********************************************************************

(defun c:cam (/     cir lo_l_c inc     up_r_c pt1a    pt2a pt1b

     pt2b pt1c pt2c pt1d     pt2d     pt1e    pt2e pt1f

     pt2f pt1g pt2g pt1h     pt2h     pt1i    pt2i pt1j

     pt2j pt1k pt2k pt1l     pt2l

     )

(setvar "cmdecho" 0)

(setq base (getreal "\nEnter base circle diameter : "))

(setq fo_heigh (getreal "\nEnter follower height : "))

(if (and (/= base nil) (/= fo_heigh nil))

(progn

(setq

    cir (* base pi)

    lo_l_c (getpoint "\nSelect lower left hand corner of graph : ")

    ;;

    ;;

    ;; Determines the outer edges of the grid, and calculates the vertical

    ;; lines of the grid. The variable lo_l_c is the lower left-hand corner

    ;; of the graph. The variable up_r_c is the upper right hand corner of

    ;; the graph. The variables pt1? represent the lower portion of the vertical

    ;; grid line. The variables pt2? represent the upper portion of the vertical

    ;; grid line.

    ;;

    ;;

    inc (/ cir 12)

    up_r_c lo_l_c

    up_r_c (subst (+ cir (car lo_l_c))

         (car lo_l_c)

         (subst (+ fo_heigh (cadr lo_l_c))

             (car (cdr lo_l_c))

             lo_l_c

         )

     )

    pt1a (list (+ inc (car lo_l_c)) (cadr lo_l_c))

    pt2a (list (car pt1a) (cadr up_r_c))

    pt1b (list (+ (* 2 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2b (list (car pt1b) (cadr up_r_c))

    pt1c (list (+ (* 3 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2c (list (car pt1c) (cadr up_r_c))

    pt1d (list (+ (* 4 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2d (list (car pt1d) (cadr up_r_c))

    pt1e (list (+ (* 5 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2e (list (car pt1e) (cadr up_r_c))

    pt1f (list (+ inc (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2f (list (car pt1f) (cadr up_r_c))

    pt1g (list (+ (* 6 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2g (list (car pt1g) (cadr up_r_c))

    pt1h (list (+ (* 7 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2h (list (car pt1h) (cadr up_r_c))

    pt1i (list (+ (* 8 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2i (list (car pt1i) (cadr up_r_c))

    pt1j (list (+ (* 9 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2j (list (car pt1j) (cadr up_r_c))

    pt1k (list (+ (* 10 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2k (list (car pt1k) (cadr up_r_c))

    pt1l (list (+ (* 11 inc) (car lo_l_c))

         (car (cdr lo_l_c))

     )

    pt2l (list (car pt1l) (cadr up_r_c))

)

;;

;;

;; Constructs a rectangle thatrepresents the outline of the grid and

;; all vertical grid lines.

;;

;;

(command "line"

     lo_l_c

     (subst (car up_r_c) (car lo_l_c) lo_l_c)

     up_r_c

     (subst (cadr up_r_c) (cadr lo_l_c) lo_l_c)

     "c"

     "line"

     pt1a

     pt2a

     ""

     "line"

     pt1b

     pt2b

     ""

     "line"

     pt1c

     pt2c

     ""

     "line"

     pt1d

     pt2d

     ""

     "line"

     pt1e

     pt2e

     ""

     "line"

     pt1g

     pt2g

     ""

     "line"

     pt1h

     pt2h

     ""

     "line"

     pt1i

     pt2i

     ""

     "line"

     pt1j

     pt2j

     ""

     "line"

     pt1k

     pt2k

     ""

     "line"

     pt1l

     pt2l

     ""

)

;;

;;

;; Calculates the horizontal grid lines and the intersections of

;; of the cam displacement graph with the grid, thus establishing the

;; location of the displacement graph.

;;

;;

(setq first_y_di

            (abs (-    (+ (* (cos (/ (* 30 pi) 180)) (/ fo_heigh 2))

                 (/ fo_heigh 2)

                )

                fo_heigh

             )

            )

     second_y_di

            (abs (-    (+ (* (cos (/ (* 60 pi) 180)) (/ fo_heigh 2))

                 (/ fo_heigh 2)

                )

                fo_heigh

             )

            )

     third_y_di    (/ fo_heigh 2)

     fourth_y_di

            (abs (-    (+ (* (cos (/ (* 120 pi) 180)) (/ fo_heigh 2))

                 (/ fo_heigh 2)

                )

                fo_heigh

             )

            )

     fifth_y_di

            (abs (-    (+ (* (cos (/ (* 150 pi) 180)) (/ fo_heigh 2))

                 (/ fo_heigh 2)

                )

                fo_heigh

             )

            )

     pt3a    (list (car lo_l_c)

             (setq fya (+ first_y_di (cadr lo_l_c)))

            )

     pt4a    (list (car up_r_c) fya)

     pt3b    (list (car lo_l_c)

             (setq fyb (+ second_y_di (cadr lo_l_c)))

            )

     pt4b    (list (car up_r_c) fyb)

     pt3c    (list (car lo_l_c)

             (setq fyc (+ third_y_di (cadr lo_l_c)))

            )

     pt4c    (list (car up_r_c) fyc)

     pt3d    (list (car lo_l_c)

             (setq fyd (+ fourth_y_di (cadr lo_l_c)))

            )

     pt4d    (list (car up_r_c) fyd)

     pt3e    (list (car lo_l_c)

             (setq fye (+ fifth_y_di (cadr lo_l_c)))

            )

     pt4e    (list (car up_r_c) fye)

)

;;

;;

;; Draws the horizontal lines and displacement diagram.

;;

;;

(command "line"

     pt3a

     pt4a

     ""

     "line"

     pt3b

     pt4b

     ""

     "line"

     pt3c

     pt4c

     ""

     "line"

     pt3d

     pt4d

     ""

     "line"

     pt3e

     pt4e

     ""

     "spline"

     lo_l_c

     (list (car pt1a) (cadr pt3a))

     (list (car pt1b) (cadr pt3b))

     (list (car pt1c) (cadr pt3c))

     (list (car pt1d) (cadr pt3d))

     (list (car pt1e) (cadr pt3e))

     (list (car pt1g) (cadr up_r_c))

     (list (car pt1h) (cadr pt3e))

     (list (car pt1i) (cadr pt3d))

     (list (car pt1j) (cadr pt3c))

     (list (car pt1k) (cadr pt3b))

     (list (car pt1l) (cadr pt3a))

     (list (car up_r_c) (cadr lo_l_c))

     ""

     ""

     ""

)

;;

;;

;; Prompts the user to select the location of the CAM profile.

;; Calculates the point defining the CAM profile. Draws the CAM

;; Profile.

;;

;;

(setq basepoint (getpoint "\nSelect location for cam profile : "))

(command

    "spline"

    (list (car basepoint) (+ (cadr basepoint) base))

    (list (- (car basepoint) (* (+ first_y_di base 0.05) 0.5))

     (+ (cadr basepoint)

         (* (+ first_y_di base 0.05) 0.866025403)

     )

    )

    (list (- (car basepoint)

         (* (+ second_y_di base 0.05) 0.866025403)

     )

     (+ (cadr basepoint) (* (+ second_y_di base 0.05) 0.5))

    )

    (list (- (car basepoint) (* (+ third_y_di base 0.05) 1))

     (+ (cadr basepoint) (* (+ third_y_di base 0.05) 0))

    )

    (list (- (car basepoint)

         (* (+ fourth_y_di base 0.05) 0.866025403)

     )

     (- (cadr basepoint) (* (+ fourth_y_di base 0.05) 0.5))

    )

    (list (- (car basepoint) (* (+ fifth_y_di base 0.05) 0.5))

     (- (cadr basepoint)

         (* (+ fifth_y_di base 0.05) 0.866025403)

     )

    )

    (list (car basepoint)

     (- (cadr basepoint) (+ fo_heigh base 0.05))

    )

    (list (+ (car basepoint) (* (+ fifth_y_di base 0.05) 0.5))

     (- (cadr basepoint)

         (* (+ fifth_y_di base 0.05) 0.866025403)

     )

    )

    (list (+ (car basepoint)

         (* (+ fourth_y_di base 0.05) 0.866025403)

     )

     (- (cadr basepoint) (* (+ fourth_y_di base 0.05) 0.5))

    )

    (list (+ (car basepoint) (* (+ third_y_di base 0.05) 1))

     (+ (cadr basepoint) (* (+ third_y_di base 0.05) 0))

    )

    (list (+ (car basepoint)

         (* (+ second_y_di base 0.05) 0.866025403)

     )

     (+ (cadr basepoint) (* (+ second_y_di base 0.05) 0.5))

    )

    (list (+ (car basepoint) (* (+ first_y_di base 0.05) 0.5))

     (+ (cadr basepoint)

         (* (+ first_y_di base 0.05) 0.866025403)

     )

    )

    (list (car basepoint) (+ (cadr basepoint) base))

    ""

    ""

    ""

    "circle"

    basepoint

    base

)

)

(princ "\nInsufficient Data Press enter to try again : ")

)

)

(princ "\nTo excute enter cam at the command prompt ")

(princ)

Resistance.lsp

;;;********************************************************************

;;;    Program Name: Resistance.lsp

;;;    Program Purpose: Calculate the voltage drop across two resistors

;;;            in a series, as well as the current for the cirrcuit.

;;;    Date: 1/13/99

;;;    Programmed By: James Kevin Standiford

;;;

;;;********************************************************************

;;;

;;;    Main Program

;;;

;;;********************************************************************

(DEFUN C:resistance (/         voltage     resistance_1

         resistance_2 equivalent     value_1

         value_2     current     name

         length_string name_truncated file_name

         )

;;;

;;; Obtain Information and Perform Calculations

;;;

(SETQ

file_name     (STRCAT (SUBSTR (GETVAR "dwgname")

                 1

                 (- (STRLEN (GETVAR "dwgname")) 4)

             )

             ".RLT"

         )

file     (open file_name "a")

voltage     (GETREAL "\nEnter voltage of circuit : ")

resistance_1 (GETREAL "\nEnter resistance of resistor #1 : ")

resistance_2 (GETREAL "\nEnter resistance of resistor #2 : ")

equivalent     (+ resistance_1 resistance_2)

current     (/ voltage equivalent)

value_1     (* current resistance_1)

value_2     (* current resistance_2)

)

;;;

;;; Print Information to Both a File and Screen

;;;

(PRINC

(PRINC (STRCAT "\nThe current drawn by this circuit is "

         (RTOS current)

     )

     file

)

)

(PRINC

(PRINC (STRCAT "\nThe equivalent resistance for this circuit is "

         (RTOS equivalent)

     )

     file

)

)

(PRINC

(PRINC (STRCAT "\nThe voltage drop across resistor #1 is "

         (RTOS value_1)

     )

     file

)

)

(PRINC

(PRINC (STRCAT "\nThe voltage drop across resistor #2 is "

         (RTOS value_2)

     )

     file

)

)

(close file)

(PRINC)

)

(princ)

(princ "\nEnter Resistance to start program ")

(princ)

Sunday, February 21, 2010

Modifying Extended Entity Data

Once the extended entity data has been retrieved using the ENTGET function, the programmer is free to modify any portion or all of the information using the list and association list functions previously discussed. At this point the extended entity data is treated just as the association list data was in Chapter Four. The dotted pair containing the old data is first obtained using the ASSOC function. Next, the new dotted pair is created using the CONS function and the two are switched using the SUBST function. Finally, the changes are recorded in the drawing database using the ENTMOD function. Using the extended entity data from the previous example the following expressions would be used to replace the dotted pair (1041 . 14.5) with the dotted pair (1041 . 0.0125).

Retrieving Extended Entity Data from an AutoCAD Object

When an object has been assigned extended entity data it cannot be accessed using traditional AutoCAD object listing or entity modifying commands (LIST, DDMODIFY, PROPERTIES, etc.). This alone ensures the developer that the information assigned to the object can not be tampered with by the user. The only way the information can be extracted once it has been assigned is with the use of the ENTGET function. Recall from Chapter Four that when this function is supplied with any entity's name it returns the definition data for the specified object. However, after a closer examination of the function's syntax one important aspect emerges. This function, when supplied with an application name in addition to the entity name, returns the entity definition along with the extended entity data that is associated with the specified application. For example, to obtain the extended entity data that was assigned to an object by the previous program, the following syntax would be used.

Command: (SETQ entity_data (ENTGET (CAR (ENTSEL)) '("EXAMPLE_1_EXTENDED_DATA"))) ~EnterKey~

Select object:

((-1 . <Entity name: 2770500>) (0 . "LINE") (5 . "20") (100 .

"AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDbLine") (10 2.19416 5.16515 0.0) (11 5.15258 2.37318 0.0) (210 0.0 0.0 1.0) (-3 ("EXAMPLE_1_EXTENDED_DATA" (1000 . "Imagine what can be saved to extended entity data") (1041 . 4.5) (1042 . 10.0))))

Command:

In order to retrieve the xdata assigned to each application associated with an object, all applications names must be supplied to the ENTGET function. To retrieve the extended entity data appended to an object's definition data by the application names applications EXAMPLE_1_EXTENDED_DATA and EXAMPLE_2_EXTENDED_DATA, the following syntax would be used.

Assigning Extended Entity Data to an AutoCAD Object.

Once the application name for the extended entity has been registered in the applications identification table, extended data may now be assigned to an AutoCAD object. This is usually accomplished by appending the extended data to the object definition data using one of the many list functions provided in AutoLISP. Then the entity data is updated in the AutoCAD drawing database using ENTMOD function and assigned the extended information. Before extended data can be appended to an existing entity, it must be contained within an association list that starts with the code –3 and is followed by the name of the application with which the data is associated. Extended data can only be assigned to existing AutoCAD objects. The entity must either already exist or be created before the extended data can be assigned. An object can be assigned multiple application names and extended entity data. The following program illustrates how extended data can be assigned to an AutoCAD object.


 

(DEFUN c:extended_entity_data ()

(SETQ select_entity (ENTGET (CAR (ENTSEL))))

; Gets the association list of

; definition data for the entity

; selected.

(REGAPP "EXAMPLE_1_EXTENDED_DATA"); Registers the application name

; EXAMPLE_1_EXTENDED_DATA

(SETQ    extend_data            ; Sets the variable extend_data

; equal

         '((-3

             ("EXAMPLE_1_EXTENDED_DATA"

                        ; to the new extended data, which

; is a text string and two

; scaleable values 1041 and

; 1042.

             (1000 . "Imagine what can be saved to extended entity data")

             (1041 . 4.5)

             (1042 . 10.0)

             )

             )            ; End of association list

            )            ; End of QUOTE function

    new_entity_def

         (APPEND select_entity extend_data)

)

                        ; Appends the extended entity data

; to the object definition data.

(ENTMOD new_entity_def)        ; Updates the entity defination in

; the AutoCAD database with the new

; definition data containing the

; extended entity data.

)

Registering an Application Name

Before AutoCAD will allow a developer to set extended entity data to an AutoCAD object, the application name in must first be registered in AutoCAD application identification or appid table. This table is used by AutoCAD to store the names of all the applications that have been registered in an AutoCAD drawing. To add an application name to the appid table, the REGAPP function (REGAPP application) must be used. This function, when supplied with the name of the application, first checks the appid table to determine if the application name is already in use. If the application name is not used then the function adds the name to the table and returns the name that was added. If the application name already exists, then the function returns nil. The nil in this particular case only means that the application name is already registered. This is illustrated in the following examples in which the application name "Visual_LISP" is registered.

Command: (REGAPP "Visual_LISP")

"VISUAL_LISP"

Command: (REGAPP "Visual_VLISP")

nil

Command:

In the first example the application name VISUAL_LISP is added to the appid table. In the second example the REGAPP function returns nil because the application name already exists in the appid table. Also notice in the first example that the application name returned by the REGAPP function is displayed as all upper case letters. When a name is supplied to the REGAPP function, all letters contained in that name are converted to upper case and are stored in the appid table as such. Application names are limited to 31 characters in length and can be made up of letters, numbers or a combination of the two. They can even contain special characters such as dollar signs ($), hyphens (-), and underscores (_), but they can not contain less-than and greater-than (<>), forward slash and backslash (/\), quotation marks ("), Question marks (?), colon (:), asterisks (*), vertical bars (|), commas (,), equal signs (=), backquotes (`) and semi-colon (;). Examples of valid and invalid application names are provided below.

Valid Application Names                Invalid Applications Names

VISUAL_LISP                    VISUAL*LISP

VISUAL_1_LISP                    VISUAL<>1_LISP

VISUAL$LISP                    VISUAL?LISP

$VISUAL_LISP                    VISUAL:LISP

$1$VISUAL_LISP                    VISUAL`LISP

$1-VISUAL_LISP                    VISUAL=LISP

Although the REGAPP function takes some precautions to ensure that an overlap of application names does not occur, there is a possibility that an overlap can happen. To guarantee that this does not occur, the AutoLISP TLBSEARCH function (TBLSEARCH table-name symbol [setnext]) can be used. This function, when supplied with the name of the table to search along with the symbol name to check for, returns either nil if the symbol is not present or an association list containing the symbol's name and table if the symbol exists. To check the application identification table to determine if the application VISUAL_1$_LISP-EXAMPLE has been registered, and if not register it, the following syntax would be used.

Attaching Extended Entity Data to an AutoCAD Object

Extended entity data is attached to an object's definition data using the DXF codes 1000 – 1071. Because of the limited range of these DXF codes and the fact that xdata can be set by any application, Autodesk has devised a method to keep this information is unique to a particular program. This reduces the possibility of information stored by one program affecting the data or even the operations of other applications. AutoCAD requires that all extended entity data be assigned an application name. That application name may only be used once in a drawing. This helps ensure that information assigned by more than one program to the same AutoCAD entity is unique as long as the application names used by these programs are different.

Using Extended Entity Data

Extended entity data is really nothing more than an extension of the objects regular entity data. By using the procedures and techniques previously discussed for handling and manipulating the association list of an AutoCAD entity along with a few specifically designed Xdata functions, extended entity data can be assigned, retrieved, modified, and even saved to an object with very little effort. Once the information has been saved to an object's definition, then it may be recalled at a later time, long after the initial drawing session has been terminated. This information remains attached to the entity until the information is either removed using a process similar to the way it was attached, or the entity is erased from the drawing. Extended entity data does have one major limitation; the amount of information that can be attached to an entity is limited to 16K bytes.

Introduction to Extended Entity Data

Chapters Three and Four introduced list manipulation and processing which is the true power of AutoLISP programming. Even though these capabilities have greatly extended the potential of AutoLISP programming, one down fall still exists concerning non-AutoCAD entity information. Unless the information is either assigned to an AutoCAD attribute or saved in an external file, the program is unable to recall any of the information once the current drawing session has been terminated. This limits the applications where these theories can be used. For example, if the resistance program illustrated in Chapter Four used attributes contained within blocks to store information concerning the resistance and voltage drop for each resistor, then extreme care would have to be taken to insure that these blocks are not exploded. If one or more of the blocks were exploded, then this would result in the program ignoring the values that were assigned to those entities thereby increasing the voltage drop for the remaining resistors. If this were to happen and the situation were to go unnoticed, then the results obtained from running the program would produce a situation in which the actual circuit could fail. Therefore the programmer is forced to rely on constructing a program that would either prevent the user from exploding the attributed blocks or one that warns the user of the potential danger involved if this process is continued. On the other hand if the program had saved the information to an external file, then a similar situation could result if the file were deleted. AutoLISP provides two possible solutions to this problem. They are Extended Entity Data (or Xdata as it is sometimes referred to) and Xrecord. While both methods are similar in concept and application each method has its advantages and disadvantages. The programmer should be well versed in the use of both of these methods. The intent of these methods is to provide the programmer with a means of storing and managing information in an object's association list using DXF codes. Attached information can be relevant or non-relevant to the particular entity.

Thursday, February 18, 2010

Introduction to List and List Processing

One of the many attributes that makes Common LISP an excellent candidate for artificial intelligence and the perfect model for AutoLISP is its ability to store large amounts of data in the form of a list. A list is nothing more than a collection of data that is either related or non-related to a particular entity or event. For example, a list describing the characteristics of a line could include the Entity Name, Entity Type, Entity Handle, Entity Color, Layer, Starting Point, and Ending Point. A list can also consist of a set of instructions or commands describing a particular sequence of events. For example, a list containing the steps for determining the area of a circle given only its diameter would be:

  1. Calculate the radius of the circle by dividing its diameter by two.
  2. Square the radius and multiplying the result by 3.14, (producing the area of the circle).

In most cases, lists provide an efficient as well as practical way of storing information over the traditional method of using variables (variables are only able to store a single item known as an atom). This is especially true if the information used by a program varies from execution to execution. For example, to write a program that would find the equivalent resistance of a series circuit and calculate the voltage drop for each resistor at first seems like an easy task to accomplish. First, add up the resistance of all the resistors in the circuit to find the equivalent resistance. Next, divide the total voltage supplied to the circuit by the equivalent resistance, producing the current supplied to the circuit. Finally, the voltage drop for each resistor can be found by multiplying the current by the resistance of the individual resistor. However, there is one small problem, the number of resistors could vary from circuit to circuit making it extremely difficult if not impossible to create a generic program using variables. An alternative is to construct a list containing values assigned to each resistor and then setting that list equal to a single variable. Not only does this solve the problem of the variant amount of information entered into the program, but also reduces the number variables used in the program and the amount of code required to create the program. A list can also contain other lists (this is often referred to as a sub-list). Each entry in a list is referred to as an Element. For example, the list (apple orange peach) contains the elements apple, orange and peach. In AutoLISP a list will always start with an opening parenthesis and end with a closing parenthesis.

Lists in AutoCAD

When information is requested from AutoCAD, that information is returned in the form of a list. This can be illustrated using the GETPOINT function. Recall from Chapter Two that the GETPOINT function prompts the user to either select or enter a point. The result returned by this function is in the form of a list (7.4366 6.16185 3.80986) regardless of whether or not the user entered the information from the keyboard or selected a point from the graphics screen.

Creating a List

In AutoLISP a list can be generated using either the LIST function (LIST [expr...]) or by placing the elements of the list inside an opening and closing parenthesis preceded by a single quote '(4 5 6). The LIST function, when supplied with one or more arguments (either expressions and/or non-expressions) returns a list. For example, to create a list containing coordinates 5, 4, 3 the following syntax would be used.

(SETQ point (LIST 5 4 3))            ;The expression returns (5 4 3).

Once a list containing coordinate information has been created and its value set to a variable, then it may be used with any of the AutoCAD commands where point information is required. For example, to construct a line starting at the coordinates supplied in the previous example, the variable name preceded by an exclamation point would by entered at the "from point" LINE prompt. This would extract the information held by the variable and return it to the LINE command.

Command: LINE ~EnterKey~

Specify first point: !point ~EnterKey~

(5 4 3)

Specify next point or [Undo]:

Other examples of lists created using the LIST function include:

  1. (SETQ list_example (LIST "A" "B" "C"))
  2. (SETQ list_example (LIST 0.5 10 "ORANGE" "GRAPE"))
  3. (SETQ list_example (LIST '(SETQ d 5) '(SETQ f 7)))
  4. In this example a list is created containing the strings A, B and C and set to the variable list_example.
  5. In this example a list is created containing the real number 0.5, the integer 10 and the strings orange and grape.
  6. In this example a list is constructed containing AutoLISP expressions. In order for a list to contain actual expression and not their evaluated results, a single quotation mark must precede the list. The single quotation mark tells AutoLISP to return the expression without evaluating it.

Combining two or More Lists into a Single List

Although the LIST function can be use to combine two of more lists into a single list, this function has one major disadvantage for using it in this capacity. Each list that is supplied to the function becomes elements of the newly created list. For example, using the LIST function to combine the lists (5.5 4.3 2.3) and (44.7 39.6 12.4) would yield the list ((5.5 4.3 2.3) (44.7 39.6 12.4)). This is illustrated in the following example.


 

(SETQ list1 (LIST 5.5 4.3 2.3))    ;Creates a new list setting it to the variable ;list1.

(5.5 4.3 2.3)    ;Result returned from the previous ;expression.

(SETQ list2 (LIST 44.7 39.6 12.4))    ;Creates a new list setting it to the variable ;list2.

(44.7 39.6 12.4)     ;Result returned from the previous ;expression.

(SETQ list3 (LIST list1 list2))    ;Combines list1 and list2 into a single list ;setting it to the variable list3.

((5.5 4.3 2.3) (44.7 39.6 12.4))    ;Result returned from the previous ;expression.

As illustrated in the above example, the lists themselves become entities that are considered as single elements in the newly formed list. In some cases this result may be desirable. In those instances where this result is not acceptable, another method must be employed. In cases where the elements of the individual list are needed to create a new list, then the APPEND function, must be used. The APPEND function (APPEND list …), extracts the elements from each individual list supplied and returns a single list. For example, by supplying the lists from the previous example as arguments to the APPEND function the result (5.5 4.3 2.3 44.7 39.6 12.4) would be returned. This is illustrated in the following example.

(SETQ list1 (LIST 5.5 4.3 2.3))    ;Creates a new list setting it to the variable ;list1.

(5.5 4.3 2.3)    ;Result returned from the previous ;expression.

(SETQ list2 (LIST 44.7 39.6 12.4))    ;Creates a new list setting it to the variable ;list2.

(44.7 39.6 12.4)     ;Result returned from the previous ;expression.

(SETQ list3 (APPEND list1 list2))    ;Combines both list1 and list2 into a single ;list setting it to the variable list3.

(5.5 4.3 2.3 44.7 39.6 12.4)    ;Result returned from the previous ;expression.

Determining if an item is a List

From time to time it becomes necessary to determine if the item that is currently set to a variable or the information that is passed to a program is in the form of a list. AutoLISP currently supplies two functions for this purpose, the LISTP function and the TYPE function. While the syntax for both functions are identical, ((LISTP item) and (TYPE item)) the result returned by these functions are different. The LISTP function when supplied with an item returns either T (if the item is a list) or nil (if the item is not a list). The TYPE function returns the actual data type. Therefore, this function has a wider range of applications that it can be used for. It is not limited to only identifying lists. In the following example, both the LISTP and the TYPE functions are used to check a variety of data types.

(LISTP 3.4)    ;Tests the item 3.4 to determine if the item

; is a list.

nil    ;The item is a real number and the value

; returned by this function is nil.

(LISTP 3)    ;Tests the item 3 to determine if the item

; is a list.

nil    ;The item is an integer and the value

; returned by this function is nil.

(LISTP "Text String")    ;Tests the item "Text String" to determine

; if the item is a list.

nil    ;The item is a string and the value

; returned by this function is nil.

(LISTP (LIST "apple" "orange" "grape"))    ;Test the result supplied by the LIST

; function. Because the LIST function is

; used to create a list, the result returned by

; this function is T.

(TYPE 3.4)    ;Tests the item 3.4 to determine its data

; type.

REAL    ;The result returned by the previous test

; indicates that the item is a real number.

(TYPE 3)                        ;Tests the item 3 to determine its data                                

; type.

INT    ;The result returned by the previous test

; indicates that the item is an integer.

(TYPE "Text String")    ;Tests the item "Text String" to determine

; its data type.

STR    ;The result returned by the previous test

; indicates that the item is a string.

(TYPE (LIST "apple" "orange" "grape"))    ;Tests the result supplied by the LIST

; function.

LIST    ;Because the LIST function is used to create

; a list, the result returned by this function is

; a list.

Retrieving Information from a List

As mentioned earlier, the individual entries in a list are known as Elements. An element can either be a string, a real number, an integer, another list, an expression (single quoted), or any combination. So how are the elements of a list extracted? By either using one or a combination of two or more of the five basic list retrieval functions. These functions are CAR, CDR, CADR, CADDR and NTH. Although, the syntax for the CXXXX functions is the same, (CXXXX list), their output are different. The CAR function returns the first element of a list, while the CDR function creates a list starting with the second element. For example, supplying the list (4.002 3.45 5.7) to both the CAR and CDR functions return the following results.

(SETQ list_example (LIST 4.002 3.45    5.7))

; Creates a list, and sets it to the variable

; list_example.

(CAR list_example)    ;Returns the first element of the list.

4.002                            ;Returned value.

(CDR list_example)    ;Creates a new list starting with the second ;element.

(3.45 5.7)    ;New list created from the CDR function.

The CADR function combines the capabilities of the CAR and CDR functions. It returns only the second element of a supplied list. To illustrate this, the following example uses the list created in the previous example to compare the results returned by the CADR function and an expression containing both the CAR and CDR functions.

(CAR (CDR list_example))    ; The CDR function creates a new list

; starting with the second element and

; returning that list to the CAR function.

; The CAR function then returns the first

; element of the list supplied by the CDR

; function.

3.45    ; Returned value.

(CADR list_example)    ; The CADR function returns only the

; second element of the supplied list.

3.45    ; Returned value.

Although both the CADR and the combination CAR/CDR functions return the same value, the CADR function provides a shorter route to obtaining the same results. If only the second element of a list is required, then the CADR function not only saves valuable time and the possibility of making a mistake, it could also reduce the overall size of the program, resulting in a program that loads and runs faster.

The last of the CXXXX functions is the CADDR function. This function returns the third element of a list. It could be compared to using the CDR function twice, followed by the CAR function or the CDR function followed by the CADR function. Again, the advantage of using this function in place of any of the combinations reduces the possibility of making a mistake, as well as shortens the length of the program. This is illustrated in the following example, where both the CADDR function and the two combinations are supplied with the list from the previous two examples.

(CADDR list_example)    ;The CADDR function returns only the third element ; of a list.

5.7    ; Returned value.

(CADR (CDR list_example))    ;The CDR function creates a new list starting with

; the second element and returns that list to the

; CADR function. The CADR function then returns

; the second element of the list supplied by the CDR

; function.

5.7    ; Returned value.

(CAR (CDR (CDR list_example)))     ;The first CDR function creates a new list starting

; with the second element and returns that list to the

; next CDR function in the expression. This CDR

; function then creates another list starting from the

; second element supplied to it from the previous

; CDR function. The list is then passed on to the

; CAR function where the first element is returned.

5.7    ; Returned value.

An alternative to using the CXXXX functions is the NTH function (NTH number list). This function, when supplied with a list, returns the element specified by the programmer. The programmer specifies which element is to be returned by entering the integer value representing the position of the element in the supplied list. The elements are numbered starting with zero and continuing in the positive direction. For example using the list provided in the previous example, the third element is extracted as follows.

(NTH 2 list_example)                ;The NTH function returns an elements specified by

; the programmer. In this example the programmer

; has specified the third element. The first element is

; considered to be located at the zero position while

; the third element is considered to be at the second

; position.

5.7                        ; Returned value.

Retrieving Information from a List

As mentioned earlier, the individual entries in a list are known as Elements. An element can either be a string, a real number, an integer, another list, an expression (single quoted), or any combination. So how are the elements of a list extracted? By either using one or a combination of two or more of the five basic list retrieval functions. These functions are CAR, CDR, CADR, CADDR and NTH. Although, the syntax for the CXXXX functions is the same, (CXXXX list), their output are different. The CAR function returns the first element of a list, while the CDR function creates a list starting with the second element. For example, supplying the list (4.002 3.45 5.7) to both the CAR and CDR functions return the following results.

(SETQ list_example (LIST 4.002 3.45    5.7))

; Creates a list, and sets it to the variable

; list_example.

(CAR list_example)    ;Returns the first element of the list.

4.002                            ;Returned value.

(CDR list_example)    ;Creates a new list starting with the second ;element.

(3.45 5.7)    ;New list created from the CDR function.

The CADR function combines the capabilities of the CAR and CDR functions. It returns only the second element of a supplied list. To illustrate this, the following example uses the list created in the previous example to compare the results returned by the CADR function and an expression containing both the CAR and CDR functions.

(CAR (CDR list_example))    ; The CDR function creates a new list

; starting with the second element and

; returning that list to the CAR function.

; The CAR function then returns the first

; element of the list supplied by the CDR

; function.

3.45    ; Returned value.

(CADR list_example)    ; The CADR function returns only the

; second element of the supplied list.

3.45    ; Returned value.

Although both the CADR and the combination CAR/CDR functions return the same value, the CADR function provides a shorter route to obtaining the same results. If only the second element of a list is required, then the CADR function not only saves valuable time and the possibility of making a mistake, it could also reduce the overall size of the program, resulting in a program that loads and runs faster.

The last of the CXXXX functions is the CADDR function. This function returns the third element of a list. It could be compared to using the CDR function twice, followed by the CAR function or the CDR function followed by the CADR function. Again, the advantage of using this function in place of any of the combinations reduces the possibility of making a mistake, as well as shortens the length of the program. This is illustrated in the following example, where both the CADDR function and the two combinations are supplied with the list from the previous two examples.

(CADDR list_example)    ;The CADDR function returns only the third element ; of a list.

5.7    ; Returned value.

(CADR (CDR list_example))    ;The CDR function creates a new list starting with

; the second element and returns that list to the

; CADR function. The CADR function then returns

; the second element of the list supplied by the CDR

; function.

5.7    ; Returned value.

(CAR (CDR (CDR list_example)))     ;The first CDR function creates a new list starting

; with the second element and returns that list to the

; next CDR function in the expression. This CDR

; function then creates another list starting from the

; second element supplied to it from the previous

; CDR function. The list is then passed on to the

; CAR function where the first element is returned.

5.7    ; Returned value.

An alternative to using the CXXXX functions is the NTH function (NTH number list). This function, when supplied with a list, returns the element specified by the programmer. The programmer specifies which element is to be returned by entering the integer value representing the position of the element in the supplied list. The elements are numbered starting with zero and continuing in the positive direction. For example using the list provided in the previous example, the third element is extracted as follows.

(NTH 2 list_example)                ;The NTH function returns an elements specified by

; the programmer. In this example the programmer

; has specified the third element. The first element is

; considered to be located at the zero position while

; the third element is considered to be at the second

; position.

5.7                        ; Returned value.