Automatically number several attributes of a block.

Automatically number several attributes of a block.

mid-awe
Collaborator Collaborator
5,705 Views
17 Replies
Message 1 of 18

Automatically number several attributes of a block.

mid-awe
Collaborator
Collaborator

Hi all,

I am struggling with how to automatically sequentially number each attribute of a block and continue with the next block. I can't think of a better way to describe my challenge than to use an image.

modules.jpg

I have a few more configurations of these blocks but the important parts are displayed. I need these numbers to begin at any provided integer and continue for all of the attributes sequentially. The top block in the image only has 12 attributes; the tags do not match and so I need to iterate through the attributes changing the values sequentially. I will need to store the last number into a global so that I can feed it back the next numbered block I insert no matter if the next block has 12, 9, 6, 3, or even 2 attributes.

 

I have seen many examples of auto incrementing the number in single attribute blocks, but nothing of how to do as I need. 

 

Please help if you are able and understand my challenge.

 

Thank you in advance.

0 Likes
5,706 Views
17 Replies
Replies (17)
Message 2 of 18

Scottu2
Advocate
Advocate

Hello Mid-awe,

I would suggest creating a block with attribute tags like c1 c2 c3 c4 c5 c6

The numbering lisp routine would scan for tags in sequence

Since their physical location matches the unique tagname just process tags in sequence.

Select the block objects with attributes

Create a list of entity names by sorting the list by x,y (left to right and top to bottom)

Set the starting value

Step though the entity name list

  Scan though attributes until the sequence ends

    When a tag is found loop though the list of tags (c1 c2 c3 c4 c5 c6)

    If block.tag.found = tag.list then change its value and increment the value

    Keep checking each tag in the list

Then keep checking each block entity name in the list

 

Based on the image posted there are three unique blocks.

One with all 6 attributes, one with none, and one with three attributes.

The block with three attributes can still have use the same tag numbering c4, c5 and c6 but does not contain c1,c2, or c3.

 

From the original post, the first block (the top three bundles) can be defined as c1 thru c12.  The routine can scan for all c1 thru c12 and will only increment if it exists.

 

0 Likes
Message 3 of 18

mid-awe
Collaborator
Collaborator

Thank you for the suggestion.  All of the 5 distinct blocks have attributes named like 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12. The idea was that if the block was exploded then the tag would serve as the value. That served well for many years, but now we are doing thousands more drawings and automation is needed. 

 

In some drawings we might have 24 circuits and we may need two six circuit systems and one twelve circuit system. In that situation the tags would be 1,2,3,4,5,6 and then 1,2,3,4,5,6 and finally 1,2,3,4,5,6,7,8,9,10,11,12. Now do you see that there is no way for me to rename the tags in any logical way. Without first exploding them on insert and renaming the tags before reconstructing the block. I can do that but I was hoping for a simpler solution. 

 

Perhaps someone can share a method of counting the number of attributes with some way of feeding a sequential stream of numbers from a globally defined start.

 

Thank you for your suggestion.

0 Likes
Message 4 of 18

Moshe-A
Mentor
Mentor

@mid-awe hi,

 

here is something to start with:

1. for start, the increment number is stored in USERI5 sysvar. it is not saved in dwg nor in registry so you will have to  decide where do you want to store your increment number?

2. you can modify each block attribute one at a time, this way you control the numbering order between blocks.

3. the lisp is expecting attributes tag name to be numbers (as you mentioned). if you still want to change tag names as @Scottu2 recomended then i will prepare it also.

 

enjoy

moshe

 

; Load ActivX Support
(vl-load-com)

;;; database object and containers
(setq *acad-object* nil)      ; Initialize global variable
(defun acad-object ()
  (cond (*acad-object*)       ; Return the cached object
    (t
     (setq *acad-object* (vlax-get-acad-object))
    )
  )
)

; return a pointer to active document
(setq *active-document* nil)  ; Initialize global variable
(defun active-document ()
  (cond (*active-document*)   ; Return the cached object
    (t
     (setq *active-document* (vla-get-activedocument (acad-object)))
    )
  )
)

(defun c:autoinc (/ askint ; local function
	            start ss n AcDbBlockReference attributes^ ;| local variables |;)

 (defun askint (msg v / ask)
  (initget (+ 2 4)) 
  (setq ask (getint (strcat "\n" msg " <" (itoa v) ">: "))) 

  (if (not ask)
   (setq ask v)
   (setq v ask)
  )
 ); askint

 ; here start c:autoinc
 (if (= (getvar "useri5") 0)
   (setvar "useri5" 1)
 )

 (if (and
       (setq start (askint "Starting number" (getvar "useri5")))  
       (setq ss (ssget "_:L:S+." '((0 . "insert") (66 . 1))))
     )
  (progn
   (setq n start)
   (vlax-for AcDbBlockReference (vla-get-ActiveSelectionSet (active-document))

    (setq attributes^ '())
    (foreach AcDbAttrib (vlax-safearray->list (vlax-variant-value (vla-getAttributes AcDbBlockReference)))
     (setq attributes^ (cons (cons (atoi (vla-get-tagString AcDbAttrib)) AcDbAttrib) attributes^))
    )

    (foreach item (vl-sort attributes^ (function (lambda (e1 e2) (< (car e1) (car e2)))))
     (vlax-put-property (cdr item) 'textString (itoa n))
     (setq n (1+ n))
    )

    ; dispose memory
    (foreach item attributes^
     (vlax-release-object (cdr item))
    )
     
    (vlax-release-object AcDbBlockReference) ; dispose memory
   ); vlax-for

   (setvar "useri5" n)
  ); progn
 ); if

 (princ)
); c:autoinc

Message 5 of 18

Scottu2
Advocate
Advocate

Mid-awe,

 

Another storage location for the increment number is to write it to a text file.

Then read it back each time the routine starts and provide an option to change its value.

 

I think the routine will still work, just as long you provide a list of tagnames to iterate through.

However, If the tagename does not match the physical clockwise pin location then generate a sequential list of attributes  by finding the larges circles, sorted x,y and

then group and sort the attributes that are within the circle using the circle's center as a reference point

(The pins are split about the center of the circle, so find the attribute order by quadrant and sorting

ascending or descending depending on which quadrant)

 

'tags do not match'

Please post the drawing to clarify.

 

 

 

0 Likes
Message 6 of 18

wael6URAQ
Enthusiast
Enthusiast

Many thanks to you all for sharing knowledge

 

MR moshe

 

I want to ask 2 questions about your code if you please

 

Can We add prefix to the increment number

for example :  R1001  ,  R1002  ,  R1003   ..........and so on.

 

Can We add a filter  to increment some attributes only  but leave the other some untouched

for example the tags containing "MARK" only to be incremented and other tags not to change 

 

I attached my block please check and help.

0 Likes
Message 7 of 18

3wood
Advisor
Advisor

You can also try the code below.

Enter "#*-MARK" as your tag search pattern, "R" as your prefix, and "1" as the start number.

FMA.gif

;;; Fill in multiple attributes in sequence
;;; 2022.5.9 by 3wood
(defun C:FMA (/ def1 def2 def3 n1 ss1)
  
  (setq FMA_PATTERN (getstring (strcat "\nEnter tag pattern <" (setq def1 (if (not FMA_PATTERN) "*" FMA_PATTERN)) ">: "))) ;Attribute search pattern, using wildcard
  (if (equal FMA_PATTERN "") (setq FMA_PATTERN def1))
  
  (setq FMA_PREFIX (getstring T (strcat "\nEnter prefix <" (setq def2 (if (not FMA_PREFIX) "" FMA_PREFIX)) ">: "))) ;Prefix in attribute value
  (cond ((equal FMA_PREFIX "") (setq FMA_PREFIX def2))
	((equal FMA_PREFIX " ") (setq FMA_PREFIX "")) ;Enter a space to remove prefix
	)

  (setq FMA_START (getint (strcat "\nEnter start number <" (setq def3 (if (not FMA_START) "1" (itoa FMA_START))) ">: "))) ;Number sequence start number
  (if (not FMA_START) (setq FMA_START (atoi def3)))
   
  (setq n1 0)
  
  (if (and
	(setq ss1 (ssget '((-4 . "<AND")(0 . "INSERT")(66 . 1)(-4 . "AND>"))))
	)
    (repeat (sslength ss1)
      (foreach r1 (vlax-safearray->list (vlax-variant-value  (vla-getattributes (vlax-ename->vla-object (ssname ss1 n1)))))
	(if (wcmatch (vla-Get-Tagstring r1) FMA_PATTERN)
	  (progn
	    (vla-Put-Textstring r1 (strcat FMA_PREFIX (itoa FMA_START)))
	    (setq FMA_START (1+ FMA_START))
	    )
	  )
	)
      (setq n1 (1+ n1))
      )
    )
  (princ)
  )
Message 8 of 18

Sea-Haven
Mentor
Mentor

My $0.05 if you have created a block it has a attribute order, you do not need to know tag names so in your case will fill in the attributes in there order, as you suggest if you have made in order 1 2 3 4 .... then its easy. The 2nd part is you could look at the block get-attributes and return how many so if you have blk1 with 5 atts blk2 with 3 atts it will number sequentially. There is in block editor a move order of attributes if needed.

 

Ok last comment before running check does block exist if so read all the blocks and attributes and get last number. Then ask use last+1 or a user number.

0 Likes
Message 9 of 18

wael6URAQ
Enthusiast
Enthusiast

Thank you very much it is exactly what i need

working properly

Many Many Many Thanks

 

 

0 Likes
Message 10 of 18

ronjonp
Mentor
Mentor

@3wood FWIW

;; This
(setq ss1 (ssget '((-4 . "<AND") (0 . "INSERT") (66 . 1) (-4 . "AND>"))))
;; Is the same as this
(setq ss1 (ssget '((0 . "INSERT") (66 . 1))))
Message 11 of 18

jbfuentes2955C
Community Visitor
Community Visitor

Can you modify it to be with letters like A, B, C, D instead of 1, 2, 3, 4... ? thanks.

0 Likes
Message 12 of 18

Sea-Haven
Mentor
Mentor

An "A" is (chr 65) or (chr x) so B is (chr 66) only issue is what happens at Z, do you go to ZA or A1 ?

 

In the code above I did not test but should be 

 

(itoa FMA_START)

(chr FMA_START)

 

 You will though need to change the start number to

 

(setq FMA_START (ascci (getstring "\nEnter character for start ")))

 

0 Likes
Message 13 of 18

thecocuk07
Participant
Participant

hi  

 

now in mass elections   numbering form   ;

last no <<<<<<<<<<<                           15 14 13 12 11     

<<<<<<<<<<<<<<<<                             10 9  8   7  6

<<<<<<<<<<<<first number                 5  4  3   2   1

 

right to left and bottom to top    .... 

----------------------------------------------

Is it possible to start from left to right and switch to a lower line when the line ends, and go from left to right again?

first no >>>>>>>                        1  2   3   4  5

>>>>>>>>>>>>>                        6  7   8   9 10

>>>>>>>>>>>>last no             11 12 13 14 15

 

 

 

 

0 Likes
Message 14 of 18

3wood
Advisor
Advisor

Can you show it in a few blocks and do a screen shot?

0 Likes
Message 15 of 18

thecocuk07
Participant
Participant
0 Likes
Message 16 of 18

3wood
Advisor
Advisor

FMA uses the selecting order to sort out the sequence number in blocks. That's why it produces a "backward" result. Because the bottom right block is the first one in your window selection.

To make a proper Left-Right / Top-Bottom sequenced automatic numbering, instead of FMA, you can try ALTEXT.

Just select the "Left-Right/Up-Down" option from the pulldown menu.

ALTEXT6.gif

 

0 Likes
Message 17 of 18

thecocuk07
Participant
Participant

thank you  

0 Likes
Message 18 of 18

thinesh_babuLE255
Explorer
Explorer

Your script is more helping us!. Thank you! 

 

But i need one more logic, How do we change the base value for each selected objects. The base value should replicate the first block value of each selected objects. Please reply!! 

0 Likes