You are on page 1of 16

September 1, 2009

Nate’s Simple Autolisp – Lesson 005

Filed under: Tutorials — nateholt @ 12:20 am

Using (nentsel…) and changing an existing block insert instance

Here’s the real-world example (happened  yesterday) that triggers quick Lisp lesson
number “005”.  The issue revolves around the color yellow.

The challenge

I reviewed some drawings from a client. Everything looked fine with dark background.
But a light background, some of the attributed blocks were difficult to read – yellow
ones. Very uncomfortable at best, bordering on impossible at worst.

Normally, I would just figure out what “layer” the attributed text was on and force that
layer’s color from yellow to a better color.

But there was a problem. This block’s single yellow text attribute definition was not set
up to have its COLOR display “ByLayer”. It was “hard-coded” to be yellow ALL the
time.

How can we tell?… Here is the result of the AutoCAD “LIST” command on the upper
“52” bubble. Note that the single attribute, tag name BUBNUM, has been defined
to always display as “YELLOW”.
A Solution

Let’s fix this. What we’ll do now is build up a little AutoLISP tool to force a picked
attribute to display in a different color. If you’d like to follow along “hands
on”, download the above sample dwg file here. What we want our little AutoLISP tool
to do is this: we pick on a yellow attribute. Our tool reads the attribute and, if the
attribute’s color was NOT set up “BYLAYER”, changes its color to color “red”. This
should show up nicely whether a dark or light background is selected.

Step-by-Step: Difference between (entsel) and (nentsel)


In each of the previous lessons here, here, here, and here we have looked at the
AutoLisp (entsel) entity selection function.

With the example dwg file open/active on your screen, type this at the “Command:”
prompt:

Command: (entsel) [Enter]


Select object: [pick on text in upper bubble] (<Entity name: 7ffffb04930> (-0.0405614
0.0279495 0.0))

The (entsel) function returns a two-element list: the first element is the entity name of
the picked entity (i.e. the block insert instance) and the second element is the XY
coordinate of the mouse pick point. We just want the entity name, the first element of
this returned list. Use the AutoLISP “car” function to extract the first element. So, let’s
do it again. Type this at the “Command:” prompt and pick on the upper bubble:

Command: (car (entsel)) [Enter]


Select object: [pick on text in upper bubble] <Entity name: 7ffffb04930>

Remember, just like in the previous lessons, we need to keep those “(” and “)” balanced
out. For each “(” you add, you need to balance it with a “)”. Okay, good so far. Now
let’s modify our “program” to open up the returned entity name with a call to “entget”:
 
Command: (entget (car (entsel))) [Enter]
Select object: [pick on text in upper bubble] ((-1 . <Entity name: 7ffffb04930>) (0 .
“INSERT”) (330 . <Entity
name: 7ffffb039f0>) (5 . “18B”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”)
(8 . “0”) (100 . “AcDbBlockReference”) (66 . 1) (2 . “bubble”) (10 0.0 0.0 0.0)
(41 . 1.0) (42 . 1.0) (43 . 1.0) (50 . 0.0) (70 . 0) (71 . 0) (44 . 0.0) (45 .
0.0) (210 0.0 0.0 1.0))
 
Okay, so this is the available information returned when we picked on the block insert
instance with (entsel). If you compare this cryptic list of data (the very top part below)
with the upper part of the LIST command’s display when pick the same item (shown
below beginning at the “list” command entry), you can see some of the potential data
match-ups. Each piece of data is represented by a “dotted pair”. There is a lead number,
referred to as the “DXF code”, identifies what the data on the right-hand side of the dot
is associated with. We can guess at the ones shown here… they seem to match up:
 
 
Here is a partial list of DXF codes (i.e. the left-hand number in each dotted pair). This
is pulled from the Visual Lisp on-line HELP (topic = “DXF group codes in numerical
order”).
 
 
 
The problem
 
No problem getting information on the overall block insert instance itself. The
problem is that we cannot get access to the attribute text embedded inside of the block
insert instance… we cannot specifically “pick” on it.  No matter what we pick on the
block insert, whether it is the circle part or the attribute part of the block, (entsel) always
returns the entity name of the overall block insert. What we really need is a pick
function that digs deeper into these complex entities and pulls out the “nested” sub-
entity name of what we pick.
 
 
Selection of nested sub-entities with (nentsel)
 
This is where the AutoLISP function (nentsel) comes into play. It works like (entsel)
but, if you pick on an entity that is part of an overall complex entity like a block insert
instance or a multi-segment polyline, (nentsel) returns the picked sub-entity name, not
the main overall entity name that (entsel) always returns.
 
So, let’s try it on the top bubble. Type this at the “Command:” prompt and pick on the
text attribute inside of the top bubble block insert:
 
Command: (entget (car (nentsel))) [Enter]
Select object: [pick on text in upper bubble] ((-1 . <Entity name: 7ffffb04940>) (0 .
“ATTRIB”) (330 . <Entity
name: 7ffffb04930>) (5 . “18C”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”)
(8 . “0”) (62 . 2) (100 . “AcDbText”) (10 -0.0606988 -0.0385562 0.0) (40 .
0.078125) (1 . “52”) (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . “Standard”) (71 . 0)
(72 . 4) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttribute”) (280 . 0)
(2 . “BUBNUM”) (70 . 0) (73 . 0) (74 . 0) (280 . 0))
 
Okay, now compare the above data return from (entget (car (nentsel))) with the original
“LIST” display on the whole bubble block insert. Note that the data returned due to the
(nentsel) pick now points at the attribute itself, NOT the overall block insert instance as
we saw with (entsel).
 
 
 
How do we know that the “62” type identifies the entity “Color” assignment? Look at
the bottom of the “DXF codes” listing. DXF code “62” is associated with a fixed color
assignment (i.e. not “ByBlock” or “ByLayer”). The value that is the right-hand part of
the 62 dotted pair is the color number.
 
Our yellow attribute text is forced to remain yellow at all times because the BUBNUM
attribute carries a (62 . 2) subrecord. Color yellow is color number 2!
 
Experiment – rewrite the attribute to color 1 – RED.
 
If we could only force this attribute’s (62 . 2) subrecord to be (62 . 1), then maybe it
would turn “red”. Let’s try.
First step, we repeat the last command but we save the entity’s data in a variable we’ll
call “old_data”. Type this at the Command: prompt.
 
Command:(setq old_data (entget (car (nentsel)))) [Enter]
Select object: [pick right on the attribute]((-1 . <Entity name: 7ffffb26940>) (0 .
“ATTRIB”) (330 . <Entity
name: 7ffffb26930>) (5 . “18C”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”)
(8 . “0”) (62 . 2)(100 . “AcDbText”) (10 -0.0606988 -0.0385562 0.0) (40 .
0.078125) (1 . “52”) (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . “Standard”) (71 . 0)
(72 . 4) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttribute”) (280 . 0)
(2 . “BUBNUM”) (70 . 0) (73 . 0) (74 . 0) (280 . 0))
 
Now we’re going to use a “substitution” AutoLISP function called “subst” along with a
couple other cryptic fuctions “cons” and “assoc”. Type this at the Command: prompt.
 
Command: (setq new_data (subst (cons 62 1) (assoc 62 old_data) old_data)) [Enter]
((-1 . <Entity name: 7ffffb26940>) (0 . “ATTRIB”) (330 . <Entity name:
7ffffb26930>) (5 . “18C”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”) (8 .
“0”) (62 . 1)(100 . “AcDbText”) (10 -0.0606988 -0.0385562 0.0) (40 . 0.078125)
(1 . “52”) (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . “Standard”) (71 . 0) (72 . 4)
(11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttribute”) (280 . 0) (2 .
“BUBNUM”) (70 . 0) (73 . 0) (74 . 0) (280 . 0))
 
Okay, now we have our new version of the entity’s data held in a variable called
“new_data”.
 
One more step. We push this new version of the data back out to the entity. Type this at
the Command: prompt.
 
Command: (entmod new_data) [Enter]

… and the attribute instantly changes from yellow (color 2) to red (color 1) !
Wrapping all this into a little utility

That was instructive, but very painful. Let’s put all of these steps into a little ASCII text
file, give it a “.lsp” extension, and APPLOAD it to use when needed.

Here it is using the Visual Lisp editor (any ASCII text editor can be used).
APPLOAD the file and, when you need it, type ATTR2COLOR [Enter] at the
Command: prompt. Change the color of as many “non-BYLAYER” colored attributes
as you can pick!

July 6, 2010
Generic text/mtext/attrib/attdef Find/Replace utility – AutoLISP

Filed under: Tips — nateholt @ 4:53 pm

Enter substrings for “find” and “replace”… then pick/pick/pick on TEXT,


MTEXT, ATTRIB, ATTDEF text string values to update.

Frustration setting in as I worked on AutoCAD libraries for an electrical sub-station


design application… copy circuit to a new drawing name, open, then use an attribute
edit command to change a substring value in a dozen or so attributes. A little
Find/Replace tool would be so welcome right now!

After 20 minutes of this tediousness, decided it was time to either find an existing tool


or create a quick one. Found previous posting for a drawing-wide MTEXT find/replace
utility. Good place to start.

Solution

Here is the result. Seems to work.

The flow is 1) enter “Find” substring, 2) enter “Replace” substring, 3) start picking on
text. The text can be attributes, text entities, attribute definitions, and even multi-line
text (multi-line attributes not covered in this version).

Here is an overview of how the original version was modified.

Step 1 – Renamed the source “.lsp” file to “text_fr.lsp”


Step 2 – Got rid of the drawing-wide “ssget” and changed to a loop of individual text
picks (below).

Step 3 – added two blocks of code to deal with Attributes/Attribute definitions and with
straight Text entities (below).
That should do it. It seems to work for me… speeded-up my effort to copy and
modify my folder of sub-circuits. 

Here’s a simple example of it in operation. Starting out with a sample drawing that
contains the substring “DN100″ in three different places: an attribute that is part of a
block insert instance, a single line of text, and a 3-line multi-line text entity just below
it.
Let’s say we want to selectively change instances of “DN100″ to now be “CM99″.

With the utility APPLOADED (download revised version  here – see update note


below) we launch by typing TEXT_FR [Enter] at the “Command:” prompt.

To use… just APPLOAD the text_fr.lsp file. Then

1. Type TEXT_FR [Enter] at the AutoCAD command prompt

2. Enter the “Find” substring, Enter the “Replace” substring


3. Start picking on individual Text, MText, Attribute or Attribute Definition entities
There it is. Seemed to work really well for me!

UPDATE: user note below correctly points out that if this tool used to find/replace
attribute values for AutoCAD Electrical “TAG1″ attribute values, there is a good chance
(especially if “IEC” tag mode is active) of confusion. This is because there is an
Xdata tag name “VIA_WD_BASETAG” that is pushed out to parent components. This
Xdata value carries the base copy of the overall component’s tag-ID. If the tag-ID is
changed by our utility above, then this Xdata value needs to be processed as well. Here
is a screenshot of the addition to our utility to deal with keeping this Xdata in synch.
This code addition should lie dormant unless the tool is used on a “TAG*” attribute
with AutoCAD Electrical in memory.
Update 2 – using the tool on ATTDEFs (as opposed to ATTRIBs) not working. Found
that the utility was set to look at subrecord 1 instead of subrecord 2. Download revised
version of tool here. I apologize for all the confusion this caused. – Nate.

You might also like