How to get the latest modified entity in a drawing?

How to get the latest modified entity in a drawing?

_Bilal
Advocate Advocate
3,585 Views
24 Replies
Message 1 of 25

How to get the latest modified entity in a drawing?

_Bilal
Advocate
Advocate

Hello, everybody

 

Is it possible to get the latest modified entity in a drawing? I try to use ssget "_P" but it doesn't play when the user uses the grip to modify an entity.

0 Likes
3,586 Views
24 Replies
Replies (24)
Message 2 of 25

cadffm
Consultant
Consultant

Object selection P selects the the last selection set of this file session, not the last modified object(s).

What you ask for is not possible,

not without an extra tool.

Sebastian

0 Likes
Message 3 of 25

_Bilal
Advocate
Advocate

You are right about ssget "_P",  but What about using a reactor object do you have any idea here? I have no experience in reactor object.

0 Likes
Message 4 of 25

_Bilal
Advocate
Advocate

I guess using object reactor in this way will be useful

(setq comwillstart (vlr-command-reactor "ComWillStart" '((:vlr-commandwillstart . StartControl))))

(defun StartControl ( startcomreactor startcominfo / e ssent )
	(setq objlst nil entlst nil)
	(setq ssent (ssget "_X"))
	(setq objreactor
		(vlr-object-reactor
			(mapcar 'vlax-ename->vla-object
				(while (/= 0 (sslength ssent))
					(setq e (ssname ssent 0))
					(ssdel e ssent)
					(setq entlst (cons e entlst))
				)
			)
			"modified-object" 
			'((:vlr-modified . ModifiedObject))
		)
	)
)
(defun ModifiedObject ( objmod objreactor paramlist / ) 
	(setq objlst (cons objmod objlst))
	;;Use Lee Mac routine 'LM:Unique to Remove repeated objects 
	(setq objlst (LM:Unique objlst))
)
;; the objlst is the list of the latest modified objects
0 Likes
Message 5 of 25

john.uhden
Mentor
Mentor

I don't get it.  You said you had no experience with reactors, yet what you just posted seems that you do.

John F. Uhden

0 Likes
Message 6 of 25

_Bilal
Advocate
Advocate

Hi John,

 

Actually, I was working for more than 5 hours to solve this problem, so I build a little experience at this time.

However, I aware that you are an expert here in this forum, could you please tell me if somethings wrong or missed in this routine?.

0 Likes
Message 7 of 25

doaiena
Collaborator
Collaborator

A vlr-command-reactor will not catch the last modified entity in all cases. If you modify an entity using 'entmod', the reactor will not be triggered.

 

You should give a bit more info, on how the entities will be modified. Will you use AutoLisp/VisualLisp functions to modify entities in the drawing?

PS:
I haven't tested your code, but just looking at it, i think you will add an object reactor, that will be monitoring every entity in the drawing, every time a command is started. That will backfire very quickly and slow down AutoCAD, until it eventually crashes.

0 Likes
Message 8 of 25

_Bilal
Advocate
Advocate

Hi Doaeina,

This is the user who edits or modified entities in the drawing by using the AutoCAD commands, otherwise, and as you know if the last modified entities were made by any AutoLISP/Visual lisp routine it is so easy to collect them.

0 Likes
Message 9 of 25

doaiena
Collaborator
Collaborator

I was not talking about entity creation, but modification.

Pseudo code example:

 

 

(defun c:SomeFunc ( / )
(select all lines in the drawing)
(if a line is on a given layer, change its color)
)

 

 

This example could modify some entities in your drawing, but if the function itself isn't reporting back the modified entities, you would not catch them with a vlr-command-reactor.

 

0 Likes
Message 10 of 25

_Bilal
Advocate
Advocate

PS:
I haven't tested your code, but just looking at it, I think you will add an object reactor, that will be monitoring every entity in the drawing, every time a command is started. That will backfire very quickly and slow down AutoCAD, until it eventually crashes.

 

I guess you are right, about the slowdown AutoCAD, this because every time the command start the number of object reactor will increase, in this case, I have to add the only new objects only to the vlr-owners of the object reactor, like this 

;;find an object reactor named '"modified-object" in the drawing
(setq objreactor	
	(car 	(vl-member-if
				'(lambda (obj) (= (vlr-data obj) "modified-object"))
				(cdar (vlr-reactors :VLR-Object-Reactor))
			)
	)
)

Then get the owner list of this object reactor 

(setq ownlst (vlr-owners objreactor))
;;let say the new generating object are collected into 'newobjlst
;;So by adding each new object into reactor owners like this
(foreach obj newobjlst
	(vlr-owner-add objreactor obj)
)
;; Finally we will have only one object reactor in the drawing,
;; where the owners are all ojects in the drawing, and when the user 
;; exits the drawing the reactor is lost. 

 

0 Likes
Message 11 of 25

_Bilal
Advocate
Advocate

You are right here in the pseudo code because the vlr-commandwillstart event never catches the modification due to an autolisp/visuallisp routine, the relevant vlr-lisp-reactor do that.

0 Likes
Message 12 of 25

doaiena
Collaborator
Collaborator

You still haven't answered my question. Do you want to know the last modified entity in all possible cases /independent, if modified by lisp or not/, or you want to know if some objects /or type of object/ is modified. You need to give more information, on what exactly you are trying to accomplish, so you get the best help possible. There are multiple approaches for tracking objects in ACAD. Specify your use case.

0 Likes
Message 13 of 25

_Bilal
Advocate
Advocate

All possible cases /independent, if modified by lisp or not

 

As for your pseudo code, here is a real example

(defun move-line ( / )
	(setq ent (entsel "Select a line from a drawing "))
	(command "Move" ent "" '(0 0 0) '(100 100 0))
)

When running this code the line moved has been collected into objlst 

!objlst--->(#<VLA-OBJECT IAcadLine 000001694e6a46a8>)

I guess the routine works fine in all cases.

0 Likes
Message 14 of 25

doaiena
Collaborator
Collaborator

No, the routine doesn't work in all cases. Try 'entmod' or 'vla-move' and you will find out. When you are using the 'command' function, that will trigger the vlr-command-reactor. All other cases won't trigger it.

0 Likes
Message 15 of 25

_Bilal
Advocate
Advocate

The below example shows that the function still working even if the entity was modified by 'entmod function

(defun addxdata ( ent / )
	;;I do not select the entity to be modified from drawing,
	;;I prefered to set it as argument in the 'addxdata function.
	(setq entdxf (entget ent))
	;;change layer group
	(setq entdxf (subst (cons 8 "1") (assoc 8 entdxf) entdxf))
	(entmod entdxf)
	(princ)
)

;; When running the 'addxdata function (addxdata ent)
;; the objlst list collects the latest modified entity which
;; is a line in this case.

 

!objlst--->(#<VLA-OBJECT IAcadLine 000001694e6a46a8>)

0 Likes
Message 16 of 25

doaiena
Collaborator
Collaborator

I really don't understand you. Are you looking for help, or are you trying to teach us how to use reactors?

 

For the last time: A vlr-command-reactor will not catch lisp modifications to entities. Just draw a few polylines in an empty drawing and test it for yourself.

(vl-load-com)
(defun c:test ( / ReactorFun commandReactor sel ctr )

;Reactor callback function
(defun ReactorFun (reactor lst)
(if (equal (vlr-current-reaction-name) ':vlr-commandWillStart)
(alert "The reactor caught a command.")
)
);defun

;Create a command reactor
(setq commandReactor (vlr-command-reactor nil '((:vlr-commandWillStart . ReactorFun))))


;Select polylines in the drawing and change their color in 3 different ways
(if (setq sel (ssget '((0 . "LWPOLYLINE"))))
(progn

;Change the color using VisualLisp
(setq ctr 0)
(repeat (sslength sel)
(vla-put-color (vlax-ename->vla-object (ssname sel ctr)) 1)
(setq ctr (1+ ctr))
);repeat
(vla-Regen (vla-get-activedocument (vlax-get-acad-object)) acAllViewports)
(alert "The polylines are now colored red by Vlisp function.")

;Change the color using AutoLisp
(setq ctr 0)
(repeat (sslength sel)
(entmod (subst (cons 62 2) (assoc 62 (entget (ssname sel ctr))) (entget (ssname sel ctr))))
(setq ctr (1+ ctr))
);repeat
(vla-Regen (vla-get-activedocument (vlax-get-acad-object)) acAllViewports)
(alert "The polylines are now colored yellow by the endmod function.")

;Change the color using an AutoCAD command
(command "_.chprop" sel "" "_color" 3 "")
(vla-Regen (vla-get-activedocument (vlax-get-acad-object)) acAllViewports)
(alert "The polylines are now colored green by an AutoCAD command.")

));if sel

;Remove the command reactor
(vlr-remove commandReactor)

(princ)
);defun

 

0 Likes
Message 17 of 25

_Bilal
Advocate
Advocate

Here is the last routine.

Please read carefully the code, the reactor who catches the modified entities is the vlr-Object-reactor and not the

vlr-command-reactor, the vlr-command-reactor  :vlr-commandwillstart generates the vlr-object-reactor and attaches it to each object in the drawing.

 

However, the below code is tested many time and it works very well.

 

; *****
; * How to get the latest modified objects in a drawing
; *

(vl-load-com)

(setq comwillstart (vlr-command-reactor "ModifiedObjects" '((:vlr-commandwillstart . StartControl))))

(defun StartControl ( startcomreactor startcominfo / objlst e ssent objreactor ownerslst)
	
	;; Initiate variables.
	;;The modobjlst(Global) is the list which collects the latest
	;;modified objects in all possible cases /independent, if it
	;;is modified by lisp or AutoCAD command. 
	(setq modobjlst nil)
	
	;;Add drawing's objects to a list 'entlst
	(setq objlst nil)
	(setq ssent (ssget "_X"))
	(setq objlst
		(mapcar 'vlax-ename->vla-object
			(while (/= 0 (sslength ssent))
				(setq e (ssname ssent 0))
				(ssdel e ssent)
				(setq objlst (cons e objlst))
			)
		)
	)
	
	;;If the object reactor exist, add new generated objects to owners list 
	(if (setq objreactor	
			(car (vl-member-if
					'(lambda (obj) (= (vlr-data obj) "Last-Modified"))
					(cdar (vlr-reactors :VLR-Object-Reactor))
				)
			)
		)
		(progn
			(setq ownerslst (vlr-owners objreactor))
			(foreach obj objlst
				(if (not (member obj ownerslst)) 
					(vlr-owner-add objreactor obj)
				)
			)
		)
		(setq objreactor
			(vlr-object-reactor
				objlst
				"Last-Modified" 
				'((:vlr-modified . ModifiedObject))
			)
		)
	)
);;Endof//StartControl


(defun ModifiedObject ( objmod objreactor paramlist / ) 
	(setq modobjlst (cons objmod modobjlst))
	;;Use Lee Mac routine 'LM:Unique to Remove repeated objects 
	(setq modobjlst (LM:Unique modobjlst))
)

 

0 Likes
Message 18 of 25

john.uhden
Mentor
Mentor
  • Yes, as @doaiena pointed out, you have to use a vlr-object reactor, and the owners must consist  of every vla-object in the drawing, both old and new.  Now I don't know if you want to include everything, such as a layer or linetype or text style (their properties), or viewports or dictionaries, etc., or only drawing objects like lines and circles etc.
  • In a busy drawing there will be so many objects for AutoCAD to check that my guess is that the slowdown will be significant.  If you could restrict your interest to only certain objects, then you might find the delays acceptable.
  • Plus, you will have to monitor if any action were undone.
  • I guess that you could speed things up a little by removing an owner that has been modified and accounted for because it seems you want your "modified_list" to contain objects that were modified even just once, in which case further modifications to the same object don't matter.  Once again, watch out for undos.
  • You may need to add more RAM to your computer.
  • Offhand, I don't know how to handle erased objects that are later oopsed, or objects that are converted to part of a block definition or polyline.

John F. Uhden

0 Likes
Message 19 of 25

john.uhden
Mentor
Mentor
I haven't studied all your code, but I did notice that since you are
checking only to see if an item is already in a list, then you can speed
things up a bit by using vl-position rather than member.

John F. Uhden

0 Likes
Message 20 of 25

_Bilal
Advocate
Advocate

Thanks for your advice.

 

@Anonymous:    "you have to use a vlr-object reactor, and the owners must consist of every vla-object in the drawing, both  old and new."
@_Bilal:   The callback function 'StartControl do that!.

 

@Anonymous:   "you will have to monitor if any action were undone."
"Once again, watch out for undos. You may need to add more RAM to your computer. Offhand,
I don't know how to handle erased objects that are later oopsed, or objects that are converted
to part of a block definition or polyline."
@_Bilal:   I have no idea how to control the undone erased objects that are later oopsed,
if someone could help with this, it will be appreciated.

@Anonymous: "Once again, watch out for undos. You may need to add more RAM to your computer. Offhand,
I don't know how to handle erased objects that are later oopsed, or objects that are converted
to part of a block definition or polyline."

0 Likes