LISP Developer Guide

This guide provides the information about secondary development with AutoLISP or ActiveX objects in ZWCAD, it contains the following topics:

  • AutoLISP Introduction

    This chapter mainly introduces AutoLISP's origin, current status, prospects, language's features and functions.

  • LISP Language Programming's Basis

    This chapter mainly introduces LISP programming's basis, the methods and skills of debugging and running LISP programs.

  • Library Functions Introduction

    This chapter introduces more than 230 library functions provided by the ZWCAD through their functionality sort, the functions of the higher frequency will be introduced by detailed examples of code presentation.

  • Working with ActiveX Objects

    This chapter mainly introduces the advantages of using ActiveX object to develop the program, ZWCAD object model and how to interact with other applications that support ActiveX etc.

  • Appendixes

    This chapter classifies more than 300 library functions (including ActiveX functions) provided by ZWCAD through their functions with a list form, and gives a brief introduction for each function on its calling formats and the main functions.


Version Overview

Version Overview

The new version of LISP enhances and improves the quality of original interfaces to some extent compared for previous version, especially in part of Curve Measurement Functions. At the same time, it adds operator function and authorization function. And we have to tell you that some unusual interfaces have not been implemented yet currently. Please refer to the next chapter contents of the updated version for detail.


AutoLISP Introduction

Before learning AutoLISP, we should know its past, present and future. This section will give brief introduction about AutoLISP in the following three topics.

  • AutoLISP's origin and current status
  • AutoLISP's features
  • AutoLISP programming's functions


AutoLISP's Origin and Current Status

AutoLISP is a subset in the LISP (List Processing Language). Since AutoCAD used LISP in the computer aided design area at the end of last century, the name AutoLISP was born in. Beside FORTRAN and COBOL, most of the programming languages which came from early sixties of last century aren't popular, however, LISP is still existing and has been as the first chosen programming language in artificial intelligence area.

At present, AutoLISP has been as a kind of computer aided design secondary development programming language which is wide applied in engineering industry, manufacturing area, costume design area, and education area etc. There are tens of thousands of the third developers using AutoLISP to develop various applications.

Although ZWCAD provides the more powerful secondary development interface, like ZDS and ZRX, which based on C/C++, users need to have deeply professional computer knowledge and abundant developing experience if they want to develop professional application with these interfaces quite proficiently. Since the common users are very difficult to master these programming methods well, AutoLISP is still the first selection for the designer.


AutoLISP's Feature

AutoLISP's Features

AutoLISP language and ZWCAD environment are dissolved as a whole, users can use AutoLISP expressions at all times, they get interpreted and then executed, so if any of the expressions are entered, they could be executed immediately. It is very convenient for the interactive program development.

AutoLISP language is easy to learn and use, even you haven't learned any of programming languages, you could also master it and use it in daily work soon. AutoLISP language has the following features:

  • Simple syntax

    • AutoLISP is one kind of programming language with weak data type, which does not need to declare the variable specially. The AutoLISP interpreter provided by ZWCAD determines variable's data type automatically according to its value;

    Its syntax rules are very single.

  • Strong library functions

    • AutoLISP provides a number of performance functions, many of which can directly control ZWCAD, and AutoLISP can directly invoke and execute all ZWCAD inner commands, and can manipulate all ZWCAD system variables. It could be said that the key of learning AutoLISP programming is learning these library functions.

  • Development environment is not critical

    • Just the common text editor application can be used to develop AutoLISP programs, such as notepad, wordpad, UltraEdit etc.

  • Strong portability

    • The application developed with AutoLISP in the old version of ZWCAD can be loaded and executed in the new version of ZWCAD without any correction; even after being corrected briefly, the AutoLISP programs which are developed in other CAD application can be loaded and executed correctly in ZWCAD.

Of course, AutoLISP also has some drawbacks. Since it is the subset of LISP programming language, it inherits LISP programming language's syntax rules that is you need to write too many brackets in AutoLISP expressions. It brings some inconvenience to the users when they write or read AutoLISP programs, so "LISP" is often interpreted as "Lost of Insipid Stupid Parenthesis". However, if you pay attention to lay out codes formats during development process (such as using indentation or blank lines), the impact of so many brackets can be reduced to the lowest.


AutoLISP Programming's Functions

ZWCAD as a common computer aided design application provides various commands to draw graphics but doesn't provides some other commands such as the command for drawing column gear. You may use AutoLISP to develop parametric design application to draw column gear, which would improve your work efficiency greatly. Actually, developing application with AutoLISP may achieve the following functions:

  • Extend ZWCAD inner commands
  • Create more practical new ZWCAD commands
  • Reduce the complicated environment setting steps or drawing steps
  • Parametric graphics design
  • ASCII file reading and writing (such as reading or writing the configuration files)

However, AutoLISP is not almighty. When you want the application program has the following functions, please don't select AutoLISP:

  • Reading or writing binary file
  • Invoking operation system's interface
  • Access hardware device directly
  • Advanced user interface (such as customize entity)


LISP Language Programming's Basis

This chapter will mainly introduce the basic knowledge of AutoLISP programming. As the mention in "AutoLISP's features", learning AutoLISP programming primarily means to learn its basic syntax and how to use library functions. So this chapter is quite important. This chapter contains the following contents:

  • Expressions and Syntax

    • This section mainly introduces AutoLISP expressions' syntax rules, AutoLISP expression block, and how to use AutoLISP in ZWCAD command bar.

  • AutoLISP Variable

    • This section mainly introduces variable's naming rules, how to assign value to variable, how to view variable's value, and how to release the memory space of the variable, AutoLISP pre-defined variable.

  • LISP Datatype

    • This section mainly introduces how to view the datatype of the variable or constant and the notes of using various datatype (integer, real, string, ename, list, pickset, VLA object, variant and file descriptor).

  • Basic Output

    • This section mainly introduces how to display information in ZWCAD command bar, how to shield echo information in command bar after function calling, and how to output control characters.

  • Custom Function and Command

    • This section mainly introduces how to create custom functions, how to create custom commands, how to re-define ZWCAD inner commands, the differences between local variable and global variable, and how to use the unnamed function.

  • Programs' Session Controlling

    • This section mainly introduces three kinds of program session controlling structure: sequence, branch and loop.

  • AutoLISP Codes Files

    • This section mainly introduces the format of AutoLISP source codes and the comments.

  • Load and Run AutoLISP program

    • This section mainly introduces how to load AutoLISP file manually in the ZWCAD, how to load AutoLISP file automatically, and how to run AutoLISP program.

  • Debugging Skill

    • This section mainly introduces the skills of debugging AutoLISP program in ZWCAD.

  • Release LISP Program

    • This section introduces how to encrypt LISP program.


Expressions and Syntax

AutoLISP expression syntax rules

Expression is the basic unit in AutoLISP program, each of the AutoLISP expression must match to the following format:

(function name paremter1 parameter2 …)

1.Expression must contains parentheses, and the left and right side must be in pairs.

2. Function name and parameter must be divided into single or multiple spaces. No blank space is permitted between the Function name/parameter and their parentheses.

3. Function name can be AutoLISP library function or user customize function/command.

4. Parameter1, parameter2 operand can be Variable or AutoLISP expression. Please refer to below:

(function1 (function2 parameter1) (function3 parameter2))

If you enter the code in the ZWCAD command line, ZWCAD AutoLISP Analysis would implement the code by the following method:

Enter the AutoLISP expression in the ZWCAD command line (command:) can be directly evaluated, please refer to below:

Command: (+ 3.1 5.4)　　　　　　　　　　　　;;;returns the sum: 8.50000
Command: (* 3.14 (+ 2.1 3.5))　　　　　　　　;;;add first, then multiply, returns the result: 17.5840

AutoLISP expression block

The capability of the single expression is limited in the program design, for example, in the "if" branch sentence (It will be introduced in the "Program process control" theme in this chapter), "Yes expression" or "No expression" is not the single AutoLISP expression in some situations. At this time, you can use progn function to build a function block for these functions, this is same as the C/C++ which uses left brace ({) and right brace (}) to build the sentence block. Please refer to the following function syntax:

(progn expression1 [expression2] [expression3]…)

Expression block returns the last value of the expression.

Use AutoLISP expression in the ZWCAD command line

We can find that it is quite difficult to match with the left and right parentheses in pairs correctly from above embedded expression. After entering the AutoLISP expression in the ZWCAD command line, the parentheses would be checked whether appear in pairs or not. For example, enter the following code in the ZWCAD command line:

command: (+ 3.14 (* 2.1 3.5)　　　　　　　　　　;;;lack one right bracket

command line will prompt as below:

Missing: 1) >

This prompt message expresses that how many layers of the right parentheses are not exposed. If this prompt appear, users should enter all the required amounts of right parentheses to evaluate the expression. Please refer to below:

Missing: 1) >)

The common reason why these kind of errors happen is that the right Double Quotes(") in the text string is ignored. In this situation, the right parenthesis is identified as a part of the string that cannot match to the corresponding left parenthesis. When this kind of errors happen, we suggest that you should not only enter the required right parentheses to finish the evaluation of the expression but click on the ESC to cancel the expression and re-enter the correct expression.


AutoLISP Variable

In computer, the variable often refers to the store data in the memory address, and only if the variable name must obey the naming rules exactly, the name can be recognized by the computer. This chapter mainly introduces variable naming rule, variable value assignment, displaying variable value, releasing variable's memory space, predefined variable.

Variable naming rules

AutoLISP Variable is a kind of string which is customized by users and used to quote data in the LISP program, for example, str1, radius are both the AutoLISP Variable.

AutoLISP quotes data through the symbol or variable. Symbol name is not case sensitive, it can be composed by the letters, numbers, special characters (except for ( (left parenthesis), ) (right parenthesis), .(period), '(single quotes), "(double quotes) and ;(semicolon)) and the symbol and variable name cannot be only composed by the digit characters.

For example, the following sample code uses setq function to assign the string "Hello, ZWCAD" to str1:

command: (setq str1 "Hello, ZWCAD!")
"Hello, ZWCAD!"

In order to facilitate yourself and others who need to read your code, please try your best to set the AutoLISP Variable name clearly so that the reader could understand significance through the name easily. We suggest that the symbol or the variable name should not exceed 8 characters for the program implementing efficiency.

Although ZWCAD allows users to use the same name for customize the variable and AutoLISP keyword (Predefined variables or built-in functions), it is not a fine program habit. Since some other applications also will depend on these AutoLISP keyword, we suggest that users should avoid to use the same name for customize variable name and the AutoLISP keyword.

Variable value assignment

AutoLISP variable value type is depended on the assignment value type. Before assigning a new value to the variable, the variable always remains the original value. You may use setq function to assign the value for variable.

(setq variable1 value1 [variable2 value2 …])

Setq function assigns the specified value to the variable which has the specified name and return this value as the function result. If using the setq function in ZWCAD command line, the function result would be displayed in the command line.

command: (setq radius 3.2 color "red")
"red"

Display variable value

If you want to display the variable current value when you using the AutoLISP to program, you only need the enter ! (Exclamatory mark) in the ZWCAD command line, please refer to below:

command: !radius
3.20000

Nil Variable

Nil is a AutoLISP variable which has not the specified value.

Since each variable occupies some memory, we should keep a good program habit that re-using the variable name or setting the redundant variable name as nil. Setting the variable as nil that can release the memory space which is used to store this variable:

command: (setq radius nil)
nil

Predefined variable

The following predefined variables can be common in the AutoLISP application:

Variable name | Significance
PAUSE | Define as a string which is composed by double Backslash (\\). This variable and command function are both used to pause the running command and wait for users' input.
PI | Symbol constant, the value nearly equals to 3.14159 (Pi)
T | Symbol constant, for non-nil value


LISP Datatype

LISP provides type function which is used to view variable and constant value type, please refer to below:

command: (type "ZWCAD") 　　　　　　　　;;;returns the data type of the string constant "ZWCAD": STR

Below is the introduction for all the kinds of the available LISP data type respectively.

Integer (INT)

Integer is the number without decimal. For example, 0,1, -512 and 9597 are all the integer. Integer in AutoLISP is 32 bit number with symbol, which in the range of -2,147,483,648 to +2,147,483,647. When a function overflows data, it can be converted to the opposite symbol, for example, -2,147,483,649 would be changed to 2,147,483,647. This phenomenon is called Loop rotation. If you add -2,147,483,649 to -1, you would get the result +2,147,483,647. Please refer to the below:

Real (REAL)

Real is the number with decimal (also be called "Float"). Although the LISP can display 6 bit decimal at most, the Real number still have 14 bit such as 2.0000000000000. The reason is that Real number is stored as double accuracy float format. You can find that the large number or the small number will be showed up in scientific notation such as 3.44861E-07 (namely 0.000000344861). The real number between -1 and 1 must be marked a prefix zero such as 0.9, 0.0 or -0.1, it cannot be showed up as .9, .0 or -.1, otherwise there are some errors appeared in ZWCAD.

String (STR)

String is character combination with English format double quotes such as "VPORT" or "Please type your name". ZWCAD supports the longest character is 132 bit. "" is called blank string.

When using the control characters, you must put the backlash in front of the characters. For example, \n is the newline prompt. You must use \" to display the quotation mark on the string, for example, "The screw is 1\" long.". You also can use "\dd" to express the string, ddd is the corresponding characters Octal ASCII code, for example, you can use "\101\141" to express string "Aa" .

Entity Name (ENAME)

Entity name is a non-character hex tab such as <Entity name: 6130ad0>. In order to distinguish the ActiveX object, it is also called AutoLISP Entity Name. Actually, it is a pointer which points to the ZWCAD Maintenance file. In LISP, you need not operate the real entity and just need to find the entity name and operate the entity name.

The specified object entity name in the drawing is efficient only in the current editable task, ZWCAD will re-assign the entity name for objects when opening the drawing next time. Since the object handle is fixed when opening the drawing every time, users could use object handle to quote the entity name in the editable task.

List (LIST)

List is a group of related values which are divided by the blank space, it provides some efficient methods about storing large amount of correlation values and is also called association table. Each legitimate form of LISP expression is list. For example, (1 2 3), (* pi 2), (cen rad) and ("The answer is : " ANS). A table composed of two numbers are usually used as a two-dimensional point X, Y coordinates such as (1.0 2.0); The number of the table consisting of three numbers are commonly used three-dimensional point X, Y, Z coordinates such as (10.0 11.0 12.0). A special table named Dotted Pair is used to describe the entity data and it is composed of two related values which is divided into the English Period. Before and after the Period, there are one or more blank spaces existing respectively such as (62 . 1). Dotted Pair is similar with the DXF code (not completely the same). For example, (62 . 1) expresses the entity color, (troop code 62) is red and (red,1 means the Color index value).

Pickset (PICKSET)

Pickset is composed of one or more entities, for example, the <Selection set: 125917216>. Users can add the object to the pickset interactively through the AutoLISP function or delete it from the pickset. Since pickset could consume temporary file storage area in ZWCAD, AutoLISP does not permit the users to open the picksets more than 128.

VLA Object (VLA-OBJECT)

The object in drawing can be expressed Visual LISP ActiveX (VLA) object such as <VLA-OBJECT IZCADLine 782e468>, this is a kind of data type in Visual LISP. When using the ActiveX function, users must quote the VLA object but not the AutoLISP entity.

Variant (VARIANT)

Variant is a flexible data type, which can store any type of data. Generally speaking, users don't use the variant variable because there are some potential running errors existing and the code is not clear when using the variant. If you want to invoke the methods of some ActiveX object in the interaction application, you must transfer the variant variable so that the variant data type can be used. Once the variant variable has been assigned value, it would have the real data type.

File Description Symbol (FILE)

File description symbol is the hex tab which points to the opened file in LISP such as <File: #785B7408>. It is similar with the entity data that you only need to operate the file description symbol but not quote the file name directly. LISP can open a file to implement reading, writing and appending, and it will hold on the open status until you close the file in AutoLISP program explicitly.


Basic Output

AutoLISP provides four basic output functions, they are prin1, princ, print, prompt. These four basic output functions can display the prompt information in graphics window or the text window and are necessary for debugging and interaction.
Furthermore, prin1, princ and print functions can write the information to the opened ASCII file. This will be not introduced in this chapter, please refer to the theme "File transaction function" in the third chapter "AutoLISP library function classification introduction" for detail.

Display information

prompt function displays information (one string) in the ZWCAD command window and return nil.

princ, prin1 and print functions all display the expression result (not necessarily a string) in the ZWCAD command window. The differences between these functions as follows:

  • princ analyzes the control character in the string and displays the string without the double quotes.
  • prin1 does not analyze the control character and just displays the string in original style with the double quotes.
  • print does not analyze the control character and just displays the string in original style with double quotes and a space followed.

The following sample codes show up the differences among these four kinds of basic output functions by the same string.

command: (setq string "The \"Max\" diameter is \24612.5.")　　　　　　 　　;;;sets variable
"The \"Max\" diameter is Φ2.5."

command: (prompt string)
The "Max" diameter is Φ2.5.nil　　　　　　　　　　　　　　　　 　　　　 ;;;prints string without quotation marks and returns nill

command: (princ string)
The "Max" diameter is Φ2.5."The \"Max\" diameter is Φ2.5."　　　　　　 　 ;;;prints string without quotation marks and returns the string

command: (prin1 string)
"The \"Max\" diameter is Φ2.5.""The \"Max\" diameter is Φ2.5."　　　　　　 ;;;prints string with quotation marks and returns the string

command: (print string)
"The \"Max\" diameter is Φ2.5."<space>"The \"Max\" diameter is Φ2.5."　　　 ;;;prints string with quotation marks and returns the string

Exiting Quietly

If you do not take a expression or string for a princ function when invoking it, this function would not display any contents and return any values.

Therefore, in order to prevent the command displaying the last expression value, it always invokes the princ function without transferred parameter when customizing the functions. This is called exiting quietly.

Control character in the string

The backlash (|) in the double quotes of the string make the string contain control characters (or Octal transition code), the following chart lists the control characters which can be identified by the AutoLISP currently:

Expression | Return value
\\ | \ character
\" | "character
\n | newline
\r | enter
\t | tab character
\nnn | Octal ASCII nnn character

If you want to use backlash (|) or quote (') in the string which is contained by double quotes, you must add the backlash before the string. For example, if you enter the following LISP code in ZWCAD command line:

command: (princ "The \"license\" is out of date(2023\\10\\20)")
The "license" is out of date(2023\10\20).

If you want to implement a strong force line break in the specific location of the string, you can use the newline character (\n), please refer to the below code to realize the usage:

command: (prompt "Sorry!\nZWCAD hasn't been installed.")
Sorry!
ZWCAD hasn't been installed.

Enter (|n) action would return the head line of the current editable line and cover the string which is displayed on the line last time (it is similar with the Rewrite function in the MS Word). It is very useful for displaying the Incremental Information, for example, the counter which is used to display the amount of the transaction object.

Tab character (\t) can make the string in alignment by the indent method or replacing the Tab-text string. The following sample code shows up the usage of the Tab-text string:

command: (princ "Aaa\tBbb\tCcc\nDdd\tEee\tFff\nGgg\tHhh\tKkk") (princ)
Aaa Bbb Ccc
Ddd Eee Fff
Ggg Hhh Kkk


Customize Function and Command

Function is structured programming function module. Appropriately using the function that can make the program's logic is more clear and improve the code reusability.

When you using the LISP complex and diverse programming function, you can generate the customize solution or extend the CAD function in ZWCAD or integrate the other application in your drawings and do the automation task. Using the LISP, you can adapt any of the advanced and highly efficient extension program in the special area/profession/industry to enhance your CAD platform.

Customize function

In the LISP program, users can use the defun function to define the function. The format is as below:

(defun [c:] function-name ([param1] [param2]… / [local var1] [local var2]…) expr1 [expr2]…)

The string followed the defun function is the function name, and the string in the parentheses after the function name is the parameter table which is divided into two parts: left the "/" means the function parameter, right to the "/" means the local variable defined by function (Please refer to the below contents to learn the local variable and global variable). This parameter table can be blank (Whether or not to provide parameter or local variable, parentheses are not omitted). Below the parameter table are the expressions which can compose of the functions, and defined function should contain one expression at least. The following sample code is a basic definition of function, this function does not accept any parameters and only display "Hello ZWCAD" in the ZWCAD command line:

command: (defun welcome ()(princ "\nHello, ZWCAD!")(princ))
WELCOME

The following sample code demonstrates that how to invoke the customize function without parameters in ZWCAD command line:

command: (welcome)(prompt "\nThis is an AutoLISP demo program.")(princ)
Hello, ZWCAD!
This is an AutoLISP demo program.

The function without any parameters looks not very useful, however, you can use this kind of function to select some system variable and the condition status and return the values which reflect the status. The following sample code defines a function paramTest which accepted two string parameter, it will mix the parameters with another string and return the result string.

(defun paramTest (arg1 arg2 / lcstr)
  (setq lcstr "ZWSoft")
  (strcat lcstr ", " arg1 " " arg2)
)

Since the AutoLISP always returns the last expression calculation result for the function, the paramTest will return one string. This is a special case that users cannot use the princ function to ahcieve silient exit. The following sample code demonstrates that how to invoke the customize function with parameters:

command: (setq company (paramTest "Chinaweal" "Longteng"))
"ZWSoft, Chinaweal Longteng"

Customize command

If the customize function name is in the format C:XXX, this function can be used in the ZWCAD command line as the inner command of ZWCAD. Since this function can add the new command in ZWCAD, this kind of customize function is also called customize command.

If you want to use the function as ZWCAD command, you must make sure that they are used in the following rules:

  • Function name must be C:XXX (no case sensitive). Must have C: in name; XXX is the command name selected by users.
  • Function must have no parameter, but the local variable may exist in the parameter table.

Users can invoke the customize command transparently when implementing any of the ZWCAD inner command. However, when invoking the command function to implement one of the ZWCAD inner command, users cannot transparently invoke the customized command. Must add the single quote (') before the XXX when invoking the customize command transparently. The following sample code demonstrates the usage:

(defun c:prtinfo ()　　　　　　　 ;;; custom command prtinfo, its function is to print a string to ZWCAD's command bar
  (princ "\nStart drawing…")
  (princ) ;;;exiting quietly
)

command: line　　　　　　　　;;;invoke the custom command "prtinfo" transparently during calling ZWCAD's inner command "line"
Start of line : 'prtinfo
begin drawing …
Start of line :
Angle(A)/Length(L)/Specify next point:
Angle(A)/Length(L)/Follow(F)/Close(C)/Undo(U)/Specify next point:

command: (command "line" 'prtinfo '(0.0 0.0 0.0) pause "") 　　;;;invoke the custom command "prtinfo" transparently during invoking command function to run ZWCAD's inner command "line"
error: Unable to recognize command

There are two methods to implement the customize command, the first one is that using the complete function name with parentheses such as (C:prinfo); the other one is that using the XXX part in function name directly. The following sample code demonstrates the second method:

command: (c:prtinfo)　　　　;;;using the whole function name with brackets
begin drawing...
command: prtinfo　　　　　;;;using part of the function name "XXX"
begin drawing...

Note: Users must use the second method to invoke the customize command in the LISP program file (The complete function name with patentheses).

Re-define the ZWCAD command

In some situations, users might want re-define the existing ZWCAD inner commands, for example, re-define the New, Open or Quit command to achieve the efficiency that writing the running information in the blog file before ending the editable task. Users could use the defun function to define command and use undefine command at the same time. Users can use the customize command to re-define the ZWCAD inner command by underdefine command, recover the ZWCAD inner command by the redefine command. Kindly note that redefining the ZWCAD inner command is just efficient in the current editable task. The ZWCAD inner commands would recover when re-starting the ZWCAD program.

Introduct some command forms in the following items. There are five forms of the ZWCAD inner command, the differences among them are as below:

  • Line General form of command
  • _Line Prevent the analysis error for the developed LISP program in the other language environment.
  • .Line Originally quote the ZWCAD inner command (Shield undefine command, cancel the definition of the ZWCAD inner command)
  • _.Line Originally quote the ZWCAD inner command in the other language environment.(Shield undefine command, cancel the definition of the ZWCAD inner command).
  • -line Implement the ZWCAD inner command in the command line transactive manner. (Not all the ZWCAD inner command can be implemented in the command line transactive manner.)

If you want to get the reminder that whether use Pline command when using the Line command every time, you can define the AutoLISP function C:Line and replace the ZWCAD inner command Line. Below sample code demonstrates the usage:

(defun c:Line ()　　　　　　　　　;;;custom command "C:Line", print a message then run ZWCAD's inner command "Line"
  (princ "\ndraw polyline or line?\n")
  (command ".Line")
  (princ)　;exiting quietly
)
(command "undefine" "line")　　　;;;cancel running ZWCAD's inner command "Line"

Currently, if entering the Line in the ZWCAD command line, ZWCAD would invoke the customize command C:Line.

Command: Line
Draw Polyline or Line ?
command: .line
Enter to use last point/Follow(F)/<Start of line >:
Angle(A)/Length(L)/Specify next point:

Tips: When using command function to invoke command, all the commands would use period prefix format to make user that the invoked command is ZWCAD inner command but not the re-defined customized command.

Local variable and Global variable

The fine habit of program is that the more use local variable less use global variable. In AutoLISP, the characters or variable which are used in the inner function are called local variable. The currently loaded characters or variable which can be accessed by all the functions in all the LISP program.

Using local variable can make sure that variable in function would not be affected by other functions, so that the ensuring the data security. And the local variable occupied memory would be released automatically to improve the program running efficiency.

The disadvantages of replacing the local variable into global variable: Firstly, you may change the value inadvertently when you declaring the variable's function. This may lead to unpredictable results and it is quite difficult to check out this kind of issues; Secondly, the memory occupied by global variable cannot be released before ending the editable task. If declaring many global variable, that can consume the system memory badly.

Although there are some disadvantages existing, rationally using the global variable will make the program logic more clear in some cases. Mark the global variable is a good habit at this time, and the common method is that adding a (*) before and after the variable name respectly, for example, *ModelSpace*.

The following sample code demonstrates how to use the local variablein the customize function (Please make sure that there is one blank space betweent the slash and local variable at least in the parameter table) :

(defun test (/ product company)    ;;;declare two local variables: product and company
  (setq	product	"ZWCAD"
    company	"ZWSoft"
  )
  (princ (strcat "\nproduct = " product))
  (princ (strcat "\ncompany = " company))
  (princ)
)

Currently, invoke Test function defined in above code, check the local variable value (product and company)

command: (test)
product = ZWCAD
company = ZWSoft

After finished the Test function invoking, check the local variable value again (product and company)

command: !product
nil
command: !company
nil

Thus, after invoking the function, the memory space occupied by the local variable which is defined in function is released automatically.

Creating Unamed Function

If you think that defining a frequent expression to a new function costs too much, you can use lambda function to define the expressions as unamed function. This is similar with the C++ Inline function, the syntax format is as below:

(lambda param-list expr1 [expr2]…)

lanbda will take the function in the location where it would be used and express the program purpose more clearly. The unamed function cannot be invoked in the ZWCAD command line, it is always used with the apply function and mapcar function so that it can implement some operations for the element in table and return the last expression value. Please refer to the below sample code, it returns the origin point pt1 which is symmetrical about the Two-dimensional point pt0.

(setq pt1 (mapcar
        '(lambda (pt)     ;;;parameter list
           (* pt -1)    ;;;expression
         )
        pt0
      )
)


Programs' Session Controlling

Same as other programming languages, AutoLISP which is a kind of structured programming also provides three basic program structures: sequence, branch and loop.

Sequence structure

Whatever programming languages you use, the program should be executed sequential in the order of expressions. Run the following sample code in ZWCAD command bar:

command: (setq a "ZWCAD")(setq b a)　　　　;;; set variable a, then assign the value of variable a to variable b and return "ZWCAD"

If the order of two expressions is reversed, the value of variable a is nil because it has not been assigned before being used, the value of variable b is also nil. Thus, users should clarify the program's logic and organize the expressions' order in the program when developing AutoLISP program.

Branch structure

Users might meet some branches during developing program, at the moment, users need to use branch structure (Branch judge structure) to get different result according to each different branch conditions. AutoLISP provides if function and cond function to achieve the single condition judgment and multiple branch judgment respectively, they are similar with if...else and switch...case statement in C programming.

  • Single condition judgment (if)

    • (if testexpr thenexpr [elseexpr])

    "testexpr" should be first evaluated, if the return value is T, execute "thenexpr"; if the return value is nil, execute "elseexpr", if no "elseexpr" exists, leave away the if function and then continue to execute next AutoLISP expressions. The following sample code defines test1 function and output the larger one in num1 and num2:

    (defun test1 (num1 num2)
  (if (< num1 num2)
    (princ num2)
    (princ num1)
  )
  (princ) ;;; exiting quietly
)

    "thenexpr" and "elseexpr" can be other if expressions to make the nested branch structure which can achieve the multiple branch selection. The following sample code defined test2 function, its function is to output "excellent"(score > 90), "competent"(60 ≤ score < 90) or "incompetent" (score < 60) according to the value of parameter score:

    (defun test2 (score)
  (if (< score 60)
    (princ "incompetent")
    (if	(>= score 90)
      (princ "excellent")
      (princ "competent")
    )
  )
  (princ) ;;; exiting quietly
)
  • multiple branch conditions judgment (cond)

    • (cond (testexpr1 [thenexpr1]) (testexpr2 [thenexpr2])…)

    This function will evaluate each condition expressions in order until one of them returns T, and then execute the corresponding "thenexpr" but not continue to evaluate the rest condition expressions. Please note that each expression only has "thenexpr" without "elseexpr", and if the "thenexpr" is omitted, the condition expression's value should be returned. The following sample code defines test3 which can achieve the same function as above test2 function:

    (defun test3 (score)
  (cond
    ((>= score 90) (princ "excellent"))
    ((and (>= score 60) (< score 90)) (princ "competent"))
    ((< score 60) (princ "incompetent"))
  )
  (princ) ;;; exiting quietly
)

Comparing with the above test2 function and test3 function, we can easily find that using cond function to achieve the multiple branch judgment will make the code easily understanding.

Loop structure

Computer is most good at executing some commands time after time, if the programming language does not provide loop structure, the program's codes might be quite long and complicated. AutoLISP provides repeat function and while function to achieve specified times loop or no-specified times loop.

  • Specified times loop (repeat)

    • (repeat times [expression…])

    The function will execute specified expressions repeatedly according to the specified times (integer), the repeated expression may be one or more ones. The following sample code output "ZWCAD" 10 times in ZWCAD command bar:

    command: (repeat 10 (princ "\nZWCAD"))

  • No-specified times loop (while)

    • (while testexpr [expr1 expr2…])

    This function first evaluates the "testexpr", if the return value is T, execute the expressions in order, after finish executing the last expression, the function will return to the beginning to evaluate the "testexpr" again, if the return value is T, continue to execute the expressions....When the "testexpr" returns nil, the while function could exit. The following sample code defines test4 function, its function is to return the sum of all integers between 1 and num (positive integer):

    (defun test4 (num / i sum)
  (setq i 1)              ;;; initialize loop variable
  (setq sum 0)
  (while (<= i num)       ;;; check the value of testexpr
    (setq sum (+ sum i))
   (setq i (1+ i))       ;;; change loop variable
  )
  sum
)

    Please note that if the "testexpr" value is always T, program would execute each of the expressions time after time without ending, this is called "dead loop". The reason leading to dead loop is that there is no change for the loop variable's value after executing all expressions of the loop, for above example, if you comment the expression (setq i (1+ i)), the function test4 would enter into dead loop.


AutoLISP Codes Files

Although users can enter the AutoLISP code in the ZWCAD command line, users need to re-enter the command after every modification. If you store the AutoLISP code in the file, you could find that loading the AutoLISP code from file when test and debug a series of commands is more convenient. AutoLISP code is always saved in the ASCII text file whose extension name is.lsp.

Source code format setting

It's not easy to read the AutoLISP with the wide used parentheses, the core solution for this problem is indent, the more deeply embedded code line the righter indent.

Appropriately using blank space or blank line can enhance the LISP code readability. In the AutoLISP code, adding a blank space between the variable name and constant name equal to an individual blank space. The following code has different format, but returns the same result:

No indent code line:
(setq pt1 (list 0.0 0.0 0.0) pt2 (list 100.0 0.0 0.0) pt3 (list 100.0 100.0 0.0))
Indent code line:
(setq pt1 (list 0.0 0.0 0.0)
pt2 (list 100.0 0.0 0.0)
pt3 (list 100.0 100.0 0.0)
)

Comments

Writing comments in the AutoLISP program file is a good habit. Comments is not only useful for the developers but also the users, the reason is that users might need to modify the program to meet their requirement. Using comments in the following tasks:

  • Give the title, author and the creating date
  • Give the descriptive comments for program functionality and algorithm
  • Add debugging comments

Comments begin with one or more semicolon and continue to the end of the line, this comments method is called single line comment.

;Single line comment
(setq radius 3.5) ;;;Set the circle radius

Any of the texts would be ignored in the ;|…|, so the comment could contain multiple lines of code, this comment method is called multiple lines comment.

;Multiple line comments
(setq radius 3.5)
;|Multiple lines comment, the following two lines for LISP code would be ignored.
(setq cenpt (list 0.0 0.0 0.0))
(setq area 6.28)
|;Multiple lines comments is in the end

Note: the multiple lines of comment cannot use in parts of the sentences in one code line, please refer to the following code:

(setq radius 3.5) ;|This text will be ignored|; (setq cenpt (list 0.0 0.0 0.0))

When loading these kind of LISP programs which contain that type of comments, ZWCAD would prompt that "Error, Malformed Sequence"


Load and Run AutoLISP Program

If you want to run the LISP program, you must load it in ZWCAD first. We will introduce that how to load the LISP program as follows.

Manually Load

The steps of manually loading the AutoLISP file is as below:

1. Click on the Tool » Load Application in dropdown menu, or input APPLOAD in command line and press enter, the "Load Application Files" dialog is opened.

load application dialog

2.Click on "Add" button to prompt the dialog showed in the following figure, select the LISP file you want to load, and then the selected file will be added in the dialog showed in the figure 2. (You may select the sample.lsp file from the Sample\LISP directory in the ZWCAD installation catalog, it is the sample program of this manual) :

3. Select the LISP file you want to load in the dialog list which is showed up in figure 2, click on "Load" button, and then the LISP program can be loaded in the ZWCAD.

Note: You may also can use the ZWCAD command to load the LISP file manually, just only need to input (load "C:\\Program Files\\ZWCAD 2023 Chs\\Sample\\LISP\\Sample.lsp") in the command line, C:\\Program Files\\ZWCAD 2023 Chs\\Sample\\LISP is the program path, sample.lsp is the LISP program file name.

Automatically Load

Sometimes you might write a LISP program to set the drawing environment, for example, setting layer, text style, dimension style etc, and you might hope that these LISP files can load and run automatically in the newly created ZWCAD drawing when starting the ZWCAD every time. You can achieve the purpose through the following two ways.

  • Use the Startup Suite to load automatically

    • 1. After implementing the above step 2, select the LISP file you want to load automatically in the dialog list which is showed in the figure2, click on the "Add to startup suite" button, the following dialog will be prompted up.

    startup suite dialog

    2. Click on "Add" button and select the LISP file you want to load automatically.

    3. The LISP files which have been added to the startup suite will be loaded automatically when starting the ZWCAD or creating the new drawing every time.

    Note: The LISP files which are from the startup suite will be grayed out in the "Load Application Files" dialog list (refer to the below figure). These files cannot be removed from the list by clicking on the "Delete" button but can be removed from the startup suite firstly.

    files in startup suite disable

  • Use the LISP startup file (zwcad.lsp) to load automatically

    • Add the LISP code which is used to set the drawing environment to the zwcad.lsp file in ZWCAD installation directory, so the code will be loaded automatically when starting the ZWCAD every time.

Run the lsp program

AutoLISP program file contains multiple customized command, customized function and some individual AutoLISP expression (DO NOT exist in any customized command or the customized function), there are some differences among these three executions

  • Customized command

    • Customized command actually is a special customized function, the function format is C:XXX. Customized command usually has no parameter and users can execute these command in the command line like execute the ZWCAD inner command, namely just need to input the XXX in command line.

  • Customized function

    • Customized functions do not need to add the function name before the "C:" prefix. Customized functions usually have parameters which support the other customized function or customized command call. And you may also execute functions in the command line, you just need to input the AutoLISP expressions which are used to invoke the functions in the command line, namely input (funcname arg1 arg2).

  • Individual AutoLISP expression

    • The individual AutoLISP expression in the AutoLISP program can be executed automatically when the file loading, they are mainly used to set the drawing environment.


Debugging Skill

It is recommended to use Visual LISP Editor for debugging. Here are some debugging techniques in ZWCAD that can effectively improve debugging efficiency.

Use the command line echo

ZWCAD has the error checking functionality that can easy to check the problems including the parameter error when calling functions, and the keyword error when calling the ZWCAD inner command by command function and the transparence command call.

By default, ZWCAD will interrupt the program execution and inform the error information to return the error code when ZWCAD checking this kind of the error. While this has brought about the security of the source code for potential problems, but the procedure is useful for debugging. However, the following cases will bring some inconveniences to the LISP program debugging:

1.When users set the system variable as 0 and the command function invokes the ZWCAD inner command, the command line will not display the process of the command execution. Therefore, it is difficult to find the bugs during this process.

2. If you have defined *error* function to handle the error, the command line will just only inform the error information but not return the error code when ZWCAD encountering some errors. This is not conductive to debug.

3.If you set the system variable _zw_xprintlsperrcode as 0, the command line will just only inform the error information but not return the error code when ZWCAD encountering some errors.

Suggestion: During the program debugging, please set the system variable cmdecho and _zw_xprintlsperrcode as 1 and make the customized *error* function have no effect.

Use alert function

Calling the alert function can prompt a dialog with only "OK" button, the LISP program will not execute until you clicking on the "OK" button in the dialog, this effect is same as setting the breakpoint in the AutoCAD IDE. Usually you need to see the value of the variable to use the function.

This function can only accept one string type parameter, so it cannot be used in viewing the non-string type variable. Users can use the functions which are introduced in the "Translation function list" to translate the non-string type variable into the string type and then transmit to that function. You may also use vl-princ-to-string function uniformly, it can translate any types of the variable value into string type.

Use global variable

We have introduced the global variable and local variable in the "Customized function an command" theme in the "LISP basic program design". Although there are many disadvantages in using many global variables, please also try you best to use global variable in the program development. The reason is that after finishing the running the LISP program or interruping by the error, you can view a variable value through the excalmatory mark (!) + variable name format in the ZWCAD command line.

Use pause (pause)

LISP program usually invokes the command function to execute the ZWCAD inner command, Maybe the execution of certain commands passed the parameters that is not correct, or the command to switch the thread, but to lead program can not achieve the desired effect, at this point you can use the parameters PAUSE interrupt command sequences in command function, troubleshoot the problem one by one.


Visual LISP Editor

ZWCAD uses Microsoft Visual Studio Code (hereinafter referred to as VSCode) as LISP editor, and implements the development, testing and debugging functions of LISP in the form of plug-ins.

In the process of installing ZWCAD, VSCode will be installed automatically.

For the first time, ZWCAD is launched, and the .vscode folder is generated in the %userprofile% directory. The plug-in folder is stored in the %USERPROFILE%\.vscode\extensions directory.

Environmen

Operating System

Support Windows 7 or later.

ZWCAD Version

Support ZWCAD 2019 SP2 or later.

Other requirements

.NET Framework 4.5 is required.

For Windows XP and above operating systems, you may need to install VSCode yourself.

Entries

The Visual LISP Editor can be accessed in three ways.

  • Ribbon: Manage » Applications » Visual LISP Editor
  • Menu: Tools » Visual LISP Editor
  • Keyboard: VLIDE or VLISP

After starting the Visual LISP Editor, the following interface pops up.

Click View » Extensions, switch to the Extended View page, and click ZwLisp to enter the corresponding interface, as shown in the following figure.

Color Theme

ZwLisp provides a set of color theme that users can set up in the following two ways.

  • The lower left gear button: Manage » Color Theme » zwlisp theme
  • Click the Set Color Theme button in the main window of ZwLisp.

Startup debugging

Add .lsp files

Click File » Open Folder, and select the folder of .LSP files in the pop-up dialog box.

Click the Debug icon on the left to switch to the debug page. The debugging panel records variables, watch, call stacks, and breakpoints.

Select debugging environment

To start debugging for the first time, you need to select the zwlisp debugging environment.

Click the [image] in the upper left corner and the system opens the configuration file launch.json automatically. Set the configuration item program to the actual installation path of ZWCAD. As shown in the figure below.

Select debugging mode

You can select one of two mode for debugging.

  • ZWCAD has been started, select the Attach to ZWCAD mode.
  • ZWCAD is not started, select the Launch ZWCAD mode.

After selecting debug mode, click Debug » Start Debugging to start debugging. A debugging toolbar appears in the VScode interface.

Set breakpoints

You can set a line breakpoint by clicking on the left margin of the line number, and the program will break at the first left bracket of the line.

Column breakpoints can be set by pressing Shift+F9 at any left bracket, and the program will break at the column breakpoints.

Example

Open foo.lsp in VScode and set a breakpoint on the second line.

Select the Launch ZWCAD mode to start debugging, load the foo.lsp file in ZWCAD, execute the custom command foo, the program interrupts at the breakpoint, as shown in the following figure.

Debugging process

When the above example is interrupted at the breakpoint, you can observe the values of the variables in the debug panel. You can also add variables to the WATCH area, such as adding e and i. The variables are not assigned and the initial values are nil.

After skipping the breakpoint and press F11, you can observe the changes of values in VARIABLES and WATCH areas.

Related Commands

  • APPLOAD
  • VLISP


Release LISP Program

Through constant coding and debugging, the LISP applications can meet your demand, but this does not mean that the whole development work has completed, because you need to release your work-product. This section will introduce the steps of releasing the LISP program:

Clear up the source code

Maybe you have finished this task during the development, if not, this work is essential before publishing the application finally. The main effect to this work is to ensure the program's maintainability and robustness. This work mainly contains the following contents:

1. Format the codes, appropriately use indentation, spaces and blank lines, add comments for key algorithms;

2. Comment the codes for debugging, including recovering some system variable's value (such as "cmdecho" etc.), recovering the customized *error* function, convert the global variables which are used to debugging into local variable;

3. Add fault-tolerant handling code. A complete application should have a great robustness, namely it should normally run when users execute some destructive operations. Although users could invoke the functions which are introduced in "Error handling function list" section of appendix to handle some errors, sometimes, it's better for the program's robustness to add codes for fault-tolerant handling when getting users' input, for example, when the program requests users to select some entities but users do not select any entities, you should add codes for fault-tolerant handling in your program, otherwise, the application can't run normally.


Library Functions Introductions

As the mention in the first chapter, Learning the AutoLISP program is primarily learning the basics of LISP and the usage of AutoLISP programming library functions, the first aspect has been introduced in the second chapter, this chapter will give the detailed introduction about the usage of the Library functions. AutoLISP provides 230 library functions, this chapter will introduce them by the functionality sort, taking the various types of function is more frequently used functions, supplemented by examples of code are introduced, mainly contains the following contents:

  • Arithmetic Functions

    • This section mainly introduces the Arithmetic functions provided by the AutoLISP, these functions also are called operation characters, we will take the / (division) function as an example to introduce the use of arithmetic functions Note.

  • Relational Functions

    • This section mainly introduces the functions which is provided by the AutoLISP and used to compare the return values between the two variables or the two expressions, we will take the = (equal), eq, equal and the wcmathc functions as the examples to introduce to the trivial differences among these functions.

  • Logical Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to construct the complex condition function, these functions are always used in the judgment conditions in selection structure and the loop structure with the relational operators, we will take the AND and OR functions as the examples to introduce the usage of this kind of functions.

  • Bit Arithmetic Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used in the binary logical arithmetic functions, and invoke the logand function to set the undo, we will take the beginning mark and the end mark as the examples to introduce the usage of this kind of functions.

  • Conversion Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to convert the variable data type or the format (such as convert the interger to string, convert the real number to the various format of the sting, convert the string to the various of the real number, convert the angle value to the various format of string etc.), convert the unit (such as convert the Mm to In. etcs) and the functions which is converted by the coordinate system, we will take the itoa, rtos, distof, angtos, angtof, ascii, chr, cvunit and trans functions as examples to introduce this kind of the function usage.

  • String Handling Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to merge the string, convert the upper case and the lower case, the number of characters Statistics, we will take the strcase, strcat and strlen as examples to introduce this kind of the function usage.

  • List Handling Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to create list, query list, modify list elements, we will take the list, nth, car, cadr, cdr, append, cons and subst functions as examples to introduce this kind of the function usage.

  • Data Input Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used in the user interaction function, we will take the getxxx, initget functions as examples to introduce this kind of the function usage.

  • Geometric Functions

    • This section mainly introduces the functions which provided by the AutoLISP and related to the Geometric functions(such as obtain the intersection point between the two lines, obtain the distance between the two points), we will take the osnap and textbox functions as examples to introduce this kind of the function usage.

  • File Handling Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to search the file, read and write the file, we will take the findfile, getfiled, open, princ, write-line and read-line functions as examples to introduce this kind of the function usage.

  • Entity Handling Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to obtain the entity data, create new entity, delete or modify the entity, add the extended data for the entity, we will take the entsel, nentsel, entnext, entdel, entget, entmod and entmake functions as examples to introduce this kind of the function usage.

  • Symbol Table Handling Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to travel the character list and query the list records, we will take the tblnext and tblsearch functions as examples to introduce this kind of the function usage.

  • Selection Set Handling Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to create the selection set, add entity to selection set, we will take the ssget, ssadd and ssdel functions as examples to introduce this kind of the function usage.

  • Dictionary Handling Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to create the dictionary and travel the dictionary items, we will take the dictsearch and dictnext functions as examples to introduce this kind of the function usage.

  • Query Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to query and set the ZWCAD system variable or the environment variable, we will take the getvar, setvar, getenv and setenv functions as examples to introduce this kind of the function usage.

  • Command Functions

    • This section mainly introduces the functions which provided by the AutoLISP and used to invoke the ZWCAD internal command, we will take the command function as an example to introduce this kind of the function usage.

  • Error Handling Functions

    • This section mainly introduces the tolerance ways for the LISP program functions, including the customized *error* function catches errors and stop the program, vl-catch-all-apply function catches the error and continue to execute the program.


Arithmetic Functions

ZWCAD provides 23 AutoLISP functions to make mathematical calculations including + (addition), - (subtraction), * (multiplication), / (division), 1+ (incremental) and 1-(decreasing). please refer to the section "Arithmetic Functions List" in appendix for the detailed list. This section will take the / (division) function as an example to introduce the notes of using arithmetic functions.

If the parameters passed to the arithmetic function is integer or real, the function would return different values. If all the parameters are integers, the return value is integer, and once one of the parameters is real, the return value is real. It's shown as follows:

command: (/ 12 5)
2
command: (/ 12.0 5)
2.40000


Relational Functions

ZWCAD provides 9 AutoLISP functions for relational calculus including = (equal), /= (non-equal), < (Less), <= (Less than or equal), > (more), >= (more than or equal), eq, equal and wcmatch. Please refer to the section "Relational Functions List" in appendix for the detailed list. The return value of relational calculus expression is nil or T, it is mainly used in conditional expressions in branch structure or loop structure. This section will mainly introduce the differences among =, eq, equal and the way of using wcmatch function to match with wildcard character.

Determining whether variables are equal absolutely

The parameters passed to = and eq function might be variables, constants or expressions. But there are some differences when using these three functions to judge whether all parameters are equal:

  • = function

    • Is used to judge whether two or more variables/constants/expressions' values are equal. And when all parameters' values are equal absolutely, the function returns T, otherwise return nil. For example:

    Expression | Return value | Description
(= "ZWCAD" "ZwCAD") | nil | Compare two string constants are equal or not
(= 3.1415 pi) | nil | Compare two real numbers are equal or not

    Notes: because real number's values are often affected by their precisions, it's suggested that do not use = function to judge whether two real numbers are equal.

  • eq function

    • Is used to judge whether two variables or expressions are the references to the same objects or variables. Although compared variables or expressions' values are equal, the function may still return nil because the objects or variables which are referred by the compared variables or expressions are not same. For example:

    command: (setq lst1 (list 10.0 12.0 0.0))
    command: (setq lst2 (list 10.0 12.0 0.0))
    command: (setq lst3 lst2)

    Expression | Return value | Description
(eq lst1 lst2) | nil | The values of lst1 and lst2 are equal, but they are from the different expression's references
(eq lst2 lst3) | T | lst2 and lst3 are from the same expression's reference

Determining whether variables are equal allowing for specified tolerance

  • equal function

    • Sometimes, when two real numbers are identical, if you use different calculation methods to compare two them, the result might have some differences. On this occasion, you may use equal function to compare variables or expressions allowing for specified tolerance by yourself. This function is usually used to compare whether two real numbers are equal or not. For example:

    Expression | Return value | Description
(equal 3.1415 pi 0.001) | T | Compare whether the two real numbers are equal or not, permitted error less than 0.001
(equal 3.1415 pi 0.00001) | nil | Compare whether the two real numbers are equal or not, permitted error less than 0.00001
  • wcmatch function

    • When comparing two strings, you can't specify its tolerance. How to determine whether two strings are same allowing for specified tolerance?

    ZWCAD provides wcmatch function to compare a string with a template string including wildcard. If the string matches to the template string, this function returns T otherwise returns nil. The wildcard is the same as which used in other system (such as Dos) and applications. In the wildcard, letters and numbers are used as themselves; Square brackets are used to specify the optional characters or the letters/numbers in special rang; Interrogation is used to match with single character; Asterisk is used to match with one or multiple characters. All these wildcard are very useful in the ssget function's filter list and entget function's checking the xdata in multiple registered applications.

    Assume that the following string variable's value is "This is a test string, the last five letters of which are \"test1\".", the following sample code shows the usage of wcmatch function:

    Expression | Return value | Description
(wcmatch string "This*") | T | Determine whether the string is begun with "This" or not
(wcmatch string "*test[3-58]*") | nil | Determine whether the string contains "test8" and one of the following three string: "test3", "test4", "test5"
(wcmatch string "That,This*,*test1") | T | Determine whether the string's content is "That", whether the string is begun with "This", whether the string is ended with "test1"


Logical Functions

Logic calculation is also called Boolean calculation and used to test the true or false value, the parameter of it always is relation expression. In AutoLISP, 0 and nil are considered as false value, non-zero and T are considered as true value. AutoLISP provides three basic boolean calculation function including "and", "or" and "not", please refer to the theme "Logic function" in appendix for the detailed list. The following true value table lists the calculation rules for the three Boolean calculation function.

Expression 1 | Expression 2 | And return value | Or return value
T | T | T | T
T | nil | nil | T
nil | T | nil | T
nil | nil | nil | nil
Expression | Not return value
T | T
T | nil

Simply speaking:
And--parameters are all T(True), return T (True);
Or-- parameters are all nil(False), return nil (False);
Not--parameters are T(True), return nil(False);parameters are nil(False), return (True).

For example, the common mathematical inequalities "60 ≤ a ≤ 79" needs to expressed by "end" function in the LISP program.

(and (>= a 60) (<= a 79))

When carrying out logic operations, if "And" and "or" function follow the calculation expression 1, the final return value for the Boolean calculation could be sure, and It will earlier end to the rest of the expression evaluation in the parameter table.

(and (< a 50) (setq a 50))

In above example, the two parameters for "and" function are (< a 50) and (setq a 50). When carrying out the expression, expression (< a 50) will be firstly evaluated. If the return value of the expression is false (0 or nil), whatever values the expression 2 returns, the final result of the "and" function is false. Thus, the expression (setq a 5) will not be evaluated. So the effect of the sample code is that check the variable value of a, make sure the values are not less than 50

(or (< a 50) (setq a 50))

In above example, the two parameters for "or" function are (< a 50) and (setq a 50). When carrying out the expression, expression (< a 50) will be firstly evaluated. If the return value of the expression is true (non-zero or T), whatever values the expression 2 returns, the final result of the "or" function is true. Thus, the expression (setq a 5) will not be evaluated. So the effect of the sample code is that check the variable value of a, make sure the values are not more than 50


Bit Arithmetic Functions

AutoLISP provides some bit operation functions such as boole, logand, logior, please refer to the theme "Bit function" in appendix for the detailed list.

Before we learning the bit operation function, we must know the data storage type in computer.

We know that computer stores the data in the binary type, the smallest unit is bit and every 8 bit could compose of a byte, each of the bit could only store 1 or 0. We always use the byte to evaluate the memory space occupied by data. The bit operation in the following introduction is a kind of logic operation for each bit. The following figure shows up each of the byte storage in the computer memory, every grid represents a bit in the byte.

In the simple arithmetic calculation, we rarely use bit operation functions. In ZWCAD, the bit operation function is always used to operate some system variable (such as AFLAGS, AUTOSNAP, CMDACTIVE, UNDOCTL, etc.) whose value is sum of optional code. The following sample code gives an example of UNDOCTL system variable to demonstrate the usage of bit operation function:

In ZWCAD, The memory storage form for UNDOCTL system variable optional bit code and the other bit code is showed up as below:

bit value | Meaning | Memory storage form
0 | Close undo |
1 | Open undo |
2 | only abandon one command |
4 | Open "Automation" |
8 | A grouping in the current active status |

The following sample code is used to check if setting the undo beginning sign, if the undo beginning sign has been finished to set, Continue to set the undo termination sign; if no, set the undo beginning sign:

(defun undosetting ()
  (if (logand 8 (getvar "undoctl"))    ;;;judge if the undo begin mark has been set
    (command "undo" "end")
    (command "undo" "be")
  )
  (princ)
)

Decimal integer 8 in binary is showed up as below figure:

The result of "0" implementing any numbers in "and" operation is always 0 (false), the result of "1" implementing "1" in "and" operation is 1 (true). The expression (logand 8 (getvar "undoctl") in the above sample code is used to check that whether the fourth bit in system variable undoctl binary form is 1 or not, if the returned value is T, the fourth bit in system variable undoctl binary form is 1. Namely there is a grouping in current active status. (set the undo beginning sign)


Conversion Functions

ZWCAD provides 11 AutoLISP library functions to make string conversion, angle conversion, ASCII conversion, unit conversion and coordinates conversion including angtof, angtos, ascii, atof, atoi, chr, cvunit, distof, itoa, rtos and trans. Please refer to the section "Conversion Functions List" in appendix for the detailed list.

String Conversion

since some output functions only accept string parameter, the arguments should be converted to string before passed to these functions.

"itoa" function can convert integer to string, the following sample code shows the usage of this function:

command: (itoa 2023)
"2023"

"rtos" function can convert real number to string. The syntax of this function is shown as below:

(rtos number [mode [precision]])

If "mode" and "precision" parameters are omitted, the result string format is determined by the ZWCAD system variables "LUnits" (Specify real number's mode) and "LUprec" (Specify real number's precision).

The following sample code shows how to invoke "rtos" function to convert the pre-defined variable "pi" to string with different mode and precision.

Expression | Return value | Description
(rtos pi 1 4) | "3.1416E+00" | mode = 1, Scientific; precision = 4
(rtos pi 2 5) | "3.14159" | mode = 2, decimal; precision = 5
(rtos pi) | "3.1416" | Do not specify the "mode" and "precision" parameters, current system variable : LUnits = 2, LUprec = 4

"distof" function can convert the string that represents a real value to a real number, it is the complementary of "rtos" function. The syntax is shown as below:

(distof string [mode])

"string" parameter must represent a real value, namely the parameter must can be analyzed correctly by various mode specified by "mode" parameter; "mode" parameter is used to specify the string's format (scientific, decimal, project, architecture or fraction) and assist ZWCAD to analyze the string, this parameter also can be omitted.

The following sample code shows how to invoke "distof" function to convert string representing a real value to real number by different mode:

Expression | Return value | Description
(distof "100.123E-3") | 0.100123 | omit "mode" parameter
(distof "12 1/3" 5) | 12.3333 | mode = 5, fraction
(distof "1'-2.30\"" 3) | 14.3000 | mode = 3, project

"angtos" function can convert angle value in radians to string. The syntax of this function is shown as below:

(angtos angle [mode[precision]])

If "mode" and "precision" parameters are omitted, the result string's format is determined by ZWCAD system variable "AUnit" (specify angle's unit) and "AUprec" (specify angle's precision).

The following sample code shows how to invoke "angtos" function to convert angle value in radians to string by different mode and precision:

Expression | Return value | Description
(angtos 1.25 0 2) | "71.62" | mode = 0, decimal angle, precision = 2
(angtos 1.25 1 2) | "71d37'" | mode = 1, angle/min/sec, precision = 2
(angtos 1.25) | "72" | Do not specify "mode" and "precision" parameters, AUnits = 0, AUprec = 0

Since the "angtos" function would consider the "AngBase" system variable when evaluating, the following code always returns "0":

(angtos (getvar "AngBase"))

If you want to return the "AngBase" system variable's angle value in WCS by various mode and precision, you could save AngBase's value in a temporary variable then set AngBase's value to 0, and then invoke the "angtos" function to evaluate the system variable's value. Finally, recover AngBase's initial value. Please refer to the following code:

(defun GetAngBase (mode precision / old_angbase temp)
  (setq old_angbase (getvar "AngBase"))
  (setvar "AngBase" 0.0)
  (setq temp (angtos old_angbase mode precision))
  (setvar "AngBase" old_angbase)
  (eval temp)
)

Assume that you have execute expression (setvar "AngBase" 0.5233) to set "AngBase" system variable's value to 0.5233 radian before executing the following expression. Implementing the following code could return AngBase in string form by the specified mode and precision.

command: (getangbase 1 2)
"29d59'"

"angtof" function can convert string that represents angle in radians to real number, it is the complementary of "rtos" function. The syntax of this function is shown as below:

(angtof string [mode])

"string" parameter must be a string representing a angle value (decimal, angle/min/sec, centigrade, radian or investigation unit ); "mode" parameter is used to specify the string's format and assist ZWCAD to analyze the string, this parameter also can be omitted.

The following sample code shows how to invoke "angtof" function to convert the string representing angle value to a real number by different mode:

Expression | Return value | Description
(angtof "35d30'20\"") | 0.453762 | omit "mode" parameter
(angtof "3.14159r" 3) | 2.97566 | mode = 3, radian

Angle Conversion

When combining the "angtos" function and "atof" function, the angle in radians (such as the return values of "angle" function and "getangle" function) can be converted into angle in degrees. Firstly, invoke "angtos" function passing 0 to the "mode" parameter to convert the real number representing radian value into the string representing degree value, and then invoke the "atof" function to convert the string to real number. Please refer to the following code:

command: (setq deg (atof (angtos (getangle "\nspecify angle (radian): ") 0)))
specify angle (radian) : Enter radian or pick a point
Next point : pick next point
17.0000

Although this method can convert radians into degrees, it is not very intuitional. Suggest that you should define transfer function according to the geometric relationship between radians and degrees. The following sample codes define two customized functions "Rad->Deg" (radians to degrees) and "Deg->Rad" (degrees to radians).

(defun Rad->Deg	(radian)
  (* (/ radian pi) 180.0)
)
(defun Deg->Rad	(degree)
  (* (/ degree 180.0) pi)
)

ASCII Conversion

When users usually need to convert characters to its ASCII or convert an integer between 0 and 255 to a character in programming. The functions "ascii" and "chr" in AutoLISP can achieve this effect. The following code shows the usage of these two functions:

Expression | Return value | Description
(ascii "\n") | 10 | return ASCII for newline character
(chr 65) | "A" | return the character whose ACSII is 65

Unit Conversion

"cvunit" function can convert data between different measure units. The syntax of this function is shown as below:

(cvunit value from-unit to-unit)

"from-unit" parameter specifies the unit that "value" is converted from., "to-unit" parameter specifies the unit that "value" is converted to. Both of them can be any unit type defined in the "zwcad.unt" file. If these two parameters are the incompliant units (such as "meter" and "kilogram"), this function would return nil.

When using "cvunit" function to make units conversion during editing drawing, ZWCAD need to search the strings specified by "from-unit" parameter and "to-unit" parameter in ZWCAD installation directory. If there are many values need to be converted from one unit to other unit, we suggest that you can individually invoke "cvunit" function to convert 1.0 from "from-unit" unit to "to-unit" system, and then use this return value as a conversion factor to convert other values. The following sample codes show this usage:

(defun batcvunit (valuelist from-unit to-unit / factor)
  (setq factor (cvunit 1 from-unit to-unit))       ;;; get the factor of unit conversion
  (mapcar '(lambda (x) (* x factor)) valuelist)
)

If you want to convert many sizes from meters (such as 12.3 45.6 25.3 24.1 68.4 etc) to inches, you can use LISP expression (batcvunit '(12.3 45.6 25.3 24.1 68.4) "meters" "inches"), it returns (484.252 1795.28 996.063 948.819 2692.91).

Coordinates Conversion

"trans" function is used to convert a point or displacement from one coordinate system to another. The syntax of this function is shown as below:

(trans pt from to [disp])

If "disp" parameter is non-zero, "pt" parameter represents a 3D displacement, if not, "pt" parameter represents a 3D point. "from" parameter specifies the coordinate system in which "pt" is expressed; "to" parameter specifies the coordinate system in which the returned point is expressed.

Next, we will give the brief introduction for ZWCAD coordinates:

Coordinate | Description
WCS | World Coordinate System. All other coordinates are defined relative to WCS. Since WCS is constant, the value measured in WCS can be steadily converted to other coordinate system. By default, ZWCAD uses WCS its current coordinate system, all points' coordinates returned by AutoLISP library functions and any other user customized functions is in WCS.
UCS | User Coordinate System. Users can set the UCS to ensure that you can draw conveniently. All points passed to ZWCAD commands (except that user add the "*" in front of the coordinates in command bar such as *12.5, 3.2) are in UCS. If the program need to convert some coordinates in WCS, OCS or DCS to ZWCAD commands, you must invoke "trans" function to convert these coordinates to current UCS firstly.
OCS | Object Coordinate System. The feature points of the sub entity in complex entity returned by "entget" function are expressed in OCS, namely the sub entity's coordinates is expressed by the main entity as the reference strain. According to the coordinates' usage, these points are usually converted into WCS, current DCS or current DCS. In reverse, before invoking "entmod" or "entmake" function to write these points to complex entity, they must be converted into OCS.
DCS | Display Coordinate System. Before displaying the graphics, the object's coordinates must be converted to DCS firstly. DCS original point is saved in ZWCAD "Target" system variable and uses Z-axis as direction of observation. These coordinates can determine the location where the objects display on the screen to ZWCAD users. OCS is often used in the operations coming down to viewports.
PSDCS | PaperSpace DCS. This coordinate system only can be converted with the current activated viewport in ModelSpace. It is actually a 2D conversion, if the parameter "disp" is 0, the X coordinate and Y coordinate are always scaled and panned proportionally, but Z coordinate is only scaled proportionally but not be panned. It can be used to evaluate the scale factor between two coordinates.

The parameters of "trans" function "from" and "to" could be specified by any of the following methods:

  • Integer code. Please refer to the "trans" section in AutoLISP function reference for its available codes and other detail.
  • AutoLISP entity name. For the 2D objects, maybe there are some differences between the OCS and WCS. If these two coordinate system are same, the conversion between these two coordinate systems is identical.

The following sample codes define "crosscenterline" command to draw cross centerline for the selected circles whatever the current UCS is.

(defun c:crosscenterline (/ osnapOld filediaOld cecolorOld
           celtypeOld sset circleNum circle-ename
           dxflist radius cenp
          )
;;; backup current system variables' values
  (setq osnapOld (getvar "osmode"))
  (setq filediaOld (getvar "filedia"))
  (setq cecolorOld (getvar "cecolor"))
  (setq celtypeOld (getvar "celtype"))
;;; load the linetype "center"
  (if (null (tblsearch "ltype" "center"))
    (command "-linetype" "L" "center" "zwcadiso" "")
  )
;;; set system variables
  (setvar "osmode" 0)
  (setvar "filedia" 0)
  (setvar "cecolor" "1")
  (setvar "celtype" "center")
  (setq sset (ssget '((0 . "CIRCLE"))))
  (setq circleNum (sslength sset))
  (setq i 0)
;;; iterate circles in selection set
  (repeat circleNum
    (setq circle-ename (ssname sset i))
    (setq dxflist (entget circle-ename))
    (setq radius (cdr (assoc 40 dxflist)))	    ;;; get circle's center point's coordinates
    (setq cenpt (cdr (assoc 10 dxflist)))  	;;; the point returned by "entget" function is in WCS
    (setq cenpt (trans cenpt circle-ename 1))	;;; convert center point's coordinates from WCS to UCS
    (command "line" cenpt (polar cenpt 0.0 (+ radius 3.0)) "")
    (command "line" cenpt (polar cenpt (* pi 0.5) (+ radius 3.0)) "")
    (command "line" cenpt (polar cenpt (* pi 1.0) (+ radius 3.0)) "")
    (command "line" cenpt (polar cenpt (* pi 1.5) (+ radius 3.0)) "")
    (setq i (1+ i))
  )
;;; recover system variables' values
  (setvar "osmode" osnapOld)
  (setvar "filedia" filediaOld)
  (setvar "cecolor" cecolorOld)
  (setvar "celtype" celtypeOld)
  (princ)
)


String Handling Functions

ZWCAD provides 17 AutoLISP library functions to handle string including strcase, strcat, strlen and substr. Please refer to the section "String Handling Functions List" in appendix for the detailed list.

"strcase" function is used to convert the characters in string to uppercase or lowercase. The syntax of this function is shown as below:

(strcase string [mode])

"string" parameter specifies the string to be converted; "mode" parameter specifies the case of the return characters. If the "mode" parameter is omitted or is set to nil, "strcase" function returns uppercase string.

command: (strcase "Hello, ZWCAD.")
"HELLO, ZWCAD."

If the "mode" parameter is T, this function returns lowercase string. AutoLISP provides predefined variable T to the users when they need to use non-nil value as the True/False switch.

command: (strcase "Hello, ZWCAD." T)
"hello, ZWCAD."

"strcat" function is used to concatenate multiple strings into one new string. The syntax of this function is shown as below:

(strcat [string1 [string2]…])

It is usually used to insert the value of a string variable to a constant string. Executing the following sample codes to save a string in variable, and then invoke "strcat" function to insert the variable's value (string) in another string.

command: (setq appname "ZWCAD") (setq msg (strcat "You're running " appname " application."))
"You're running ZWCAD application."

"strlen" function is used to evaluate the amount of characters in a string (contains blanks) or the total number of characters in multiple strings. The syntax of this function is shown as below:

(strlen [string1 [string2]…])

If the variable msg is set as the above string ("You're running ZWCAD application."), the following code could evaluate the number of characters.

command: (strlen msg)
31

"substr" function is used to return a substring of a string. The syntax of this function is shown as below:

(substr string start [length])

"string" parameter specifies the string to be processed; "start" parameter specifies the location of the first character of substring in "string". Please note that the first character in "string" is position 1; "length" parameter specifies the number of characters in substring, if "length" is omitted, the substring continues to the end of "string". The following sample code shows how to get the main file name (actually, the "vl-filename-base" function can be used to achieve this effect):

command: (setq flname "dasetup.log")
"dasetup.log"
command: (setq newlen (- (strlen flname) 4))
7
command: (setq mflname (substr flname 1 newlen))
"dasetup"

Users need to get a string which contains all the characters in addition to the last four (period and extension of three letters). Invoke "strlen" function to get the length of the file name string and subtract 4 of the return value, namely it is the required "length" parameter for "substr" function.


List Handling Functions

AutoLISP provides 32 kinds of the list functions including the append, assoc, car, cadr, caddr, cdr, cons, foreach, length, list, listp, mapcar, member, nth, reverse and subst. Please refer to the "List function" theme in the appendix for the detailed list. List provides an effcient method that how to save a mass of relative values. The list functions also can implement the table traversal with high efficiency and read the element. You can create the stronger and more flexible application if you can operate the list proficiently.

Create and query list

List function provides an easy way that how to group the relative items to list, it is a high frequency function in AutoLISP. Each of the element in the list can be the same or different.

command: (setq ls1 (list 1.0 "one" 1 "ZWCAD" "AutoLISP"))
(1.00000 "one" 1 "ZWCAD" "AutoLISP")

If all the elements in the list are constant, this list can be defined by quote function explicitly without having use the list function. quote function returns the expression without having evaluate the value, single quote represents quote function for short. The following code constructs a Three-dimension point, and then assign this Three-dimension point to the variable pt1:

Command: (setq pt1 '(52.0 12.5 0.0))
(52.0000 12.5000 0.000000)

nth function can check the items with specified sequence, the function syntax structure is as below:

(nth index number list)

"index number" specify the sequences of the return values (the first element sequence in the list is 0). The following sample code returns the second item in the ls1.

command: (setq elem2 (nth 1 ls1))
"one"

car function is another way of reading items from list, they can be seen as derivative of car and cdr. car function returns the first element in the list, cdr function returns all the elements in addition the first element by list form.

command: (car ls1)
1.00000
command: (cdr ls)
("one" 1 "ZWCAD" "AutoLISP")

AutoLISP supports for up to four in-depth car and cdr series, such as aaaar, caaadr, caadar, cadaar, cdaaar, caaddr, cadadr, cdaadr, caddar, cdadar, cddaar, caaar, caadr, cadar and cdaar. They are efficient AutoLISP functions and have the same effect as invoking the car and cdr functions embeddedly.

(caar ls1) equal to (car (car ls1))
(cdar ls1)equal to (cdr (car ls1))
(cadadr ls1)equal to (car (cdr (car (cdr ls1))))

A function of the formation of these series often used to handle two-dimensional or three-dimensional point of the table, for example, the following code demonstrates taht how to get the X, Y and Z coordinates from the Three-dimension point list.

command: (setq x_val (car pt1))
52.0000
command: (setq y_val (cadr pt1))
12.5000
command: (setq z_val (caddr pt1))
0.000000

Modify or add list element

AutoLISP provides three functions to modify the current list:

  • append Add new item at the end of the list and return new list
  • cons Add new item at the beginning of the list and return new list
  • subst Replace the found items with new items and return new list.

The above functions do not modify the orignallist and just return the modified list, if you want to modify the original list, you must assign new value to the variable which is used to store te original data explicitly.

append function is acceptable any number of and merges them in a new list, so all the parameters of the functions must be list. The following sample code adds another "ZWCAD" to the ls1, please note that the "ZWCAD" must be translated into list before transmitted to append function:

command: (setq ls2 (append ls1 '("ZWCAD")))
(1.00000 "one" 1 "ZwCAD" "AutoLISP" "ZWCAD")

cons function is used to make the single element in combination with list. cons function could add an element to the beginning of the list. Pleae refer to the below code:

command: (setq ls3 (cons "ZWCAD" ls1))
("ZWCAD" 1.00000 "one" 1 "ZWCAD" "AutoLISP")

subst function is used to replace the same items appeared one or more times. The following code shows us that all the "ZWCAD"strings are translates into "ZWCADSoft" strings:

command: (setq ls4 (subst "ZWSoft" "ZWCAD" ls2))
(1.00000 "one" 1 "ZWSoft" "AutoLISP" "ZWSoft")

Pair translation

There is another way to organize data is using a special type list in ZWCAD: Pair. Pair is a special list and must contain two elements which is divided into period (.). The reason why it is called special list is that an error would appear when obtain the last cdr of this kind of list structure (because the last cdr is not nil), the following code demonstrates this difference:

command: (setq lst '(0 "LINE"))
(0 "LINE")
command: (cddr lst)
nil
command: (setq pair (cons 0 "LINE"))
(0 . "LINE")
command: (cddr pair)
error: error parameter type

We have mentioned that cons function is used to add new items before the first item in the current list, if the second parameter of this function is not list structure, you can create a pair for the function. For example, the following sample code creates a pair relative list:

command: (setq entity (list (cons 'type "circle") (cons 'color 1) (cons 'radius 1.25) (cons 'cenpt '(0.0 0.0 0.0))))
((TYPE . "circle") (COLOR . 1) (RADIUS . 1.25000) (CENPT 0.000000 0.000000 0.000000))

car, cdr and assoc functions are always used to process the pair. The following sample code demonstrates this usage:

command: (setq temp (assoc 'radius entity))　　　　　　;;;get radius of the circle from the dxf list
(RADIUS . 1.25000)
command: (cdr temp)
1.25000


Data Input Functions

Aside from using PAUSE character to wait for user's input through command function, users can also use a number of functions deicated to prompt the user to input data (angle, point, distance, string etc), for example getangle, getcorner, getdist, getint, getkword, getorient and getpoint etc. Please refer to the "Input function" theme in the appendix for detailed list.

getxxx function

All the input functions getxxx will display a prompt information in the command line and pause to waite for users entering the specified type data.

We have mentioned that users need to catch the error and deal with the error when developing the AuoLISP application. When users using the ZWCAD, they can check the trivial error and deal with the error automatically through the ZWCAD error checking functionality in the input functions. Invoking the initget function in advance can provide additional filtering capabilities.

getkword function is used to pause and waite for the users' input keyword of the keyword abbreviation. All the keywords must be defined by initget function before invoking the getword function. All the users input functions (except for getstring)except for the nomal return values can accept the keyword.

The "prompt" parameter in the gerkword function is used to print one record of prompt information, if no the specified parameter, command line would not display any information and not inform to users to input commands. Although the users can inoke the promt or princ functions to print the prompt information, it is not a great way since the print information ("prompt" parameter)would appear again after the gerkwork function checking the illegal input. If there is no the "prompt" parameter and the users' input is illegal, ZWCAD command will print "Does not recognize input. Please try again". Since the original prompt info may not exists in the command prompt area, it would cause confusion.

Condition control for Input function

initget function can implement the low-level control for the next invoked input function. It can accept the following functions: getint, getreal, getdist, getangle, getorient, getpoint, getcorner, getkword, entsel, nentsel and nentselp. getstring is the only one input function which does not accept keyword. The initget function syntax structure rule is as below:

(initget [bit] keyword list)

"bit" parameter specify one or more control code, it is used to control whether permit the type of value for the next input function. "Key list" parameter is used to specify the keyword and its abbreviations. And the next user input function call will be to identify the keyword or its abbreviation.

The control bit and keyword set up by the initget function are effective in the next user input function call. Yet they will have no effect after this function call and the application should not invoke the initget function again to clear the keyword.

We will give the detailed instruction for the usage of "bit" and "keyword list" parameter

  • "bit" parameter

    • This parameter value limits the type of the next user input function, so that narrow the scope of the error checking. If you want to set multiple conditions one time, you can evaluate the sum of these values to get a "bit" value which is between 0 to 255. If do not use the "bit" parameter or set it as 0, the next user input function should not use any control conditions. Please refer to the following code:

    (initget (+ 1 2 4))
    (getreal "\nEnter the weight: ")

    This sample code requests users to input weight, when users try to input negative, zero, string or just press enter, ZWCAD will display the error information and prompt that "Please input weight" again. Please refer to the following code:

    command: (initget (+ 1 2 4))
    nil
    command: (getreal "\nEnter the weight: ")
    Please input weight: a
    Does not recognize input. Please try again.
    Please input weight: -3
    Need positive number. Please try again:
    Please input weight: 0
    Need integer between 1 to 20000.
    Please input weight: 12.5
    12.5000

  • "Keyword list" parameter

    • This parameter specify a keyword sequence, the next user input function call will identify these keywords.

    ZWCAD has the following format requirements for the keyword sequence.

    1. Each of the keyword and the followed keyword are separated by one or multiple blank space, for example, "Radius Perimeter Area" defines three keywords.

    2. Keyword is only composed of letters, numbers and hyphens

    Aside from the complete keyword, initget function also permit secifying the abbreviation of the keyword. When users entering the same string as the key word (no case sensitve) or the keyword abbreviation (case sensitive), the input function will return the pre-defined keyword. There are two types of the keyword abbreviation:

    • Keyword must partly use uppercase letter and the rest are lowercase. The abbreviation of the uppercase letters can be located anywhere (such as "LType", "eXit", "toP")
    • The complete keyword is composed of uppercase letters and there is a comma followed it, and then the abbreviation follow the comma. (such as "LTYPE,LT"). In this situation, the abbreviation of the keyword must contain the first letter of the keyword, that means "EXIT,X" is invalid.

    In the following sample code, the initget function is invoked before the getkword function call, it specifies three keywords. This program will check the keyword and implement the corresponding code:

    (defun c:draw (/ op)
  (initget "Rectangle Circle Line")
  (setq op (getpoint "Rectangle(R)/Circle(C)/<Line(L)>:"))
  (cond
    ((= (type op) 'list) (command "_line" op))
    ((or (= op nil) (= op "Line")) (command "_line"))
    ((= op "Rectangle") (command "_rectangle"))
    ((= op "Circle") (command "_circle"))
  )
  (princ)
)

    The initget function does not limit the next user input function call and build a sequence which contains three keywords "Rectangle", "Circle" and "Line". And then, calling the getkword function to get a string and display the following prompt:

    Rectangle(R)/Circle(C)/<Line(L)>:

    The result will be saved in the local variable op. If the users sketch a point in the drawing area directly, they would permit to continue to draw this line from this point through the judgment of the cond function; If users enter L or lor press enter, they would enter into the line drawing command; If users enter R or r, they would enter into the rectangle drawing command; If users enter C or c, they would enter into circle drawing command.


Geometric Functions

AutoLISP provides angle, distance, inters, osnap, polar and textbox angle Geometric functions which are used in calculating the intersection, angle, distance etc. Please refer to the "Geometric function" theme for the detailed list. This chapter will introduct the detailed usage of osnap and textbox functions.

Function can get the radian value between specified two points connection and X coordinate. (In current UCS)

distance function can get the Three-dimension distance between two specified points, it is similar with the dist command in ZWCAD.

polar function can get a point which has a certain distance and angle relative to the specified point. (Polar)

inters function can get the intersection point of two lines or their extension line.

Object osnap

osnap function can use the ZWCAD object snap mode to snap point. The function syntax rule is as below:

(osnap point mode string)

"point" parameter specifies the snap base point; "mode string" parameter specifies snap mode, the effective osnap contains nea (The nearest point), end (Endpoint), mid(Mid point), cen(Center point), gcen(Geometric center point), per(Perpendicular point), tan(Tangent), qua(Quadrant point), ins(Insert point), nod(Node), int(Intersection point), app(Appearance of the intersection), para(Parallel), ext(Extension).

The following sample code get the closest object endpoint of the pt1:

(setq pt2 (osnap pt1 "end"))

The following sample code get the closest object center point, endpoint or center of circle of the pt1:

(setq pt3 (osnap pt1 "mid,end,cen"))

if there is point matched with the requirement, osnap function would return the point coordinate by the Three-dimension list format; If there multiple points matched with the requirement, the returned value would be determined by the system variable SortEnts setting; If there is no point matched with the requirement, return nil.

Note: when the osnap function implementing the osnap action, the osnap precision is determined by the system variable AperTure which is used to set the object osnap target size.

Text area

textbox function is used to measure the text object (single line text or multiple lines text) tangent border, it returns the bottom left point of the tangent border and the upper right point of the coordinate. The function syntax structure is as below:

(textbox dxf-list)

"dxf-list" parameter is entity definition list, the format of this list is similar with the returned list type of the entget function. This list can contain the completed relation list for text object, and also contain the list described the text contents (group code 1).

textbox function is only used to measure the text object border range, it gives an assumed condition that the bottom left point of text object tangent border is located in (0,0,0) and the rotation angle is 0. The returned value is a relation list which contains two Three-dimension point list and is effected by the text object contents (group code1), font (group code2), height (group code 40), width ratio(group code 410), tilted angle (goup code 51) and the generated text method(group code 71). Therefore, the parameters (entity definition list) in the textbox function should provide these information as more as possible, otherwise the default value would be tested.

The following sample code shows us that transfering an simple entity definition list (only contains group code 1) to the textbox is used to set the text contents. Since there is no specified additional information (font, height, width radio, tilted angle and the generated text method), the current lack of text styles and text height will be measured.

command: (textbox '((1 . "Hello ZWCAD")))
((0.000000 0.000000 0.000000) (25.0000 2.50000 0.000000))

The following sample code shows us that transfering an entity definition list which contains all the additional information (text style is standard, text height is 6.0, width radio is 0.667, rotation angle is 18 degree, reverse text build), measure the text object border.

command: (textbox '((1 . "Hello ZWCAD") (7 . "standard") (40 . 5.0) (41 . 0.667) (51 . 0.314) (71 . 2)))
((-34.7031 0.000000 0.000000) (0.000000 5.00000 0.000000))

The following code could achieve the function that add the text border for the selected single line text object in any UCS.

(defun c:AddTextBox (/ txtobj txtdxf roangle inspt border lbpt rupt)
  (setq txtobj (car (entsel "\nselect text object: ")))
  (setq txtdxf (entget txtobj))
  (setq roangle (/ (* (cdr (assoc 50 txtdxf)) 180.0) pi))
  (setq inspt (cdr (assoc 10 txtdxf)))
  (setq border (textbox txtdxf))
  (setq lbpt (car border))
  (setq rupt (cadr border))
  (command "rectangle" lbpt rupt)
  (command "_move" "L" "" "0.0,0.0" inspt "_rotate" "L" "" "@" roangle)
  (princ)
)


File Handling Functions

AutoLISP provides 17 kinds of file transaction functions including close, findfile, open, read-char, read-line, vl-file-copy, vl-file-rename and vl-mkdir, they are used in file search, reading/writing file, copying fille, creating catalog. Please refer to the "file transaction function" theme in the appendix for the detailed list.

File search

findfile function is used to search the specified file. The function syntax structure is as below:

(findfile filename)

"file name" parameter specified the searched file. If the parameter just specfiies the file name (does not specified the file path), this file would just be searched in the ZWCAD search path; If the parameter specifies the complete path and file name, this file would be searched in the specified ZWCAD search path. If the search succeeded, return the completed file name and path, please refer to the following code:

command: (setq filename (findfile "zwcad.lsp"))
"C:\\Program Files\\ZWCAD 2023 Chs\\zwcad.lsp"

command: (setq filename (findfile "C:\\Program Files\\test.dat"))
"C:\\Program Files\\test.dat"

Note: When you specifying the file path, you must add a backlash before the first backlash or use the a slash (/) as directory separator. Thus, AutoLISP could identify the path name.

getfiled function is used to invoke the ZWCAD standard dialog and displayed the file list in the dialog and the files in the file list are specified extension name in the specified dirctory. The function syntax structure is as below:

(getfiled title default ext flags)

"title" parameter specifies the prompt window title; "default" parameter specifies the default catalog when extending the dialog, if it only contains file name, the prompt window would extend the "desktop" by default; If it contains completed path and file name, prompt window would extend the specified directory; "ext" parameter specifies the default file extension name, if it is blank string, the default value is * (all the file types); "flags" parameter is a flag which is used to set dialog behavior. If the dialog contains the user specified file name, the gefiled would return the string of the specified file name, otherwise would be the nil. The following sample code demonstrates the function usage:

command: (getfiled "Select File" "C:\\Program Files\\test.dat" "dat" 0)
select file dialog

Reading/Writing file

Users must invoke open function to open an existing file before reading or writing the file in AutoLISP. The function syntax structure is as below:

(open file name mode)

"File name" parameter specifies the file needed to open, it generally transfers the findfile function return value; "Mode" parameter specifies the next file operation mode (Read, write, or append). If the specified file exists and the specified operation mode is available, this function returns a file description character, please refer to the following sample code:

(setq filename (findfile "zwcad.lsp"))
(if (null filename)
  (princ "\nThe specified file was not found.")
  (setq fileId (open filename "a"))
)

The above code ahcieves the function that open the zwcad.lsp file in the ZWCAD search path by append:

<File: #785B7428>

We have introducted the princ, prin1 and print functions which can input information to ZWCAD command in the "Input function" theme. The way how to invoke these functions is as below (take the princ function as an example):

(princ string [file description character])

If the file specified by "file decription character" parameter has done, it can write the information to the specified file. Implementing the following sample code and writing the (princ "\nHello, ZWCAD.") in zwcad.lsp file in the ZWCAD search path.

command: (princ "\n(princ \"\\nHello, ZWCAD\")" fileId)
"\n(princ \"\\nHello, ZWCAD\")"
command: (close fileId)

Since the zwcad.lsp file is the automatically loaded LISP file, when the users start the ZWCAD application after running above code, command line will display "Hello, ZWCAD".

write-line function also can write the information to the specified file. The function syntax format is as below:

(write-line string [file description character])

"String" parameter specifies the string which needs to write; "File description character" parameter specifies the file which needs to write. (If there is not the transfered "file descpription characer" parameter or the parameter is nil, this function would input information to the ZWCAD command). Write-line function will add a newline character followed the string automatically after writing a character to specified file unlike the princ, prin1 and print functions. The following sample code has the same functionality as the above code.

command: (write-line "(princ \"\\nHello, ZWCAD\")" fileId)
"(princ \"\\nHello, ZWCAD\")"
command: (close fileId)

(read-line [file description character])

"File description character" parameter specifies the file which needs to read. Repeated implementation of the read-line function can return each line of the contents of specified file line by line, if reached the end of the file, return nil. The following sample code achieves the function that reading the string wrote in above code in zwcad.lsp file from ZWCAD search path.

command: (read-line fileId)
"(princ \"\\nHello, ZWCAD\")"

The following sample code defines a function which is used to add text in the zwcad.lsp file in ZWCAD search path. (Program will travel all the files firstly. If the text already exists, not to add)

(defun AddText (string / IsExist filename fileId txttemp)
  (setq IsExist 0)
  (setq filename (findfile "zwcad.lsp"))
  (if (null filename)
    (princ "\nThe specified file was not found.")
    (progn
      (setq fileId (open filename "r"))
      (if (null fileId)
    (princ "\nOpen file failed.")
    (while (setq txttemp (read-line fileId))
      (if (= txttemp string)
        (setq IsExist 1)
      )
    )
      )
    )
  )
  (close fileId)
  (if (= IsExist 1)
    (princ "\nThis string already exists.")
    (progn
      (setq fileId (open filename "a"))
      (if (null fileId)
    (princ "\nOpen file failed.")
    (progn
      (write-line string fileId)
      (close fileId)
    )
      )
    )
  )
  (princ)
)

Note: When no longer needed to operate the file, be sure to explicitly call the close function to close the file, otherwise it might lead to the expected content of the file is not written correctly, this function accept parameter which is a file description character.


Entity Handling Functions

AutoLISP provides 12 kinds of the object handling functions including the ntsel, nentsel, nentselp, entnext, handent, entget, entdel, entmod, entmake and entupd, they are used in selecting entity, traveling entity, getting entity, getting dxf data of entity, removing entity, updating entity, creating entity etc. Please refer to the "Entity handling function" theme in appendix for the detailed list.

Obtain entity name

In order to operate an entity (such as modify entity color, line types, layers, etc.), you must first obtain the entity name? AutoLISP provides two ways to obtain the entity name:

  • Obtain entity name by interaction

    • AutoLISP provides entsel and nentsel functions to obtain the entity name by interaction, they both require users to interactively pick up point to select single entiy in drawing area, so the entities which are invisible in drawing area or the entities located on the frozen layer cannot be obtained.

    entsel function is only used to obtain entity name for the simple entity, complicated entity (block, old polyline, Three-dimension polyline etc), major entity. The function syntax format is as below:

    (entsel [prompt])

    "Prompt" parameter is used to export the prompt information in command line, if omitted this parameter, the command line would not display any prompt information when the program pause to wait for users selecting entity. If the function has not been invoked and invokes the initget function and set the keyword list, users could enter specified keyword to execute the other operations before selecting the objects. entsel function return value is an association table, please refer to the below:

    (<Entity name: 6140140> (218.919 109.551 0.000000))

    The first element in association table is the entity name for the selected entity, you can obtain it through invoking the car function again; The second element is the pickup point position when selecting the entity, you can obtain it through invoking the cdr function again, some entity operations (ZWCAD command break, tri, and extend etc.) need these information.

    Nentsel function is usually used to obtain entity name in the child entity of the complicated entity (block, old polyline and Three-dimension polyline etc.). The function syntax format is same as the entsel function. It can accept the input keyword. The return value of the nentsel function is also an association table, the following value is the return value after selecting an entity in embedded block:

    (<Entity name: 8018160>
    (5.23647 2.88034 0.000000)
    ((1.00000 0.000000 0.000000) (0.000000 1.00000 0.000000) (0.000000 0.000000 1.00000) (3.20364 2.88034 0.000000))
    ((<Entity name: 8038230>
    <Entity name: 80312e0>
    <Entity name: 8012030>))

    The first element in the association table is the entity name for the selected child entity; the second element is the pickup coordinate when selecting object; the third element is a 4*3 Matrix which is used in coordinate translation (it will be introduced in the following "Matrix translation" chapter), its last element is the inserted point coordinate of the block in current UCS; the fourth element is a table which contains the entity name for all levels of embedded blocks the object in.

  • Obtain the entity name through specifying the parameter

    • In some cases, users want to obtain the special entity name by the silent way in program, for example, obtain the entity name for the newest drawed entity, obtain the entity name of the child entities in block in turn, obtain the entity name of the entity near to one point (the point might be calculated by the program). AutoLISP provides nentselp, entlast and entnext functions to achieve these functionality, they make up the defect that entsel and nentsel function cannot obtain the invisible entity and entity located in the frozen layer.

    Entlast function is used to obtain the entity name for the last entity(Main entity of the simple entity or complicated entity) added to the drawing, no need any of the parameter.

    Entnext function is used to obtain the entity name for the next entity of the specified entity by the list database, the function syntax format is as below:

    (entnext [ename])

    "ename" parameter is used to specify the traversal beginning point, if there is no the parameter, return the entity name for the first entity added in the graphics database, if there is not any of the entity after specifying the entity, return nil. The following sample code demonstrates that how to travel all the entity for the model space:

    (setq curent (entnext))   ;;;get the first entity in dwg database
(while curent
  ;;;other entity handling expression
  (setq curent (entnext curent))
)

    Handent function returns entity name according to the entity handle. ZWCAD can re-assigns the entity name for the entities in the graphics data base when opening the drawing every time. When the entity handles keep consistant with entities added in the graphics database, users can achieve the absolute quote for the entities by handles.

    Nentselp function is similar with the nentsel function, it can also use to obtain the entity name of the child entity for the complicated entity, it just need users to select the entity by interactive operation, the function syntax format is as below:

    (nentselp [prompt] [point])

    "Point" parameter picks up the point coordinate for mouse, it is a Three-dimension or Two-dimension table, if there is no the parameter, it will inform users to select entity by interactive method. This function also can accept the keyword input. The returned value of nentselp function is also an association table, the following code shows us the returned value after selecting the entity in an embedded block:

    (<Entity name: 7fec6f0>
    (304.018 142.767 0.000000)
    ((1.00000 0.000000 0.000000 282.205) (0.000000 1.00000 0.000000 160.614) (0.000000 0.000000 1.00000 0.000000) (0.000000 0.000000 0.000000 1.00000))
    (<Entity name: 7fdc8d0>
    <Entity name: 7fee140>
    <Entity name: 7fdfe00>))

    Same as the returned value of nentsel function, the first element in the association table is entity name of the child entity for the selected entity; the second element is the pickup point coordinate when selecting the object; the third element is a 4*4 matrix used in the coordinate translation (will be introducted in the following section "Matrix transformation"); the fourth element is a list which contains the all levels of the entity name for the embedded block the object in. (from the innermost layer to the outermost layer)

Delete entity

Entdel can delete the specified entity from the drawing area including the invisible entity and the entity cannot be deleted by erase command. The function syntax format is as below:

(entdel entity name)

Note, the function can only remove the simple entity and the major entity of complicated entity. If invoke the function by the same enttiy again, this entity can be recovered in the drawing area.

Obtain the entity data

Entget function return the specified entity dxf data by the list format. The function syntax format is as below:

(entget entity name[application name list])

"Entity name" parameter specifies the entity name for the entity need to be queried, it can be entity or the character list; "application name list" specifies the application names which are belonged to the extension data need to be selected. The returned value of invoking the function to select the line entity dxf data:

((-1 . <Entity name: 7fe5890>) (0 . "LINE") (5 . "12F") (67 . 0) (8 . "0") (410 . "Model") (62 . 256) (6 . "ByLayer") (370 . -1) (48 . 1.00000) (60 . 0) (39 . 0.000000) (10 12.7434 5.04827 0.000000) (11 17.5946 6.80717 0.000000) (210 0.000000 0.000000 1.00000))

The returned value is an association table, each of the element in the table is list or pair and make the dxf group code as the first element for each of the child list or the pair. For example, the group code -1 represents the entity name in the above returned value, group code 0 represents the entity type, group code 5 represents the entity handle, Please refer to the <DXF reference> for each of the dxf group code meaning. The following sample code defines a listen command to invoke the prtdxf function, ist is used to query the dxf data of the selected entity:

(defun c:listen	(/ pickdxf entname pt entdxf enttype op)
  (setq pickdxf (entsel "\nSelect the object:"))
  (setq entname (car pickdxf))
  (setq pt (cadr pickdxf))
  (setq entdxf (entget entname))
  (setq enttype (cdr (assoc 0 entdxf)))
  (if (or (= enttype "INSERT") (= enttype "POLYLINE"))     ;;;the selected entity is block insert or 3D polyline
    (progn
      (initget "Main Sub")             ;;;define the keyword list, determines to print the main entity's or sub entity's data
      (setq op (getkword "\nSelect main entity(M)/<sub entity(S)>: "))
      (if (or (= op "Sub") (null op))
    (prtdxf (car (nentselp pt)))      ;;;get sub entity's name
    (prtdxf entname)
      )
    )
    (prtdxf entname)      ;;;the selected entity is simple entity
  )
  (princ)
)

(defun prtdxf (entname / dxflist elementnum i)        ;;;accept one parameter (entname) to print dxf data of the entity in the form of one group code and its value in each row
  (terpri)
  (setq dxflist (entget entname))
  (setq elementnum (length dxflist))
  (setq i 0)
  (while (< i elementnum)
    (princ (nth i dxflist))
    (princ "\n")
    (setq i (1+ i))
  )
)

Modify entity

Entmod function is used to modify the entity (simple entity, major entity for the complicated entity or the child entity for the child entity), character table. The function syntax format is as below:

(entmod dxf list)

"dxf list" parameter is the entity dxf data, the returned value is same as the entget function's returned value. The method of modifying the entity is that firstly invoke the entget function to obtain the entity dxf data, and then invoke the subst function to modify the elements in the dxf list, finally invoke the entmod function to transmit the modified dxf data to the graphics database. For the simple entity and the major entity of the complicated entity, it can update the entity screen display automatically after transmiting the modified dxf data to the graphics database, however, for the child entity of the complicated entity, after invoking the entmod function to transmit the modified child entity dxf data, users must invoke the entupd function to update the major entity, and then the screen display can be updated. The entupd function syntax format is as below:

(entupd eneity name)

"Entity name" parameter is major entity name for the complicated entity which is needed to update the screen display. Some complicated entities still cannot update the screen display after invoking the entupd such as the embedded block, at this time users need to invoke the command function to execute the regen command. The following sample code defines the chgltype command to modify an entity line:

(defun c:chgltype (/ filedia_old entname dxflist)
  (setq filedia_old (getvar "filedia"))
  (if (tblsearch "ltype" "center")    ;;;judge if "center" linetype has been loaded
    (progn
      (setvar "filedia" 0)    ;;;stop popping up "Select Lintype File" dialog
      (command "linetype" "l" "center" "zwcadiso" "")   ;;;load linetype "center"
    )
    (princ "\nThe linetype has been loaded.")
  )
  (setq entname (car (entsel "\nselect the objects to change linetype: ")))
  (setq dxflist (entget entname))     ;;;get entity's dxf data
  (setq dxflist (subst (cons 6 "center") (assoc 6 dxflist) dxflist))   ;;;modify entity's dxf data, group code 6 represents entity's linetype
  (entmod dxflist)    ;;;return the modified dxf data to dwg database
  (setvar "filedia" filedia_old)   ;;;recove system variable's value
  (princ)
)

When the entmod function modifies the entity attributes related to the character record, such as the line, text style, dimention style and so on. Please ensure that the assigned values of these attributes have effect, for example when you modify the entity line please ensure the line has been loaded otherwise the corresponding attributes cannot be modified. Although the entity layer attribute is related to the character list, it is just an exception. When modifying the entity layer, no need to check that whether the lay is existing or not, if the layer does not exist, ZWCAD would create the layer automatically before modifying the layer attributes.

Create new entity

We have introduced a way of adding entity in graphics database, namely invoking the command function to implement the ZWCAD drawing command to draw entity, but it is an inefficient way, the reason is that it need to analyze the string firstly, and then invoke the ZWCAD command, finally write the data in graphics database. Aside from that, this way of creating the entity cannot create the entity with extension data. Here we introduce a relatively cost-effective approach of adding a new entity graphics database approach which can also create the entity with extension data (will be introduced in the following section "Extension data" ), namely invoke the entmake function, the function syntax format is as below:

(entmake [dxflist])

"dxf list" parameter is entity dxf data same as the returned value for entget function, but it is a incomplete lsit. It must meet the following rules:

  • The first element of the list must specify the entity type, namely the first element must be the pair which is composed of the group code 0 and the entity types.
  • The assigned values for each of the group code must be available (Simliar with the entmod function).

We will introduce that how to invoke the entmake function to create the simple entity (take circle for the example) and the complicated entity (take the un-name block for the example) by the detailed example:

  • Create the simple entity

    • The following sample code created a circle with the center (group code is 10) in (100.0 200.0 0.0), the radius (group code is 40) is 50.0, the line (group code is 6) is "center" and the color (group code is 62) is red. (Assume that the center line has been loaded)

    command: (entmake '((0 . "circle") (10 100.0 200.0 0.0) (40 . 50) (6 . "center") (62 . 1)))

  • Create complicated entity

    • ZWCAD block command cannot create the un-named block, the following sample code defines the MakeUname command to create the un-name block, the operated way is similar with the block command.

    (defun c:MakeUnameBlk ()
  (prompt "\nselect entities to create block: ")
  (setq sset (ssget))
  (setq entnum (sslength sset))
  (setq i 0)
  (setq basept (getpoint "\npick base point: "))
  (entmake      ;;;create block's head
    (list '(0 . "BLOCK") '(2 . "*U") '(70 . 1) (cons 10 basept))
  )
  (while (< i entnum)    ;;;create entities which would be included in block
    (entmake (entget (ssname sset i)))
    (setq i (1+ i))
  )
  (entmake '((0 . "ENDBLK")))     ;;;create block's end
  (while (setq blockdxf (tblnext "block"))   ;;;traverse block table to search the block record created just now
    (setq myblock (assoc 2 blockdxf))
  )
  (entmake (list '(0 . "INSERT") myblock (cons 10 basept)))   ;;;create block insert
  (command "erase" sset "")    ;;;erase entities which are included in the unnamed block
)

    When creating the complicated entity, users need to invoke the entmake function to create each of the child entity. Firstly, invoke the entmake function to create the complicated entity head (such as the block list head), it will create a temporary file to collect the next defined data; secondly invoke the entmake function to create each of the child entity every time, the entmake function must check that whether the temporary file exists of not before adding the entity data to the graphics database, if it exits, add the new child entity to the file, if it does not exist, create a simple entity; finally invoke the entmake function to create the complicated entity tail (namely create the seqend or the entblk child entity) and check that whether the complicated entity head is consistent with the complicated entity tail, if it is legitimate, add the complicated entity to the charater list or display the complicated entity on screen. After finishing to create the complicated entity, the created temporary files wil be removed automatically, users may explicitly invoke the entmake function without parameter to delete the temporary to cancel the complicated entity creating.

Extended data

Every entity has a suite of dxf data which is used to control the entity screen display. AutoLISP provies another suite of the dxf group code which is used to define the entity extended data, they can append more the information after the normal dxf data and not affect the entity screen display. If appending the extended data for the entity could distinguish the professional information of the two lines with the same profile, for example the two lines represent the lighting system wire and power system wire respectly.

Before we learn the steps of adding the extended data for entiy, we must realize the definition way of the structure for the extended data. Dxf group code -1, -2, 0~239 are used to define the normal data for the entity, -3, 1000~1071 are used to define the extended dxf data for the entity, regarding the group code meaning please refer to the "DXF reference". To -3 group code as the first element of an association table that is used to define an extended data for entity, this table is generally located after the normal dxf data, each of the elements in the list are the child lists which contains the registrated application name and the corresponding extension data field. The format is as below:

((-1 . <Entity name: 5ea3840<)
(0 . "LINE")
(5 . "2EE")
(67 . 0)
(8 . "0")
(410 . "Model")
(62 . 256)
(6 . "ByLayer")
(370 . -1)
(48 . 1.00000)
(60 . 0)
(39 . 0.000000)
(10 207.466 86.7622 0.000000)
(11 292.240 122.952 0.000000)
(210 0.000000 0.000000 1.00000)    ;;;all above is common dxf data
(-3                                ;;;all below is Xdata
("ZWCAD"                           ;;;application namw 1
(1003 . "0") (1000 . "AAA"))
("MECH"                            ;;;application name 2
(1000 . "BBB") (1070 . 25)))
)

Before creating the entity with extension data or appending extension data in the existing entity, must ensure that the required application names have been existed in the appid list. AutoLISP provides regapp function to register the applicatin name, the function syntax format is as below:

(regapp application name)

"Application name" could be the random string. If successfully register the name, this application name will be saved in the appid table, if the appid table has been existed in the application needed to register, this function will not add records any more and return nil. The following sample program is that adding the extension data for the selected entity:

(defun c:addxdata ()
  (if (tblsearch "appid" "zwcad_elec")      ;;;check if application name "zwcad_elec" has been registered
    (princ "\nApplication name \"zwcad_elec\" has been registered.")
    (if	(= (regapp "zwcad_elec") nil)      ;;;register application name "zwcad_elec"
      (princ "\nRegister application name failed.")
      (princ)
    )
  )
  (setq entname (car (entsel "\nselect entity to attatch Xdata: ")))
  (setq dxflist (entget entname))
  (setq   ;;;make xdata dxf list, attatch string "lighting lead" and "copper" to the selected entity
    xdatalist '((-3 ("zwcad_elec" (1000 . "lighting lead") (1000 . "copper"))))
  )
  (setq dxflist (append dxflist xdatalist))
  (entmod dxflist)
  (princ)
)

There are two ways to query the extension data for entity:

1. Execute the XDLIST command to display the extension data in command line.

2. Invoke the entget function to query the extension data for entity, please refer to the following code:

command: (entget entname '("zwcad_elec"))
((-1 . <Entity name: 8a93cb0>) (0 . "LINE") (5 . "412") (67 . 0) (8 . "0") (410 . "Model") (62 . 256) (6 . "ByLayer") (370 . -1) (48 . 1.00000) (60 . 0) (39 . 0.000000) (10 376.978 40.3657 0.000000) (11 459.095 122.482 0.000000) (210 0.000000 0.000000 1.00000) (-3 ("zwcad_elec" (1000 . "lighting lead") (1000 . "copper"))))

If the entity contains multiple application names, users could use the wildcard, such as (entget entname (list "*"))


Symbol Table Handling Functions

ZWCAD drawing database contains three kinds of records including the entity (drawing object), symbol table (non-drawing object) and the dictionary. The symbol tables introduced in this section contain appid (application table), block (block table), dimstyle (dimension style table), layer (layer table), ltype (line type table), style (text style table), UCS (users coordinate system table), view (view table) and the vport (view port table). Every table contains zero or multiple records, for example the layer table contains at least one record corresponded to the layer 0, the style table contains at least one record corresponded to the text style "standard".

ZWCAD provides some library functions to handle these symbol tables including tblnext, tblobjname and tblsearch etc. please refer to the section "Symbol Table Handling Functions" in appendix for the detailed list. The functions entget, entmake, entmod and handent which are introduced in the section "Entity Handling Function" can also be used to handle symbol tables. This section will take some examples to introduce how to iterate symbol table and how to get the data of specified record in the symbol table.

Iterate Symbol Table

"tblnext" function is used to iterate the specified symbol table, and its syntax is shown as below:

(tblnext table-name [rewind])

"table-name" parameter is used to specify the symbol table to iterate, the available symbol table contains appid (application table), block (block table), dimstyle (dimension style table), layer (layer table), ltype (line type table), style (text style table), UCS (users coordinate system table), view (view table) and the vport (view port table); if the "rewind" parameter is omitted or is set to nil, where this function would iterate the records from depends on whether "tblsearch" function resets the iteration's starting point (if resetting, "tblnext" function would iterate the symbol table from the new starting point, otherwise from the last "tblnext" calling). If the "rewind" parameter is specified and is non-nil value, the function would iterate the symbol table from its first record.

"tblsearch" function is used to query the special record in the specified symbol table, and its syntax is shown as below:

(tblsearch table-name item [setnext])

If the "setnext" parameter is set to non-nil value, when calling "tblnext" function without "rewind" parameter to iterate the same symbol table, the iteration would start from the next record of the item specified by "item" parameter.

Get the data of specified record

"tblnext" and "tblsearch" functions' return values are both dxf lists, they are similar with the return value of "entget" function, but "entget" function's return value is more detailed. Generally, users need to invoke "tblonjname" function to get the entity name of the record in symbol table, and then invoke "entget" function to get its detailed dxf data. The following sample codes define the "statsColor" command to count the types of the color used by all entities in the whole drawing database and count the amount of all entities basing on their colors. When handling the entity whose color is "bylayer", the program needs to get its color from the dxf data of corresponding layer record in layer table:

(defun c:statsColor (/ colorstatslist colorstatslist_1
             sset entnum i j entname
             dxflist  entcolor layername layercolor
             colornum string curcolor entqty
            )
  (setq colorstatslist nil)
  (setq	sset (ssget "X"       ;;; filter out dimension and block insert
            '((60 . 0)
              (-4 . "<not")
              (-4 . "<or")
              (0 . "DIMENSION")
              (0 . "INSERT")
              (-4 . "or>")
              (-4 . "not>")
             )
         )
  )
  (setq entnum (sslength sset))
  (setq i 0)
  (while (< i entnum)
    (setq entname (ssname sset i))
    (setq dxflist (entget entname))
    (setq entcolor (cdr (assoc 62 dxflist)))
    (if (or (null entcolor) (= entcolor 256))
      (progn          ;;; entity's color is bylayer
         (setq layername (cdr (assoc 8 dxflist)))
         (setq layercolor
            (cdr (assoc 62 (tblsearch "layer" layername)))    ;;; get dxf data of entity's layer
         )
         (setq entcolor layercolor)
      )
    )
    (setq colorstatslist (append colorstatslist (list entcolor)))     ;;; save all used colors' index value to "colorstatslist" variable
    (setq i (1+ i))
  )
  (setq colorstatslist_1 (vl-sort colorstatslist '<))       ;;; filter out repeating color index value from "colorstatslist" list, and set the result to "colorstatslist_1" variable
  (setq colornum (length colorstatslist_1))
  (princ (strcat "\nThere're " (itoa colornum) " colors used in the drawing."))
  (prompt "\nThe statistical data is shown in the following table: ")     ;;; start iterating "colorstatslist" and "colorstatslist_1" list to count used colors
  (setq j 0)
  (setq string "\ncolor\tentity's num\n")
  (while (< j colornum)
    (setq entqty 0)
    (setq i 0)
    (setq curcolor (nth j colorstatslist_1))
    (while (< i entnum)
      (if (= (nth i colorstatslist) curcolor)
    (setq entqty (1+ entqty))
      )
      (setq i (1+ i))
    )
    (setq
      string (strcat string (itoa curcolor) "\t\t" (itoa entqty) "\n")
    )
    (setq j (1+ j))
  )
  (setq sset nil)
  (princ string)
  (princ)
)


Selection Set Handling Functions

ZWCAD provides 9 AutoLISP library functions to handle selection set including ssadd, ssdel, ssget, sslength and ssname etc. Please refer to the section "Selection Set Handling Functions List" in appendix for the detailed list, this section will take some examples to introduce how to use "ssget" function.

Selection mode

There are multiple kinds of selection mode existing when executing ZWCAD command "select" to select entity, for example, ALL / Add / Remove / Previous / Last / Window / Crossing / Outside / WPolygon / CPolygon / OPolygon / WCircle / CCircle / OCircle / Box / POint / Fence / AUto / Multiple / Single / PROperties / Dialog. "ssget" function is the most basic method to create selection set in AutoLISP programming, its syntax is shown as below:

(ssget [mode] [pt1 [pt2]] [pt-lst] [filter-lst])

Setting different "mode" parameter can achieve part of the selection mode provided by "selection" command, the available values of "mode" parameter and its selection effects are shown in following table:

Mode parameter | Selection effect
omitted | It is similar with the "AUto" mode provided by "selection" command. If "pt1" or "pt2" parameter is omitted, this function prompts "select object" in ZWCAD command bar and allows users to select entities interactively by multiple times; If "pt1" or "pt2" parameter is specified, this function adds the entity at the point to selection set.
C | It is similar with the "Crossing" mode provided by "selection" command. It needs to specify the parameter "pt1" and "pt2", as long as any part of the entity is in the rectangular box enclosed by a rectangle which takes the points "pt1" and "pt2" as its two corner points, it will be added to selection set.
CP | It is similar with the "CPolygon" mode provided by "selection" command. It needs to specify the parameter "point-lst", as long as any part of the entity is in the polygon box enclosed by all lines defined by any two contiguous points of the points list provided by "point-lst" parameter, it will be added to selection set.
F | It is similar with the "Fence" mode provided by "selection" command. It needs to specify the parameter "point-lst", all the entity which intersects the lines defined by any two contiguous points of the points list provided by "point-lst" parameter would be added to selection set.
I | Implied selection (just when the system variable "PICKFIRST" is set to 1, this selection mode takes effect), it is suitable for selecting entities first and then calling this function to create selection set.
L | It is similar with the "LAST" mode provided by "selection" command. Last visible object would be added to selection set.
P | It is similar with the "Previous" mode provided by "selection" command. Returns the previous selection set.
W | It is similar with the "Window" mode provided by "selection" command. It needs to specify the parameter "pt1" and "pt2", only the entities which are located entirely in the rectangular box enclosed by a rectangle which takes the points "pt1" and "pt2" as its two corner points would be added to selection set.
WP | It is similar with the "WPolygon" mode provided by "selection" command. It needs to specify the parameter "point-lst", only the entities which are located entirely in the polygon box enclosed by all lines defined by any two contiguous points of the points list provided by "point-lst" parameter, it will be added to selection set.
X | It is similar with the "ALL" mode provided by "selection" command. All entities including entities on layers that are off, frozen, and out of the visible screen would be added to selection set.
:S | Only allow to select entity through the smartsnap marker, its effect is similar with the "entsel" function

Although the parameters "mode", "pt1", "pt2", "point-lst" and the "filter-list" are all optional, they depend on each other. As introduced in above table, if the parameter "mode" is set to "C" or "W", you should provide the parameters "pt1" and "pt2"; If the parameter "mode" is set to "F", "CP" or "WP", you should provide "point-lst" parameter; If the parameter "mode" is set to "I", "L" or "P", you could not provide the parameters "pt1", "pt2" and "point-lst". The parameter "filter-lst" is suitable for any of above selection modes. Using the filter list to select entities is similar with ZWCAD "qselect" command.

Selection set filter list

User can make sure the selection range through setting the selection mode, however, it's not enough when we only want to add some specified kinds of entities in an area to selection set especially there are too many various entities distributing confusedly in this area. In this case, we need to set the filter list to filter the entities in the area again. Filter list is a dxf list and its format is similar with the return value of "entget" function. If it contains the entity name (dxf code -1), handle (dxf code 5) and the xdata (any dxf code more than 1000), they would be ignored automatically, namely the "ssget" function cannot select the entities with the specified entity name, handle and xdata.

The following sample code shows some methods of creating selection set through the simple filter conditions:

Sample code | Selection effect
(ssget '((0 . "LINE"))) | prompt user to use multiple interactively select entities by "window" or "crossing" mode, but just add the line entity in the selection area to the selection set
(ssget "X" '((0 . "LINE") (62 . 1))) | Add the line entity with red color in the entire drawing database to the selection set

Although user cannot use xdata as the filter condition to create selection set, they still use the application name which contains the xdata as the filter condition. For example, executing the following sample code to add all the line entities with the application name "ZWCAD_ELEC" in the entire drawing database to the selection set:

command: (ssget "X" '((0 . "LINE") (-3 ("ZWCAD_ELEC"))))

If user wants to add the entities which contain two application names ("ZWCAD_ELEC" and "ZWCAD_MECH") to the selection set, they should invoke the "ssget" function in the following way:

command: (ssget "X" '((0 . "LINE") (-3 ("ZWCAD_ELEC") ("ZWCAD_MECH"))))

If user wants to add the entities which contain the any one of the two application names ("ZWCAD_ELEC" or "ZWCAD_MECH") to the selection set, they should invoke the "ssget" function in the following way:

command: (ssget "X" '((0 . "LINE") (-3 ("ZWCAD_ELEC, ZWCAD_MECH"))))

User can use the wildcard, relational operators or logical operators in the filter list to set more complex filter conditions.

  • Use wildcard in filter list

    • Using wildcard in the filter list is similar with using wildcard in the "wcmatch" function. Executing the following sample code to add the texts or mtexts whose content (dxf code 1) satisfies the rule: starting with the word "Door" and there is only one number following the word to the selection set.

    command: (ssget "X" '((1 . "Door[0-9]")))

    Please note that, the unnamed block's name is defined as "*Unnn", the asterisk (*) can also be used as wildcard (representing uncertain number of characters). How to add the unnamed block with the name "*U1" to the selection set? Please refer to the below:

    command: (ssget "X" '((2 . "\*U1")))

    As shown above, if adding unnamed block to selection set by its block name, user needs to add a backslash (\) before the asterisk (*) in order to shield asterisk wildcard in the filter list. Actually, using unnamed block's name as the filter list is of little practical significance, because the name of unnamed blocks in the drawing would be assigned again during different editing task. Here we just shows how to use the backslash (\) to shield the asterisk (*) wildcard in filter list.

  • Use relational operators in filter list

    • The relational operators can be used in filter list include * (constant equal), = (equal to), != (not equal to), /= (not equal to), <> (not equal to), < (less than), <= (no more than), > (more than), >= (no less than), & (bitwise and) and &= (bitwise xor). If there is not the specified any relational operator, all the elements in the filter list will be tested by the equal operator. The above relational operators can't be used in filter list unless constructing its string form and dxf code -4 to dotted pair. For example, executing the following sample code to add the visible entities (dxf code 60) whose radius (group code 40) is more than 10.0 to the selection set.

    command: (ssget "X" '((0 . "CIRCLE") (60 . 0) (-4 . ">") (40 . 10.0)))

    If taking entity's feature points (dxf code 10 and 11) as the filter list, since they are the 2D or 3D point, user may make three relational operators to a string and constructing a dotted pair with dxf code -4 as the filter list to check each element of the point list, for example, executing the following sample code to add all 3D line entities whose starting point and end point's Z coordinate is zero to the selection set:

    command: (ssget "X" '((0 . "LINE") (-4 . "*,*,/=") (10 0.0 0.0 0.0) (-4 . "*,*,/=") (11 0.0 0.0 0.0)))

  • Use logical operator in filter list

    • The logical operators used in filter list must appear in pair, same as the logical functions provided by AutoLISP, the operators of each logical operator group must be the expression whose return value is True or False in the filter list. The logical operators can be used in filter list include "<and" (logical and), "<or" (logical or), "<xor" (logical xor) and "<not" (logical not), the corresponding close operators are "and>", "or>", "xor>" and "not>". If there is not the specified logical operator in the filter list, all the elements in the list should be tested by the operators "<and" and "and>". The above logical operators can't be used in filter list unless constructing its string form and dxf code -4 to dotted pair. Executing the following sample code to add the line entities and circle entities in the entire drawing database to the selection set:

    command: (ssget "X" '((-4 . "<or") (0 . "LINE") (0 . "CIRCLE") (-4 . "or>")))

    User can also use logical operators in the filter list to add the entity which contains any one of the two application names ("ZWCAD_ELEC" or "ZWCAD_MECH") to the selection set. Please refer to following code:

    command: (ssget "X" '((0 . "LINE") (-4 . "<or") (-3 ("ZWCAD_ELEC")) (-3 ("ZWCAD_MECH")) (-4 . "or>")))

Operate Selection set

The following will mainly introduce how to add entity to an existing selection set, how to remove some entity from selection set and how to release a selection set.

"ssadd" function is used to add the specified entity to a specified selection set, its syntax is shown as follows:

(ssadd [ename[ss]])

If the parameters "ename" and "ss" are omitted, this function would created a new blank selection set. It is different from the "ssget" function. Although "ssget" function can also be used to create a selection set, it will not create selection set (return nil) when there is nothing matched with the filter conditions in the specified area.

"ssdel" function is used to remove the specified entity from a selection set, its syntax is shown as follows:

(ssdel ename ss)

If the specified entity does not exist in the selection set, the function returns nil without any error information.

Releasing the selection set is an important topic which could usually be ignored. Since the selection set could consume ZWCAD's temporary file memory block, AutoLISP does not permit opening more than 128 selection sets. If the number of selection sets reaches the limit, ZWCAD will refuse to create new selection set and only return nil in the next "ssget" function calling. We suggest releasing the selection sets which you won't need any more. Setting the selection set to nil could release it. Please refer to below:

command: (setq sset nil)


Dictionary Handling Functions

Dictionary is a container object, it is same as symbol table on the function. Each dictionary item is composed of a keyword string and the handle of the dictionary object containing this item. AutoLISP provides dictsearch and dictnext function to query the specified keyword of dictionary, dictadd and entmakex function to add new dictionary or add new record to an existing dictionary. Please refer to the section "Dictionary Handling Functions" in appendix for the detailed list.

Read dictionary data (Access Group)

The group data in the drawing is saved in the dictionary whose name is "ACAD_GROUP", each group's name is used to the keyword in the dictionary. The handle of the "ACAD_GROUP" dictionary object and the handles of all the entities in the group are saved in the keyword. The following sample codes define a function "chggpcolor" to change the color of all the entities in a specified group to another specified color:

(defun chggpcolor (gpname color / gpdict gprecord gpdesc dxflist)
  (setq gpdict (cdar (dictsearch (namedobjdict) "ACAD_GROUP")))    ;;; get the dictionary "ACAD_GROUP"
  (if (null (setq gprecord (dictsearch gpdict gpname)))    ;;; get the dictionary item including gpname
    (progn
      (princ (strcat "\n" gpname " group didn't exist."))
      (exit)
    )
    (progn
      (setq gpdesc (cdr (assoc 300 gprecord)))
      (setq i 0)
      (repeat (length gprecord)   ;;; iterate the dictionary item including gpname
    (if (= (car (nth i gprecord)) 340)   ;;; dxf code 340 represents the name of entity in group
      (progn
        (setq dxflist (entget (cdr (nth i gprecord))))
        (setq dxflist
           (subst (cons 62 color) (assoc 62 dxflist) dxflist)
        )
        (entmod dxflist)
      )
    )
    (setq i (1+ i))
      )
      (princ (strcat "\nThe colors of all entities in the group with "
             groupdesc
             "description have been changed."
         )
      )
    )
  )
  (princ)
)

Open a drawing including "test" group, and enter the expression (chggpcolor "test" 1) in ZWCAD command bar, the color of all the entities in the "test" group would be changed to red.

Write data to dictionary

Writing the non-drawing information such as production name, material and the production company in the dictionary is quite useful for reading the drawing information by PDM. The following sample codes define the "writeprodinfo" function to write production size, material, weight, factory, address, phone number, and contact person's name in the dictionary:

(defun writeprodinfo (size material weight factory address phonenum contactPerson
              /	productdict Dict XRecord xname prodinfoXrcd factinfoXrcd
             )
  (setq productdict (cdar (dictsearch (namedobjdict) "ZWCAD_PRODUCT")))
  (if (null productdict)     ;;; determine if the "ZWCAD_PRODUCT" dictionary exists or not
    (progn
      (setq Dict
         (list '(0 . "DICTIONARY") '(100 . "AcDbDictionary"))
      )
      (setq xname (entmakex Dict))    ;;; create "ZWCAD_PRODUCT" dictionary
      (setq productdict
         (dictadd (namedobjdict) "ZWCAD_PRODUCT" xname)    ;;; attach the "ZWCAD_PRODUCT" dictionary to the drawing database
      )
    )
  )
  (setq prodinfoXrcd (dictsearch productdict "PRODUCT_INFOMATION"))
  (if (null prodinfoXrcd)	  ;;; determine if the "PRODUCT_INFOMATION" xrecord exists or not
    (progn
      (setq XRecord
         (append (list '(0 . "XRECORD") '(100 . "AcDbXrecord"))
             (list '(300 . "SIZE")
               (cons 300 size)
               '(300 . "MATERIAL")
               (cons 300 material)
               '(300 . "WEIGHT")
               (cons 300 weight)
             )
         )
      )
      (setq xname (entmakex XRecord))	    ;;; create the "PRODUCT_INFOMATION" xrecord
      (dictadd productdict "PRODUCT_INFOMATION" xname)	   ;;; attach the "PRODUCT_INFOMATION" xrecord to "ZWCAD_PRODUCT" dictionary
    )
  )
  (setq factinfoXrcd (dictsearch productdict "FACTORY_INFOMATION"))
  (if (null factinfoXrcd)	;;; determine if the "FACTORY_INFOMATION" xrecord exists or not
    (progn
      (setq XRecord
         (append (list '(0 . "XRECORD") '(100 . "AcDbXrecord"))
             (list '(300 . "FACTORYNAME")
               (cons 300 factory)
               '(300 . "ADDRESS")
               (cons 300 address)
               '(300 . "PHONENUMBER")
               (cons 300 phonenum)
               '(300 . "CONTACTPERSON")
               (cons 300 contactPerson)
             )
         )
      )
      (setq xname (entmakex XRecord))   	;;; create the "FACTORY_INFOMATION" xrecord
      (dictadd productdict "FACTORY_INFOMATION" xname)	;;; attach the "FACTORY_INFOMATION" xrecord to "ZWCAD_PRODUCT" dictionary
    )
  )
  (princ)
)

Creating a new drawing or open an existing drawing in ZWCAD, enter the expression (writeprodinfo "12cm*30cm*45cm" "copper " "158.6kg" "ZWSOFT CO., LTD.(Guangzhou)" "Room 01-08, 32/F, No.15, Zhujiang West Road, Tianhe District, Guangzhou 510623, China" "020-38289780" "Kevin") to write the information about the production and its supplier to the dictionary (suggest viewing the dictionary date with "OdaMfcApp.exe").


Query Functions

AutoLISP provides 6 kinds of the inquiry functions including getenv, getvar, setenv and setvar which are used to check and modify the operate system environment, ZWCAD environment or the ZWCAD system variable value. Please refer to the "Inquiry function" theme in appendix for the detailed list.

Check and set the system variable

Setvar function specifies the value according to the system variable types. ZWCAD system variable contains the following types: integer, real number, string, Two-dimension point and Three-dimension point. Some of system variables are saved in the registry, some are efficient in the current editable task. Once restarting the ZWCAD application, the system variables would be restored into the initial value (such as undoctl, clayer etc.). Users need to modify some system variables to serve the application when programing LISP, and after finishing the application, these modified system variables should be restored into to status before running the program, this requires saving the original value before the modification. Please refer the following code.

(setq oldcecolor (getvar "cecolor"))
(if (/= oldcecolor "1")
  (setvar "cecolor" "1")
)
(setq oldceltype (getvar "celtype"))
(if (/= oldceltype "center")
  (setvar "celtype" "center")
)

The effection of above code is that recording the color and line in the oldcecolor and oldceltype variables respectly for the current new object, and then set the new object's color is red, linear for the center. (Make sure that the center line has been loaded). The similar operations that saving and setting the system variable will be implemented at the beginning of the program.

(setvar "cecolor" oldcecolor)
(setvar "celtype" oldceltype)

The effection of the above two lines of code is that recovering the new object color and line according to the oldcecolor and oldceltype variable values. The similar operations that saving and setting the system variable will be implemented at the end of the program

Check and set the environment variable

Setenv function must use the string to specify the variable values, the ZWCAD environment variable will be saved in registry HKEY_CURRENT_USER\Software\ZWSoft\ZWCAD\2023\en-US\Profiles\Default\Config, if the ZWCAD environment variable has been existed in the registry, modify its value.

Getenv function is used to get the operate system or ZWCAD environment variable, the checking sequence is: search in the registry key value HKEY_CURRENT_USER\Environment firstly, return the corresponding value in this key, otherwise return nil.


Command Functions

AutoLISP provides 7 kinds of command function including command and vl-cmdf which can invoke the inner ZWCAD command to draw, it is the most common communication way between the AutoLISP and ZWCAD. The running way of the command function is similar with implementing the same command in ZWCAD, but is a command-line approach to implement user interaction, rather than the dialog box method. Please refer to the "command function" theme in appendix for the detailed list.

Command commited

Command function sends out a ZWCAD command and the response sequence directly for this ZWCAD command. Command function has a variable length parameter list, these parameters must keep consistent with the command prompt response type and value for the command request sequence: They can be strings, real numbers, integers, point coordinates, pixel name and choice set name. Angle, distance and point coordinates can be transmitted either by strings or by digital method (integer, real number or point list). The effection of an empty string ("") is equivalent to pressing the spacebar on the keyboad.

The following sample code shows typical usage of command functions:

(command "line" "10.2,12.3" "@10<30" "")
(command "textstyle" "standard")
(setq pt1 '(100.0 100.0 0.0))
(command "circle" pt1 "6.0")

Implement the above code in the ZWCAD command prompt character, the following operation would be carried out:

1. The first command function call will transmit the point coordinate (absolute coordinates and relative coordinates) to the line command by the string format (Draw a line, the length of the line was 10.0, with the current UCS under the X-axis positive direction into the 30-degree angle)

2. The second function call will transmit the first string to the textstyle command (set the current text type as standard)

3. The last command function call will transmit a Three-dimension to circle command by the variable format. Draw a circle with the circle point at (100.0, 100.0, 0) and the radius of 6.0.

Pause to wait for input

If the ZWCAD command meets the pre-defined character PAUSE which is regarded a command function parameter during the ZWCAD command operation, ZWCAD would pause the command operation(command function is in a pending state) to wait for users's input (Usually select points, or drag). This feature is similar with the backlash(\) mechanism provied in the file menu. When the users get the efficient input, command fuction would continue to run.

When the command function is in the pending status, If you send a clear order, command functions will continue to maintain a pending state, and then the users could use the _nea, _mid commands to set the temporary snap point when pausing the command. For example, the following code firstly run the circle command to draw a 6.0 radius of circle, secondly, run the move command and use the circle center as the base point for moving, and then pause the command to let users specify the new circle center. When the users specifying the required point, continue to run the command to draw hexagon with the circle tangent. Please refer to the below:

command: (command "circle" "0,0" 6.0 "move" "L" "" "@" pause "polygon" 6 "@" "C" 6.0)

If the users meet the PAUSE when inputing the string or property, ZWCAD just pauses to wait for input when the TextEval system variable is not zero. Otherwise, ZWCAD does not wait for user input and the PAUSE symbol will be resolved to a backslash (\) as the text content. Please refer to the below:

command: (command "-text" "10.2,15.3" "5.0 "0.0" PAUSE)

When the command functon pausing to waite for the input, this function is still active. So the users should not input another AutoLISP expression to get evaluation.

If the command function specifies PAUSE to the select command and the system variable PickFirst is setting as ON, ZWCAD will be suspended to await the user to select entities when the current selected set is not empty, otherwise will not pause and transmit the former selected set entities to select command.

Abandon the implemented command in Command function

ZWCAD will create individual undo group for each of the running command function. If the users enter the U command after running AutoLISP program, it will abandon the last line of the command but not the whole command sequences from the command function call (might contain mutiple ZWCAD inner command); if the users implement the U command for multiple times, it will abandon the ZWCAD inner command from the command function call. If users want to ahcieve the function that all the ZWCAD inner command can be abandoned after implementing U command only once, they should use "Start" and "Finish" options of the undo command. Please refer to the following sample code:

command: (command "undo" "be") (command "circle" "0,0" 6.0 "move" "L" "" "@" pause "polygon" 6 "@" "C" 6.0) (command "undo" "end")

This usage is often used to recover the drawing environment and remove the un-finished drawing after the * error * function capturing errors.


Error Handling Functions

Auto LISP provides 21 kinds of the math functions including alert, *error*, exit, quit, vl-catch-all-apply, vl-catch-all-error-p and vl-catch-all-error-message which are used to catch errors, provide the relative error information, recover the ZWCAD drawing environment and skip the error to continue the program. Please refer to the "Error handling function" theme in the appendix for the detailed list.

Use *error* function

Using the *error* function corrctly can insure that ZWCAD could return the special status when encountering some errors. If do not define the *error* function or just define the "nil", AutoLISP would stop implementing the LISP expressions and print the error information and display the incorrect the LISP code, for example, implenting the following code:

command: (+ 12 "a")
error: incorrect parameter type
(+ 12 "a")

The +(sum) function requires integer or real number parameter, but the above code transmits the second parameter is string, so ZWCD checks error and returns the error information and error code. This is more useful in debugging program.

The newest error number will be saved in the ZWCAD system variable ERRNO and can be searched by the getvar function. Regarding the error number and the meaning, please refer to the appendix "AutoLISP error number". Please note that this variable will be cleared out once a drawing is started, otherwise will not be cleared out. So users easily give rise to misunderstanding for the error represented by the saved error number.

Before defining the *error* function, please save the *error* current contents, it can recover the original error handling program when exiting. If there is error existed, ZWCAD would invoke the current defined *error* function and transmit a parameter, this parameter is a text string which is used to describe the error property. *error* functon should be designed to ahcieve the some behaviors as below, it should cancel the functin call when users pressing the ESC or implement the silent exit by the exit function. (do not display the error information). The standard method of achieving this function is that adding the following sentences in the customized *error* function:

(if (or	(= msg "Function cancelled")            ;;;user press ESC to cancel current command
    (= msg "quit / exit abort")    ;;;invoke exit function to abort current LISP program
    )
  (princ)
  (princ (strcat "\nError: " msg))
)

This code checks the transmitted error information and notifies the error type to users. If users press ESC to cancel the program when running the AutoLISP or invoke the exit function, this code would not return any contents.

The main problem caused by this error handling is that *error* function is also the usual AutoLISP function which might be canceled by users. Therefore, the error handling function should be made as short as possible, and do not contain interactive function call.

Use warning dialog

Alert function is used to prompt the little dialog only with "OK" button, it can be used to inform the user of the error condition occurs. The following sample code will display a warning dialog:

command: (alert "Enter a positive integer!")
alert dialog

Catch error and continue to implement program

In the most situation, capturing the application error and notifying the error message are not enough, users' application should capture the error and continue to implement the program in terms of the error type. vl-catch-all-apply function can invoke any of the functions and the return values and capture errors that may occur. Calls the function syntax is as below:

(vl-catch-all-apply 'function name table)

"Function name" parameter specifies a function under test or the lambda expression; "list" parameter specifies a parameter list which is transmitted to the function under test. The following sample code uses vl-catch-all-apply function to implement the connection between the two strings:

command: (setq catchit (vl-catch-all-apply 'strcat '("Chinaweal" " " "Longteng")))
"Chinaweal Longteng"

The result of this sample code is same as the result of using apply function to invoke strcat function, however, vl-catch-all-apply can capture the errors and apply functon cannot work.

The following is a sample program, it ahchieves to connect the two strings(or string and integer) and return the merged new string functionality, it also demonstrates the incorrect way of capturing errors by vl-catch-all-apply and vl-catch-all-error-p functions.

(defun NewCat (arg1 arg2 / catchit)
  (setq catchit (vl-catch-all-apply 'strcat '(arg1 ", " arg2)))
  (if (vl-catch-all-error-p catchit)
    (strcat (vl-princ-to-string arg1)
        ", "
        (vl-princ-to-string arg2)
    )
    catchit
  )
)

Now, use the following sample code to invoke function.

command: (NewCat "Chinaweal" "Longteng")
"Chinaweal, Longteng"
command: (NewCat "ZWCAD" 2023)
"ZWCAD, 2023"

If change the vl-catch-all-apply function to the apply function and then load an run the connection string and integer code, the program would be pending after "apply" mistaking. Invoke the *error* function and return the error information. Please refer to the below:

command: (newcat "ZWCAD" 2023)
command: wrong parameter type


Working with ActiveX Objects

We use the ActiveX object to develop the applications in LISP, they pack each of the ZWCAD entities as the objects. While using the AutoLISP to develop the applications is based on the list operation, the relationship between them is similar with the development modes relationship between Object-oriented and process-oriented. In the AutoLISP, we call the ZWCAD graphics objects as the entities, but they are called VLA objects in the ActiveX. The chapter mainly contains the following contents:

  • ActiveX Object Introduction
  • Invoke Active X Object's Method
  • Get and Set ActiveX Object's Property
  • Working with Collection Objects
  • ActiveX to Interact with Other Applications


ActiveX Objects Introduction

Using the Active X object to develop program in the LISP can pack the ZWCAD entities to the objects. However, using the AutoLISP to develop the program based on the list operation, they are Object-Oriented mode and Process Oriented mode respectly. In the AutoLISP, we called each of the ZWCAD graphics object is entity, but called them is VLA object in the ActiveX. When users generally operating the ZWCAD graphics, ActiveX is faster than the traditional AutoLISP function and the application source code has the better readability and the more convenient maintenance. For example, the following sample code uses the AutoLISP function to get the entity color:

(setq color (cdr (assoc 62 (entget ename))))

Firstly invoke the entget function to get the entity dxf list, and then invoke the assoc function to search the element in where the group code represents the colors and invoke the cdr function to get the group code value, actually travel the link list. You need to know the relative group code for the searched features, next we will use the COM object to modify the above code:

(setq color (vla-get-color vla-obj))

Only need to to invoke the vla-get-color function, it packs all the detailed information.

If you want to use Active X object in the ZWCAD, you must firstly invoke the vl-load function to initialize the ActiveX environment. vl-load-com function firstly check that whether the function supported by the COM object has been loaded or not, if it has been loaded, do not implement any of the actions, otherwise will load the function supported by the Active X object and the other assist functions and there is no return value.


Invoke ActiveX Object's Method

This section will take a circle as an example to introduce that how to invoke the method of Active X object, this example creates circle with the circle center in (120.0 130.0 0.0) and the radius is 53.0 in the mode space.

Determine which method of the ActiveX object is called

We have introduced that how to list the attribute and method of the Active X object through the vlax-dump-object, but they are just some method name. Program goal is to draw a straight line, we can know that line object has some upper objects including the Block, ModelSpace and PaperSpace from the ZWCAD, users need to get the ModelSpace object firstly, and then click on the ModelSpace object in the ZWCAD object model to enter into the detailed introduction page of the ModelSpace, please refer to below:

ModelSpace collection object's introduction

The above page lists the "ModelSpace" object supported event, method and the attributes, click on the "AddCircle" hyperlink in the "Methods" list to enter into the detailed introduction page. Please refer to the below:

It tells the user "AddCircle" approach is the role of "Creates a circle given a center point and radius.", therefore, the "AddCircle" is the required method.

Invoke the syntax of the Active X object method

The above page shown that the AddCircle syntax of the method is defined as follows.

RetVal = object.AddCircle(Center, Radius)

For the LISP users, the syntax is very strange, the reason is that it is defined for the Visual Basic users, but as long as understanding the meaning of the description expression can be comprehend by analogy. One object is the model space, paper space, or block a collection of objects; Center represents the circle center of the circle, the data type is vla-object; Radius represents the radius of the circle and it is a positive number with the double percision; return value is the created object, the data type is vla-object.

After understanding of using Visual Basic to describe the syntax of AddCircle method, the following two things need to be done:

1.Paraphrasing the sentences in the Visual Basic to the LISP expression.

2.Translate the AutoLISP data into the required data type of the Active X

In the ZWCAD, there are two ways to invoke the method of the Active X, the syntax format is as follows:

1.(vlax-invoke-method vla object method name parameter1 [parameter2…])

2.(vla-method name vla object parameter1 [parameter2…])

In the ZWCAD object model, Model Space object is the upper level object of the line object, ModelSpace is the first parameter and the Center and Radius are the rest of the parameter for that method. vlax-3d-point is the ActiveX function provided by the LISP and it is used to translate the AutoLISP Three-dimension point into the Visual Basic as described above AddCircle method call syntax used LISP expression is as below:

(setq circleObj (vla-AddCircle mspace (vlax-variant->vla-object (vlax-3d-point (list 120.0 130.0 0.0))) 53.0))

or (setq circleObj (vlax-invoke-method mspace 'AddCircle (vlax-variant->vla-object (vlax-3d-point (list 120.0 130.0 0.0))) 53.0))

One mspace is the ModelSpace object, to obtain the object's expression is as follows:

(setq *ZWCADObject* (vlax-get-zwcad-object))

(setq *CurDoc* (vla-get-ActiveDocument *ZWCADObject*))

(setq mspace (vla-get-ModelSpace *CurDoc*))

The parameter transfer fo invoking the Active X object method

The key of using the Active X object in the LISP is that paraphrasing the syntax structure described by the Visual Basic to the LISP expression, please refer to above example, the translation relationship between them is as below:

VBA and LISP syntax translation

We can say that all the Active X method description in the Visual Basic can paraphrase the LISP exression according to the translation rule in above figure, the next most important job is that translating theLISP type parameter to the required data type for ActiveX method call.

Some data type definitions in AutoLISP are similar with some in the Active X, Active X can be translated automatically when meet these kinds of data type. Please refer to the below list, the first column in the list is the required data type in the Active X, the first line is the required data type in the AutoLISP. If there is a clasp in the list intersection, it represents that these two kinds of the data type can be converted automatically:

datatype's translation between ActiveX and AutoLISP

We can find that the vla object and entity name (ename), variant and the other data type, array and the other data type can not convert automatically, but these kind of translation are usually used in the Active X program design, we will introduce the three aspects detailly in the following section:

  • Translation between the vla object and the entity name

    • vlax-ename-> vla-object function can translate the return entity name for the entsel function into VLA object used by ActiveX function. The function syntax is as below:

    (vlax-ename->vla-object entity name)

    "entity name" parameter specifies the graphics object entity name needed to be converted, users could use the entsel, nentsel functions to get it; the return value of the function is vla object. The following sample code demonstrates that how to use the users interaction way to obtain a VLA object:

    command: (setq entname (car (entsel "\nselect line: ")))　　　　　　　　;;;select a line, returns the line's enttity name: <Entity name: 56ba920>
    command: (setq vlaobj (vlax-ename->vla-object entname)) 　　　　　　　;;;translate entity name to VLA object, returns the object's point: #<VLA-OBJECT IZWCADLine 7c086d8>

    vlax-vla-object->ename is used to translate the VLA object into the ZWCAD entity name, please refer to below:

    command: (setq entname-1 (vlax-vla-object->ename vlaobj))　　　　　　;;;translate VLA object to entity name, returns the entity's name: <Entity name: 56ba920>

  • Use the variant data type

    • Variant actually is the customized data structure, it can store different type of data. The main feature of the variant is that the data type and value are stored together. This self-definition feature is quite useful when transmiting the parameter to the Active X server, the reason is that the server based any of the languages all can understand the data.

    • Create variant

      • vlax-make-variant function is used to create the variant, the function syntax format is as below:

      (vlax-make-variant [value [type]])

      If there is "value" parameter, assign the value to it when creating variant; "type" parameter specifies the created varianet real data type, please refer to the "vlax-make-variant" theme in the LISP function for the variant type pre-defined by ZWCAD ; If there is only the "value" parameter, the function determines the default Active X data type according to the "value" parameter. Here are some expressions for creating the variant:

      Expression | Return value | Explanation
(setq varnil (vlax-make-variant)) | #<variant 0 > | Create the un-initailized variant, the real data type of the variant is 0, namely is the vlax-vbEmpty, value is nil
(setq varint (vlax-make-variant 30 vlax-vbInteger)) | #<variant 2 30> | Creat a variant, the real data type is 2, namely is vlax-vblnteger, value is 30
(setq varstr (vlax-make-variant "ZWCAD")) | #<variant 8 ZWCAD> | Create a variant, the real data type is 5, namely is vlax-vbString, the value is "ZWCAD"
    • Query the variant real data type

      • vlax-variant-type function is used to query the variant data type, the function syntax format is as below:

      (vlax-variant-type variant)

      If the "variant" parameter passed is not the variant type of a variant, this function would inform "parameter type error"; this function returns the variant data type code, if you want to know the data type represented by the code, please refer to the " vlax-variant-type" theme in LISP function:

      Expression | Return value | Explanation
(vlax-variant-type varnil) | 0 | varnil is the un-initialized variant, the variant real data type is 0, namely vlax-vbEmpty
(vlax-variant-type varint) | 2 | varint real data type is 2, namely vlax-vbInteger
(vlax-variant-type varstr) | 8 | varstr real data type is 5, namely vlax-vbString
    • Query the variant value

      • vlax-variant-value function is used to query the variant value, the function syntax format is as below:

      (vlax-variant-value variant)

      If the "variant" parameter passed is not the variant type of a variant, the function will inform that "parameter type error", this function returns the variant value. Here are some variants of the value of the query expression:

      Expression | Return value | Explanation
(vlax-variant-value varnil) | nil | nil varnil is un-initialized variant, variant value is nil
(vlax-variant-value varint) | 30 | varint value is 30
(vlax-variant-value varstr) | "ZWCAD" | "ZWCAD" varstr vlaue is "ZWCAD"
    • Change the variant data type

      • vlax-variant-change-type function is used to change the variant real data type, the function syntax format is as below:

      (vlax-variant-change-type variant new type)

      If the "variant" parameter passed is not the variant type of a variant, this function will inform "parameter type error" ; If users cannot translate the "variant" parameter transmitted variable into the specied type, the function returns nil, if convert successfully, returns the specified variant type. Here are some variants of the value of the query expression:

      Expression | Return value | Explanation
(vlax-variant-change-type varnil vlax-vbInteger) | #<variant 2 0> | varnil is the un-initailized variant, the real data type will be translated into the vlax-vblnteger from vlax-vbEmpty
(vlax-variant-change-type varint vlax-vbString) | #<variant 8 50> | The real data type will be translated into the vlax-vbstring from vlax-vblnteger
(vlax-variant-change-type varstr vlax-vbSingle) | nil | Since the varstr real data type cannot translate into the vlax-vbString from the vbString, returns nil
  • Use safe array

    • We have introduced that LISP is a kind weak data type programming language, after importing the ActiveX, when the AutoLISP and Active object implement the data interchange, ActiveX object cannot accept the special AutoLISP list data type. Safe array is generated for solving this problem, it is a special array and does not permit assigning values outside boundary value, therefore it will not case some exceptins, namely the safe array.

    • Create the safe array

      • vlax-make-safearray function is used to create the safe array, the function syntax format is as below:

      (vlax-make-safearray type '(Lower . Limit) ['(Lower . Limit)…])

      "type" parameter is used to specify the element data type for the created safe array, if you want to realize the available pre-defined data type, please refer to the "vlax-make-safearray" theme in the LISP function reference; Each of the pair (Lower, Limit) is used to specify the dimension size for the array, users can create the 16 dimensions safe array at most. The function return value is the created safe array. Here are some variants of the value of the query expression:

      Expression | Return value | Explanation
(setq array1 (vlax-make-safearray vlax-vbDouble '(0 . 2))) | #<safearray...> | array1 which contains 3 elements, each of the element data type is double precision real number
(setq array2 (vlax-make-safearray vlax-vbString '(0 . 1) '(1 . 3))) | #<safearray...> | (2*3) array (array2), the first dimentsion Lower is 0, Limit is 1, it contains two elements; the second dimentsion Lower is 1, Limit is 3, it contains three elements and each of the element data type is string

      ZWCAD will create the safe array according to the "type" parameter automatically, the rule is as below:

      Data type | Initailized value
vlax-vbInteger (2) | 0
vlax-vbLong (3) | 0
vlax-vbSingle (4) | 0.00000
vlax-vbDouble (5) | 0.00000
vlax-vbString (8) | ""
vlax-vbObject (9) | nil
vlax-vbBoolean (11) | -1
vlax-vbVariant (12) | #<variant 0 >
    • Assign values for the whole safe array

      • vlax-safearray-fill function is used to assign the value to the whole safe array, the function syntax format is as below:

      (vlax-safearray-fill variable value list)

      If "variabe" parameter does not transmit the safe array, the function will inform "parameter type error"; "value list" parameter is specified when you create a safe array data type is compatible with the values, the list length is equal to the number of the array element, namely cannot only be the parts of the assigned values in the safe array. For the multiple dimension array, the value list must be the embedded list, each of the list must match with one dimension of the array. This function return the safe array of the assigned value. The following expressions assign values for the two arrays (array1 and array2) created before:

      Expression | Return value | Explanation
(vlax-safearray-fill array1 '(120.0 130.0 0.0)) | #<safearray...> | Array 1 an one-dimension array with 3 element, the elements are 120.0, 130.0 and 0.0 after assigned values
(vlax-safearray-fill array2 '(("a" "b" "c") ("d" "e" "f"))) | #<safearray...> | Array 2 is an two-line/three-column array, the three elemens value in the first dimentsion are "a", "d", "c" after the assigned value; the three elements value in the second are "d" "e" and "f"
    • List the contents of the safe array

      • vlax-safearray->list function is used to list the elements values for in the safe array, the function syntax format is as below:

      (vlax-safearray->list variable)

      If the "Variable" parameter does not transmit safe array, the function would inform "parameter type error". This function returns the elements values in the array by list form. The following two expressions list all the elements values in two safe array (array 1 and array 2)after assign values:

      Expression | Return value
(vlax-safearray->list array1) | (120.000 130.000 0.000000)
(vlax-safearray->list array2) | (("a" "b" "c") ("d" "e" "f"))
    • Assign values for the specified element in the safe array

      • vlax-safearray-put-element function is used to assign values for the specified element in the safe array. The function syntax format is as below:

      (vlax-safearray-put-element variable one-dimension index[two-dimension index…] value)

      If the "Variable" parameter does not transmit safe array, the function would inform "parameter type error". Must specify one index value for the one-dimension array; Specify two index value for two-dimension array, use the same calculation way for the following arrays. "Value" parameter is the assigned value for the specified element in the safe array, the data type must be consistent with the element data type. This function returns the assigned value for the specified value. The following two expressions modify the specified elements values in above two arrays (array 1 and array 2):

      Expression | Return value | Explanation
(vlax-safearray-put-element array1 1 140.0) | 140.000 | Modify the second element value130.0 to 140.0 in the one-dimension array 1 (index value is 1)
(vlax-safearray-put-element array2 0 2 "B") | "B" | Modify the second element value "b" (index value is 0.)which is in the first line to "B" in the two-dimension array
    • Use the safe array in the variant

      • Users cannot use the safe array directly when implementing the data interchange between AutoLISP and the ActiveX objects, must use the variant to transmit the safe array to ActiveX. If you want to create a variant for one array, must invoke the vlax-make-safearray function to create the safe array and then invoke the vlax-make-variant function to use the created safe array to create the variant. Next we will use vlax-make-safearray function and the vlax-make-variant function to achieve the functionality of vlax-3d-point function, namley create a real data type for the safe array variant, the safe array contains three elements and each of the element is the double precision real number:

      1.Assign space for array:

      (setq array (vlax-make-safearray vlax-vbDouble '(0 . 2)))

      2.Assign value for array:

      (vlax-safearray-fill array '(120.0 130.0 0.0))

      3.Create variant by safe array

      (setq var_array (vlax-make-variant array))

      Therefore the variable var_array is the variant for the array which contains three double precision real number.

Invoke the ActiveX object method of bringing the return value by parameter

There are some methods of the ActiveX object require users to provide the variable in the Active X and VBA reference manual, this can assign values for variable when invoking these methods, for example, most of the ActiveX objects support the GetBoundingBox method. The following figure depicts this method in Active X and VBA reference manual:

We can know that from the above figure, using the GetBoundingBox method can access to the WCS under the smallest rectangle that contains graphic objects MinPoint and the lower-left corner point of the upper right corner point MaxPoint. The method call format in the VBA is as below:

object.GetBoundingBox MinPoint, MaxPoint

It is different from the syntax of the AddCircle method, therefore, we cannot use the translation rule introduced before to paraphrase the VBA sentence. The following sample code give an example to introduce that how to paraphrase the Active X method of using method to bring return value in VBA, this example get the WCS model space under the one-line text object that contains the smallest rectangle in the lower left corner point and the upper right corner point:

1. Obtain the entity name for the single line text entity

(setq ename_txt (car (entsel "\nselect text object: ")))

2.Translate the entity name into the VLA object

(setq txtObj (vlax-ename->vla-object ename_txt))

3.Invoke the GetBoundingBox method to get one-line text object that contains the smallest rectangle in the lower left corner point and the upper right corner point:

(vla-getboundingbox txtObj 'minpoint 'maxpoint)

vla-getboundingbox function return value is nil, but it brings the return values by minpoint and maxpoint variables (The one-line text object bounding box of the lower left point and the upper right corner coordinates of points stored in these two variables), please note that you must add the single quote (') before these two brought return values, both of them are VLA object, users can invoke the vlax-vla-object->variant function to translate it into the variant, the variant real data type is the safe array which contains three double precision real number, and then invoke the vlax-variant-value and vlax-safearray->list function to list the values for minpoint and manpoint variable:

(vlax-safearray->list (vlax-variant-value (vlax-vla-object->variant minpoint))) 　　　　　;;;returns: (190.726 123.380 0.000000)
(vlax-safearray->list (vlax-variant-value (vlax-vla-object->variant maxpoint))) 　　　　 ;;;returns: (235.406 128.060 0.000000)

Determine that whether the Active X object supports some method

If some object invokes the method which isn't suitable to it, ZWCAD will return an error. If you don't know the method whether to be suitable to the object, you can invoke the function vlax-method-applicable-p to test, the syntax is as following:

(vlax-method-applicable-p VLA object method name)

"Method name" parameter is used to specify the Active X method which is needed to be tested, it can be charater or string. If this object supports this method, this function returns T, otherwise returns nil. The following two expressions demonstrate the usage for this function (Assume that the line-obj variable stores a pointer of the line object):

Expression | Return value | Explanation
(vlax-method-applicable-p line-obj "copy") | T | "Method" parameter is string which is used to test whether the object supports the "copy" method.
(vlax-method-applicable-p line-obj 'extend) | nil | "Method" parameter is character which is used to test whether the object supports the "extend" method.


Get and Set ActiveX Object's Property

If you want to obtain the attribute of the Active X, you must obtain the object at first. There are two ways to obtain the Active object:

1. Get along ZWCAD Object Model to obtain the ActiveX Objects

2. Obtain the entity name through AutoLISP at first, and then invoke the vlax-ename->vla-object function to translate the entity name into VLA object.

We have introduced that users could use the vlax-dump-object function to query the Active object attribute in the "ZWCAD object model" section, but it just simply lists attributes name for the object. This section will introduce that how to obtain the Active X object attribute, how to modify the Active X object attribute, how to check that whether one object has some objects.

Obtain the attribute of the Active X object

When running the current program and the other programs are also operating some ZWCAD objects, the current program may not access those objects, for example, one text style in the text style list is purged, it cannot access the "TextStyle" object any more; if one set is released (assign the nil), it cannot access the "SelectionSet" object etc. When query the attribute for some ActiveX object, users should check that whether this object can be queried and whether the object has the attribute could be queried firstly.

vlax-read-enabled-p function is used to check that whether the specified object can be queried, the function syntax format is as below:

(vlax-read-enabled-p VLA object)

If this object could be queried, the function returns T; If the object has been removed or released by the vlax-release-object function, this object cannot be queried and the function returns nil.

vlax-property-available-p function is used to check that whether the object has the specified attribtue, the function syntax format is as below:

(vlax-property-available-p VLA object attribtue name[T])

"Attribute name" parameter specifies the attribute name of the VLA object needed to be checked, it is string or the character; If there is not the "T" parameter, when the specified VLA object has the specified attribute, the function returns T, otherwise returns nil. If there is the "T" parameter, only when the specified VLA object has the specified attribute and the attribute could be modified, this function returns T. The following two expressions demonstrate the usage of the function (assume that the circle-obj variable stores a pointer of the circle object) :

Expression | Return value | Explanation
(vlax-get-available-p circle-obj "radius") | T | "Attribute name" parameter is a string, check that whether the circle object has the "radius" attribute
(vlax-get-available-p circle-obj 'area) | T | "Attribute name" parameter is character, check that whether the circle object has the "acrea" attribute
(vlax-get-available-p circle-obj 'area T) | nil | "Attribute name" parameter is character, check that whether the circle object has the "acrea" attribute and whether the "acrea" attribtue could be modified.

vlax-get-property is used to obtain the ActiveX object attribute, the function syntax format is as below:

(vlax-get-property VLA object attribtute name)

"Attribute name" parameter specifies the VLA attribute name needed to be obtained, it is string or character. This function return attribute value specified by the VLA object. The following expressions demonstrate the usage of the function (assume that the circle-obj variable stores a pointer for the circle)

Expression | Return value | Explanation
(vlax-get-property circle-obj "radius") | 9.37200 | "Attribute name" parameter is string, obtaint the radius of the circle
(vlax-get-property circle-obj 'area) | 275.940 | "Attribute name" parameter is character, obtain the aceage of the circle

Note, users also can obtain some object attribute through the following ways:

(vla-get-attribute name VLA object)

The above two expressions can be paraphrased as (vla-get-radius circle-obj) and (vla-get-area circle-obj)

Modify the attribute of the ActiveX object

Similarly, we need to check that whether the object could be modified, whether the object has the specified attribute and whether the specified attribute could be modified before modifying the Active X object. (The attribute with the RO mark in the VLA attribute which is listed by using the vlax-dump-object function is Read-only and cannot be modified).

vlax-write-enabled-p function is used to check that the VLA object can be modified, the function syntax format is as below:

(vlax-write-enabled-p VLA obeject)

If the object can be modified, the function returns T, if the object is removed or placed on the frozen kayer, this object cannot be modified and this function return nil.

vlax-property-available-p function is used to judge that whether the specified object attribute could be modified, in the above have been introduced, we are not elaborate.

vlax-put-property function is used to modify the specified attribute for the VLA object, the function syntax format is as below:

(vlax-put-property VLA object attribtue name value)

"Attribute name" parameter specifies the attribute name of the VLA object needed to be obtained, it is string or character; The data type of "Value" parameter must be consistent with the attribute data type specified by the VLA object, otherwise will exposure error and the attribute could not be modified. If the attribute has been modified successfully, the function returns nil. The following expressions demonstrates the usage of that function:

Expression | Return value | Explanation
(vlax-put-property circle-obj "Center" (vlax-variant->vla-object (vlax-3d-point (list 0.0 0.0 0.0)))) | nil | "Attribute name" parameter is string, move the center point to the coordinate origin point, since the data type of the "Center" parmeter is VLA object, users need to invoke the vlax-variant->vla-object function to translate the variant into the VLA object.
(vlax-put-property circle-obj 'Color 1) | nil | "Attribute name" parameter is character, modify the circle object color as red (index value is 1)

Note: in some cases, after modifying the attribute of the VLA object, the screen display could be updated immediately, at this time users should invoke the update method of this object.

You can also use the following way to modify the attribute for the object:

(vla-put-attribute name VLA object value)

The above expression can be paraphrased as: (vla-put-Center circle-obj (vlax-variant->vla-object (vlax-3d-point (list 0.0 0.0 0.0)))) and (vla-put-Color circle-obj 1).


Working with Collection Objects

The concept of collection is imported by the ZWCAD object model, all the objects in the ZWCAD object model are grouped with the collection, for example, Layers collection object is composed of all the layer objects in the ZWCAD drawing, the AutoLISP has the same relationship and the layer list contains all the layer data in drawing. The main functions for handling the collection objects in VLISP are "vlax-map-collection" and "vlax-for".

Each collection object provides the item method to travel every object in collection, for example, the following sample code defines PrtLayerInfo command which is used to print all the layers' names and layers' colors in the drawing:

(vl-load-com)　　　　　;;; initialize ActiveX environment
(if (null *ZWCADOBJECT*)　　　　　;;; get ZWCAD application object
  (setq *ZWCADOBJECT* (vlax-get-zwcad-object))
)
(if (null *ACTIVEDOCUMENT*)　　　　　;;; get current active document object
  (setq *ACTIVEDOCUMENT* (vla-get-ActiveDocument *ZWCADOBJECT*))
)
(defun c:PrtLayerInfo (/ string layers layernum i
                      layerobj layername layercolor)
  (setq string "Layer name\tcolor\n")
  (setq layers (vla-get-layers *ACTIVEDOCUMENT*))　　　　　　;;; get layers collection object
  (setq layernum (vla-get-Count layers))
  (setq i 0)
  (repeat layernum
    (setq layerobj (vla-item layers i))　　　;;; invoke layers collection object's item method to get each layer object
    (setq layername (vla-get-Name layerobj))　　　;;; get layer object's name property
    (setq layercolor (vla-get-Color layerobj))　　　;;; get layer object's color property
    (setq string (strcat string layername "\t" (itoa layercolor) "\n"))
    (setq i (1+ i))
  )
  (princ string)
  (princ)
)

Apply one function to every object in collection

vlax-map-collection function is used to apply one function to every object in collection, the function's syntax is as below:

(vlax-map-collection collection function)

"function" parameter specifies the function which will be applied to every object in collection, it can be function name or the non-name function defined by lambda, and it can only accept a VLA-object type parameter. If the objects in collection have been traveled successfully, the function returns the pointer of collection object (VLA object). The following sample code defines ChgLayerName command which is used to edit all the layer names in the drawing in batch (add the "ZW" prefix) :

(vl-load-com)   　　　　 ;;; initialize ActiveX environment
(if (null *ZWCADOBJECT*)
  (setq *ZWCADOBJECT* (vlax-get-zwcad-object))  　　　 ;;; get ZWCAD application object
)
(if (null *ACTIVEDOCUMENT*)
  (setq *ACTIVEDOCUMENT* (vla-get-ActiveDocument *ZWCADOBJECT*))   　 ;;; get current active document object
)
(defun c:ChgLayerName (/ layers layername)
  (setq layers (vla-get-layers *ACTIVEDOCUMENT*))
  (vlax-map-collection
    layers
    '(lambda (x) 　　　　　 ;;; lambda expression, accepts argument x representing a VLA object
       (setq layername (vla-get-Name x))  　　　 ;;; get each object's name property in the colletion object
       (if (/= layername "0")  　　　　  ;;; filter out layer 0 because its layer name is readonly
     (vla-put-Name x (strcat "ZW_" layername)) 　　　;;; modify each object's name property in the collection object
       )
     )
  )
  (princ)
)

Apply a series of functions to every object in collection

vlax-for function is used to apply multiple expressions to every object in collection, the function's syntax is as below:

(vlax-for formal param collection expr1 [expr2…])

When invoking this function, assign every object in collection to the "param" firstly, and then evaluate the expression through the "param". If the objects in collection have been traveled successfully, the function returns the value of the last expression. The following exemplary code defines the "statsCircle" command which is used to count the number of circles and the total area on the drawing (including the circles in block insert):

(vl-load-com)		;;; initialize ActiveX environment
(if (null *ZWCADOBJECT*)		;;; get ZWCAD application object
  (setq *ZWCADOBJECT* (vlax-get-zwcad-object))
)
(if (null *ACTIVEDOCUMENT*)		;;; get current active document object
  (setq *ACTIVEDOCUMENT* (vla-get-ActiveDocument *ZWCADOBJECT*))
)
(defun c:statsCircle (/	cmdecho_old	MSpace num area
                        vlaObj objType sset subObj
                        subObjType i resultstr
                        )
  (setq cmdecho_old (getvar "cmdecho"))		;;; backup the system variable "cmdecho"
  (setvar "cmdecho" 0)		;;; set "cmdecho" to "OFF" to prevent echoing information in ZWCAD command bar
  (setq MSpace (vla-get-ModelSpace *ACTIVEDOCUMENT*))
  (setq num 0)
  (setq area 0.0)
  (vlax-for vlaObj MSpace
    (setq objType (vla-get-EntityName vlaObj))
    (cond ((= objType "Circle")		;;; if the entity is circle
       (setq num (1+ num))
       (setq area (+ area (vla-get-Area vlaObj)))
      )
      ((= objType "BlockInsert")	;;; if the entity is block insert, starting iterate all subentities in the block
       (setq i 0)
       (command "Explode" (vlax-vla-object->ename vlaObj))	;;; explode block, if the scaling factors in three axises direction (X, Y, Z) are not equal, the circle subentity would be explode to ellipse
       (setq sset (ssget "P"))
       (repeat (sslength sset)
         (setq subObj (vlax-ename->vla-object (ssname sset i)))
         (setq subObjType (vla-get-EntityName subObj))
         (if (= subObjType "Circle")	   ;;; if the subentity is circle
           (progn
         (setq num (1+ num))
         (setq area (+ area (vla-get-Area subObj)))
           )
         )
         (setq i (1+ i))
       )
       (command "undo" 1)	;;; give up the explode operation to block
      )
      (T (princ))
    )
  )
  (setq	resultstr (strcat "\nThere are "
              (itoa num)
              " circles\nTheir total area is: "
              (rtos area 2 3)
          )
  )
  (princ resultstr)
  (setvar "cmdecho" cmdecho_old)	;;; recover the system variable "cmdecho"
  (princ)
)


Using ActiveX to Interact with Other Applications

We have introduced that using the ActiveX and the standard ZWCAD object to implement the transaction, for example, obtain and modify the ZWCAD graphics object attribute, invoke the ZWCAD object method, actually the Active X also can transact with the other applications which support the ActiveX, such as the Microsoft Word, Microsoft Excel, particularly with the Microsoft Excel application, the interaction is a very practical, it can generate the report according to the dwg drawing and provide it to the ERP system.

As you use the ActiveX in ZWCAD developing applications you need to know ZWCAD object model and the object's properties and methods, when you using the AciveX to transact with the other applications, you also need to realize the attribute and method for the application object model, you may refer to their help document to obtain the related information.

And other applications that support ActiveX interactions need to follow the following steps:

1.Input type library

We have introduced that there are two ways to invoke the ZWCAD object method, they are invoking the "vla-method name" or "vlax-invoke-method" function; There are two ways to obtain the ZWCAD object attributes, invoking the "vla-get attribute name" or "vlax-get-property" function; There are two ways to modify the ZWCAD object attribute, invoking the "vla-put-attribute name" or "vlax-put-property" function. The "vla-method name", "vlax-get-attribute name" and "vlax-put-attribute name" are not introduced in the LISP function reference, they are the wrapper function created by the ZWCAD type library. If they need to be transacted by the other application supported the ActiveX, must invoke the vlax-import-type-library function input type lirary, ZWCAD will create the corresponding the wrapper function, the function syntax format is as below:

(vlax-import-type-library type library[:methods-prefix method call prefix:properties-prefix attribute call value prefix :constants-prefix constant prefix])

"type library" is string which is used to specify the type library, it can be the type library file (*.tlb), object library (*.olb), execution file (*.exe), the dynamic link library file which contains the type library resource (*.dll). If omit the file path, ZWCAD will search the file int he supported path; "Method call prefix" is string whic is used to specify the wrapper function of the Active X object method in the application, for example, the parameter is "vla-" when transacting with the ZWCAD applications ; "attribute call prefix" is string which is used to obtain and modify the wrapper function prefix or the Active X object attribute in the application, for example, the parameter is "vla-" when transacting with the ZWCAD applications; "constant prefix" is also a string which is used to specify the prefix mark in the quoted application. The effect of the three prefix mark is that determin the call method and whether the accessed attribute or the constant are belonged to the application, it is similar with the name space in the C++. The following code defines the Load-TypeLib-Excel function to input Microsoft Excel 2003 type library:

(defun Load-TypeLib-Excel ()
  (if (/= msxlc-xl24HourClock nil)    ;;;check if the constant "msxlc-xl24HourClock" of Microsoft Excel 2003 is null
    (princ "\nMicrosoft Excel 2003 type library has been loaded.")
    (progn
      (setq xlsInstDir
         (vl-registry-read       ;;;get Microsoft Excel 2003 application's installation  path from windows registry
           "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\Office\\11.0\\Excel\\InstallRoot"
           "Path"
         )
      )
      (if (null xlsInstDir)
    (progn
      (princ "\nMicrosoft Excel 2003 isn't installed yet.")
      (exit)
    )
    (progn
      (setq tblfile (strcat xlsInstDir "\\Excel.exe"))
      (vlax-import-type-library       ;;;import Microsoft Excel 2003 type library
        tblfile	       :methods-prefix	  "msxlm-"
        :properties-prefix "msxlp-"		  :constants-prefix
        "msxlc-"
       )
      (princ "\nLoad Microsoft Excel 2003 type library successfully.")
    )
      )
    )
  )
  (princ)
)

After inputting the type library, you need to add the "msxlp-" prefix when invoking the Microsoft Excel 2003 object method, need to add the "msxlp-get" prefix when obtain the Microsoft Excel 2003 object attribute, add the "msxlp-put" prefix when modify the Microsoft Excel 2003 object attribute, add the "msxlc-" prefix when quote the Microsoft Excel 2003 constant, for example, the above function uses the "msxlc-xl24HourClock" to quote the "xl24HourClock" constant in the Microsoft Excel 2003.

In order the run the code in different mechine, users should avoid to use the absolute path when transmit the "type library" parameter, suggest that search the relative application installation path through the registry, and then contitute the path and the type library file name to the completed type library file and transmit to the "type library" paramter, the above function invokes the vl-registry-read function to read the Microsoft Excel 2003 installtion path from registry.

2.Build the connection with the application

Building the connection with applicaion actually is that obtain the root object of the application needed to be transact and supports the ActiveX, just as the former need to interact with the ZWCAD application objects to obtain ZWCAD (object model root object). If a sample is running currently, users could invoke the vlax-get-object function to obtain the application root object, the function syntax format is as below:

(vlax-get-object prog-id)

"prog-id" parameter specifies the ActiveX object needed to be connect, the format is as below:

program name.components name.version number

For example, "Excel.Application.11" represents that the application needed to be connected is Miscrosoft Excel 2003. If obtain the application object successfully, this function returns the program root object by the VLA object, otherwise returns nil.

If there is not the running application which is needed to connect, users need to invoke the vlax-create-object function to create a new samole for that application. The function syntax format is as below:

(vlax-create-object prog-id)

The p arameter meaning is same as it in the vlax-create-object function, we do not describe it here. If create the new application example successfully, this function returns the root object of the created application by the VLA object, otherwise returns nil.

vlax-get-or-create-object integrates functionality of both of the two functions, it try to obtain the running application root object currently, if fail to obtain, create a new sample for the application, the function syntax format is as below:

(vlax-get-or-create-object prog-id)

After invoking the vlax-create-object or vlax-get-or-create-objec functions to create the new application sample, the application is running in backgroud, users should set the object visible attribute as True to display the application window, for example, implementing the following code will start and display the Miscrosoft Excel 2003 window:

(setq xlsobj (vlax-create-object "Excel.Application.11"))
(vla-put-visible xlsobj :vlax-true)

Comprehensive appliction sample

This sample achieves that export the cells in DWG to the Excel, this is quite useful in the report statistic.


Appendixes

The "library category description" section only gives the more detailed description for the functions used in high frequency in the various library functions, this chapter will briefly describes other functions calls format and the main functions in all kinds of library function, mainly contains the following contents:

  • Arithmetic Function List
  • Relational Function List
  • Logical Function List
  • Bit Arithmetic Function List
  • Conversion Function List
  • String Handling Function List
  • List Handling Function List
  • Data Input Function List
  • Geometric Function List
  • File Handling Function List
  • Windows Registry Functions
  • Entity Handling Function List
  • Symbol Table Handling Function List
  • Selection Set Handling Function List
  • Dictionary Handling Function List
  • Query Function List
  • Command Function List
  • Error Handling Function List
  • Curve Measurement Functions


Arithmetic Function List
Function name and the syntax | Functionality and the return value
(+ value1 value2…) | Return the sum of the real number and integer
(- value1 value2…) | Return the first value minus the second value and subsequent value
(* value1 value2…) | Return the product of the real number and integer
(/ value1 value2…) | Return the first value divides the second value and subsequent value
(~ value) | Return the bitwise non of the integer (the complement of 1)
(1+ value) | Incremental value of 1
(1- value) | Decrement value 1
(abs value) | Return the absolute value of a numerical
(atan value1 value2) | Return arctangent of a numeric value
(cos angle) | Return a certain angle (in radians) of the cosine value
(exp value) | Return the constant e (2.718282 ...) the designated power
(expt base index) | Returns a specified number base the value of the number of power
(fix value) | Truncated fractional part of the real numbers, it would be converted to an integer and returned to the Integer
(float value) | The value is converted to real values
(gcd value1 value2) | Return the greatest common divisor of two integers
(log value) | Returns a real number of the natural logarithm(based on e)
(log10 value) | Returns a real number of the natural logarithm(based on 10)
(logand value1 value2…) | Return multiple integer bitwise logical and (AND) and the result
(logior value1 value2…) | Return multiple integer bitwise logical or (OR) and the result
(lsh value1 value2) | Return results of displacement which is value 1 according to the logic value 2 specified times
(max value1 value2…) | Return the real numbers or integer multiple of the maximum value
(min value1 value2…) | Return real numbers or integer multiple of the minimum value
(minusp value) | To determine whether a negative value
(numberp value) | To determine whether the value of a variable is an integer or real number
(rem value1 value2) | Return the remainder of value of 1 divided by the value 2 (modulus)
(sin angle) | Return a certain angle (in radians) of the sine value
(sqrt value) | Return the square root of a value
(zerop value) | Check whether the value of a variable is 0 (zero)


Relational Function List
Function name and syntax | Functionality and the return value
(= expression 1 expression 2…) | Compare whether the two or more variables, constants, or the value of an expression are equal to each other
(/= expression 1 expression 2…) | Compare whether the two or more variables, constants, or the value of an expression are not equal to each other
(< expression 1 expression 2…) | Compare that whether each of the expression (variable and constant) values are less than the right expression value of it.(variable or constant)
(<= expression 1 expression 2…) | Compare that whether each of the expression (variable and constant) values are no more than the right expression value of it.(variable or constant)
(> expression 1 expression 2…) | Compare that whether each of the expression (variable and constant) values are more than the right expression value of it.(variable or constant)
(>= expression 1 expression 2…) | Compare that whether each of the expression (variable and constant) values are no less than the right expression value of it.(variable or constant)
(eq expression 1 expression 2) | Make sure that whether the expression 1 and expression2 have the same constraints (for the return value is an expression LIST type)
(equal expression 1 expression 2) | Compare two expressions (variable or constant) value is equal to each other within the specified error range
(wcmatch expression 1 expression 2) | Wildcard pattern to compare two strings are equal


Logical Function List
Function name and syntax | Functionality and return value
(and expression1 expression2…) | Return the result of multiple expression's logical AND.
(not expression) | Return the result of multiple expression's logical NOT.
(or expression1 expression2…) | Return the result of multiple expression's logical OR.


Bit Arithmetic Function List
Function name and syntax | Functionality and return value
(boole operation code value1 value2…) | Return more than one integer by "operation code" specifies the logical operations result.
(logand value1 value2…) | Return the result of multiple expression's logical AND
(logior value1 value2…) | Return the result of multiple expression's logical NOT
(lsh value1 value2) | Return results of displacement which is value 1 according to the logic value 2 specified times


Conversion Function List
Function name and syntax | Functionality and return value
(angtof string [mode]) | Translate the string expressed the angle into the real number (floating number) form of arc
(angtos angle [mode [precision]]) | An angle in radians as the unit value is converted into a string
(ascii string) | Translate the first character in string into the corresponding ASCII code (integer) and the return this value
(atof string) | Translate string into real number
(atoi string) | Translate string into integer
(chr value) | The integer expressed the character ASCII is converted to the string which contains the corresponding single character,
(cvunit value original unit translation unit) | Between the different units of measure conversion
(distof string [mode]) | Translate the real (floating point) number string into a real number
(itoa integer) | Translate integer into string
(rtos value mode [precision]) | Translate number into string
(trans point original location new location[displacement]) | Translate a point (or displacement) from one coordinate system into another coordinate system


String Handling Function List
Function name and syntax | Functionality and return value
(read string) | Return the first word of the string by the corresponding data type.
(strcase string [mode]) | Translate all the characters into uppercase or lowercase in the string and return them.
(strcat [string1 [string2]…]) | Stitching multiple strings into one long string and return
(strlen [string1 [string2]…]) | Return the number of characters in the string
(substr string beginning location[length]) | Return a sub-string in a string
(vl-prin1-to-string variable) | Return a string representation of the variable (anti-analytic control characters)
(vl-princ-to-string variable) | Return a string representation of the variable
(vl-string->list string) | Return all the characters from the string composed of ASCII code value of the table
(vl-string-elt string location) | Return the string specified in the location of the ASCII character codes.
(vl-string-left-trim charset string) | From the beginning of the string to delete the specified characters within the character set
(vl-string-mismatch string1 string2 [beginning location1 beginning location2 mode]) | Return two string starting from the specified location, the length of the longest common prefix
(vl-string-position integer string [beginning location[mode]]) | Find the string with the specified ASCII character code and returns its position in the string
(vl-string-right-trim charset string) | From the end of the string to delete the specified characters within the character set.
(vl-string-search sub-tring string [beginning]) | Search the specified sub-string in the string and return its position in teh string
(vl-string-subst new sub-string old sub- string string [beginning]) | Using the new substring in the string to replace the old sub-string
(vl-string-translate source charset target charset string) | In the target character set using the string of characters to replace characters in the source character set
(vl-string-trim charset string) | From the beginning and the end of the string to delete the specified characters within the character set


List Handling Function List
Function name and syntax | Functionality and return value
(acad_strlsort list) | Sort by the ASCII code for the list element which is composed of the character or string
(append [list1 list2…]) | Any number of tables will be combined into one table
(assoc key element list) | Return the table that contains the key elements of the elements (sub-table)
(car list) | Return the first element in the list
(cadr list) | Return the second element in the list
(caddr list) | Return the third element in the list
(cdr list) | Return all the other element except for the first element in the list
(cons new element variable) | Add new element in list head, or build a pair
(foreach parameter list expression) | All the element woudl be took into evaluator in the specified shap parameter identity.
(last list) | Return the last element in the list
(length list) | Return the number of elements in the list
(list [element1 element2…]) | Any number of expressions will be combined into a list
(listp variable) | Check whether the variable is list
(mapcar function list1 list2…) | Translate the elements in one or more list into function to evaluate, and return the list composed by the evaluation result.
(member key element list) | Search that whether the list contains key element, and return the rest part of the list from the position in which this element first appear
(nth index list) | Return the element at the specified index location in list
(reverse list) | Adjust the order of the elements in the table upside down and return it
(subst new element old element list) | Replace the table with the new element in each of old elements, return the modified form
(vl-consp variable) | Check list whether nil
(vl-every test function list1 [list2]…) | One or more tables for each element is passed to the test function, test whether the return value is true
(vl-list* variable1 [variable2]…) | Construct and return the list
(vl-list->string integer list) | Translate the integer elements into string and combine into a string to return
(vl-list-length list) | Calculate the element in the list
(vl-member-if test function list) | Translate each of the element in list into the test function, return the rest of the list from the position where the test function return value is true for the first time
(vl-member-if-not test function list) | Translate each of the element in list into the test function, return the rest of the list from the position where the test function return value is false for the first time
(vl-position element list) | Return an element position in list
(vl-remove element list) | Delete the element in list
(vl-remove-if test function list) | Return the list which is composed of the elements who make the false return value for all the test function
(vl-remove-if-not test function list) | Return the list which is composed of the elements who make the true return value for all the test function
(vl-some test function list1 [list2]…) | The corresponding elements of each table will be passed to the test function, test the return value is non-nil
(vl-sort list comparison function) | According to the specified comparison function to sort the elements in the list
(vl-sort-i list comparison function) | According to the specified comparison function to sort the elements on the table and returns the index number of elements


Data Input Function List
Function name and syntax | Function name and syntax
(getangle [base point] [prompt]) | Pause waiting for the users to input angle value (relative to curvature in the current UCS X-axis direction)
(getcorner [base point] [prompt]) | Pause waiting for the users to input rectangular coordinates of the second corner
(getdist [base point] [prompt]) | Pause waiting for the users to input distance
(getint [prompt]) | Pause waiting for the users to input integer
(getkword [prompt]) | Pause waiting for the users to input keyword
(getorient [base point] [prompt]) | Pause waiting for the users to input angle (relative to curvature in the east direction)
(getpoint [base point] [prompt]) | Pause waiting for the users to input point
(getreal [prompt]) | Pause waiting for the users to input integer
(getstring [mode] [prompt]) | Pause waiting for the users to input string
(initget [bit] keyword list) | Create keyword list for the followed users input function call


Geometric Function List
Function name and syntax | Function name and syntax
(angle point1 point2) | Return the angle of the connection lines between the two points (relative the current UCS X-axis direction)
(distance point1 point2) | Return the Three-dimension distances between the two points.
(inters point1 point2 point3 point4 [mode]) | Return the intersection of the point 12 line and the point 34 line or their extension lines
(osnap point mode string) | Return the obtained Three-dimension point which is from the specified point applied the Object snap
(polar base point radian distance) | Return the specified distance from the base, and with the point of connection with the current UCS under the X-axis positive direction to the specified point of view three-dimensional
(textbox dxf list) | Check the specified text object border, (bottom left corner point and the upper right corner point)


File Handling Function List
Function name and syntax | Functionality and return value
(close file description) | Close the opened file
(findfile file name) | Search the specified file in the specified directory of the ZWCAD search path
(getfiled title default file name extension name behavior mode) | Use the standard ZWCAD file dialog to inform users to select a file name
(open file name mode) | Open the specified file by reading, writing or appending
(read-char [file description character]) | From the keyboard input buffer or an open file to read a character and returns the ASCII character codes
(read-line [file description character]) | From the keyboard input buffer or an open file to read a character
(vl-directory-files [directory file name mode mode]) | Lists the specified directory file name pattern consistent with all the files
(vl-file-copy source file name target file name [mode]) | Copy or append the source file contents to the target file
(vl-file-delete file name) | Remove the specified file
(vl-file-directory-p file name) | To determine whether a file name that contains a file path
(vl-file-rename old file name new file name) | Rename file
(vl-file-size file name) | Return the specified file size (in bytes)
(vl-file-systime file name) | Return the last modification time for the specified file
(vl-filename-base file name) | Return the main file name, delete the file path and the extension name
(vl-filename-extension file name) | Return the file extension name
(vl-filename-mktemp file name mode directory extension name) | Specify a temporary file using the unique file name
(vl-mkdir directory name) | Create the specified directory
(write-char integer [file description character]) | Write a ASCII character code which is the specified integer in screen or the specified file
(write-line string [file description character]) | Write the specified string to the screen or the specified file


Windows Registry Functions
Function and syntax | Functionality and the return value
(vl-registry-delete key [value name]) | Remove the specified key or the key value from the Windows registry
(vl-registry-descendents key [value name]) | Return the specified key or the value name list from the Windows registry
(vl-registry-read key [value name]) | Return the one value name in the specified key from the Windows registry
(vl-registry-write key [value name data]) | Create the key in the Windows registry


Entity Handling Function List
Function and the syntax | Functionality and the return value
(entdel entity name) | Delete the entity or recover the removed entity last time
(entget entity name [application name list]) | Return the entity dxf data
(entlast) | Return the last major entity name added in the drawing (graphics object)
(entmake [dxf list]) | Create the new entity in the drawing (graphics object)
(entmakex [dxf list]) | Create a new entity, assign a handle and entity name (does not specify the owner) to the new eneity and return the new entity name
(entmod dxf list) | Modify the entity through dxf data
(entnext [entity name]) | Return the next entity name of the specified entity in the drawing
(entsel [prompt]) | Inform users to select the point to select the entity (it is suitable for simple entity)
(entupd entity name) | Update the screen display for the specified entity
(handent handle) | Return the entity name according to the entity handle
(nentsel [prompt]) | Inform users to specify the point to select entity (it is suitable for the complicated entity)
(nentselp [prompt] [point]) | Select the single entity without users input (it is suitable for the complicated entity)


Symbol Table Handling Function List
Function name and syntax | Functionality and return value
(layoutlist) | Return all the layout space name list in the current graphics
(setview dxf list view port id) | Build a view for the specified view port
(tblnext character list name [beginning point]) | Search the next item for the specified character list
(tblobjname character list name item name) | Return the specified item entity name in the specified character list
(tblsearch character list name item name[set the beginning point]) | Search the specified item in the specified character list


Selection Set Handling Function List
Function name and syntax | Functionality and return value
(ssadd [entity name[selection set]]) | Create new selection set or add the specified entity to the specified selection set
(ssdel entity name selection set) | Remove the specified entity from the specified selection set
(ssget [mode] [point1 [point2]] [point list] [filter list]) | Inform the users to select the entity and return the selection set which contains the selected entities
(ssgetfirst) | Judge that which kind of the objects are selected and which kind of the objects are nipped.
(sslength selection set) | Return the amount of the entity contained in the selection set
(ssmemb entity name selection set) | Check that whether one entity is contained in the selection set or not
(ssname selection set index) | Get one entity name in selection set
(ssnamex selection set[index]) | Get the information of the creating way for selection set
(sssetfirst selection set1 selection set2) | Set the entities which either are selected or nipped


Dictionary Handling Function List
Function name and syntax | Functionality and return value
(dictadd dictionary name keyword entity name) | Add a non-graphics object to a specified dictionary
(dictnext dictionary name [mode]) | Search next item in the dictionary
(dictremove dictionary name keyword) | Remove the keyword from the specified dictionary
(dictrename dictionary name old keyword new keyword) | Rename the keyword in dictionary
(dictsearch dictionary name keyword [set beginning point]) | Search the keyword in the dictionary
(namedobjdict) | Return the current graphics naming object dictionary, it is the root of all the dictionary object
(vlax-ldata-delete dictionary name keyword) | Remove the LISP data from the graphics dictionary
(vlax-ldata-get dictionary name keyword [default data]) | Get the LISP data from the graphics dictionary
(vlax-ldata-list dictionary name) | List LISP data in the graphics dictionary
(vlax-ldata-put dictionary name keyword data) | Store the specified keyword and LISP data in the graphics dictionary
(vlax-ldata-test data) | To determine whether the task can be cross-border data to store the LISP data


Query Function List
Function name and syntax | Functionality and return value
(getcfg parameter name) | Return the user data from registry
(getenv environment variable name) | Return the specified operate system or the environment variable value
(getvar system variable name) | Return the ZWCAD system variable value
(setcfg parameter value) | Write the user data from registry
(setenv environment variable name value) | Set the operate system of the ZWCAD environment variable value
(setvar system variable value) | Set the ZWCAD system variable value


Command Function List
Function name and syntax | Functionality and return value
(acad_colordlg default color value [mode]) | Display the standard ZWCAD color option dialog
(command ZWCADcommand name command option…) | Implement the ZWCAD command
(help [help file [theme [window status]]]) | Call the help program
(setfunhelp command name [[theme[window status]]]) | A user-defined function with the help documentation is associated with a certain theme
(vl-cmdf ZWCADcommand command option…) | First calculate the value of each parameter before running the command ZWCAD
(vlax-add-cmd command name function name) | A self-defined functions will be added as a built-in command ZWCAD
(vlax-remove-cmd command name) | Remove the self-defined functions which have been added to the ZWCAD built-in command from the ZWCAD built-in command


Error Handling Function List
Function name and syntax | Functionality and return value
(alert string) | Prompt warning dialog to display the error or the warning message
(*error* string) | Automatically invoke the function when encountering error
(exit) | Force Quit the current LISP program, return to the command line prompt ZWCAD
(quit) | Force Quit the current LISP program, return to the command line prompt ZWCAD
(vl-catch-all-apply 'function name list) | Invoke specified function and capture the error
(vl-catch-all-error-message error object) | Return the error information from the error object
(vl-catch-all-error-p variable) | Judge whether a variable is an error object


Curve Measurement Functions
Function and syntax | Functionality and the return value
(vlax-curve-getArea VLA object) | Return to the curve area
(vlax-curve-getClosestPointTo VLA object point list[whether extend]) | Return the nearest point of the designated point on the curve of WCS
(vlax-curve-getClosestPointToProjection VLA object point list three-dimensional vector[whether extend]) | After the curve projected onto the plane, return the nearest point on the curve of WCS
(vlax-curve-getDistAtParam VLA object parameter) | Return the length of the curve from the beginning to the specified parameters to the segments curve
(vlax-curve-getDistAtPoint VLA object point list) | Return the length of the curve from the beginning to the specified point to the segments curve
(vlax-curve-getEndParam VLA object) | Return the parameters of the endpoint curve
(vlax-curve-getEndPoint VLA object) | Return the coordinates of the curve endpoints in WCS
(vlax-curve-getFirstDeriv VLA object parameter) | Return the first derivative at the specified location of the curve in WCS
(vlax-curve-getParamAtDist VLA object distance) | Return the curve parameter which is the a specified distance from the curve starting point
(vlax-curve-getParamAtPoint VLA object point list) | Return the specified point of curve parameters
(vlax-curve-getPointAtDist VLA object distance) | Return the point which has a specified distance from the starting point in the curve of WCS
(vlax-curve-getPointAtParam VLA object parameter) | Return the curve point with the specified parameter values
(vlax-curve-getSecondDeriv VLA object parameter) | Return the second derivative at the specified location of the curve in WCS
(vlax-curve-getStartParam VLA object) | Return the beginning parameter of the curve
(vlax-curve-getStartPoint VLA object) | Return the beginning point of the curve in the WCS
(vlax-curve-isClosed VLA object) | Check that whether the curve is closed
(vlax-curve-isPeriodic VLA object) | To determine whether the specified curve is infinite in all directions, while there is a cycle, the value of dT, such that for any parameter u, have a point on the curve (u + dT) = point (u) set up
(vlax-curve-isPlanar VLA object) | Check that whether contains the plane of the curve


What's new in lisp?

Version Overview:

The new version of LISP enhances and improves the quality of original interfaces to some extent compared for previous version, especially in part of Curve Measurement Functions. At the same time, it adds operator function and authorization function. And we have to tell you that some unusual interfaces have not been implemented yet currently. Please refer to the next chapter contents of the updated version for detail.

Contents of Updated Version:

1.New implemented VLAX- interfaces:

  • vlax-Curve-getPointAtDist
  • vlax-Curve-getParamAtPoint
  • vlax-Curve-getParamAtDist
  • vlax-create-object
  • vlax-erased-p
  • vlax-property-available-p
  • vlax-typeinfo-available-enable-p
  • vlax-method-available-p

2.New implemented VL- interfaces:

  • vl-cmdf
  • vl-filename-mktemp
  • vl-sort-i

3.New improved VLR- interfaces:

  • vlr-acdb-reactor
  • vlr-beep-reaction
  • vlr-docmanager-reactor
  • vlr-object-reactor
  • vlr-reactors
  • vlr-type
  • vlr-types

4.New implemented LISP interfaces:

  • log10
  • lsplicense

5.New improved LISP interfaces:

  • cmdecho
  • eq
  • erase
  • entmod
  • dictnext
  • get_attr
  • menuunload
  • ssget
  • tblnext

Top

6.Not implemented interfaces:

  • acad_pop_dbmod
  • acad_push_dbmod
  • acad_truecolorcli
  • acad_truecolordlg
  • acdimenableupdate
  • acet-layerp-mode
  • acet-layerp-mark
  • acet-laytrans
  • acet-ms-to-ps
  • acet-ps-to-ms
  • defun-q-list-ref
  • defu-q-list-sef
  • layerstate-addlayers
  • layerstate-delete
  • layerstate-getlayers
  • layerstate-has
  • layerstate-import
  • layerstate-rename
  • layerstate-restore
  • layerstate-save
  • mem
  • vl-acad-defun
  • vl-acad-undefun
  • vl-arx-import
  • vl-bb-ref
  • vl-bb-set
  • vl-doc-export
  • vl-doc-import
  • vl-doc-ref
  • vl-doc-sef
  • vl-exit-with-error
  • vl-exit-with-value
  • vl-get-resource
  • vl-list-exported-functions
  • vl-list-loaded-vlx
  • vl-propagate
  • vl-unload-vlx
  • vl-vlx-loaded-p
  • vl-curve-getClosestPointToProjection
  • vlr-current-reaction-name
  • vlr-data-set
  • vlr-deepclone-reactor
  • vlr-dwg-reactor
  • vlr-dxf-reactor
  • vlr-editor-reactor
  • vlr-insert-reactor
  • vlr-lisp-reactor
  • vlr-miscellaneous-reactor
  • vlr-notification
  • vlr-owner-add
  • vlr-owner-remove
  • vlr-owners
  • vlr-pers-list
  • vlr-pers-p
  • vlr-pers-release
  • vlr-reaction-name
  • vlr-reaction-set
  • vlr-reactions
  • vlr-remove-all
  • vlr-set-notification
  • vlr-sysvar-reactor
  • vlr-trace-reaction
  • vlr-undo-reactor
  • vlr-wblock-reactor
  • vlr-window-reactor
  • vlr-xref-reactor
  • zrx
  • zrxload
  • zrxunload

Top

7.Minor part of LISP interfaces still have problems currently in some special conditions.

For more details, please refer to http://www.zwcad-doc.com/helppad/Lisp function.htm


ZWCAD Object Model

ZWCAD uses hierarchical structure to organize all the objects, ZWCAD application object is the root object for all the objects. The view of this hierarchical structure is called object mode, which shows that each object can provide access to which object of next level, as shown in the following figure.

ZWCAD object model

ZWCAD sorts all the objects in the object model through collection, for example, "blocks" is a collection object which contains the all the block insertion in the ZWCAD graphics. A box is used to identify a collection object by boxes in object model.

All the objects in the ZWCAD object model have one or more attributes which are used to describe the object feature, for example, circle object has the "radius", "area" attributes.

All the objects in the ZWCAD object mode have their own methods which provide actions to the certain type of object. Some methods can be applied in most part of graphic objects, for example, mirror and copy method, but some methods just can be applied in the specified objects, such as offset etc.

You can refer to the "ZWCAD VBA Reference", if you want to know about the attributes and methods of some special type of ZWCAD objects.

Next getting the first graphic object in model space of the drawings will be taken as an example to introduce general steps of accessing the ZWCAD object:

1.Initialize the ActiveX object environment

The VLISP function should be invoked if you want to access the ZWCAD object, and if you want to use the functions, you must invoke the vl-load-com functions firstly to load the supportive code:

(vl-load-com)

2.Get the root object of the object model

ZWCAD application object is the root object of the ZWCAD object model. Access to other objects must begin from the root object and then search level by level from the hierarchical structure. It can invoke the vlax-get-zwcad-object function to get the ZWCAD application object, the format is as below:

(setq *zwcadObject* (vlax-get-zwcad-object))

This function has no parameters, return the pointer of pointing the ZWCAD applications #<VLA-OBJECT IZWCADApplication 57a9de4>, the type of return value is VLA-object. In order to maintain compatibility of LISP programs, ZWCAD supports the vlax-get-acad-object function which is equal to vlax-get-zwcad-object function,

3.Realize the attributes and the methods of the ZWCAD application objects

vlax-dump-object function is used to list the attributes and methods of the specified VLA objects, its syntax is shown as follow:

(vlax-dump-object VLA-obj [T])

It just lists the attributes of specified VLA objects if there is no the "T" parameter. Executing the following code to list the attributes and methods of ZWCAD application objects:

(vlax-dump-object *zwcadObject*)

The command bar shows as below:

Property values:
; ActiveDocument (RO)
; Application (RO)
; Caption (RO)
; DefaultFilePath
; Documents (RO)
; FullName (RO)
; Height
; LocaleID (RO)
; WindowLeft
; Library (RO)
; Name (RO)
; Path (RO)
; PlotManager (RO)
; Preferences (RO)
; StatusBar
; WindowTop
; VBE (RO)
; Version (RO)
; Visible
; Width
; HWND (RO)
; WindowState
; LockHardID (RO)
; StatusID (RO)
Methods supported:
; LoadZVB (1)
; UnloadZVB (1)
; RunMacro (1)
; ZoomAll ()
; ZoomCenter (2)
; ZoomExtents ()
; ZoomPrevious ()
; ZoomPickWindow ()
; ZoomScaled (2)
; ZoomWindow (2)
; Update ()
; DefineFunction (2)
; UndefineFunction (1)
; Help (3)
; Quit ()
; ListZDS ()
; LoadZDS (1)
; UnloadZDS (1)
; LoadLISP (1)
; RunCommand (1)
; RunScript (1)
; GetInterfaceObject (1)
; IsFunctionLoaded (1)
; SetAppForMPrint (1)
; MPrint (1)

In "Property values", it partly lists the attributes of ZWCAD application objects, such as ActiveDocument, Application (ZWCAD application), Caption and so on. The attribute with "(RO)" mark is read-only and cannot be modified, such as the attribute Caption(RO), it means that the information on the title bar of current ZWCAD application can not be modified.

In "Methods supported", it partly lists some methods which could operate ZWCAD application objects, such as Update, ZoomWindow, Quit and so on. The number in the parentheses means the number of parameters which should be passed when invoking the method. For example, the method Quit(), it means that there is no need to pass any parameters when invoking the Quit method in ZWCAD application.

From the object model we can find that the upper layer of the "mode space" object is "document" object, so the ActiveDocument of ZWCAD application objects is our required attribute.

4.Get the current active document object

You need to firstly get the document set objects "Documents" before get the general document objects, and then travel set objects to search the required document object. Since the current document object needs to be accessed frequently, in the object model can get the required document directly through the root object. Please refer to the below:

(setq curdocument (vlax-get-property *zwcadObject* 'ActiveDocument))

Return the pointer of current active document object #<VLA-OBJECT IZWCADDocument 21440c>

5.Realize the attributes of active document object

(vlax-dump-object curdocument)

Following is a part of the returned the attribute information:

; ModelSpace (RO)

ModelSpace is one of the active object attributes, and is also a VLA object.

6.Get the model space object

(setq mspace (vlax-get-property curdocument 'ModelSpace))

Return the pointer of model space object #<VLA-OBJECT IZWCADModelSpace 20cd5c>

7.Realize the attributes and methods of the model space

(vlax-dump-object mspace T)

Following is a part of the returned information of the method:

; Item (1)

Item is one of the methods of the model space object, it accepts a parameter which is used to get the specified index graphics object of the model space, and it is also a VLA object.

8.Get the first graphic object of the model space.

(setq circleObj (vlax-invoke-item mspace 'Item 0))

Return the pointer of first graphic object of model space#<VLA-OBJECT IZWCADCircle 21d974>

Note: the above steps 3, 5 and 7 in the exemplary steps are not the essential steps. The tress steps can be omitted if the users are quite familiar with the ZWCAD object model.