Is there any substance to ronjonp's post about removing references to the xrefs'?
http://www.cadtutor.net/forum/showthread.php?p=299135#post299135
What happened when you tested this for yourself?
I've just tested the Erase() Method here, and all is well... Just be sure to erase the entity, and not the block definition (even though you need to test this for IsXref), and also test for locked layers, and restore as needed.
HTH I did, but was attempting to delete the blockdef - which of course generated an automation error
That would be a solution if I were trying to create an Unreferenced xref. The xref's I'm removing are based on the user's selection to
Remove Unreferenced
Remove Unloaded
Remove FileNotFound
or any combination
Namely, my testing first centered on Unreferenced types, which means there are no inserts to Erase() (vla-erase).
I sure do like to create lisp packages that function wholy without other languages, but I'm starting to finally understand autolisp's limitations.
A complete side note... vla-IsXref will also return nested xref's. There's a way to elliminate nested xref's in lisp, but it involves making a list of subnested xref's and their xref's, etc., so if a tested xref is a member of the nested list, then it's a nest, not a direct. LeeMac has a routine that does that (xreflist me thinks). Negating that, I used a seperate .net LispFunction that simply returns the result of .net .IsFromExternalReference, which eliminates attempts to detach a nested xref.
The following code bits are my final the result... minus good LispFunction var handling (see http://www.theswamp.org/index.php?topic=43063.msg483195#msg483195)
The following is the function called during the dbx operations.
The var "cd: xrefclean: operation" is a vl-propagate'd and contains the initial command that obtained the user's options.
(defun cd:clean-xref (dbxdoc / cd:detach status statuses blk blocks blockname detach outdata ename reflist ref vla_ref )(defun cd:detach (xref /) ;(vla-detach xref) ;(vla-delete xref) ;(vla-erase xref) (cd:xref-detach (vlax-vla-object->ename xref)) );defun cd:detach(setq blocks (vla-get-Blocks doc));make a collection list of all true xref block enames(vlax-for blk blocks (if (and (= :vlax-true (vla-get-isxref blk)) (setq ename (vlax-vla-object->ename blk)) (cd:block-isxref ename));(setq blockname (vla-get-name blk)) ;get it now before it's deleted;(setq blockpath (vla-get-path blk)));build a list first, then submit to .net to get results all at once.(setq reflist (append reflist (list ename))));if );vlax-for blk in blocks(if (and (< 0 (length reflist)) (setq statuses (cd:xref-status reflist))) (foreach ref statuses(setq detach nilstatus (cdr ref)vla_ref (vlax-ename->vla-object (car ref))blockname (vla-get-name vla_ref)blockpath (vla-get-path vla_ref))(if (and (not detach) (wcmatch cd:xrefclean:operation "*R*") (= status "Unreferenced"))(setq detach (cd:detach vla_ref)))(if (and (not detach) (wcmatch cd:xrefclean:operation "*F*") (or (= status "FileNotFound")(= status "Unresolved")))(setq detach (cd:detach vla_ref)))(if (and (not detach) (wcmatch cd:xrefclean:operation "*L*") (= status "Unloaded"))(setq detach (cd:detach vla_ref)))(if (and (not detach) (wcmatch cd:xrefclean:operation "*A*") (or (= status "FileNotFound")(= status "Unloaded")(= status "Unresolved")(= status "Unreferenced")))(setq detach (cd:detach vla_ref)))(setq outdata (cons (list blockname status (if detach "Detached" "Remains Attached") blockpath)outdata)));foreach ref in reflist );ifoutdata);defun cd:clean-xref
-Split into two posts. -Continued
The first step was to ensure the block def wasn't a nested block.
public bool Block_isXref(ResultBuffer rb){if (rb == null){ return false; }TypedValue[] args = rb.AsArray();if (args.Length > 1 || (LispDataType)args.TypeCode != LispDataType.ObjectId){ return false; }ObjectId ObjId = (ObjectId)args.Value;using (Transaction tr = ObjId.Database.TransactionManager.StartTransaction()){ try {BlockTableRecord btr = (BlockTableRecord)tr.GetObject(ObjId, OpenMode.ForRead, false);if (btr.IsFromExternalReference) return true; } catch (System.Exception) {tr.Abort();return false; }}return false;}
The next step was to get an accurate status of the xref. It was important that the function only invoked .ResolveXrefs() once per dbx drawing, thus the need to send it a list of enames/objectid's to work with.
public object Xref_Status(ResultBuffer rb){if (rb == null){ return false; }TypedValue[] args = rb.AsArray();ObjectId ObjId = new ObjectId();if (args.Length == 1){ ObjId = (ObjectId)args.Value; }else { ObjId = (ObjectId)args.Value; }using (Transaction tr = ObjId.Database.TransactionManager.StartTransaction()){ ResultBuffer res = new ResultBuffer(); try {res.Add(new TypedValue((int)LispDataType.ListBegin));if (!HostApplicationServices.WorkingDatabase.Equals(ObjId.Database))ObjId.Database.ResolveXrefs(true, false);foreach (TypedValue arg in args){ try { BlockTableRecord btr = (BlockTableRecord)tr.GetObject((ObjectId)arg.Value, OpenMode.ForRead, false); res.Add(new TypedValue((int)LispDataType.ListBegin)); res.Add(new TypedValue((int)LispDataType.ObjectId, (ObjectId)arg.Value)); res.Add(new TypedValue((int)LispDataType.Text, btr.XrefStatus.ToString())); res.Add(new TypedValue((int)LispDataType.DottedPair)); } catch (System.Exception) { }}res.Add(new TypedValue((int)LispDataType.ListEnd));return res; } catch (System.Exception) {tr.Abort();res.Add(new TypedValue((int)LispDataType.ListEnd));return false; }}}
And finally, function to detach the file using .net.
public Boolean Xref_Detach(ResultBuffer rb){if (rb == null){ return false; }TypedValue[] args = rb.AsArray();if (args.Length > 1 || (LispDataType)args.TypeCode != LispDataType.ObjectId){ return false; }ObjectId objId = (ObjectId)args.Value;using (Transaction tr = objId.Database.TransactionManager.StartTransaction()){ try {BlockTableRecord btr = (BlockTableRecord)tr.GetObject(objId, OpenMode.ForRead, false);if (btr.IsFromExternalReference == true){ objId.Database.DetachXref(objId); tr.Commit(); return true;}else return false; } catch (System.Exception) {tr.Abort();return false; }}} Sorry to nitpick, but the cd : detach and cd : xrefclean : operation LispFunction Methods appear to be missing, and you've posted cd : xref-detach (the Xref_Detach() Method) instead.
Also, you really should make use of either Gile's LispException* Classes that I mentioned in your other thread at TheSwamp, or the code contract that Tony offered in his prototype design, rather than simply having an empty catch statement that neither handles the exception, nor reports to you what went wrong.
They may be interchangeable (I honestly have not tried it for myself), but generally one would return bool value in lieu of a Boolean Class type... Compare your Block_isXref() and Xref_Detach() Methods.
Just to throw the idea out there for your consideration, might I suggest that instead of creating separate LispFuntion Methods for each Block_isXref(), Xref_Status(), and Xref_Detach(), that you instead consider (for this specific task) coding a single, (bit-coded?) XrefDetachIf() Method.
While functional, and also an enhancement to LISP as is, I think you'll find a significant increase in performance, if you simply take a step back and plan your plug-in around what you're actually attempting to do here.
Were you to use a single XrefDetachIf() Method, you would reduce your overhead as you would need only a single Transaction for each call to the LispFunction Method, as compared to using each of the three LispFunction Methods you posted above.
Considering what your LISP does now....
For each DBX Document, you iterate the Block Collection, and test each usingBlock_isXref() (1+ Transaction for each call) in order to build a list of Block References that are External References.
Next, you iterate the resultant list of External References, testing for Xref_Status() (1+ Transaction for each call)... This step you do good, by utilizing the ResultBuffer to pass ObjectId[] as an argument.
However, were you to effectively code a XrefDetachIf() LispFunction Method, you would preclude the need to build a valid list of External References, and then iterate that list to determine which are of a particular status in the first place, and simply pass ObjectId[] for a given DBX Document's Block's eNames (as you do for Xref_Status()), and the internal .NET logic would minimize the processing, sorting, and 'meat' of the LISP routine for you.
HTH Pseudo code:
/// /// First argument - ObjectId[] of enames /// Second argument - Bit-coded value for external /// reference statuses to filter for: /// /// 1 FileNotFound /// 2 Nested /// 4 Unloaded /// 8 Unreferenced /// /// Third argument - Reload unloaded references (T / nil) /// /// Example: /// (Xref-Detach-If listOfXrefEnames 9 T) /// /// /// public ResultBuffer XrefDetachIf(ResultBuffer res) { } I've formed a response twice, and this forum has timed me out twice and it lost my composition. Actually more than twice, but I copied my response before preview a few times. This time though I just forgot. Must mean I should not post today.
Is it like 3 minutes or something????
Well... I guess the point of my reply was a big thank you for the pointers and guidance.
cd : detach is a nested defun. It's there
cd : xrefclean : operation is a text var, not a defun, begotten from the c:xrefclean wrapper command
Here's a snip of that section
(initget "L R F A LR LF LRF LFR RL RF RFL RLF FL FR FLR FRL")(princ "\nYou can use any combination like RF or FL")(setq cd:xrefclean:operation (getkword "\nXref Cleaner: Detach : "))
Referenced that post, and gave mea culpas
Good catch. vs autocomplete
The rest of your suggestion is sound advice. What I accidentally found out, while proving your suggestion was that vla-get-isxref provides a considerable time savings, as it filters out blocks defs that are not xref's at all.
Elapsed milliseconds / relative speed for 512 iteration(s): (CD:XREFTEST1 XREFLIST)......13634 / 19.58 (CD:XREFTEST2 XREFLIST).....266996 / 1.00
The above xreflist is a 1432 length vla-object collection of vla-get-blocks. 383 are actuall xref's and 9 are direct xref's.
Both functions use your suggested method of combining the cd : block-isxref and cd : xref-status into a single function. I left the determination of whether to detach to lisp.
So the difference in the above function tests are that cd : xreftest1 included a pre-test for vla-get-isxref, while cd : xreftest2 sent every block def to be tested in .net.
After reminiscing. I believe I will still keep it seperate. Each Lisp Function I've created has a specific role; that thought actually did go into creating the functions, as my intention was to expand lisp in the spirit of lisp. Where logic is kept in lisp, and the lispfunctions provide expanded capability.
For instance. It could be thought that having a function to return boolean for IsUnloaded, is IsResolved, and IsFromExternalReference, might be condiered obsolete if I just returned the string for XrefStatus, however I can envision scenarios where each would serve purpose in the situation needed.
I just realized I took this thread over. I'm gratefull I stumbled on your original post, because I'd be further behind the curve than I already am.
Sincerely,
You're welcome; I'm happy to help.
Perhaps I should have broken things out a bit more, but I wanted to 'get it all in' before I left work to vote. Again, as you already know from my participation over at TheSwamp, I am no expert when it comes to the finer points of .NET, but I genuinely hope that my comments are of help to you.
No worries; I too am glad you chimed in. I've been wanting to delve more and more into .NET development, but often do not make the time to plan out my own initiatives (I do it all in my spare time), so more often than not helping others with their interests is something I look for first.
Besides, I think your LispFunction Methods would make a good addition to this thread, where I may very well code that XrefDetachIf() LispFunction also.
页:
1
[2]