Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

need help with LSP to modify parametric block and its attributes

edited February 21 in LISP Codes

Hi.
I have a parametric block of a pipe.
the parameter is the length.
I need help with writing a lisp that will do the follows (I've also attached a sample drawing):
1. select the parametric block (the Pipe Block).
2. use the DIST command to get the required length of the parameter (the required pipe length).
3. assign that value to the length parameter of the selected block (in the sample it is parameter "d1" of the pipe block).
4. assign that DIST value to the "value" field of the "QUANTITY" attribute of the selected block.

in the example file it is the transition from situation 1 to situation 2.

thanks,
Ari.

dwg
dwg
Exp1.dwg
33K

Best Answers

  • :-)
    be careful with (rtos ...), it implicitly uses the system variables for unit and precision ...
    and the string passed-in is then converted into the double value as the parameter/property requires.

    For safety + stability, I would always use (rtos 2 10) to be independent on the system variables ...

    Just a hint for the "property name" : there might be multiple, same-named properties ... using only the "short name" might cuase trouble, if such a same-named property is found in a different property namespace ...
    better to always use the "long property name" (PropertyNameSpace~PropertyName), as shown by (dumpallproperties ename).

    many greetings !

  • Dear Ari,

    1. about the rtos line - do you mean that it is better to write the code like this: (setpropertyvalue obj "d1" (rtos di 2 10))?

    yes, the main idea is to create the string with enough precision : (rtos di 2 10)

    1. about the long property name - can you help me with an example of the code?

    example :
    (dumpallproperties (entlast))

    output :
    ----- Database Properties
    :
    Color (ident: "Color~Native") (AcCmColor [string]) = "ByLayer"
    :
    ----- BIM Properties
    :
    Centerline (ident: "Centerline~BIM") (integer) = ...

    "Color" is the short name, "Color~Native" is the long (and more specific) name ... "Color" might be a property of multiple NameSpaces
    "Centerline" is the short name, "Centerline~BIM" is the long name

    So my suggestion was to always use the "long name" (PropertyName~PropertyNameSpace) to prevent ambiguous cases.

    hope it will clarify ?
    many greetings !

Answers

  • edited February 23

    Dont double post, its confusing

    ; Pick a line and put its length in a attribute
    ; By Alan H Feb 2021 info@alanh.com.au

    (defun c:llen ( / obj objid str )
    (setq obj (vlax-ename->vla-object (car (entsel "\nPick line obj "))))
    (setq objid (rtos (vla-get-Objectid obj) 2 0))
    (setq str (strcat "%<\AcObjProp Object(%<\_ObjId " objid ">%).length \f \"%lu6\">%"))
    (setq obj (vlax-ename->vla-object (car (nentsel "\nPick attribute "))))
    (vla-put-textstring obj str)
    (command "regen")
    (princ)
    )

  • edited February 23

    @ALANH
    Hi and thanks for the reply!
    the lisp is almost good.
    there 2 issues with it:
    1. when I'm inserting the block, the attribute ("QUANTITY" in that case) is invisible. is it possible to set the name of the attribute in the lsp code rather then prompt the lsp to choose it?
    2. the text inserted in to attribute is the code string ( "%%).length " ) in stand of the value it self. i tried to fix the code but I failed... (See Attached Screenshot).
    3. is it possible to write a code that use the "DIST" command to get the length value in stand of getting it from a line object?

    many thanks,
    Ari.

    Capture1.JPG
    1291 x 441 - 35K
    1. The code can look inside the block and use Tagname then set the text value, insert 1st then update else field will appear as the att string.
    2. You removed the format \f
    3. Yeah can do dist but much easier pick line and use Vl-get-length function.
    4. If you change length the field will update re 3. If you never change length then use this.

    Something like this not tested

    (defun c:llen ( / len )
    (setq len (vlax-get (vlax-ename->vla-object (car (entsel "\nPick line obj"))) 'Length))

    (setvar 'attdia 0)
    (command "-insert" blkname pause 1 1 0)

    (foreach att (vlax-invoke (vlax-ename->vla-object (entlast )) 'getattributes)
    (if (= "QUANTITY"(strcase (vla-get-tagstring att)))
    (vla-put-textstring att (rtos len 2 2))
    )
    )

    (command "regen")
    (setvar 'attdia 1)
    (princ)
    )

  • edited February 24

    @ALANH
    I've made small modification to your first code, note the use of the getpoint and getdist functions:

    (defun c:llen ( / obj p1 di )
    (setq p1 (getpoint "\nPoint 1: "))
    (setq di (getdist p1 "\nDistance: "))
    (setq obj (vlax-ename->vla-object (car (nentsel "\nPick attribute "))))
    (vla-put-textstring obj di)
    (command "regen")
    (princ)
    )

    now, with this code i pick the distance without the need for a guide line, and the attribute and the length value is correct.
    my question is that - is it possible to pick the block and not the attribute itself, and let the LSP to find the QUANTITY attribute and put the length value in to it?
    the issue is that:
    the block is already in the drawing (the insert command is redundant) and I set the QUANTITY attribute to be invisible (All my blocks have the QUANTITY attribute invisible),
    then i need to assign the length, sometimes to change it.
    Thanks,
    Ari.

  • Hi Ari,

    at least, to retrieve the properties, you might also use the "generic properties fucntions" :
    (getpropertyvalue ename property)

    "property" is the string name of a property here ... you can list all avaliable properties by :
    (dumpallproperties ename)

    That way it is probaly easier to get the requires Quantity value :-)
    many greetings !

  • edited February 24

    O.K.
    with a little help...
    here is a code that do the work:

    (defun c:PipeLenBL (/ obj p1 di)
    (setq p1 (getpoint "\nPoint 1: "))
    (setq di (getdist p1 "\nDistance: "))
    (setq obj (car (entsel "\nSelect Block ")))
    (setpropertyvalue obj "QUANTITY" (rtos di))
    (setpropertyvalue obj "d1" (rtos di))
    (command "regen")
    (princ)
    )

    when executing the command:
    1. select the distance that will be the QUANTITY attribute value.
    2. select the block to set that value to the QUANTITY attribute value.
    3. update d1 parameter, and as a result of that the length of the block is also updated.

    *clarification: in all of my blocks I have "QUANTITY" attribute, and all of my pipe blocks are parametric with d1 parameter that controls the
    length, and that is why I can use those fixed names.
    obviously, it is limiting the demand for flexibility and make things much more simple...

    subject close.
    Ari.

  • edited February 25

    This will fail if you miss pick say a line (setq obj (car (entsel "\nSelect Block "))) you can use

    (princ "\nSelect Block"))
    (setq ss (ssget "_+.:E:S" '((0 . "Insert")))) this forces select a block can add the blockname filter also.
    I would check that ss exists before continuing
    (setq obj (ssname ss 0))

  • edited February 25

    @Torsten Moses said:
    :-)
    be careful with (rtos ...), it implicitly uses the system variables for unit and precision ...
    and the string passed-in is then converted into the double value as the parameter/property requires.

    For safety + stability, I would always use (rtos 2 10) to be independent on the system variables ...

    Just a hint for the "property name" : there might be multiple, same-named properties ... using only the "short name" might cuase trouble, if such a same-named property is found in a different property namespace ...
    better to always use the "long property name" (PropertyNameSpace~PropertyName), as shown by (dumpallproperties ename).

    many greetings !

    Torsten MANY THANKS!

    1. about the rtos line - do you mean that it is better to write the code like this: (setpropertyvalue obj "d1" (rtos di 2 10))?
    2. about the long property name - can you help me with an example of the code?

    thanks,
    Ari.

  • edited February 25

    @ALANH said:
    This will fail if you miss pick say a line (setq obj (car (entsel "\nSelect Block "))) you can use

    (princ "\nSelect Block"))
    (setq ss (ssget "_+.:E:S" '((0 . "Insert")))) this forces select a block can add the blockname filter also.
    I would check that ss exists before continuing
    (setq obj (ssname ss 0))

    Hi alanh and thanks for the reply.
    The idea of the routine is that you MUST have a specific block to edit, and a specific distance to update that block length to, and it should be fast process with out too many clicks and verifications (there is a specific block and specific value for the length).
    in some way you can look on it as a substitute to dynamic blocks that bricscad don't have.
    one thing that can be interesting to do is maybe to create a LSP routine that will update group of blocks with d1 parameter to a specific length value,
    but this is not the case here.
    Ari.

  • edited February 25

    @Torsten Moses said:
    ...
    yes, the main idea is to create the string with enough precision : (rtos di 2 10)

    Thanks - I've got it. (rtos number [mode [precision]])
    About the long property name - I'll take time to learn this and try to implement it, it looks quite important, Thanks!

    one more issue back to the code it self - my drawing units is mm, but I need the quantity to be in M, and only 3 digits of precision,
    so I've attach the revised code here with the relevant row highlighted:

    (defun c:PipeLenBL (/ obj p1 di )
    (setq obj (car (entsel "\nSelect Block ")))
    (setq p1 (getpoint "\nPoint 1: "))
    (setq di (getdist p1 "\nDistance: "))
    (setpropertyvalue obj "d1" (rtos di 2 10))
    (setpropertyvalue obj "QUANTITY" (rtos (* di 0.001) 2 3))
    (command "regen")
    (princ)
    )

Sign In or Register to comment.
Origami
Origami is the Japanese word for paper folding. ORI means to fold and KAMI means paper and involves the creation of paper forms usually entirely by folding.

Powered by VanillaForums, Designed by Steam