Finding the object reactor belonging to an entity

Finding the object reactor belonging to an entity

sem.keijsper
Participant Participant
600 Views
9 Replies
Message 1 of 10

Finding the object reactor belonging to an entity

sem.keijsper
Participant
Participant

Hi there,

 

We have a large AutoLISP codebase which provides a lot of extra functionality. One functionality is keeping a "label" together with an entity, such as a polyline:

acad_jQFmvjOKGc.gif

 

This works using a persistent object reactor. By default, labels are not present on objects in a drawing. When users want to add a label to an object, they select entities to add these labels to. Our code then retrieves whether or not an object is already owned by a persistent object reactor, through (vlr-owners). We do this check to make sure there are no duplicate reactors, and to access the data via (vlr-data).

 

The current way we are doing this, is by looping through all persistent object reactors, checking what its (vlr-owners) are, and matching it with the entity we are looking for. The code for that looks like this:

 

 

;| 
   description: find what reactor belongs to a parent entity, by checking each reactor inside the current drawing
   param: $entity - the parent entity
   returns: the associated reactor, or nil if no reactor can be found
|;
(defun REA:GET_BY_ENTITY ($entity / $break $i $owners $reactor $reactors $vlaObject) 
  (setq $vlaObject (WTN:ENSURE_VLA $entity))
  (setq $reactors (vlr-pers-list))
  (setq $i     0
        $break nil
  )
  (while (and (< $i (length $reactors)) (not $break)) 
    (setq $reactor (nth $i $reactors))
    (setq $owners (vlr-owners $reactor))
    (if (/= (member $vlaObject $owners) nil) 
      (setq $break T)
    )
    (setq $i (1+ $i))
  )
  (if $break $reactor nil) ; if break has occurred, return reactor. otherwise no reactor found
)

 

 

 

This works great for a drawing with a few reactors. However, the drawings our users require can contain up to 10.000 entities and reactors. The performance tanks under these circumstances, and often just hangs.

 

Another approach we have attempted is generating an associated list with entity handles as keys, and reactor objects as values. The code for that looks like this:

 

 

;| 
   description: generate a list of entity handles and reactors
   remarks: if a persistent reactor's owner is no longer present in the drawing, it is released (removed)
    an association list with parent entity handles and the reactor it owns
|;
(defun REA:GET_MAP (/ fetch_entry $reactor $owner $entget $entity) 
  ;| 
     description: returns reactor paired with the enthandle of the owner
     remarks: local function for improved readability (instead of a lambda)
     param: $reactor - current persistent reactor to process
     returns: `(cons <enthandle> <reactor>)` or `nil`
  |;
  (defun fetch_entry ($reactor) 
    (if 
      (and (setq $owner (car (vlr-owners $reactor))) 
           (setq $entity (WTN:ENSURE_ENAME $owner))
           (setq $entget (entget $entity))
      )
      (cons 
        (cdr (assoc 5 $entget))
        $reactor
      )
      (progn 
        (vlr-pers-release $reactor)
        (vlr-remove $reactor)
        nil
      )
    )
  )
  (vl-remove-if 'null (mapcar 'fetch_entry (vlr-pers-list)))
)

 

 

 

We then query this map/dictionary for the entity handle of an object, and then retrieve the reactor it belongs to:

 

 

;| 
    description: find what reactor belongs to a parent entity, using a reactor map
    param: $entity - the parent entity
    param: $reactorMap - reactor map generated by `REA:GET_MAP`
    returns: the associated reactor, or nil if no reactor can be found
|;
(defun REA:GET_FROM_MAP ($entity $reactorMap / $entget $handle) 
  (if 
    (and 
      (setq $entity (WTN:ENSURE_ENAME $entity))
      (setq $entget (entget $entity))
      (setq $handle (cdr (assoc 5 $entget)))
    )
    (cdr (assoc $handle $reactorMap))
    nil
  )
)

 

 

 

However, we are running into an issue here. When the drawing contains over 6000 reactors, AutoCAD will just hang when trying to generate this map/dictionary using REA:GET_MAP.

 

We have thought of a way to fix it. As we are in full control of when these reactors are created and added, we could write some kind of link into each entity as to what object reactor belongs to it. But it seems that persistent object reactors do not have a unique ID. 

 

Now our question is: Is it true that persistent object reactors do not have a unique ID we can store somewhere and retrieve when needed? Is there any way we can get a persistent reactor belonging to an object without iterating through all persistent reactors, and thus tanking the performance?

 

Thank you for reading this, if you have come this far. We hope the community can help us progress with our AutoLISP scripts. If you need more information or context, feel free to ask.

 

-Sem

 

0 Likes
Accepted solutions (1)
601 Views
9 Replies
Replies (9)
Message 2 of 10

Moshe-A
Mentor
Mentor

@sem.keijsper hi,

 

I never used presistent reactors and from what you are telling us i feel an extra use of AutoCAD power\technology for simple actions. instead i would create a simple lisp command based on ALIGN and saves the extra database.

 

??

 

Moshe

 

 

 

 

0 Likes
Message 3 of 10

dbroad
Mentor
Mentor

Are you using a unique reactor for each object?  I can't see how you end up with 10k reactors.  Aren't you using the data storage in reactors? 

Architect, Registered NC, VA, SC, & GA.
Message 4 of 10

sem.keijsper
Participant
Participant
Yes, each object has a unique object reactor. This is needed to respond to changes to each object. We are using (vlr-data) to store data in each reactor, which we need to access.
0 Likes
Message 5 of 10

Moshe-A
Mentor
Mentor

maybe store the objects handle in reactor data and the object data in xdata?

this way 1 editor reactor will have links to many drawing objects

 

 

Message 6 of 10

sem.keijsper
Participant
Participant
this gave me an idea. we can create one (persistent) object reactor, and add every object in the drawing as an owner to this single reactor.

I already rewrote our data storage system to no longer use (vlr-data), but instead use the extension dictionary of each object. It's looking positive so far 🙂
0 Likes
Message 7 of 10

dbroad
Mentor
Mentor
Accepted solution

You do realize that vlr-data supports lists, right?  You could store separate data for each object and still have only one reactor. You can also store the data in each object's xdata or in another dictionary.

 

IMO, reduce your reactor count.

Architect, Registered NC, VA, SC, & GA.
Message 8 of 10

Sea-Haven
Mentor
Mentor

In CIV3d there are label style for lines etc so it is all handled automatically, as you make objects they are labelled, may be useful to you. 

 

Why not just have a lisp that you use when you want to change a line it will rub out label and recreate much easier than using reactors. Just drag an end using grread.

0 Likes
Message 9 of 10

sem.keijsper
Participant
Participant
thanks for your reply

we figured that out yesterday and are now only using one reactor which solved our issues. we never thought about using vlr-data for more than one object, as we already had a nested data structure inside it. The data we store in reactors are the entity handles of the MText objects belonging to each segment of a polyline. so the structure is 3 layers nested: segment index > mtext key > mtext handle

We are moving towards storing the necessary data in the NOD however. we think the performance of dictionaries is much faster compared to vlr-data. Maybe you have some experience with that, but testing will reveal if that is true 🙂
Message 10 of 10

sem.keijsper
Participant
Participant
unfortunately we cannot use civil3d as its not supported by the esri arcgis connector we use. but thank you for the suggestion
0 Likes