Select lines/objects that are duplicated

Select lines/objects that are duplicated

pallen9JA6T
Enthusiast Enthusiast
6,047 Views
27 Replies
Message 1 of 28

Select lines/objects that are duplicated

pallen9JA6T
Enthusiast
Enthusiast

Hi. I'm looking for a lisp routine that will create a selection of all duplicated objects. Similar to overkill, but instead of deleting, I want it to select them. The reason I want this is that I copied a lot of linework out of an existing drawing and pasted it into a new drawing. I put everything on the same layer so that I could just make it all grayscale except for a few specific things. In hindsight, that was a bad choice. I want to recopy some of the objects on their correct layer, but now I have the duplicate that is on a layer with 800,000 other objects.

0 Likes
Accepted solutions (2)
6,048 Views
27 Replies
Replies (27)
Message 2 of 28

JBerns
Advisor
Advisor

@pallen9JA6T

 

Could you be more specific as to the objects you want to find?

 

A google search found these examples that might get you close:

 

https://www.cadtutor.net/forum/topic/33136-help-select-duplicate-entities/ 

 

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/autocad-tool-required-for-selecting-...

 

https://www.eng-tips.com/viewthread.cfm?qid=7266 

 

Each of these examples express the challenge of determining what is a duplicate.

 

Do you have backups of the original drawing before you copied in the duplicates?

 

Perhaps you could identify the last object in that original drawing.

Locate that object in the merged drawing.

Then select all objects after (newer) than that object.

Just a thought.  

 

Looking forward to your response.

 

 

Regards,

Jerry

-----------------------------------------------------------------------------------------
CAD Administrator
Using AutoCAD & Inventor 2025
Autodesk Certified Instructor
Autodesk Inventor 2020 Certified Professional
Autodesk AutoCAD 2017 Certified Professional
Message 3 of 28

Moshe-A
Mentor
Mentor

@pallen9JA6T  hi,

 

Check this OVER-KILL command. the result of it's process, all the deleted objects from overkill is highlighted.

also assigned to ss1 selection set variable. do you know how to take it from there?

 

note:

pre invoke over-kill, prepare all overkill settings.

 

enjoy

Moshe

 

(defun c:over-kill (/ ss ename lst0 lst1)
 (if (setq ss0 (ssget "_x" (list (cons '410 (getvar "ctab")))))
  (progn
   (setq lst0 (mapcar '(lambda (ename) ename) (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss0)))))   
   (command "-overkill" "_si" ss0 "")
   
   (setq lst1 (vl-remove-if
    		'not
     		(mapcar
       		  '(lambda (ename)
         	     (if (vl-catch-all-error-p (vl-catch-all-apply 'vlax-ename->vla-object (list ename)))
           		ename
         	     )
        	   ); lambda
      		 lst0 
     		); mapcar
   	      ); vl-remove-if
   ); setq

   (command ".undo" 1)

   (setq ss1 (ssadd))
   (foreach ename lst1
    (ssadd ename ss1)
   )

   (sssetfirst ss1 ss1) ; select what's were deleted by overkill
  ); progn
 ); if

 (princ)
); c:over-kill

 

Message 4 of 28

john.uhden
Mentor
Mentor

These two functions could help you find duplicates.

It's based on the theory that the only things different about two otherwise identical objects are its ename (dxf -1) and handle (dxf 5).

I had serious trouble figuring out how to use mapcar for this, thus the two functions:

(defun @Anonymous (dxfs ent)
  (foreach dxf dxfs (setq ent (vl-remove (assoc dxf ent) ent)))
)
(defun @Anonymous (e1 e2)
  (equal (@remove '(-1 5)(entget e1))(@remove '(-1 5)(entget e2)) 1e-8)
)

I haven't wrapped it up into what you want, but the process would be to compare each graphic entity to all the rest, and all those the same as any earlier would be placed in your selection set.

Notice that I used a tiny fuzz factor because with real numbers AutoCAD often provides slightly different values.  If you increase the fuzz factor it's likely that two similar entities will be considered as equal (as in close enough).  For example, Hulk Hogan and Danny DeVito are probably equal with a fuzz factor of 2 feet.

If I don't get to wrapping it up, fear not, there are a good number of masters here who can and probably will, complete with appropriate use of mapcar.

John F. Uhden

Message 5 of 28

Sea-Haven
Mentor
Mentor

To make it run faster think about sorting the entities and say making multiple lists of just Lines, Plines, circle, arc etc.

Then compare each list individually.

Message 6 of 28

john.uhden
Mentor
Mentor

@Sea-Haven 

Wait a minute, Alan.  We are both being dumb.

Entities such as 3D and heavy polylines and attribute blocks don't show all their data with one entget of the primary object.  They have vertices or attributes that follow.  And then there are things like regions that reveal no decipherable point data via entget.

So I think this method can apply only to POINTS, LINES, ARCS, LWPOLYLINES, RAYS, XLINES, CIRCLES, DIMENSIONS, SHAPES, non-attribute BLOCKS, and maybe XREFS.  Oh yeah, we have to exclude (dxf 2) for dimensions and anonymous blocks.

Plus, we should incude '(-3 "*") for xdata.  But then what about dictionary data, or are we talking only about apparent duplication?

 

John F. Uhden

0 Likes
Message 7 of 28

JBerns
Advisor
Advisor

Reminder, we are still waiting for OP to respond to what object types are being searched for duplication.

-----------------------------------------------------------------------------------------
CAD Administrator
Using AutoCAD & Inventor 2025
Autodesk Certified Instructor
Autodesk Inventor 2020 Certified Professional
Autodesk AutoCAD 2017 Certified Professional
0 Likes
Message 8 of 28

john.uhden
Mentor
Mentor

@JBerns 

Agreed.  I sure hope his criteria is simple.

Yes, we can do it, but I just don't feel like comparing all the separate vertices and bulges and widths.

John F. Uhden

0 Likes
Message 9 of 28

Sea-Haven
Mentor
Mentor

"comparing all the separate vertices and bulges and widths"

 

Maybe is area1 = area2 is first test then yes horrible check all vertices etc. lee-mac has a nice get all pline properties.

0 Likes
Message 10 of 28

pallen9JA6T
Enthusiast
Enthusiast

All of the geometry is exploded. It's 2d lines and arcs. Thanks for your help in figuring this out.

0 Likes
Message 11 of 28

pallen9JA6T
Enthusiast
Enthusiast

Here is an example drawing of what I'm working with. I want to delete the items on layer "other exterior" that have items on top of them that are a different layer. If I run the overkill command, it's random as to which line it leaves. Sometimes it leaves the one on the "other exterior" layer and sometimes it doesn't. I tried locking the other layers and only leaving "other exterior" unlocked, but then the overkill doesn't recognize the delicate item.

0 Likes
Message 12 of 28

john.uhden
Mentor
Mentor

@pallen9JA6T 

"on top of them?"  I thought "other exterior" meant the lines/arcs that were imported on top of earlier lines/arcs, and that you want to create a selection set of the "newer" duplicates.

Now you are saying that there are duplicates on other layers that you want to keep and to delete the matching "other exteriors."  At that rate does it matter if one is on top of or under another?

John F. Uhden

0 Likes
Message 13 of 28

pallen9JA6T
Enthusiast
Enthusiast

Essentially, I wanna be able to turn off the layers for doors and window. I’m trying to delete the lines that I put on “other exterior” earlier in the process. I know it was dumb to do it that way, but I’m trying to find an easier way than redoing it or deleting each line manually.

0 Likes
Message 14 of 28

john.uhden
Mentor
Mentor
Accepted solution

@pallen9JA6T 

This might work (though untested):

(defun c:SelectDupes ( / @remove @same ss1 i ss2 j e1 e2 badlayer ssbad)
  (defun @remove (dxfs ent)
    (foreach dxf dxfs (setq ent (vl-remove (assoc dxf ent) ent)))
  )
  (defun @Same (e1 e2)
    (equal (@remove '(-1 5 8)(entget e1))(@remove '(-1 5 8)(entget e2)) 1e-8)
  )
  (setq badlayer (getstring t "\nLayer name of entities to be selected <\"other exterior\">: "))
  (if (= badlayer "")(setq badlayer "other exterior"))
  (setq ss1 (ssget "x" (list '(0 . "LINE,ARC")(cons 8 badlayer))))
  (setq ss2 (ssget "x" (list '(0 . "LINE,ARC")(cons 8 (strcat "~" badlayer)))))
  (setq ssbad (ssadd))
  (repeat (setq i (sslength ss2))
    (setq e2 (ssname ss2 (setq i (1- i))))
    (repeat (setq j (sslength ss1))
      (setq e1 (ssname ss1 (setq j (1- j))))
      (if (@same e1 e2)
        (setq ssbad (ssadd e1 ssbad)
              ss1 (ssdel e1 ss1)
        )
      )
    )
  )
  (sssetfirst nil ssbad)
  (princ (strcat "\nFound " (itoa (sslength ssbad)) " duplicates on layer " badlayer))
  (princ)
)

John F. Uhden

0 Likes
Message 15 of 28

john.uhden
Mentor
Mentor

Of course I could/should have used the Kosteresque method...

Instead of:
      (if (@same e1 e2)
        (setq ssbad (ssadd e1 ssbad)
              ss1 (ssdel e1 ss1)
        )
      )
This:
      (and (@same e1 e2)
        (ssadd e1 ssbad)
        (ssdel e1 ss1)
      )

 

John F. Uhden

Message 16 of 28

pallen9JA6T
Enthusiast
Enthusiast

Is there a way to make it where the lisp only looks at a pre-selected group rather than the entire drawing? It would be great to select a certain area of the drawing and only run the command for that area. It's a very large file and the lisp routine worked on my example, but it just spins and spins on the whole file.

0 Likes
Message 17 of 28

john.uhden
Mentor
Mentor

@pallen9JA6T 

Just remove the "X" after each of the two (ssget)s.

Just be sure to pick pretty much the same window or crossing for each one.

 

John F. Uhden

0 Likes
Message 18 of 28

john.uhden
Mentor
Mentor
Accepted solution

@pallen9JA6T 

Just experimenting (untested).

See if this works better...

(defun c:SelectDupes ( / @remove @same ss ss1 i ss2 j e1 e2 badlayer ssbad)
  (defun @remove (dxfs ent)
    (foreach dxf dxfs (setq ent (vl-remove (assoc dxf ent) ent)))
  )
  (defun @Same (e1 e2)
    (equal (@remove '(-1 5 8)(entget e1))(@remove '(-1 5 8)(entget e2)) 1e-8)
  )
  (setq badlayer (getstring t "\nLayer name of entities to be selected <\"other exterior\">: "))
  (if (= badlayer "")(setq badlayer "other exterior"))
  (setq ss (ssget)'((0 . "LINE,ARC"))))
  (setq ss1 (ssget "_P" (list '(0 . "LINE,ARC")(cons 8 badlayer))))
  (command "_.select" ss "")
  (setq ss2 (ssget "_P" (list '(0 . "LINE,ARC")(cons 8 (strcat "~" badlayer)))))
  (repeat (setq i (sslength ss2))
    (setq e2 (ssname ss2 (setq i (1- i))))
    (repeat (setq j (sslength ss1))
      (setq e1 (ssname ss1 (setq j (1- j))))
      (and (@same e1 e2)
        (ssadd e1 ssbad)
        (ssdel e1 ss1)
      )
    )
  )
  (sssetfirst nil ssbad)
  (princ (strcat "\nFound " (itoa (sslength ssbad)) " duplicates on layer " badlayer))
  (princ)
)

John F. Uhden

0 Likes
Message 19 of 28

yee_t
Observer
Observer

Here's what I got together and it works really well. Hope all the commenting and simplifying work helps it make sense, but it basically just iterates through every entity/object and compares it's attributes to a list of all other entities of the same type. It isolates a list of those at the end, which you can delete if you want.

(defun C:du ()   ;isolates duplicate entities---------------------------------------------------------------------------------------------------------------------------------------------
  (setq SUZY (ssget '((0 . "LINE,LWPOLYLINE,CIRCLE,ARC,ELLIPSE,SPLINE,INSERT")))) ;makes "SUZY" a set of entities of these types
  (setq COUNTER 0)
  (setq duplicatelist (ssadd))                              ;creates a new list to hold the duplicates
  
  (setq SSLINE        (ssadd))                              ;creating new selection sets for each entity type
  (setq SSLWPOLYLINE  (ssadd))
  (setq SSCIRCLE      (ssadd))
  (setq SSARC         (ssadd))
  (setq SSELLIPSE     (ssadd))
  (setq SSSPLINE      (ssadd))
  (setq SSINSERT      (ssadd))                              ;INSERT is for blocks
  
  (while 
    (setq EDNA (ssname SUZY COUNTER))                       ;sets value of EDNA to the value of SUZY at the index location of counter
    (setq ED (entget EDNA))                                 ;sets value od ED to the entity info of EDNA
    (cond                                                   ;condition of while function
     ((= (dxf 0 ED) "LINE")       (ssadd EDNA SSLINE))
     ((= (dxf 0 ED) "LWPOLYLINE") (ssadd EDNA SSLWPOLYLINE))
     ((= (dxf 0 ED) "CIRCLE")     (ssadd EDNA SSCIRCLE))
     ((= (dxf 0 ED) "ARC")        (ssadd EDNA SSARC))
     ((= (dxf 0 ED) "ELLIPSE")    (ssadd EDNA SSELLIPSE))
     ((= (dxf 0 ED) "SPLINE")     (ssadd EDNA SSSPLINE))
     ((= (dxf 0 ED) "INSERT")     (if (not (ASSOC 66 ED)) (ssadd EDNA SSINSERT)))   ;if the flag value is false, INSERT=Block references
     (t nil) 
    )
    (setq COUNTER (+ 1 COUNTER))
  )
  
  (setq entityType SSLINE)        (findit)                  ;changes the search list from one entity type to the next
  (setq entityType SSLWPOLYLINE)  (findit)
  (setq entityType SSCIRCLE)      (findit)
  (setq entityType SSARC)         (findit)
  (setq entityType SSELLIPSE)     (findit)
  (setq entityType SSSPLINE)      (findit)
  (setq entityType SSINSERT)      (findit)
  
  (print "Number of Total Duplicates:") (princ (sslength DUPLICATELIST))  ;The end of the code, pretty self-explanatory
  (command "PSELECT" DUPLICATELIST "")  (command "ISOLATEOBJECTS")
)

(defun dxf (n ed) (cdr (assoc n ed)))                       ;subfunction "dxf" needs inputs "n" and "ED", takes all but 1st info searhes nth element in list "ED"

(defun findit()
  (setq LENGTHEntityType (sslength EntityType))          
  (if (> LENGTHEntityType 1)                                ;skip if there are no entities of that type
    (progn
     (setq COUNTER 0)
     (while (setq EDNA (ssname  entityType COUNTER))        ;defines value of "EDNA" as the name of the object specified by location "COUNTER" in list "EntityType"
        (setq ED (cddddr (entget EDNA)))                    ;defines value of "ED" as data taken from EDNA, but not the first 4 items (cddddr comes from LISP)
        (setq COUNTERNEXT 1)
        (while (setq EDNANEXT (ssname  entityType (+ COUNTER COUNTERNEXT)))   ;defines value of "EDNANEXT" as the name of the object specified by location "COUNTER" in list "EntityType"
          (setq NAMY (dxf 0 (entget EDNANEXT)))             ;defines value of "NAMY" as the output of the fn "dxf" with inputs of n=0 and ED=EDNANEXT
          (setq EDNEXT (cddddr (entget EDNANEXT)))          ;compares lists ED and EDNEXT, asks if the first list is member of the second list
          (if  (member ED (list EDNEXT))                    ;if "ED" is a member of the dummy list "EDNEXT"
            (progn
              (print "Duplicate found. TYPE:")(princ NAMY)
              (ssadd EDNANEXT duplicatelist)
              (ssdel EDNANEXT entityType)
            )
            (PROGN
              (setq COUNTERNEXT (+ 1 COUNTERNEXT))
            )
          )  
        )
        (setq COUNTER (+ 1 COUNTER))
     )
   )
 )
  (princ)
)

 

0 Likes
Message 20 of 28

cool.stuff
Collaborator
Collaborator

Hi!

 

I cannot get highlighted elements.. Any tips please?

Also could this be changed to work on a selection please?

 

I do not know how to code lisp, but from the lisp routine comments, should I get ss1 elements selection after running this lisp? I tried "(ssget ss1)" but got an error and I could find anything that works.

 

Many thanks 🙂

0 Likes