PolyLines and Blocks.
PolyLines and Blocks!!! Come back... Don't run away....
Honestly, they are a lot easier to deal with than you think.
I know that they are called "complex entities", but the only
difference between them and other entities is that we just have to dig a
bit deeper to get to what we want. In fact, once we get there I'll show
you a couple of things that you swear is magic. So bear with me, take your
time, and hang on for a ride on the magic carpet.......
PolyLines.
The lwpolyline entity, or "optimized polyline," is new to
Release 14.
A lwpolyline is defined in the drawing database as a single graphic
entity.
This is different than a standard polyline, which is defined as a group of
subentities. Lwpolylines display faster and consume less disk space and
RAM.
In Release 14, 3D polylines are always created as standard polyline
entities.
2D polylines are created as lwpolyline entities unless they have been
curved or fitted with the PEDIT command. When a drawing from a previous
release is opened in Release 14, all 2D polylines convert to lwpolylines
automatically unless they have been curved or fitted or contain xdata.
We will have a look at the R13 and below Polyline first.
First of all draw 3 joined polylines. (3DPoly if you are using R14).
Then type this :
Command: (setq e (entget (car (entsel))))
AutoLisp should return something like this :
Select object: ((-1 . ) (0 . "POLYLINE") (5 . "27B") (100
. "AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDb3dPolyline") (66 . 1) (10 0.0
0.0 0.0) (70 . 8) (40 . 0.0) (41 . 0.0) (210 0.0 0.0 1.0) (71 . 0) (72 . 0) (73
. 0) (74 . 0) (75 . 0))
Hey, wait a minute!!!......AutoLisp has returned the entity list, and I
can see that it's a Polyline, but there are no co-ordinates, and where
does AutoLisp get the co-ordinates for all the vertices?
As I said earlier, we need to dig a little bit deeper to get the
information we require. This is where the (entnext) function comes into
play.
Now type the following 5 code segments :
Command: (setq e1 (entget (entnext (cdr (car e)))))
((-1 . ) (0 . "VERTEX") (5 . "27C") (100 . "AcDbEntity")
(67 . 0) (8 . "0") (100 . "AcDbVertex") (100 . "AcDb3dPolylineVertex") (10
391.774 521.633 0.0) (40 . 0.0) (41 . 0.0) (42 . 0.0) (70 . 32) (50 . 0.0) (71
. 0) (72 . 0) (73 . 0) (74 . 0))
Command: (setq e2 (entget (entnext (cdr (car e1)))))
((-1 . ) (0 . "VERTEX") (5 . "27D") (100 . "AcDbEntity")
(67 . 0) (8 . "0") (100 . "AcDbVertex") (100 . "AcDb3dPolylineVertex") (10
758.971 383.418 0.0) (40 . 0.0) (41 . 0.0) (42 . 0.0) (70 . 32) (50 . 0.0) (71
. 0) (72 . 0) (73 . 0) (74 . 0))
Command: (setq e3 (entget (entnext (cdr (car e2)))))
((-1 . ) (0 . "VERTEX") (5 . "27E") (100 . "AcDbEntity")
(67 . 0) (8 . "0") (100 . "AcDbVertex") (100 . "AcDb3dPolylineVertex") (10
257.549 377.344 0.0) (40 . 0.0) (41 . 0.0) (42 . 0.0) (70 . 32) (50 . 0.0) (71
. 0) (72 . 0) (73 . 0) (74 . 0))
Command: (setq e4 (entget (entnext (cdr (car e3)))))
((-1 . ) (0 . "VERTEX") (5 . "27F") (100 . "AcDbEntity")
(67 . 0) (8 . "0") (100 . "AcDbVertex") (100 . "AcDb3dPolylineVertex") (10
391.774 521.633 0.0) (40 . 0.0) (41 . 0.0) (42 . 0.0) (70 . 32) (50 . 0.0) (71
. 0) (72 . 0) (73 . 0) (74 . 0))
Command: (setq e5 (entget (entnext (cdr (car e4)))))
((-1 . ) (0 . "SEQEND") (5 . "280") (100 . "AcDbEntity")
(67 . 0) (8 . "0") (-2 . ))
The (cdr (car e)) returns the entity name of entity list e. Each code
segment then uses the (entnext entity name) of the entity that precedes
it.
Take note of the entity type of each variable :
e (0 . "POLYLINE")
e1 (0 . "VERTEX")
e2 (0 . "VERTEX")
e3 (0 . "VERTEX")
e4 (0 . "VERTEX")
e5 (0 . "SEQEND")
Do you see that a 3 line Polyline consists of a master or, parent list,
4 vertex and an end-of sequence ("SEQEND") list.
To extract the entitity list for each vertex is therefore, quite easy.
We just need to loop through the sequence of vertices until we reach the
SEQEND list.
Here's an example of a function that will print the coordinates for each
vertex of a Polyline :
(defun c:coord ( / e r)
(setq e (entget (car (entsel))))
;get the parent entity list
(setq r 1)
;set loop control number to 1
(while r
;while loop control is not nil, carry on looping
(setq e (entget (entnext (cdr (car e)))))
;get the vertex entity list
(if (/= (cdr (assoc 0 e)) "SEQEND")
;if it is not "end-of-sequence
(progn
;do the following
(terpri)
;new line
(princ (cdr (assoc 10 e)))
;print the co-ordinates
);progn
(setq r nil)
;if end of sequence, stop looping
);if
);while
(princ)
);defun
(princ)
There is a quicker way of retrieving the entity list of a Polyline vertex.
(nentsel) let's you select an entity and returns the name of the entity
even if it belongs to a polyline. Try this. Type this, then select any
vertex of a polyline.
(setq e (entget (car (nentsel))))
AutoLisp should return something like this :
Select object: ((-1 . ) (0 . "POLYLINE") (5 . "270") (100
. "AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDb3dPolyline") (66 . 1) (10 0.0
0.0 0.0) (70 . 9) (40 . 0.0) (41 . 0.0) (210 0.0 0.0 1.0) (71 . 0) (72 . 0) (73
. 0) (74 . 0) (75 . 0))
How's that? Straight to the entity list!!
Now, while we're here, let's have a quick look at blocks.....
Blocks.
Create a block consisting of a couple of lines and a circle with a
radius of 20.
Now type this :
(setq e (entget (car (nentsel))))
Now pick the circle. AutoLisp should return something like this:
Select object: ((-1 . ) (0 . "CIRCLE") (5 . "282") (100 .
"AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDbCircle") (10 0.0 -1.51849 0.0) (40
. 20.0) (210 0.0 0.0 1.0))
Hey, Hang about. It's returned the entity list of the circle even
though it's part of a block!! Now type the following:
(setq d (assoc 40 e))
(setq e1 (subst '(40 . 50.0) d e))
(entmod e1)
Now REGEN the drawing.
Did you noticed what happened? The radius of the circle has change even
though it's part of a block. Not only that, it has also redefined the
block definition.
In other words, every block in the drawing with the same name would have
changed.
I told you it was magic......
Let's change the layer of the circle:
(setq d (assoc 8 e1))
(setq e2 (subst '(8 . "STEEL") d e1))
(entmod e2)
Again, REGEN the drawing. The circle has changed to Layer
"STEEL".
Now do you see what I mean by magic. I bet you never thought you would be
able to modify a block without exploding it. Well you can now.....
LwPolylines.
As we mentioned earlier, LwPolylines are a new feature in AutoCad
Release 14.
They differ in that they are defined as a single entity. Let's have a look
at a LwPolylines entity list. Draw a LwPolyline and enter this:
(setq e (entget (car (entsel))))
AutoLisp should return something like this:
Select object: ((-1 . ) (0 . "LWPOLYLINE") (5 . "287")
(100 . "AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDbPolyline") (90 . 3) (70 .
1) (43 . 0.0) (38 . 0.0) (39 . 0.0) (10 597.908 661.3) (40 . 0.0) (41 . 0.0)
(42 . 0.0) (10 1179.86 476.045) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 479.39
397.084) (40 . 0.0) (41 . 0.0) (42 . 0.0) (210 0.0 0.0 1.0))
As you can see, there is no need to use (entnext) to step through the
vertex entities as the group 10 entity code is already part of the parent
list.
But, we do have another problem!! There are numerous group 10 entity
codes.
(As well as Group 40 - Start Width; Group 41 - End Width and Group 42 -
Bulge)
To extract these, we need to first, find the length of the list. Then we
must loop through each code entity in the list searching for a group 10.
Once found, we can easily extract the vertex co-ordinates. The following
function does just that:
(defun c:lwcoord (/ e len n e1)
(setq e (entget (car (entsel))))
;get the entity list
(setq len (length e))
;get the length of the list
(setq n 0)
;set counter to zero
(repeat len
;repeat for the length of the entity list
(setq e1 (car (nth n e)))
;get each item in the entity list
;and strip the entity code number
(if (= e1 10)
;check for code 10 (vertex)
(progn
;if it's group 10 do the following
(terpri)
;new line
(princ (cdr (nth n e)))
;print the co-ordinates
);progn
);if
(setq n (1+ n))
;increment the counter
);repeat
(princ)
);defun
(princ)
Well, that's it concerning Polylines and Blocks. I told you it was easy!!!
Remember, I've only scratched the surface with the things that you can do
once you dig into entity lists, especially with complex entities.
One last thing. Want to create your own entity?
Normally, in AutoLisp you would draw a line like this:
(command "Line" pt1 pt2 "")
Now, create you own line by doing this:
(setq e '((0 . "LINE")(8 . "0")(10 50.0 50.0 0.0)(11 100.0 100.0 0.0)))
(entmake e)
Makes you think, doesn't it??
Cheers for now................ |