Author Topic: Seperating Xrefs from blocks  (Read 10274 times)

0 Members and 1 Guest are viewing this topic.

Hangman

  • Swamp Rat
  • Posts: 566
Seperating Xrefs from blocks
« on: July 28, 2006, 06:20:45 PM »
Does anyone know or have a routine that seperates xrefs from blocks in any given dwg ?

I am working on a bind program, but if I have nested xrefs, it won't bind the dwg.  I need to find a way to alert the user if there are nested xrefs.

Thanks,
Hangman  8)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Drafting Board, Mechanical Arm, KOH-I-NOOR 0.7mm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Seperating Xrefs from blocks
« Reply #1 on: July 31, 2006, 01:22:43 PM »
Here is a cheap way to do it.

Code: [Select]
(defun c:ListNestedXrefs (/ XrefList BlkCol)

(setq BlkCol (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-Acad-Object))))
(vlax-for Blk BlkCol
 (if
  (and
   (= (vla-get-IsXref Blk) :vlax-true)
   (not (ssget "x" (list (cons 0 "INSERT") (cons 2 (setq XrefName (vla-get-name Blk))))))
  )
  (setq XrefList (cons XrefName XrefList))
 )
)
XrefList
)
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Hangman

  • Swamp Rat
  • Posts: 566
Re: Seperating Xrefs from blocks
« Reply #2 on: July 31, 2006, 05:28:28 PM »
T.Willey,
Thank you.  This is good.  Why would you call it cheap, this is like gold.  (at least to me, it is. )  :?
So, now I can take the XrefList, and if it is not nil, then ALERT to the user.
This will work for now.  Eventually I will come back and beg you to help me put something together that may take the nested xrefs out before binding.  :D

Which reminds me, if I may pick your brain just a bit more.
I am having a similar problem with images.
Can I use the same scenario for images, that is, the vla-get-ImageFile kinda like this (but I don't know how to put it together :(  )
Code: [Select]
(setq ImgBlk (vla-get-ImageFile (vla-get-ActiveDocument (vlax-get-Acad-Object))))
(vlax-for Img ImgBlk
 (if
  (and
   (= (vla-get-ImageFile Img) :vlax-true) ;;; I don't think this is going to work here.
   (not (ssget "x" (list (cons 0 "INSERT") (cons 2 (setq ImageName (vla-get-name Img))))))
  )
  (setq ImageList (cons ImageName ImageList))
 )
)
ImageList
)

And how would the code be put together to detach an unreferenced image on the list ??

Thanks again for your help. 
Hangman  8)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Drafting Board, Mechanical Arm, KOH-I-NOOR 0.7mm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Seperating Xrefs from blocks
« Reply #3 on: July 31, 2006, 05:49:19 PM »
It's cheap because I couldn't figure out a way to do it the way I wanted to.  I probably could have, but it would have been a much longer code.  If it works for you, then it is all good.  :-)

Images are stored in a dictionary.  But you can search from them in kind of the same way.  One quick way to get all images would be
Code: [Select]
(setq ss (ssget "x" '((0 . "IMAGE"))))

If you want to see if they are loaded, then you will have to check the dictionary.  Or (just checked something) you can convert it to an ActiveX object, and get the file path, and then use findfile to see if it finds it.  So something like

Code: [Select]
(if (setq ss (ssget "x" '((0 . "IMAGE"))))
 (while (setq Ent (ssname ss 0))
  (setq Obj (vlax-ename->vla-object Ent))
  (if (not (findfile (vla-get-ImageFile Obj)))
   (setq ImgList (cons (vla-get-Name Obj)))
  )
  (ssdel Ent ss)
 )
)

This will get us a list of all the unreferenced images.  Now to detach them, you will have to delete the xrecord (?) in the image dictionary.  Something like

Code: [Select]
(setq DictCol (vla-get-Dictionaries (vla-get-ActiveDocument (vlax-get-Acad-Object))))
(setq ImgDict (vla-Item DictCol "ACAD_IMAGE_DICT"))
(foreach ImgName ImgList
 (vla-Delete (vla-Item ImgDict ImgName))
)
This will error is you run it on a drawing with no images, because the dictionary doesn't exist unless there is at least one image in the drawing.

Hope the helps.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Hangman

  • Swamp Rat
  • Posts: 566
Re: Seperating Xrefs from blocks
« Reply #4 on: July 31, 2006, 06:24:55 PM »
Cool !
This is a bit to chew on, thank you again.
I'll go play with this stuff and see what I can put together.  I don't have a lot of time to play, so it might be a week or so before I can get back with you, but I'll let you know what I come up with.
Just out of curiosity, how did you want to list the xref's ??
Hangman  8)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Drafting Board, Mechanical Arm, KOH-I-NOOR 0.7mm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Seperating Xrefs from blocks
« Reply #5 on: July 31, 2006, 06:37:52 PM »
I wanted it to list the xrefs, and then any nested xrefs, and then any nested xrefs... and so one.  It would have to be a recursive type of program, but that style I'm not good at.  So the list would look like
Quote
(("xref") ("xref1" "xref2") ("xref3" ("xref4" "xref5")) ("xref6" "xref7" "xref8"))
Where "xref" would have no nesting
"xref1" would have one nested named "xref2"
"xef3" would have one nested named "xref4", which would have one nested named "xref5"
"xref6" would have two nested named "xref7" and "xref8"

And maybe print out something like
Quote
Xref name = xref
Xref name = xref1
  nested name = xref2
Xref name = xref3
  nested name = xref4
    nested name = xref5
Xref name = xref6
  nested name = xref7
  nested name = xref8

Maybe later when I have some time I will try and figure that one out.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Seperating Xrefs from blocks
« Reply #6 on: July 31, 2006, 07:46:23 PM »
WooooHoooooo!!!
I got it to work the way I wanted it to.  Here is the code.  The other one is better for what you want thought (I think).
Code: [Select]
(defun ListXrefs (Doc / XrefNameList)

(defun FindInList (LstItem Lst)

(if (assoc LstItem Lst)
 (assoc LstItem Lst)
 (while
  (or
   Lst
   (not (assoc LstItem Lst))
  )
  (setq Lst
   (vl-remove-if
    'null
    (mapcar
     'cadr
     Lst
    )
   )
  )
 )
)
)
;--------------------------------------------------
(defun PrintResults (Lst StrSpace)
(foreach Item Lst
 (if (equal (type Item) 'LIST)
  (PrintResults Item (strcat "  " StrSpace))
  (prompt (strcat "\n" StrSpace "|-> Nested Xref = " Item))
 )
)
)
;-----------------------------------------------------
(setq BlkCol (vla-get-Blocks Doc))
(vlax-for Blk BlkCol
 (if (= (vla-get-IsXref Blk) :vlax-true)
  (setq XrefNameList (cons (list (vla-get-Name Blk)) XrefNameList))
 )
)
(foreach XrefName XrefNameList
 (vlax-for Obj (vla-Item BlkCol (car Xrefname))
  (if
   (and
    (= (vla-get-ObjectName Obj) "AcDbBlockReference")
    (vlax-property-available-p Obj 'Path)
   )
   (setq XrefNameList
    (subst
     (cons (car XrefName) (cons (FindInList (vla-get-name Obj) XrefNameList) (cdr (assoc (car XrefName) XrefNameList))))
     (assoc (car XrefName) XrefnameList)
     (vl-remove-if '(lambda (x) (= (car x) (vla-get-Name Obj))) XrefNameList)
    )
   )
  )
 )
)
;(print XrefNameList)
(foreach i XrefNameList
 (prompt (strcat "\n Main Xref = " (car i)))
 (PrintResults (cdr i) "  ")
)
(princ)
)
Output like
Quote from: Acad command line
Command: (ListXrefs (vla-get-activedocument (vlax-get-acad-object)))

 Main Xref = XrefMain
    |-> Nested Xref = Xref2
      |-> Nested Xref = Cube
    |-> Nested Xref = Xref1
 Main Xref = XREF
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Seperating Xrefs from blocks
« Reply #7 on: July 31, 2006, 08:27:02 PM »
Hi Tim,
I saw your post about how you wanted to see the result and immediately thought of a lisp I found years ago. I then had an urgent meeting and subsequent plan changes to tend to before I got back to it. I see that you figured out a solution but figured I'd post this to show how someone else approached the problem:
Code: [Select]
;;; Stephan Koster 2002, posted to adesk customization
;;;  newsgroup on 4/21/2002
(defun XrefTree (/ nested_p build_retlist firstLevelXrefs name
                   nested-xrefs nestList xrefDBase retList i
                )
 (defun nested_p (blockname / tn tmp)
  (and (setq tn (tblobjname "block" blockname))
       (setq tmp (entget tn))
       (setq tmp (cdr (assoc 330 tmp)))
       (setq tmp (entget tmp))
       (not (member '(102 . "{BLKREFS") tmp))
  )
 )
 ;;;
 (defun build_retlist(name / next)
  (setq retList (cons (cons i name) retList))
  (and (setq next (cdr (assoc name nestList)))
       (setq i (1+ i))
       (foreach z next (build_retlist z))
       (setq i (1- i))
  )
 )
 ;;;
 (vlax-for x (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
  (if (= (vla-get-isXref x) :vlax-true)
   (progn
    (setq name (vla-get-Name x))
    (or (nested_p name)
        (setq firstLevelXrefs (cons name firstLevelXrefs))
    )
    (setq nested-xrefs (list name))
    (setq xrefDBase (vl-catch-all-apply 'vla-get-xrefdatabase (list x)))
    (or (vl-catch-all-error-p xrefDBase)
        (vlax-for xx (vla-get-Blocks xrefDBase)
         (if (= (vla-get-isXref xx) :vlax-true)
          (setq nested-xrefs (cons (vla-get-Name xx) nested-xrefs))
         )
        )
    )
    (if (cdr nested-xrefs)
     (setq nestList (cons (reverse nested-xrefs) nestList))
    )
   )
  )
 )
 (foreach x firstLevelXrefs
  (setq i 0)
  (build_retlist x)
 )
 (reverse retList)
)
;;;
(defun c:XrefTree()
 (foreach x (XrefTree)
  (repeat (* 2 (car x)) (princ " "))
  (princ (cdr x))
  (princ "\n")
 )
 (princ)
)

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Seperating Xrefs from blocks
« Reply #8 on: August 01, 2006, 11:50:09 AM »
Thanks for posting it Jeff, but I like what mine returns a little better.  The one you posted returns this.
Quote
C:XREFTREE

Command: xreftree
Xref2
  Cube
XrefMain
  Xref1
  Xref2
    Cube
XREF
Xref2 should not have it's own section, since it is nested in XrefMain (IMO).  This one shows it in two places.

Mine returns like
Quote
Command: (listxrefs (vla-get-activedocument (vlax-get-acad-object)))

 Main Xref = XrefMain
    |-> Nested Xref = Xref2
      |-> Nested Xref = Cube
    |-> Nested Xref = Xref1
 Main Xref = XREF

But non-the-less, I can learn from it, so thanks again.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Seperating Xrefs from blocks
« Reply #9 on: August 01, 2006, 11:55:24 AM »
FYI.....

With both routines, you have to have all the xrefs loaded for them to work correctly.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Hangman

  • Swamp Rat
  • Posts: 566
Re: Seperating Xrefs from blocks ... Aaahhgggg
« Reply #10 on: August 18, 2006, 08:12:34 PM »
HELP !!!
I'm at a loss.
Tim, Jeff, can you help me, I don't have a clue what I'm doing.  I can't even get a stupid tutorial to work if I type it in letter for letter.
I put the following code together following Tim's example to try and get the xref's listed.
I ended up getting closer & closer to Tim's example, but I still can't get it to work.
I have a drawing with 5 xrefs attached.  1 of those xref's I then renamed so it could not be found.  Another one of those xrefs has two xrefs in it.  One of those was renamed so it is not found.  So I have two nested xrefs, one not found the other is found.
Code: [Select]
;;;TEST RUN
;;;
;;;
(vl-load-com)
;;;
(defun C:NXR (/ )
  (setq dwgblks (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-Acad-Object))))
  (vlax-for Blk dwgblks
    (if (= (vla-get-IsXref Blk) :vlax-true)
      (and (not (ssget "X" (list (cons 0 "INSERT") (cons 2 (setq XrefName (vla-get-name Blk)))
                           )
                )
           )
      )
      (setq XrefList (cons XrefName XrefList))
    )
  XrefList
  )
)

This returns  nil
no matter what I have in the drawing.

So after fighting with this until I threw my book across the room, I put together the next sequence.
The following code is to List the images in the drawing.
Code: [Select]
(defun C:IMGL (/ )

  (if (setq ss (ssget "X" '((0 . "IMAGE"))))
    (while (setq Ent (ssname ss 0))
      (setq Obj (vlax-ename->vla-object Ent))
      (if (not (findfile (vla-get-ImageFile Obj)))
        (setq ImgList (cons (vla-get-Name Obj)))
      )
      (ssdel Ent ss)
    )
  )
)
I got a better response but not what I expected.
It returned  <selection set: 49>
OK, so I put together the last segment.  To delete the Image Dictionary if the image is unreferenced.
Code: [Select]
(vl-load-com)
(defun C:IMGD (/ )
  (if (setq ss (ssget "X" '((0 . "IMAGE"))))
    (while (setq Ent (ssname ss 0))
      (setq Obj (vlax-ename->vla-object Ent))
      (if (not (findfile (vla-get-ImageFile Obj)))
        (setq ImgList (cons (vla-get-Name Obj)))
      )
      (ssdel Ent ss)
    )
  )
  (setq DictCol (vla-get-Dictionaries (vla-get-ActiveDocument (vlax-get-Acad-Object))))
  (setq ImgDict (vla-Item DictCol "ACAD_IMAGE_DICT"))
  (foreach ImgName ImgList
    (vla-Delete (vla-Item ImgDict ImgName))
  )
)

I have the same drawing with the xrefs, with one xref missing the image file so it is labeled as unreferenced.  The image in the main dwg is also unreferenced.
the return I get for this is  nil.

I don't understand this vla stuff.  I can't find anything that works to give me something to study.
Can somebody PLEASE help me get a grip on this shhhhtuff,  Thanks.
Hangman  8)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Drafting Board, Mechanical Arm, KOH-I-NOOR 0.7mm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Joe Burke

  • Guest
Re: Seperating Xrefs from blocks
« Reply #11 on: August 19, 2006, 11:02:45 AM »
Here is a cheap way to do it.

Code: [Select]
(defun c:ListNestedXrefs (/ XrefList BlkCol)

(setq BlkCol (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-Acad-Object))))
(vlax-for Blk BlkCol
 (if
  (and
   (= (vla-get-IsXref Blk) :vlax-true)
   (not (ssget "x" (list (cons 0 "INSERT") (cons 2 (setq XrefName (vla-get-name Blk))))))
  )
  (setq XrefList (cons XrefName XrefList))
 )
)
XrefList
)

Hi Tim,

I suspect the cheap way won't work in all cases because (I guess) it assumes a nested xref cannot be inserted as a standalone xref block, which isn't true.

Regards

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Seperating Xrefs from blocks
« Reply #12 on: August 21, 2006, 12:17:23 PM »
From what I remember, getting the correct image file path is not that easy.  If you reference a different image than the one supplied in the dictionary, then you can't tell from it dictionary record, but you might be able to find it from the image that is inserted into the drawing itself.  I haven't test this theory yet, as I don't use images that much, and when I do it's only one image per drawing, and the name is the same.

If you still need help, let me know.

Joe,

  You are correct.  I guess the only way to find what really is nested is to test each xref and see which one's are xrefs, and then if so make a list of those xrefs, and return that list.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Hangman

  • Swamp Rat
  • Posts: 566
Re: Seperating Xrefs from blocks
« Reply #13 on: August 22, 2006, 11:17:31 AM »
Yesssir, I could use the help.  I could use all the help I can get.   :|
My problem is the VLA code.  I'm having the most difficult time trying to understand it.  For some reason, it's just not click'n with me.  I've tried some of the tutorials and other training utilities (Mind you nothing extravagant, I haven't been able to find anything that teaches me, it's mostly just examples and do-it-yourself ideas) but it's not getting me anywhere.
Then again, perhaps I'm just trying to do things that are far beyond the capabilities of LiSP, I dunno, I'm grasping at straws here.

Anyway, to get off my soapbox and back to the discussion at hand, the Xref may or may not recognize a nested xref inserted as a standalone as Joe mentioned, but the BIND program will only go one tier deep anyway.  So for any nested Xref, the user needs to be alerted that the BIND will not work.
Wait a minute.  Perhaps I am looking at this the wrong way.  If a nested xref is inserted as a standalone, would it not become a standard xref ??  Or another words, how can you get a nested xref as a standalone in a drawing ??

As for the Image, isn't the 'unreferenced' image file coded differently than the 'referenced' ??  How can I find an 'unreferenced' image file and detach it from the drawing ??  I was assuming the the drawing would have two dictionaries, one for referenced and one for unreferenced.
i.e.: If you take a drawing, xref in a titleblock with the company logo (an image) and then create a tab with a Calcsheet on it and the company logo, save the drawing, then delete the tab, you will get a referenced image from the xrefed title block and an unreferenced image from the deleted Calcsheet.
Along those same notes, if you have two xrefs in a drawing (the title block and the calcsheet) with one of those xrefs having an 'unreferenced' image (the calcsheet), how do we code the program to find the dictionary for that unreferenced image from the xref and delete it ??  Or even a nested xref with an 'unreferenced' image ??
Holy dogsnots, ...  the Hangman must be hung.  Somebody please put me out of my misery.
Hangman  8)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Drafting Board, Mechanical Arm, KOH-I-NOOR 0.7mm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Seperating Xrefs from blocks
« Reply #14 on: August 22, 2006, 12:00:14 PM »
I try my best not to used nested xrefs, and have only used them to test some code, so I might not be the best to explain, but I will try.  :wink:

<speculation>

A nested xref will always be a nested xref.  You can insert the same drawing as a regular xref, but the name has to be different.

</speculation>

As for 'reference' vs 'unreferenced', this just means that an xref/image definition is inserted into the drawing, but has not been put on the drawing.  ie: with blocks, you can have the definition in the block collection, but it doesn't mean that the block has been inserted, these blocks would be 'unreferenced'.  Hope that works for you.  As for images, there is only one dictionary for all (that I know of).  To see if an xref/image is 'referenced' you will need to search the database (layouts) and see if those objects have been inserted anywhere.  If you are checking in the current drawing, then you can use (ssget "x" .... ) to see, if you want to use ObjectDBX to check this stuff out, then you will have to search through the definition of the layouts (their block definition).  Hope I didn't lose you there.

As for code, that will have to come later.  I hope this helps you understand a little more, and if anyone reading this sees anything that I put that is wrong, please let us know.  Thanks.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.