Author Topic: When to use entmake?  (Read 9001 times)

0 Members and 1 Guest are viewing this topic.

Lee Mac

  • Seagull
  • Posts: 12857
  • London, England
Re: When to use entmake?
« Reply #15 on: March 02, 2013, 11:04:26 AM »
You're very welcome Tannar, I'll to try to explain as best I can:

Code: [Select]
(cons 10 pt1)
(cons) is used to to take the user input from pt1, combine it with 10 to turn it into a dotted pair to generate the necessary syntax for the DXF code, correct?

Almost. cons is indeed combining the point input assigned to the variable pt1 with the DXF Group 10 integer code, however, in this case a dotted pair is not returned since the second argument of the cons function is a list, not an atom.

Consider the following examples:
Code: [Select]
_$ (cons 1 2)
(1 . 2)
_$ (cons "a" "b")
("a" . "b")
_$ (cons 1 '(2 3 4))
(1 2 3 4)
_$ (cons '(1 2 3) 4)
((1 2 3) . 4)
_$ (cons '(1 2 3) '(4 5 6))
((1 2 3) 4 5 6)

Notice that a dotted pair is only returned if the second cons argument is an atom (excluding nil, since although nil is considered both an atom and an empty list, cons considers nil an empty list).

If the second argument supplied to cons is a list, the first argument is added to the front of the list - you see this a lot when constructing a list within a loop, e.g.:
Code: [Select]
(foreach x '(0 1 2 3 4 5)
    (setq lst (cons x lst))
_$ lst
(5 4 3 2 1 0)

Why no apostrophe when using (cons)?

The apostrophe (or quote) is used to mark an expression or symbol as a literal, to be taken at 'face-value' and not evaluated. In this case we need to evaluate the variable pt1 to obtain the point value assigned to the symbol, and so cons must be used. If the apostrophe is used instead, the pt1 symbol is not evaluated:
Code: [Select]
_$ (setq pt1 '(1 2 3))
(1 2 3)
_$ (cons 10 pt1)
(10 1 2 3)
_$ '(10 . pt1)
(10 . PT1)

For a more in-depth explanation of the apostrophe, see here.

Code: [Select]
(progn)Reading the documentation I can't follow exactly what this function does. I read it, but just doesn't click for me? Hoping to get more insight from you if you wouldn't mind. ;)

The progn function in itself doesn't actually do all that much, it simply evaluates every expression passed to it and returns the result of the last evaluation, e.g.:
Code: [Select]
_$ (progn (setq a 10.0 b 6.0) (/ a b))

However, progn provides us with a convenient 'wrapper' in which we can evaluate multiple expressions and pass the set of expressions to be evaluated as a single argument to another function. Think of progn as creating a 'block' of code, which can then be passed to another function to be evaluated.

In my example:
Code: [Select]
(defun c:mypline ( / pt1 pt2 lst )
   (if (setq pt1 (getpoint "\nSpecify First Point: "))
           (setq lst (list (cons 10 pt1)))
           (while (setq pt2 (getpoint "\nSpecify Next Point: " pt1))
               (setq lst (cons (cons 10 pt2) lst)
                     pt1 pt2
                      '(000 . "LWPOLYLINE")
                      '(100 . "AcDbEntity")
                      '(100 . "AcDbPolyline")
                       (cons 90 (length lst))
                      '(070 . 0)
                   (reverse lst)

Here, if the user has correctly specified a valid point at the getpoint prompt, we then want to evaluate multiple expressions within the 'then' argument for the if function.

However, the 'then' argument will only accept a single expression to be evaluated, so the set of expressions to be evaluated are grouped within the progn function, and this single expression (the progn expression) may then be passed to the if function as a single argument.

If progn was not present, the setq expression would be taken as the 'then' argument, the while expression would be the 'else' argument, and the entmake expression would cause the if function to error with too many arguments.

Note that other functions which accept multiple arguments could equally be used as such a 'wrapper', however, other such functions will come with certain restrictions and will exhibit different behaviour, for example, although and will accept any expression, this function will cease evaluation when an expression returns a nil value (which may be unsuitable for some situations, but perhaps suitable for others); the + function could be used if all expressions to be evaluated return a numerical value... etc.

However, progn is useful in that it will accept any expression, and will simply evaluate all supplied expressions regardless of their returned value, and returning the value of the last expression evaluated.

I describe progn some more in this post.

Code: [Select]
    '(000 . "LWPOLYLINE")
    '(100 . "AcDbEntity")
    '(100 . "AcDbPolyline")
     (cons 90 (length lst))
    '(070 . 0)
  (reverse lst)
The (append) function is new to me, but after reading up on the documentation I think I follow. In your other lists from the first three main routines, you used multiple arguments but did not append them. Any particular reason you did on the c:mypline routine?

In the other programs, the number of parameters is known and fixed: to create the Line we have two point variables; for the Circle we have a point variable and a numerical variable; for the Point we have a single point variable; however, for the LWPolyline, the number of parameters is unknown since the while loop allows the user to continuously pick points in the drawing.

Hence, rather than assigning every picked point to a separate variable, it is far easier and convenient to collect the points into a list and then append this list to the DXF data list supplied to entmake.

Also, is the (list) function the only argument that (append) handles?

Note that the list function is not being passed to the append function as an argument; the result of evaluating the list function forms the argument for the append function.

append will accept any number of list arguments and will return the result of appending the supplied lists into a single list. Whether the supplied lists are constructed using list, cons (not dotted pair), vl-list*, or are a quoted literal list makes no difference, since a list argument is supplied in all cases.
« Last Edit: March 02, 2013, 11:11:06 AM by Lee Mac »


  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: When to use entmake?
« Reply #16 on: March 02, 2013, 10:28:47 PM »
Not to Hi-Jack this thread, just let me know if I should start a new one. 
With ENTMAKE "INSERT", how do I get a block w/ATTRIBUTES to place the attributes in the proper location and Rotation Angle as the rest of the line work etc.

It seems the ATTRIBUTES like to stay where they where created.....

See the following code, for the method I am using.

Code - Auto/Visual Lisp: [Select]
  1.  (defun ABLKInsert (BlockName / Ename NextEnt Data Attdefs)
  2.   (cond
  3.     ((setq Ename (tblobjname "block" BlockName))        ;; get Parent entity name
  4.      (setq NextEnt (entnext Ename))                     ;; first sub entity
  6.      (while NextEnt                                     ;; get ATTDEF subentities
  7.        (setq Data (entget NextEnt))
  8.        (if (= "ATTDEF" (cdr (assoc 0 Data)))
  9.          (setq Attdefs (cons Data Attdefs))
  10.          )
  11.        (setq NextEnt (entnext NextEnt))
  12.        )
  13.      (setq attblk (if (= nil attdefs) 0 1))
  14.      (and
  15.        (entmake (list '(0 . "INSERT")
  16.                       '(100 . "AcDbBlockReference")
  17.                        (cons  8 Lname    )              ;; layer name
  18.                        (cons 66 attblk   )
  19.                        (cons  2 BlockName)
  20.                        (cons 10 blkIP)          ;; Insert Point
  21.                        (cons 41 1.0)
  22.                        (cons 42 1.0)
  23.                        (cons 43 1.0)
  24.                        (cons 50 0  )))          ;; Rotation angle default = 0
  25.      (foreach x (reverse Attdefs)               ;; entmake ATTRIBs based on ATTDEFS
  26.        (entmake
  27.          (list  '(0 . "ATTRIB")
  28.                 (assoc  8 x)
  29.                 (assoc 10 x)
  30.                 (assoc 40 x)
  31.                 (assoc  1 x)
  32.                 (assoc 50 x)
  33.                 (assoc 41 x)
  34.                 (assoc 51 x)
  35.                 (assoc  7 x)
  36.                 (assoc 11 x)
  37.                 (assoc  2 x)
  38.                 (assoc 70 x)
  39.                 (assoc 71 x)
  40.                 (assoc 72 x)
  41.                 (assoc 73 x)
  42.                 (assoc 74 x)
  43.                 ))
  44.        )
  45.        (entmake '((0 . "SEQEND")(8 . "0")))    ;; entmake SEQEND
  46.        )
  47.      )
  48.     (T nil)
  49.     )
  50.   (setq ent (entlast))
  51.   )

With this one function plain blocks or blocks with multiple attributes can be inserted.  However the attribute's inserted location is not correct.

« Last Edit: March 02, 2013, 10:31:56 PM by snownut2 »


  • Guest
Re: When to use entmake?
« Reply #17 on: March 03, 2013, 05:31:33 AM »
There are only certain entity types where the order of the code is imperative.
  Group 90 must be stated before group 10s
  Groups 10 41 42 declare the order of the points, so it imperative they are listed in the proper order.
Others would include SPLINEs MLINEs ( if you dare )
You have the MESH also.
For a detailed explanation on entmaking mesh entities you can see my class at Autodesk University 2012:
You have to register to watch the class. There are a handout and a dataset that can be downloaded.
It is composed by 8 Video Modules, explanation starts from scratch.
By the way I believe it is the first time this has been documented and published, enjoy!

David Bethel

  • Swamp Rat
  • Posts: 656
Re: When to use entmake?
« Reply #18 on: March 03, 2013, 06:22:14 AM »
It seems the ATTRIBUTES like to stay where they where created.....

Getting an ATTRibute correct is a VERY complex  procedure

You will need to take into consideration :

  • INSBASE of the block - group 10 of the BLOCK table definition
  • groups 10 & 11 of the ATTDEF
  • group 41 of the ATTDEF
  • group 50 of the ATTDEF
  • groups 72 & 74 of the ATTDEF
  • the insert point of the INSERT
  • the rotation of the INSERT
  • the X Y & Z scales of the INSERT
  • the UCS of the INSERT
The correct point would be the translation of all of these factors.  Not something that I would want to consider, so here the (command) sequence makes a lot more sense. 

Even if you force the ATTRbute to "'", you can go back with (entlast) and the populate the values.

My $0.02  -David

Oh I forgot !
  • UCS group 210 of the ATTDEF
« Last Edit: March 03, 2013, 08:14:40 AM by David Bethel »
R12 Dos - A2K


  • Bull Frog
  • Posts: 401
Re: When to use entmake?
« Reply #19 on: March 03, 2013, 07:32:50 AM »

The option of whether to use entmake[x] / command calls / ActiveX mostly depends on the application; entmake[x] is the certainly the fastest method for entity generation in AutoLISP,

I concur and its AutoCAD Mac versions friendly. (pun intended)  :)

Lee Mac

  • Seagull
  • Posts: 12857
  • London, England
Re: When to use entmake?
« Reply #20 on: March 04, 2013, 12:09:23 PM »
Were my explanations comprehensible Tannar?  :-)


  • Guest
Re: When to use entmake?
« Reply #21 on: March 04, 2013, 12:12:42 PM »
Were my explanations comprehensible Tannar?  :-)
Absolutely!! I'm still tinkering with things but your explanations were VERY helpful. CAB's homework links also were super beneficial, too.

I've already got some more questions jotted down but want to muscle through some trial and error of my own first. :kewl:

Lee Mac

  • Seagull
  • Posts: 12857
  • London, England
Re: When to use entmake?
« Reply #22 on: March 04, 2013, 12:39:05 PM »
Excellent  8-)

Ask away if you get stuck or don't understand something - it's great to see you finally plunge into the rabbit hole that is LISP  :lol: