TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Hangman on July 28, 2006, 06:20:45 PM

Title: Seperating Xrefs from blocks
Post by: Hangman 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,
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey 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
)
Title: Re: Seperating Xrefs from blocks
Post by: Hangman 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. 
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey 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.
Title: Re: Seperating Xrefs from blocks
Post by: Hangman 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 ??
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey 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.
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey 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
Title: Re: Seperating Xrefs from blocks
Post by: Jeff_M 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)
)
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey 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.
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey 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.
Title: Re: Seperating Xrefs from blocks ... Aaahhgggg
Post by: Hangman 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.
Title: Re: Seperating Xrefs from blocks
Post by: Joe Burke 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
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey 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.
Title: Re: Seperating Xrefs from blocks
Post by: Hangman 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.
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey 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.
Title: Re: Seperating Xrefs from blocks
Post by: Krushert on August 22, 2006, 12:41:21 PM
Just watching and learning.

<long story don't ask)
Title: Re: Seperating Xrefs from blocks
Post by: Hangman on August 22, 2006, 01:45:47 PM
I wish I could get away with not using nested xrefs, but unfortunately, when an architects drafter or some other discipline sends us drawings, nine times out of ten, there are xrefs within xrefs within xrefs.  Most of the time I mearly use these to overlay my drawing and take the time to sketch what they have so I don't have to fight their drawings.  but then, my fellow drafters use their drawings for "simplicity & time" in putting our drawings together.  It's the changes & re-editing that's the killer.
So, the most we have in our drawings is an xref'ed title block and gridlines (depending on the project size).  We BIND our drawings when sending them to the architect or other discipline, which brought me to this topic.  Not very often, but on occasion we have a nested xref & unreferenced image(s) which crashes the LiSP.

Ooops, (what a monolog   :oops: )
Anyway, ok, I understand the referenced vs unreferenced with blocks & xrefs.  And Images for that matter.  I'm just not understanding the correlation of the connection.  I know the image isn't a raster so it has to be connected differently than a block, but how it's connected is a mystery.
Quote
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).
Ok, so I want to check the current drawing as you mentioned, (I'm assuming that by checking the current drawing, it will also check the layout tabs ??) for both a nested xref and an unreferenced image.  As I mentioned in my monolog, there are xrefs that we use, but there are others from other disciplines caught in the drawing as well.  Therefore, I can't search for it by name, but I have to at least be alerted to the fact that I have a nested xref in the drawing, referenced or unreferenced.  If I list ALL the xrefs, then that defeats the purpose of the BIND, so I need to list only those xrefs that are nested or tier two or deeper.  So I'm not sure that I need to ObjectDBX to check them out, I just want to know that they are there .??
With the Images, it's appearing that the only way to automatically detach them is to know their name ??  I don't care about the images, if they are there, great, they get bound with the drawing when running the BIND command.  But if they are unreferenced, then the BIND crashes.  I want to simply detach them, I don't care what their name is or where they came from, just detach if they are unreferenced.

Ok, I think you lost me there, I'm sort of understanding your explanation, but I'm not seeing what's right under my nose.    :-(

I thank you for your patience though, and anyone who can help knock this into my thick skull, please bring in your expertise as well, I could use a swift kick in the head.   ^-^
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 22, 2006, 02:25:34 PM
Here is one for looking for nested xrefs.  This will print to the screen in a tree format the nesting levels.
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)
)
I might have posted this before, I'm not sure right now.
Call this like
(ListXrefs (vla-get-ActiveDocument (vlax-get-Acad-Object)))
Here are the results
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

As for images, you will have to see if the dictionary exist, if it does, then there are images attached to the drawing, and you can search for each one, then if it exist, then don't erase it, but if it doesn't then delete the entry in the dictionary.

Code: [Select]
(not
  (vl-catch-all-error-p
   (setq ImDict
    (vl-catch-all-apply
     '(lambda ()
      (vla-Item
       (vla-get-Dictionaries
        (vla-get-ActiveDocument
         (vlax-get-Acad-Object)
        )
       )
       "ACAD_IMAGE_DICT"
      )
     )
    )
   )
  )
 )

This will return true if the dictionary exist, and nil if not.  I will have to do a little more research on images, as I don't see an easy way to get the info you want.

Hope this helps so far though.

FYI... another reason why xref/images are unreferenced (I think) is that they can't find the file they are pathed to.
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 22, 2006, 02:39:36 PM
Can you post the portion of code that deals with the binding?  Maybe we can error proof that.
Title: Re: Seperating Xrefs from blocks
Post by: Hangman on August 23, 2006, 12:26:16 PM
Uuummmm, ...  Well ...  Yessir I can post it.  It's quite simple really.
Code: [Select]
  (command "purge" "A" "" "N")
  (command "purge" "A" "" "N")
  (command "purge" "A" "" "N")
  (command "qsave")
  (command "-xref" "R" "*")
  (command "-xref" "B" "*")
  (command "qsave")

It's a ... kind of embarrasing to post this, it's so simple.  But it does the trick until you have a nested xref, then it goes awry.
The program searches for the bind path & verifies it's there.  If not, it creates it, if so, saves the drawing as it is to the bind path.
It then changes to paperspace, zoom extents and sets the current layer to zero.
It then runs the code above and then closes.
I need to place the xref search and Image search between the purging and the -xref reload and bind.

I guess this is where the code would get so much more technical.
I couldn't find a way to do this with LiSP, and I don't know VLA nor am I successful in learning it.  So this is where I need your help.
And thank you again for your help.
Title: Re: Seperating Xrefs from blocks
Post by: Hangman on August 23, 2006, 12:55:51 PM
Ok, when I run your most recently posted code, I get the following return

Command: AP
APPLOAD TST-XRefList3.lsp successfully loaded.

Command:
Command:
Command: (ListXrefs (vla-get-ActiveDocument (vlax-get-Acad-Object)))

Code: [Select]
Main Xref = 4
 Main Xref = 3
 Main Xref = 2
 Main Xref = 1
 Main Xref = TESTdwg_ARW-TTL
My drawing (TESTdwg_0-75.dwg) consists of (5) xref dwgs.  These drawings are 1,2,3,4, & TESTdwg_ARW-TTL
The drawing '3' was renamed, so it is 'unreferenced' or 'can't be found' in the 0-75.dwg.
The last dwg, ARW-TTL has two xrefs in it; S2-8-11 & S2-8-12.  The S2-8-12 is 'unreferenced' or 'can't be found' in the ARW-TTL dwg.
So the code is listing the xrefs "assigned" (if you will) to the drawing 0-75.dwg, but it is not listing the xrefs within the xref ARW-TTL, the nested xrefs.

I hope this bit helps, ...  I don't know how to help you trouble shoot this thing.

<Message Updated>

This is what I get when running the code Jeff posted earlier.

Command: ap
APPLOAD TST-XRefList4_JM-swamp.lsp successfully loaded.

Command:
Command:
Command: (xreftree)
Code: [Select]
((0 . "4") (0 . "3") (0 . "2") (0 . "1") (0 . "TESTdwg_ARW-TTL"))
Basically the same listing.  It doesn't tell you that one xref is not found nor does it tell you there are nested xrefs and one of those are not found.
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 23, 2006, 01:24:36 PM
If you want a routine to reload and bind xrefs, maybe this will work for you.
Code: [Select]
(defun ReloadBindXrefs (Doc / XrefList LstLen)

(vlax-for Blk (vla-get-Blocks Doc)
 (if (= (vla-get-IsXref Blk) :vlax-true)
  (progn
   (vla-Reload Blk)
   (vla-Bind Blk :vlax-true)
   (if
    (and
     (= (vla-get-IsXref Blk) :vlax-true)
     (not (vl-position (vla-get-Name Blk) XrefList))
    )
    (setq XrefList (cons Blk XrefList))
   )
  )
 )
)
(setq LstLen (length XrefList))
(while
 (and
  (> LstLen 0)
  (>= LstLen (setq LstLen (length XrefList)))
 )
 (foreach Blk XrefList
  (if
   (or
    (= (vla-get-IsXref Blk) :vlax-false)
    (and
     (vla-Bind Blk :vlax-true)
     (= (vla-get-IsXref Blk) :vlax-true)
    )
   )
   (setq XrefList (vl-remove Blk XrefList))
  )
 )
)
(foreach Blk XrefList
 (prompt (strcat "\n Unable to bind xref:" (vla-get-Name Blk)))
)
(princ)
)
To be called like (for current drawing)
(ReloadBindXrefs (vla-get-ActiveDocument (vlax-get-Acad-Object)))


In respones to your last post.  Try this routine and see if it works for you.  It will prompt which drawings it could not bind if any.
Title: Re: Seperating Xrefs from blocks
Post by: Hangman on August 23, 2006, 01:55:16 PM
I'll have to play with this a bit.
This is what I get at the moment when I run it.

Command: ap
APPLOAD TST-XRefList5.lsp successfully loaded.

Command:
Command:
Command: ReloadBindXrefs
Unknown command "RELOADBINDXREFS".  Press F1 for help.

Command: (ReloadBindXrefs (vla-get-ActiveDocument (vlax-get-Acad-Object)))
Code: [Select]
; error: Automation Error. File access error

This is going to be trick (at least for me), but I have a bit I can go study and learn why they work the way they do.

Thanks Tim for your help.  I appreciate it.  I know you've learned a think or two but you've put a lot of time in to find a solution for me.  Thank you.
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 23, 2006, 01:59:47 PM
Can you post a zip that has the drawings you are testing these routines on?  I would like to see what I can come up with.  I'll only be here or about another hour and a half today.
Title: Re: Seperating Xrefs from blocks
Post by: Hangman on August 24, 2006, 11:09:59 AM
Tim,
Yeah, I'll do that.

It finally dawned on me what you were asking earlier about posting the code and try to work out the errors.
So, here's another angle to this dilemma until we can find this fix.

When I run the program, and I have a nested xref or an xref that is not found, I get the following error:
Code: [Select]
Command: -xref
Enter an option [?/Bind/Detach/Path/Unload/Reload/Overlay/Attach] <Attach>: R
Enter xref name(s) to reload: *
Reload Xref "ARW-TTL": D:\temp\Tests\Xref\ARW-TTL.dwg
D:\temp\Tests\Xref\ARW-TTL.dwg has not changed.

Reload Xref "1": D:\temp\Tests\Xref\1.dwg
D:\temp\Tests\Xref\1.dwg has not changed.

Reload Xref "2": D:\temp\Tests\Xref\2.dwg
D:\temp\Tests\Xref\2.dwg has not changed.

Reload Xref "3": D:\temp\Tests\Xref\3.dwg
"3.dwg" cannot be found.
*Invalid*
Error: Function cancelled

How can I catch that error so if it occurs, an ALERT will pop up telling the user there are problems ??

As the program is right now, when the error crashes, it leaves the drawing open in the BIND directory.  If the user is not paying real close attention, they will not notice the error and run the program again which then creates the drawing in the BIND\BIND directory.  I have had a user who was zipping through his drawings and finally realized he had been binding the same drawing over and over because of the crash.  So his directory structure was something like:
D:\Drawings 2005\05132\BIND\BIND\BIND\BIND\BIND\BIND\BIND\BIND\BIND\BIND\BIND\BIND\BIND\BIND\05132_S3-2.dwg

So if an error occurs, I want to throw up an ALERT so the user will not continue blissfully down the wrong path.
Any ideas on how to reference an error ??
Code: [Select]
  (setq $error$ $error) ;;; ??
  (if (/= $error$ nil) ;;;  I don't know how I would work this line here
    (ALERT "an error has occured, please check your drawing before continuing."))

<message updated>

I do have this up in the beginning of my program
Code: [Select]
(defun $error (msg /)
    (if (or (= msg "Function cancelled")
            (/= msg "quit / exit abort")
        )
        (princ (strcat "Error: " msg))
    )
    (command ".undo" "e" "undo" "")
    (command ".redraw")
    (setvar "cmdecho" echoprv)
    (setvar "expert" xprtorg)
    (setq *error* old_err)
    (setq echoprv nil)
    (princ)
  );end error
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 24, 2006, 11:31:07 AM
Here you go.  I didn't know it would error if it couldn't relaod an xref.  This version will print to the command line which drawings could not be bound.
Code: [Select]
(defun ReloadBindXrefs (Doc / XrefList LstLen TroubleList)

(vlax-for Blk (vla-get-Blocks Doc)
 (if (= (vla-get-IsXref Blk) :vlax-true)
  (progn
   (if
    (vl-catch-all-error-p
     (vl-catch-all-apply 'vla-Reload (list Blk))
    )
    (setq TroubleList (cons Blk TroubleList))
    (progn
     (vla-Bind Blk :vlax-true)
     (if
      (and
       (= (vla-get-IsXref Blk) :vlax-true)
       (not (vl-position (vla-get-Name Blk) XrefList))
      )
      (setq XrefList (cons Blk XrefList))
     )
    )
   )
  )
 )
)
(setq LstLen (length XrefList))
(while
 (and
  (> LstLen 0)
  (> LstLen (setq LstLen (length XrefList)))
 )
 (foreach Blk XrefList
  (if
   (or
    (= (vla-get-IsXref Blk) :vlax-false)
    (and
     (vla-Bind Blk :vlax-true)
     (= (vla-get-IsXref Blk) :vlax-true)
    )
   )
   (setq XrefList (vl-remove Blk XrefList))
  )
 )
)
(foreach Blk (append XrefList TroubleList)
 (prompt (strcat "\n Unable to bind xref: " (vla-get-Name Blk)))
)
(princ)
)
Quote from:  Acad command line
Command: (ReloadBindXrefs (vla-get-ActiveDocument (vlax-get-Acad-Object)))

 Unable to bind xref: Xref1
 Unable to bind xref: Xref2
 Unable to bind xref: XrefMain
 Unable to bind xref: Cube
Title: Re: Seperating Xrefs from blocks
Post by: Hangman on August 24, 2006, 11:40:24 AM
Cool Tim,
I'll go play with it.

I've figured out a way to display my error message by adding to my error control code.
Code: [Select]
(defun $error (msg /)
    (if (or (= msg "Function cancelled")
            (/= msg "quit / exit abort")
        )
        (princ (strcat "Error: " msg))
    )
    (command ".undo" "e" "undo" "")
    (command ".redraw")
    (setvar "cmdecho" echoprv)
    (setvar "expert" xprtorg)
    (ALERT "ERROR !!! There are nested xref's and / or unreferenced images found in your drawing.") ;;; <<<<<
    (setq *error* old_err)
    (setq echoprv nil)
    (princ)
    (command "close" "Y") ;;; <<<<<
  );end error

It's not very pretty, but it does the trick until I can find a way to automatically detach the unreferenced stuff.   Thanks Tim.
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 24, 2006, 11:55:44 AM
If you want to detach the ones that can't be found, then we only need to change one part of the code I just posted.
Code: [Select]
(vlax-for Blk (vla-get-Blocks Doc)
 (if (= (vla-get-IsXref Blk) :vlax-true)
  (progn
   (if
    (vl-catch-all-error-p
     (vl-catch-all-apply 'vla-Reload (list Blk))
    )
    (setq TroubleList (cons Blk TroubleList))
    (progn
     (vla-Bind Blk :vlax-true)
     (if
      (and
       (= (vla-get-IsXref Blk) :vlax-true)
       (not (vl-position (vla-get-Name Blk) XrefList))
      )
      (setq XrefList (cons Blk XrefList))
     )
    )
   )
  )
 )
)
to
Code: [Select]
(vlax-for Blk (vla-get-Blocks Doc)
 (if (= (vla-get-IsXref Blk) :vlax-true)
  (progn
   (if
    (vl-catch-all-error-p
     (vl-catch-all-apply 'vla-Reload (list Blk))
    )
    (if
     (vl-catch-all-error-p
      (vl-catch-all-apply 'vla-Detach (list Blk))
     )
     (setq TroubleList (cons Blk TroubleList))
     (prompt (strcat "\n Detached xref: " (vla-get-Name Blk)))
    )
    (progn
     (vla-Bind Blk :vlax-true)
     (if
      (and
       (= (vla-get-IsXref Blk) :vlax-true)
       (not (vl-position (vla-get-Name Blk) XrefList))
      )
      (setq XrefList (cons Blk XrefList))
     )
    )
   )
  )
 )
)

The new part will try and detach it, if it can it will tell you it detached it, if not it will add it to the list of xref's it wasn't able to do anything with.  Hope that helps.
Title: Re: Seperating Xrefs from blocks
Post by: GDF on August 24, 2006, 04:41:13 PM
Tim

I just caught this thread and tried your revised routine.
Works great, I can sure use this one. Thanks.

Gary
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 24, 2006, 04:52:45 PM
Tim

I just caught this thread and tried your revised routine.
Works great, I can sure use this one. Thanks.

Gary
Cool! 8-)
Thanks for testing Gary.

Edit: Gary/all the way it's coded, it should work with drawings opened with ObjectDBX.  It will print to the current drawing opened.
Title: Re: Seperating Xrefs from blocks
Post by: GDF on August 24, 2006, 05:03:13 PM
Tim

Tim

I just caught this thread and tried your revised routine.
Works great, I can sure use this one. Thanks.

Gary
Cool! 8-)
Thanks for testing Gary.

Edit: Gary/all the way it's coded, it should work with drawings opened with ObjectDBX.  It will print to the current drawing opened.

So, I can use objectdbx to bind all xrefs within a directory, by using this function within an objectdbx routine?
Kool.

Gary

Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 24, 2006, 05:15:26 PM
Yup.  You would need to make small changes (to make it work like it should with multiply drawings).
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 25, 2006, 12:53:42 PM
Aaron,

  This code works on your drawing.  I had some bad order in the way it worked.  I detached the xref, and then tried to get the name, and that won't work, so I had to get the name first.

Let me know it still causes problems.

Code: [Select]
(defun ReloadBindXrefs (Doc / XrefList LstLen TroubleList *error* tmpName)

(defun *error* (msg)
;(vl-bt)
(prompt (strcat "\n Error--> " msg))
)

(vlax-for Blk (vla-get-Blocks Doc)
 (if (= (vla-get-IsXref Blk) :vlax-true)
  (progn
   (if
    (vl-catch-all-error-p
     (vl-catch-all-apply 'vla-Reload (list Blk))
    )
    (if
     (and
      (setq tmpName (vla-get-name Blk))
      (vl-catch-all-error-p
       (vl-catch-all-apply 'vla-Detach (list Blk))
      )
     )
     (setq TroubleList (cons Blk TroubleList))
     (prompt (strcat "\n Detached xref: " tmpName))
    )
    (progn
     (vla-Bind Blk :vlax-true)
     (if
      (and
       (= (vla-get-IsXref Blk) :vlax-true)
       (not (vl-position (vla-get-Name Blk) XrefList))
      )
      (setq XrefList (cons Blk XrefList))
     )
    )
   )
  )
 )
)
(setq LstLen (length XrefList))
(while
 (and
  (> LstLen 0)
  (> LstLen (setq LstLen (length XrefList)))
 )
 (foreach Blk XrefList
  (if
   (or
    (= (vla-get-IsXref Blk) :vlax-false)
    (and
     (vla-Bind Blk :vlax-true)
     (= (vla-get-IsXref Blk) :vlax-true)
    )
   )
   (setq XrefList (vl-remove Blk XrefList))
  )
 )
)
(foreach Blk (append XrefList TroubleList)
 (prompt (strcat "\n Unable to bind xref: " (vla-get-Name Blk)))
)
(princ)
)
Call with (for current drawing)
(ReloadBindXrefs (vla-get-ActiveDocument (vlax-get-Acad-Object)))
Title: Re: Seperating Xrefs from blocks
Post by: Hangman on August 25, 2006, 05:53:23 PM
Hey Tim,
This works superbly.  THANK YOU very much.  I appreciate your help.

btw, I was reading the One Up link from Se7en and found your comment about tidying up an eleven year stint.
I hope it's in your best interest.
And why would you put so much time into helping me when you have more pressing issues at hand ???  Now I owe you a double THANK YOU !!

Best of luck in your endeavors.  And if there's anything I can do for you, let me know, you have my email addr.

And so, ... now we need to work on the images.  :-D
Title: Re: Seperating Xrefs from blocks
Post by: T.Willey on August 25, 2006, 06:44:18 PM
Hey Tim,
This works superbly.  THANK YOU very much.  I appreciate your help.
You're welcome.  I seem to be drawn to questions about xrefs.  It's like I must answer.  :-D

btw, I was reading the One Up link from Se7en and found your comment about tidying up an eleven year stint.
I hope it's in your best interest.
This was directed toward Michael.  I haven't been coding that long.  :wink:

Best of luck in your endeavors.  And if there's anything I can do for you, let me know, you have my email addr.
Thanks.

And so, ... now we need to work on the images.  :-D
Did you see I started a thread about them.  I can't seem to figure that one out, and it looks like I'm not the only one.  I have started looking into coding with C# (.Net) and didn't see anything about images that would help, but it was a quick look.  This really bugs me that I/we can't figure it out.
Title: Re: Seperating Xrefs from blocks
Post by: Maverick® on August 26, 2006, 01:09:41 PM
Tim, Have you been learning reply ettique from Cadaver?   :-D