Set annotative scales in an object without using "command" or vl-cmdf

Set annotative scales in an object without using "command" or vl-cmdf

Anonymous
Not applicable
3,309 Views
12 Replies
Message 1 of 13

Set annotative scales in an object without using "command" or vl-cmdf

Anonymous
Not applicable

Hello folks, I am managing a large collection of blocks that contains labels and measures; I need those texts and mtexts to be annotative and add them a list of annotative scales. Im currently exploding those blocks, making them annotative, adding scales through commands then recreating the block.

 

I want to make that without using commands because exploding and recreating the block slows my script, and also make it silent. Those commandline prompts ("1 object updated to support annotation scale <1:500>") are really annoying and cant be supressed (as far as I know).

 

My question, is there any VLA functions that can suit my needs? Or some workaround that I could use?

 

Thanks a lot

 

0 Likes
3,310 Views
12 Replies
Replies (12)
Message 2 of 13

Moshe-A
Mentor
Mentor

@Anonymous  hi,

 

i google a little and it looks like there is a way to add annotation to object with XDATA just did

not found the full solution yet but if you do, you'll not have to explode the blocks.

 

can you post the code you already have?

 

moshe

 

 

0 Likes
Message 3 of 13

Moshe-A
Mentor
Mentor

>> check this thread << the greatest Lee Mac introduce (LM:annoscale). it's not exactly what you are looking for but you will get a direction on how to access entity annotation scales.

 

moshe

 

0 Likes
Message 4 of 13

Anonymous
Not applicable

The subroutine Im already using is this one. Receives Obj as a vla-object or ename (usually vla) and a list of scale names.

 

(defun GiveAnnotativeScale (obj scaleList / )
     (vl-cmdf "_chprop" (ename obj) "" "_a" "_y" "")
     (foreach scale scalelist
          (vl-cmdf "-objectscale" (ename obj) "" "add" scale "")
     )
     T
)

 

(defun ename (obj)
     (if (= (type obj) 'vla-object) (vlax-vla-object->ename obj) obj)
)

0 Likes
Message 5 of 13

Moshe-A
Mentor
Mentor

 

(vl-cmdf "_chprop" (ename obj) "" "_a" "_y" "")

 

Hmmm....

Are you sure (vl-cmdf) can accept VLA-object? 

 

 

Signature

(vl-cmdf [arguments ...])
arguments

Type: Integer, Real, String, List, or ads_name

AutoCAD commands and their options.

The arguments to the vl-cmdf function can be strings, reals, integers, or points, as expected by the prompt sequence of the executed command. A null string ("") is equivalent to pressing Enter on the keyboard. Invoking vl-cmdf with no argument is equivalent to pressing Esc and cancels most AutoCAD commands.

 

???

0 Likes
Message 6 of 13

Anonymous
Not applicable

In fact it does not support vla objects, that's why I have that (ename ..) function (it is a shortcut for (vlax-vla-object->ename ...) )

 

I have never used dictionaries, have a little idea on how they work but not a clue about how to edit them.

It seems to be preety messed up in there. Labirinth to get to annotation scales seems to be something like this:

 

(entget entity) has a dictionary called ACAD_XDICTIONARY

     ACAD_XDICTIONARY has another one called AcDbContextDataManager

          AcDbContextDataManager has another called AcDbAnnotationScales

               AcDbAnnotationScales contains a bunch of "annotative instances".

Down here, keys 10 and 11 are used for insertion points, 50 for rotation, and 340 is another set of data representing an annotation scale.

 

Seems I need to edit AcDbAnnotationScales to add data. Guess one way could be to copy another annotation instance, then change the annotation scale it refers to and add it to the dictionary. But I dont know how to get the new annotation scale dictionary to replace in the annotative instance. Guess I need to get it from the drawing file somehow.

When I get that done I have to entmod the object. I dont know if I can directly entmod it or I have to entmod  AcDbContextDataManager, then ACAD_XDICTIONARY , then the object

 

There's a lot of things I dont know about dictionaries Smiley Sad

0 Likes
Message 7 of 13

Moshe-A
Mentor
Mentor

well you right it's a big mess i either did not use much dictionaries.

 

0 Likes
Message 8 of 13

Anonymous
Not applicable

I managed to remove an annotative scale from a text object using dictremove. Thing is, I continue viewing the erased annotative scales in screen and properties tab until I close and reopen the drawing file. Tryed with entupd and vl-update but still the same issue. But if I copy that text, erase it then paste, its created with the modification done. Is there any way to make a deep redraw of the object without recreating it?

Still didnt wrote the AddScale part of the script...

 

Here is a sample of the code:

 

(defun vla (obj)
    (if (= (type obj) 'ename) (vlax-ename->vla-object obj) obj)
)
(defun ename (obj)
    (if (= (type obj) 'vla-object) (vlax-vla-object->ename obj) obj)
)
(defun SetAnnotativeScales (object scaleList / objectScales scale scales+ scales-)
    (setq objectScales (LM:annoscales (ename object)))
    (foreach scale scaleList
    (if (not (member scale objectScales))
      (setq scales+ (cons scale scales+))
    ))
    (foreach scale objectScales
    (if (not (member scale scaleList))
      (setq scales- (cons scale scales-))
    ))
    (foreach scale scales+ (AddScale object scale))
    (foreach scale scales- (RemoveScales object scales-))
    (LM:annoscales (ename object))
)
(defun RemoveScales (object scale / enx diclv1 diclv2 diclv3 handles itm)
    (and
      (member scale (LM:annoscales object))
      (setq enx (entget object))
      (setq dicLv1 (cdr (assoc 360 (cdr (member '(102 . "{ACAD_XDICTIONARY") enx)))))
      (setq dicLv2 (cdr (assoc -1 (dictsearch dicLv1 "acdbcontextdatamanager"))))
      (setq dicLv3 (cdr (assoc -1 (dictsearch dicLv2 "acdb_annotationscales"))))
      (setq handles (MultipleAssoc 3 (entget diclv3)))
      (while (setq itm (dictnext dicLv3 (not itm)))
        (if (= (cdr (assoc 300 (entget (cdr (assoc 340 itm))))) scale)
          (setq newDicLv3 (dictremove dicLv3 (car handles)))
        )
        (setq handles (cdr handles))
      )
      (entupd object)
    )
    ;(LM:annoscales object)
)
;Mine
 
;-----------------------------------------------------------------------
(defun LM:annoscales ( ent / dic enx itm rtn )
(if
(and
(setq enx (entget ent))
(setq dic (cdr (assoc 360 (cdr (member '(102 . "{ACAD_XDICTIONARY") enx)))))
(setq dic (cdr (assoc -1 (dictsearch dic "acdbcontextdatamanager"))))
(setq dic (cdr (assoc -1 (dictsearch dic "acdb_annotationscales"))))
)
(while (setq itm (dictnext dic (not itm)))
(setq rtn (cons (cdr (assoc 300 (entget (cdr (assoc 340 itm))))) rtn))
)
)
(reverse rtn)
)
;LeeMac, from Adesk forums
;-----------------------------------------------------------------------
 

;-----------------------------------------------------------------------
(defun MultipleAssoc (key alist / x nlist)
(foreach x alist
(if (eq key (car x))
(setq nlist (cons (cdr x) nlist))
)
)
(reverse nlist)
)
(defun GetScaleList (/ scaleListDict scaleListEnts n )

(setq scaleListDict (dictsearch (namedobjdict) "ACAD_SCALELIST")
scaleListEnts (MultipleAssoc 350 scaleListDict)
scaleList (list "")
N 0
)
(repeat (length scaleListEnts)
(setq scaleList (cons (cons (cdr (assoc 300 (entget (nth n scaleListEnts)))) (nth n scaleListEnts)) scaleList)
n (1+ n)
)
)
(setq ScaleList (cdr (reverse ScaleList)))
)

;--
;Daniel J. Altamura, R.A.
;Altamura Architectural Consulting
;and SoftWorx, Autodesk Authorized Developer
;http://partnerproducts.autodesk.com/popups/company.asp?rdid=2139

;Modified By Jonatan Opazo in 2019, needed another kind of return value
;-----------------------------------------------------------------------

0 Likes
Message 9 of 13

Moshe-A
Mentor
Mentor

why do you want to remove records?

 

the problem with dictionary is it like freestyle database and there is not documentation, you have to dig deep to uncover it.

 

i will try my luck and see if i will come up with something positive.

 

 

0 Likes
Message 10 of 13

Anonymous
Not applicable

In adition to the last lines of code, i tryed to add a scale to the dictionary but it fails. I guess entmake is not the correct way to do this, but idk what else to try. Can someone show me the right way to do this? 

 

(defun AddScale (object scale / DefineNewDictHandle)
      (defun DefineNewDictHandle(lst / leeter numbre handles retVal)
          (foreach letter '("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K")
              (foreach number '(0 1 2 3 4 5 6 7 8 9)
                  (setq handles (cons (strcat "*" letter (itoa number)) handles))
          ))
          (setq handles (reverse handles))
          (while (member (setq retVal (car handles)) lst)
              (setq handles (cdr handles))
          )
          retVal
      )
      (and
          (not (member scale (LM:annoscales object)))
          (setq enx (entget object))
          (setq dicLv1 (cdr (assoc 360 (cdr (member '(102 . "{ACAD_XDICTIONARY") enx)))))
          (setq dicLv2 (cdr (assoc -1 (dictsearch dicLv1 "acdbcontextdatamanager"))))
          (setq dicLv3 (cdr (assoc -1 (dictsearch dicLv2 "acdb_annotationscales"))))
          (setq handle (DefineNewDictHandle (MultipleAssoc 3 (entget diclv3))))
          (dictadd dicLv3
                          handle
                          (entmake (list
                              ;'(-1 . <Entity name: 1c1a7100d90>) ;ename
                              '(0 . "ACDB_MTEXTOBJECTCONTEXTDATA_CLASS")
                              '(5 . "2828A441");wtf is this
                              '(102 . "{ACAD_REACTORS")
                              (cons 330 dicLv3)
                              '(102 . "}")
                              '(cons 330 dicLv3)
                              '(100 . "AcDbObjectContextData")
                              '(70 . 4)
                              '(290 . 0)
                              '(100 . "AcDbAnnotScaleObjectContextData")
                              (cons 340 (obtener scale (GetScaleList)));ename from scalelist
                              '(70 . 1)
                              '(10 1.0 0.0 0.0)
                              '(11 2.58795e+06 5.97714e+06 0.0);insertion points?
                              '(40 . 42.2016)
                              '(41 . 0.0)
                              '(42 . 57.1154)
                              '(43 . 30.8432)
                              '(71 . 2)
                              '(72 . 1);maybe alignment?
                              '(44 . 42.2016)
                              '(45 . 150.0)
                              '(73 . 0)
                              '(74 . 0)
                              '(46 . 0.0)
              ))
          )
          (entupd object)
      )
      ;(LM:annoscales object)
)

0 Likes
Message 11 of 13

Moshe-A
Mentor
Mentor

after my dig i come to this conclusion:

to each annotation scale has a reactor attached to it and that data (ename of the reactor)  you don't have  and you do not know how to generate it. that exactly what OBJECTSCALE command does.

 

i think you have to take another approach:

i'm not sure i remember well we are talking about block + attributes = yes?

than i suggest to do a replacement of the attributes (instead of using OBJECTSCALE)

set CANNOSCALE appropriately  and add a new attrib and let's hope the default will be applied to the new object

than delete the old attrib

 

moshe

 

 

 

 

0 Likes
Message 12 of 13

Moshe-A
Mentor
Mentor

@Anonymous ,

 

hope you did not give up yet cause i think i have 'some' solution:

if you use activex to add text (or replace) where the current text style is annotative the added text would have annotative=yes

after adding the text setting cannoscale would apply the annotation scale

so attached a sample command i did and it works neat with out any echo's to command line (no explode to blocks is needed)

 

the only drawback is you cannot assign annotation scale to each text object but assign it to all globally

and if all the annotative objects should have the same annotation scales then it's not a problem Smiley LOL

 

moshe

 

 

(defun c:addt (/ blocks AcDbBlockTableRecord AcDbEntity)
 (setq blocks (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))))

 ; set annotative text style to be current 
 (setvar "textstyle" "Annotative")
  
 (vlax-for AcDbBlockTableRecord blocks
  (vlax-for AcDbEntity AcDbBlockTableRecord
   (if (eq (vla-get-objectName AcDbEntity) "AcDbText")
    (progn
     (setq text (vla-get-textString AcDbEntity))
     (setq p0 (vla-get-insertionPoint AcDbEntity))
     (setq hgt (vla-get-height AcDbEntity))
     (setq obj (vla-addtext AcDbBlockTableRecord text p0 hgt))  ; add new text, annotative = yes

     (vla-delete AcDbEntity) ; remove old text
    ); progn
   ); if
   (vlax-release-object AcDbEntity) 
  ); vlax-for
   
  (vlax-release-object AcDbBlockTableRecord) 
 ); vlax-for

 (vlax-release-object blocks)

 ; globally apply annotation scales to annotative objects
 (setvar "cannoscale" "1:2")
 (setvar "cannoscale" "1:5")
 (setvar "cannoscale" "1:10")
  
 (princ)  
)
0 Likes
Message 13 of 13

Moshe-A
Mentor
Mentor

Jonatan,

 

please close this thread and mark it as your solution.

 

thanks

moshe

 

0 Likes