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

Retrieving data related to an object during a :vlr-erased event (object reactor)

1 REPLY 1
SOLVED
Reply
Message 1 of 2
sem.keijsper
147 Views, 1 Reply

Retrieving data related to an object during a :vlr-erased event (object reactor)

Hi there,

 

We have a large LISP project that adds labels to a polyline, like so:

acad_WsBNpdTzXE.gif

This is very similar to Civil3D, but we had to recreate it in AutoCAD as Civil3D isn't an option for us.

 

A label consists of multiple entities (MText and Hatch objects). In the NOD, we store the entity handle of the polyline, along with the entity handles of all the label entities, like so:

semkeijsper_0-1678698686797.png

The polyline handle here would be F011, and the polyline segment would be 0, and inside the XRecord "HANDLE_BOBBEGIN" is the string value 6FB90.

We use entity handles as they remain unchanged when saving, closing and opening a DWG file.

 

We use a single object reactor to react to changes to the entities. This is created as follows:

 

(defun REA:CREATE_GLOBAL () 
  (vlr-pers 
    (vlr-object-reactor (list)  ; owner registry, defaults to nil
                        "WATERNET_REACTOR"
                        '((:vlr-modified . REA:HANDLE_MODIFIED)
                          (:vlr-erased . REA:HANDLE_ERASED)
                          (:vlr-unerased . REA:HANDLE_UNERASED)
                          (:vlr-goodbye . REA:HANDLE_GOODBYE)
                          (:vlr-modifyUndone . REA:HANDLE_MODIFY_UNDONE)
                         )
    )
  )
)

 

The :vlr-modified event works great. All our handlers look like this (same parameters used by all events):

 

(defun REA:HANDLE_MODIFIED ($parentVla $reactor $parameters / ...)
    ...
)

 

We get the VLA-object of the polyline that is currently reacting, the reactor, and parameters, which is always nil.

We then use (vlax-vla-object->ename) to convert the VLA-object to an ENAME, which allows us to perform (entget) to retrieve the polyline handle. We can then use this handle to update our label entities, retrieved from the NOD.

 

So, our main goal is to retrieve the entity handle of the current object reacting. However, when using :vlr-erased and :vlr-openedForModify, we run into the following issues:

 

  • :vlr-erased
    • (vlax-vla-object->ename) + (entget) returns nil, as the entity is flagged as deleted
    • (vla-get-Handle) throws "Automation Error. Object was erased"
  • :vlr-openedForModify
    • (vlax-vla-object->ename) + (entget) returns nil
    • (vla-get-Handle) throws "Automation Error. Object was open for write"

We fully understand the limitations of LISP, so we are trying to figure out a way to work around this. In the end, we just need to be able to get the entity handle of the VLA-object that is reacting, so that we can retrieve the label data.

 

We are currently trying an approach where we create a map/dictionary in-memory with all VLA-objects in the drawing and their associated string handle (key-value map). This map is created upon opening the drawing, and kept up to date when new labels are added. I'll update the post if we know more about how well this approach works, but we wanted to ask the community, hoping for a more creative and clever solution to this problem.

 

Kind regards,

Sem

1 REPLY 1
Message 2 of 2
sem.keijsper
in reply to: sem.keijsper

We have figured it out 🙂

 

Just to update this post in case anyone ever has the same problem; we create a map containing all VLA-object that are added as owners to the object reactor, like so:

 

(setq $$$vlaObjectMap (mapcar 
                        '(lambda ($owner) 
                          (cons $owner (WTN:VLA_PROP $owner "Handle"))
                        )
                        (vlr-owners $$globalReactor)
                      )
)

 

$$globalReactor would be your reactor - I have omitted the code that is responsible for creating this reactor, and adding and removing owners from the reactor. You can retrieve the global reactor from the drawing like so:

 

(setq $$globalReactor (car 
                        (vl-remove-if-not 
                          '(lambda ($reactor) 
                            (= (vlr-data $reactor) "WATERNET_REACTOR")
                          )
                          (vlr-pers-list)
                        )
                      )
)

 

WATERNET_REACTOR of course would be different for your own implementation, just use a unique key for vlr-data.

 

Of course, when you add an owner to the reactor, you also need to add it to the $$$vlaObjectMap:

 

(defun ...
  (setq $$$vlaObjectMap (WTN:ADD_OR_REPLACE 
                          $vlaOwner
                          (vla-get-Handle $vlaOwner)
                          $$$vlaObjectMap
                        )
  )
)

(defun WTN:ADD_OR_REPLACE ($key $value $list) 
  (if (setq $current (assoc $key $list)) 
    (subst (cons $key $value) 
           $current
           $list
    )
    (append $list (list (cons $key $value)))
  )
)

 

Now, you can retrieve the entity handle during a :vlr-erased event, like so:

 

(defun REA:HANDLE_ERASED ($parentVla $reactor $parameters) 
  (setq $handle (cdr (assoc $parentVla $$$vlaObjectMap)))
)

 

 

Another key component to make this work is to create a list for VLA-objects that shouldn't be modified, when multiple events are being called. You insert the current $parentVla into this list during :vlr-erased, :vlr-unerased and :vlr-handleModifyUndone. Then, during :vlr-modified, you check if $parentVla is a (member) of this list. If so, you skip the action you usually take, and remove it from the list, like so:

 

(setq $$$dontModifyList (vl-remove $parentVla $$$dontModifyList))

 

All of this combined, looks like this:

acad_G5rt1Yzbth.gif

That's it! Hopefully this can be useful for someone if they ever google this really specific issue 🙂

Feel free to ask more questions about this implementation.

- Sem

 

PS: In case you are wondering why we prefix our variables with dollar signs, we use the following convention:

 

; $variable   - Local scope variable
; $$variable  - Global immutable variable
; $$$variable - Global mutable variable

 

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