Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to acces entities within a block

15 REPLIES 15
SOLVED
Reply
Message 1 of 16
Kycau
13150 Views, 15 Replies

How to acces entities within a block

Hello,

I have a drawing, with lots of entities (lines, arcs, polylines, etc. and blocks).

 

For example, I need to change all of them to a new layer, adjust their linetype and color, or whatever.

I first creation a selection set, and while running it through, I make all necessary changes to every entity.

Things a clear to me, untill I get to blocks.

I learned that there are different block: block, insert block, endblock... But I don't understand what is the difference between them.

How can I get entity names, of the subentities, of which the block is composed ?

I browsed the internet, in hope to find a solution... I looked at nentsel, nentselp, entnext functions... but the best what I have found, is this:

;; GetBlockEntities   by Lee McDonnell   [07.05.09]

;; ARGS:
;; Blk   ~  Block Name [Str]

;; RETURN:
;; List of Entities (Enames)

(defun GetBlockEntities  (Blk / tStr)
  (if (tblsearch "BLOCK" Blk)
    (GetObj (tblobjname "BLOCK" Blk))))

; Get Sub-Entities from Table Def
(defun GetObj  (bObj)
  (if (setq bObj (entnext bObj))
    (cons bObj (GetObj bObj))))

 

I tried to understand how this piece of code works, and it seems I did, but here's the question.

When a block is created, it's entityname (entity order) is placed after the subentities' names, isn't that so?

 

What I mean, is that if I draw two lines, and make a block of them, and then try the next code :

(setq en (car (entsel)))   ; I select the block
(setq en1 (entnext en))    ; I get "nil" instead of first subentity name

 

What am I missing ?

 

 

15 REPLIES 15
Message 2 of 16
Lee_Mac
in reply to: Kycau


@Kycau wrote:

When a block is created, it's entityname (entity order) is placed after the subentities' names, isn't that so?


You are correct, however, when the block definition is created, not the block reference.

 

When creating a block definition using entmake[x], the BLOCK entity (AcDbBlockBegin) is created  and is followed by the various entities that make up the block definition geometry, and finally an ENDBLK entity which indicates to AutoCAD that we are finished constructing the block definition.

 

When inserting a block reference (or INSERT) entity, the INSERT entity (AcDbBlockReference) is created and is followed by any attribute reference entities (ATTRIB) held by the block reference, before a terminating SEQEND entity to instruct AutoCAD that we have finished adding attribute references.

 

The key to accessing the block definition using Vanilla AutoLISP is the tblobjname function; this function will return the BLOCK entity (AcDbBlockBegin), which is the header of the block definition as stated above.


[ Aside: note also that the entity returned by the tblobjname function differs from the object returned when retrieving the same block definition from the Block Collection through Visual LISP via the vla-item method - this method will return the VLA-object representation of the BLOCK_RECORD entity (AcDbBlockTableRecord), which is the parent of the BLOCK entity ]

To better explain, below is the entity hierarchy of a block definition as it appears in the Block Table:

 

+-- TABLE (AcDbBlockTable)
|
+--+-- BLOCK_RECORD (AcDbBlockTableRecord)
   |
   +--+-- BLOCK (AcDbBlockBegin)
      |
      +-- < Block Geometry Entity >
      |
      +-- < Block Geometry Entity >
      |
     ...
      |
      +-- < Block Geometry Entity >
      |
      +-- ENDBLK

 

Therefore, after retrieving the BLOCK entity using the tblobjname function, we can step through the entities composing the block definition using the entnext function to sequentially iterate over the entities in the drawing database.

 

For example:

 

(defun get-block-entities ( blk / ent lst )
    ;; Define the function, declare local variables
    
    (if ;; If the following returns a non-nil value
        ;; i.e. if the block exists in the drawing

        (setq ent (tblobjname "block" blk)) ;; get the BLOCK entity

        (while (setq ent (entnext ent))
            ;; Step through the entities in the block definition
            
            (setq lst (cons ent lst))
            ;; Construct a list of the block components
            
        ) ;; end WHILE
        
    ) ;; end IF
    
    (reverse lst) ;; Return the list
    
) ;; end DEFUN

 

You would call the above with the block name to return a list of entities that make up the block definition.

 

Message 3 of 16
Kent1Cooper
in reply to: Kycau


@Kycau wrote:

....

 

.... if I draw two lines, and make a block of them, and then try the next code :

(setq en (car (entsel)))   ; I select the block
(setq en1 (entnext en))    ; I get "nil" instead of first subentity name

....


What you want is not the next entity after the insertion or reference of the Block [there isn't one if the Block is the last thing in the drawing], but the next entity after the Block's definition as a sort of "virtual" entity, which you can get to with the (tblobjname) function, extracting for the purpose the Block name from the insertion.  You can get the first object in the Block definition this way:

 

(setq en1 (entnext (tblobjname "block" (cdr (assoc 2 (entget en))))))

Kent Cooper, AIA
Message 4 of 16
dbroad
in reply to: Kycau

My first question is what do you want to do with these block entites?  I hope you want to set everything to bylayer.  But there is already a command to do that:  SETBYLAYER.

 

That said, you've gotten some great responses.  Here is an addition that uses vla techniques.  Normally you can work directly with the collection of objects of the block definition rather than making a list of enames and working with them via entget and entmod techniques.

 

(vl-load-com)

;;Get all the block entities within a selected block
;;Does not get all the subobjects of all the nested blocks.
;;D.C. Broad, Jr. 2013
;;FORMAT: (GETBLOCKITEMS <INSERTENAME>)
(defun getblockitems (e / o n blks blk enames)
  (setq
    o	 (vlax-ename->vla-object e)	;insert object
    n	 (vla-get-effectivename o)	;name
    blks (vla-get-blocks (vla-get-document o)) ;block collection
    blk	 (vla-item blks n)		;block of interest
  )
  ;;build a list with the block definitions enames
  (vlax-for n blk
    (setq enames (cons (vlax-vla-object->ename o) enames))
  )
  (reverse enames)			;return list otherwise nil
)

;;Command branch form of getblockitems
(defun c:getblockitems (/ ss)
  (if (setq ss (ssget ":S:E" '((0 . "insert"))))
    (getblockitems (ssname ss 0))
  )
)

(princ "\getblockitems and c:getblockitems loaded...")

 Very nice explanation Lee Mac.

Architect, Registered NC, VA, SC, & GA.
Message 5 of 16
Lee_Mac
in reply to: dbroad


@Anonymous wrote:
Very nice explanation Lee Mac.

Cheers Dave Smiley Happy

Nice to see you in these parts... and an 'Expert Elite' no less!

Message 6 of 16
Kycau
in reply to: Kycau

Lee_Mac, Kent1Cooper,

 

Thanks a lot for your exhaustive explanations! Now everything is clear.

 

dbroad,

 

Actually I need the opposite thing 🙂 I need to switch from "bylayer" linetype, to the specific linetype of the layer.

I mean, if an entity has a "byLayer" linetype, and the Layer's linetype is "HIDDEN", I need the entity to have the "HIDDEN" linetype instead of "byLayer".

Maybe there is a command similar to "setbylayer" ?

I also intend to make some specific color adjustments for different entities, so I'll have anyway to make this lisp-routine, which I'm working on.

 

Lee_Mac, dbroad,

 

Thanks for your VisualLISP solutions, but unfotunately, I haven't managed yet to learn VisualLISP.

All I have learned so far,  are Ron Leigh's lessons (http://ronleigh.com/autolisp/alessons.htm).

 

Would you recommend some nice literature on VisualLISP, please ?)

 

And one more thing... I wonder if the information from (http://exchange.autodesk.com/autocad/enu/online-help/browse) is up-to-date, because at the bottom of the page, is written "Copyright ©2011... "

Message 7 of 16
Kycau
in reply to: Kycau

1. shouldn't it be:

 

(GetObj (tblobjname "BLOCK_RECORD" Blk))))

instead of:

 

 

(GetObj (tblobjname "BLOCK" Blk))))

?

 

2. Should I always write the table-name with capital letters?

Message 8 of 16
dbroad
in reply to: Lee_Mac

Lee,

Thanks.  It's Doug by the way.  Yes.  I was surprised to be nominated to EE.  Have enjoyed your contributions.

Architect, Registered NC, VA, SC, & GA.
Message 9 of 16
Lee_Mac
in reply to: dbroad


@Anonymous wrote:

Lee,

Thanks.  It's Doug by the way.  Yes.  I was surprised to be nominated to EE.  Have enjoyed your contributions.


My sincere apologies Doug, you have almost the same handle as Dave Broad who frequents the CADTutor forums - hence the confusion. Smiley Embarassed

 

Nevertheless, congratulations on your EE nomination, and many thanks for your compliments for my contributions!

 

Lee

Message 10 of 16
Lee_Mac
in reply to: Kycau


@Kycau wrote:

1. shouldn't it be:

 

(GetObj (tblobjname "BLOCK_RECORD" Blk))))

instead of:

 

(GetObj (tblobjname "BLOCK" Blk))))

 


 

Good question, but no, "BLOCK" corresponds to the Block Table, not the type of entity to be retrieved.

 

There are a limited number of valid table-name arguments accepted by the tblsearch, tblnext & tblobjname functions corresponding to the various tables, these are:

 

"APPID"

"BLOCK"

"DIMSTYLE"

"LAYER"

"LTYPE"

"STYLE"

"UCS"

"VIEW"

"VPORT"

 


@Kycau wrote:

2. Should I always write the table-name with capital letters?


 

As stated in the documentation, the table-name argument is not case-sensitive, so either uppercase or lowercase is fine.

 

Message 11 of 16
dbroad
in reply to: Kycau

Kycau,

I don't know your application but for most users, I would discourage making the changes to blocks that you are making.  It makes it harder to make changes to drawings if colors, linetypes, and lineweights are managed at the object level.  I used to use that approach until a fellow 

Just because the functions I gave you are vlisp doesn't mean that you cannot use them. They return enames, which I believe is what you wanted.  Vlide has some good help files on the vl, vlr, vla functionality.  Daniel Stein has a free visual lisp text floating around.  Afralisp is another good source.

Architect, Registered NC, VA, SC, & GA.
Message 12 of 16
Kycau
in reply to: dbroad

dbroad,

 

Thanks,

The thing is that I receive multiple drawings from different architectural companies, and I have to adjust all of them to my needs... And quite often, a lot of objects in these drawings come to me with specific propreties at the object level.

 

And thanks for your recommendations )

I go from time to time to AlfraLISP, while searching for answers, but never read it from A to Z 🙂

Message 13 of 16
Anonymous
in reply to: Kycau

Thanks for all, so i have the same question but for dynamic blocks. Please help.

Message 14 of 16
Anonymous
in reply to: Kycau

Is there a way to access dynamic parameters as an entity name ?

 

For example in a block editor if I dump an flip parameter I get these:

 

((-1 . <Entity name: 7ff6022d6e50>))
; IAcadBlockFlipParameterEntity: IAcadBlockFlipParameterEntity Interface
; Property values:
; Angle = 0.0
; Application (RO) = #<VLA-OBJECT IAcadApplication 00007ff6034e3f10>
; BasePoint = (0.0 50.0 0.0)
; BaseStateLabel = "Not flipped"
; ChainActions = 0
; Document (RO) = #<VLA-OBJECT IAcadDocument 000000447200bc38>
; EndPoint = (100.0 50.0 0.0)
; EntityTransparency = "ByLayer"
; FlipDescription = ""
; FlipLabel = "Flip state1"
; FlippedStateLabel = "Flipped"
; Grips = 1
; Handle (RO) = "39D"
; HasExtensionDictionary (RO) = 0
; Hyperlinks (RO) = #<VLA-OBJECT IAcadHyperlinks 0000003ca5a471c8>
; LabelPosition = (100.0 50.0 0.0)
; Layer = "0"
; Linetype = "ByLayer"
; LinetypeScale = 1.0
; Lineweight = -1
; Material = "ByLayer"
; Name = "Flip"
; ObjectID (RO) = 46
; ObjectName (RO) = "AcDbBlockFlipParameterEntity"
; OwnerID (RO) = 43
; PlotStyleName = "ByLayer"
; ShowProperties = -1
; TrueColor = #<VLA-OBJECT IAcadAcCmColor 0000003ca5a48f60>
; Visible = -1

 

But with the lisp above (getblockentities) this entity name cannot seen in the entity list.

 

Message 15 of 16
JBerns
in reply to: Anonymous

The code above would be used to get object info from the block definition, correct?

 

How would you modify the code to get the object info from a block insert?

 

I have a function that creates a plate (rectangle) and inserts one of three blocks based on user input.

The blocks are a hole, notch, or keyway. Each block is available in two sizes, but are not dynamic blocks.

The geometry inside the block that I am trying to access is either a circle or an arc.

The inserts are placed at various positions on the plate, also based on user input.

 

The goal is to add a dimension to the arc or circle of the first Insert, to the right of the left bend line, along the bottom of the plate. The block to be dimensioned is encircled in yellow in the image.

2018-09-28_13-46-32.png

 

 

 

I know I can use the DIM command to manually select the circle/arc inside the block, but I want to accomplish the dimensioning with automation.

 

I have attached a drawing for your convenience. The block names are Hole56TP, Key56, and Notch150.

 

Thanks for your time and attention. I look forward to the replies.

 

 

Kind regards,

Jerry

 

 

-----------------------------------------------------------------------------------------
CAD Administrator
Using Inventor 2022
Autodesk Certified Instructor
Autodesk Inventor 2020 Certified Professional
Autodesk AutoCAD 2017 Certified Professional
Message 16 of 16
brew2u
in reply to: Kycau

I solved that submital problem in 1998

Created MSIO.LSP that creates

new layers with overrides in the

layer name.

email me for your copy

Works on any outside dwg,

especially good for bound xrefs

or old ms v5 imports

all plain lisp NO VLISP

Bruce Wyche autocad since 1983

Mechanical Eng.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report