LISP

Developing solutions can be a challenge and on this page notes are maintained - maybe they can help you!

If you use AutoCAD or BricsCAD, you probably want to optimize work flows. Customizing is a packet of actions to do this and it often involves creating a user interface that fit your needs and automating drawing tasks in a smart way. If you want to dive into that, you'll have a long road ahead of you. However, that shouldn't keep you from doing so. Why? Because there is so much written on the net to help you, with relative small actions you can achieve great results and, we are here to help you.

There is much to gain but managers are in general hard to convince to put money in customizing. Keep them informed and show them how much easier and faster CAD-challenges can be solved, you may get their support. Keep them involved.



If you want to do some easy programming to do smart things with CAD, you need a programming language. So, we've seen them come: VisualBasic and .NET. Then why on earth would we program in LISP? Good question! There are reasons enough not to use it. LISP is old, not from this time and not user friendly. In fact LISP saw the light in 1958, seriously, it is far more than half a century old. It is long time neglected by Autodesk while pushing for more modern stuff. No, just forget LISP. Or...?

Why on earth LISP?

Bricsys did a great job reanimating LISP and this is our guess with reasoning:

  • It is platform independent, runs on your Mac and Linux system too, where VB and NET are not an option. And with the choice for MS-Windows not so obviously any more, this is a valid argument.
  • Millions of programs are written in LISP, an investment that is not easy to neglect.
  • People often prefer LISP over the alternatives.
  • LISP does the job, period. It was a logical choice for John Walker (founder AutoCAD). By that time in 1986, LISP was almost three decades old.
  • With an initial steep learning curve, it is still relative easy to master.

More can be found here: https://en.wikipedia.org/wiki/AutoLISP

From AfraLISP http://www.afralisp.net/visual-basic-for-applications/:

In recent times, VBA has fallen out of favour with Autodesk, who are now promoting the use of more modern development environments with AutoCAD, specifically VB.NET.

This happened around 2010 and it laid a bomb under programming investments done with VBA. Guess what will happen with VB.NET when people favour OS-X for example?


Knowledge Base

Documentation Tools

Manuals

Platform independent software, open-source:

Screen casts

See http://www.vanderworp.org/Screen-casting

Programming Tools

  • Notepad ++ is useful to write code. Notepad ++ recognizes the syntax and uses colors to clarify the structure. Download: https://notepad-plus-plus.org/

    • Search and Replace: ctrl + h
    • Indent: selecting block, tab or shift + tab
  • Cygwin you mainly use to search, it's a bash command line in Windows, and therefore similar to the OS X command line. You can find it here: https://cygwin.com/.

    • Some examples:
      Wiebe@win7ws ~ << ~ This means that you are in your home directory (/home/Wiebe).
      $ cd /cygdrive/c/ << Change directory to drive C:.
      
      Wiebe@win7ws /cygdrive/c << There you are now.
      $ cd /cygdrive/c/ProgramData/cadchup/ << To the cadchup folder.
      
      Wiebe@win7ws /cygdrive/c/ProgramData/cadchup
      $ find . -iname "*adch*.dwt" << Search from current directory (.), case insensitive to (-iname) a pattern.
      ./cadchup.dwt  < This conforms to the pattern.
      
      Wiebe@win7ws /cygdrive/c/ProgramData/cadchup
      $ cd /cygdrive/c/ProgramData/Autodesk/ApplicationPlugins/cadchup.bundle/  << Other folder ...
      
      Wiebe@win7ws /cygdrive/c/ProgramData/Autodesk/ApplicationPlugins/cadchup.bundle
      $ grep -i 'alert' *  << Search all files (*) case insensitive (-i) for text "alert".
      grep: contents: Is a directory << That does nothing because it is a folder without files.
      
      Wiebe@win7ws /cygdrive/c/ProgramData/Autodesk/ApplicationPlugins/cadchup.bundle
      $ grep -i -r 'alert' *  << This provides us with something, thanks to -r (including subdirectories. These are all file names and lines in files with that text and can therefore be very much.
      contents/abc_start_cad.lsp: (t (setq alerttxt (strcat "CADchUP is not found in " programdata locac " nor " appdata locac ". Please fix this first.")) (alert alerttxt) (exit))
      ...
      
      Wiebe@win7ws /cygdrive/c/ProgramData/Autodesk/ApplicationPlugins/cadchup.bundle
      $ grep -i -r 'alert' * | wc -l  << Send output to grep wc (via |). Word Count with -l gives the number of lines.
      32  << so 32 lines with word "alert".
      Moral: Cygwin is a Linux command line and a powerful tool to perform complex tasks and what is above is just a starting point.

Concepts

BricsCAD and AutoCAD and dealing with AutoLoader

Read this page: BricsCAD_and_AutoCAD_and_dealing_with_AutoLoader.

Start sequence AutoCAD and BricsCAD

What happens, and in what order, when you start your CAD program? The answer - a bit outdated - can be found here: http://www.blog.cadnauseam.com/2008/09/01/what-is-loaded-at-autocad-startup-and-when/, look at the list.

LISP start files

You want your CAD program to do things at start or during opening a document.

When\Vendor

BricsCAD

AutoCAD

At program start

on_start.lsp

acad.lsp

At document loading

on_doc_load.lsp

acaddoc.lsp

Read the previous paragraph for more options, but these work fine. If menu's are used you may find menuname.mnl also a proper construction to use. In AutoCAD, TRUSTEDPATHS can complicate things. If these files do not exist you can make them and put them in the search path. First find out if and where they live by pasting something like this on the command line:

(findfile "on_start.lsp")

If these files don't exist you can create a directory where you put them and append it to the "Support File Search Path" or put them in %appdata% like:

C:\\Users\\%username%\\AppData\\Roaming\\Bricsys\\BricsCAD\\V17x64\\en_US\\Support

Running commands at start up

Regular CAD commands should be run as a final step. Otherwise they can interfere with other things that are about to start or have been started during initializing the program. The construction for this is using (S::STARTUP).

The problem with all startup files like (S::STARTUP), acad.lsp, acaddoc.lsp is that there is only one valid file and it may be used or created by other app. A nice programming technique is checking for existence, checking if it contains the right code and - if not - append the right code. For example, CADchUP contains these measures.

As far as (S::STARTUP) is concerned you may want to take a look at http://www.cadtutor.net/forum/showthread.php?26336-S-STARTUP-Function to see how code is appended by using a defun-q construction. Alternative: https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2016/ENU/AutoCAD-Customization/files/GUID-FDB4038D-1620-4A56-8824-D37729D42520-htm.html. An example of this, in on_doc_load.lsp (BricsCAD) or acaddoc.lsp AutoCAD):

; Your other LISP code

; Putting commands in a list, yes, this is a list.
(defun-q finalstepcommands ()
  (command "._ribbonclose")
  (command "._-layer" "m" "0" "")
  (command "._filetabclose")
  (command "._taskbar" "1")
)

; Appending this list to to special STARTUP list
(setq S::STARTUP (append S::STARTUP finalstepcommands))

; More LISP code ...

As an alternative you can also start your program with a /b switch. This looks like cadprogram.exe /b startup.scr, where startup.scr can contain commands, but also LISP.

vla-get vla-put

You can control much with this combo. The question is: How to use it? Reading this is not enough, paste code on the command line and study it (F2)...

If you paste:

(setq ss (vlax-get-acad-object))

... you get an object - assigned to variable ss. Next you want to know the properties of ss:

(vlax-dump-object ss)

You see the list of properties and one of the entries is "Preferences". Let's see what it offers, if you paste each line...

(setq ss (vla-get-preferences (vlax-get-acad-object)))
(vlax-dump-object ss)

... you get an object files. So the next step:

(setq ss (vla-get-files (vla-get-preferences (vlax-get-acad-object))))
(vlax-dump-object ss)

Now we have all files settings. As long is there is not a (RO) text (Read Only), we can change it.

For example, we have all plotter configurations on a server drive. The current locations are:

(vla-get-printerconfigpath ss)
(vla-get-printerdescpath ss)
(vla-get-printerstylesheetpath ss)

We assign a different location:

(vla-put-printerconfigpath ss "x:\\cad_users\\19.1\\plotters")
(vla-put-printerdescpath ss "x:\\cad_users\\19.1\\plotters\\pmpfiles")
(vla-put-printerstylesheetpath ss "x:\\cad_users\\19.1\\plotters\\plotstyles")

Cool?

In summary: You start with (vlax-get-acad-object) for building a selection set, making it complexer as described, where (vlax-dump-object ss) is your friend. If you know the properties by using "get", you can change them with "put".

Easy Peacy!

Calling LISP from within LISP

If you have code that you want to reuse, there is the load construction like:

(load filename [onfailure])

This evaluates filename. Another less common way is to define your command like (defun c:runthis ()...) and call it from within another LISP function like:

(princ "\nYour code to run... ")
(c:runthis)
(princ "\nDone. ")

You can consider this construction as an addition to error handling as described at http://www.afralisp.net/autolisp/tutorials/error-trapping.php

LISP and groups

How can we handle named and unnamed groups?

If you want to do operations within a group you can use what is documented here: http://adndevblog.typepad.com/autocad/2012/12/how-to-add-a-group-in-a-selection-set-from-an-autolisp-function.html. A cached version:

(defun selgrp (grpname)
   ;; grpname is the group name, it accepts
   ;; unnamed groupnames, such as *A1
   (setq grp (dictsearch (namedobjdict) "ACAD_GROUP"))
   (setq a1 (dictsearch (cdr (assoc -1 grp)) grpname))
   (setq ss (ssadd))
   (while (/= (assoc 340 a1) nil)
      (setq ent (assoc 340 a1))
      (setq ss (ssadd (cdr ent) ss))
      (setq a1 (subst (cons 0 "") ent a1))
   )
   ss
)

Settings in LISP file

You probably do record settings like this:

(setq ortho_org (getvar "orthomode"))

... and more as needed. Then you code your program and change ORTHOMODE as needed:

(setvar "orthomode" 1)

However, a user should get all changed settings back after your code is finished. So you end with:

(setvar "orthomode" ortho_org)

If you do it properly, you put that line of code in your error handler too, in particular because many people press Esc too frequently.

A Consideration

For a small LISP program there is nothing wrong with this approach. However, for a big and interactive program it is not always the right way. Consider a program that interactively asks for input and finally comes up with a result. Somewhere during the proces a user switches on OSNAP. Can you imagine how user feels after finishing the command? "Hey, I thought I turned Osnap on, #@#$".

In this case we should respect the user and add code on a local base, not on a general base. To give an example:

(setq pt1 (getpoint "\nSpecify first point of line: "))
(setq pt2 (getpoint "\nSpecify last point of line: "))
(command "_.line" pt1 pt2 "")

But running object snap mode can spoil it. The last line could become:

(command "_.line" "_non" pt1 "_non" pt2 "")

Problem solved... Unless the command is an impressive list like:

(command "_.pline" pt2 "_w" "0.0" "0.0" "_a" "_d" hkd2 pt4 "_l" pt5 "_a" pt6 "_l" pt7 "_a" pt8 "_l" pt9 "_a" pt11 "_l" pt13 "_a" "_d" hkd3 pt15 "_l" pt16 "_a" pt17 "_l" pt18 "_a" pt19 "_l" pt20 "_a" pt22 "_l" "_cl")

In such a case you can consider making two functions, (commandpre) and (commandpost), where (commandpre) stores object snap mode and turns it off and (commandpost) restores it. Read on how to use boole to achieve this.

More on OSMODE

OSMODE or object snap mode. This is a number, a bitsum of many settings:

0 None
1 Endpoint
2 Midpoint
4 Center
8 Node
16 Quadrant
32 Intersection
64 Insertion
128 Perpendicular
256 Tangent
512 Nearest
1024 Quick
2048 Apparent Intersection
4096 Extension
8192 Parallel

For example, value 511 (green "P" button in CADchUP) is a bitsum of 1+2+4+8+16+32+64+128+256=511

You could use a construction as illustrated with ORTHOMODE, but you will find out it doesn't work perfectly. Why? Because OSNAP on and off is also included in the code.

16384 Object Snap on or off, F3 (on: subtract value, off: add value)

To illustrate: Do OSMODE 1. OSMODE is set to "endpoint", value 1 (check). Press F3 for turning off object snap. This is not the same as setting it to value 0, it is just a switch to turn off or turn on the setting of OSMODE (read this twice). Do OSMODE and see that it changed to 1+16384=16385.

So you want to turn osnap on and simply substract 16384? That works for 16385, but not if the value is unknown and set by the user, for example 1-16384 is a bad idea. So we need a different solution. We use a function called boole for truth tables.

Turning OSNAP off:

(setvar "osmode" (boole 7 (getvar "osmode") 16384))

Turning OSNAP on:

(setvar "osmode" (boole 2 (getvar "osmode") 16384))

Toggle OSNAP:

(setvar "osmode" (boole 6 (getvar "osmode") 16384))

Selection

Selecting objects and points. The pointer is square, dimensions (width and height) are in pixels:

  • Pickbox: The square pointer when you select objects.
  • Aperture: The square pointer when object snap is active for selecting a point based on a part of an entity.
  • Gripsize: The magnetic handles of selected objects when no command is active. In AutoCAD, the magnetic area is the same as the gripsize value. In BricsCAD, the magnetic area is set with variable AttractionDistance.

All in all, it is easy to set all values for selection squares to values using LISP. Tuning these values to users needs is preventing them from missing clicks or wrong object clicks. Importance of setting this to optimal values is often underestimated.

This site is hosted by NedCAD.

De inhoud van deze site wordt aangeboden zoals het is, zonder enige vorm van garantie en heeft verschillende licenties. Meer informatie over licenties staat hier.