TheSwamp
Code Red => .NET => Topic started by: T.Willey on May 02, 2008, 02:55:41 PM
-
So I knew there had to be a way to do it, but it just wasn't as simple as I thought it would be, but here you go. It will show where each xref is, and which xrefs are within each. No need to cycle through the block table record to see if an xref is nested within the definition.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.IO;
using System.Text;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Windows;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
[CommandMethod("TestXrefPrint")]
public void TestXrefPring() {
Document Doc = acadApp.DocumentManager.MdiActiveDocument;
Database Db = Doc.Database;
Editor Ed = Doc.Editor;
XrefGraph XrGraph = Db.GetHostDwgXrefGraph(false);
for (int i = 1; i < XrGraph.NumNodes; i++) {
XrefGraphNode XrNode = XrGraph.GetXrefNode(i);
Ed.WriteMessage("\n Name: {0}", XrNode.Name);
for (int j = 0; j < XrNode.NumIn; j++) {
int tempInt = IsXrNodeEqual(XrGraph, XrNode.In(j));
if ( tempInt.Equals(-1) )
continue;
Ed.WriteMessage("\n Is In: {0}", XrGraph.GetXrefNode(tempInt).Name);
}
for (int j = 0; j < XrNode.NumOut; j++) {
int tempInt = IsXrNodeEqual(XrGraph, XrNode.Out(j));
if ( tempInt.Equals(-1) )
continue;
Ed.WriteMessage("\n Has within: {0}", XrGraph.GetXrefNode(tempInt).Name);
}
Ed.WriteMessage("\n");
}
}
public int IsXrNodeEqual(XrefGraph xrGraph, GraphNode grNode) {
for (int i = 0; i < xrGraph.NumNodes; i++) {
if (grNode == xrGraph.GetXrefNode(i) as GraphNode)
return i;
}
return -1;
}
Sample output, where the drawing is named XrefIsIn2.dwg.
Command: testxrefprint
Name: XrefMain
Is In: XrefIsIn2
Has within: Xref2
Has within: Xref1
Name: Xref2
Is In: XrefMain
Has within: Cube
Name: Xref1
Is In: XrefMain
Name: Cube
Is In: Xref2
-
one thing I ran accross before when resolving nested xrefs from files opened as dbx docs, you need to add this line for it to work.
db.ResolveXrefs(false, false);
before the line:
XrefGraph XrGraph = Db.GetHostDwgXrefGraph(false);
Otherwise I believe you can get the nested block names, but no other info on the nested items like the path.
It slows things down a lot too.
Now what I do, is dig through the top level of xrefs, then dig through those, and then their children until no more nesting.
Then I use that info to compile a tree for any file I want involving those xrefs.
Doing it that way is much faster if you are making a tool like your own etransmit, where say all 10 sheets you are gathering info on will have the same xrefs. Simply skip xrefs you already dug into, this saving a lot of time.
Its probably not appropriate for single file investigation though.
I'm doing an app that catalogs the xref info, then shows me a tree of xrefs for any file in a project, then even rename an xref and fix the sheet paths for me. I wonder if doc management systems do this type of thing well. Any tool that investigated files, and let you change xref names and paths quickly would be so nice.
There are lots of xref repathers, but none that catalog xref trees for later retrieval.
thx
-
How about the following. I used some code from a number of posts and created a little generic method to return the paths for ALL xrefs.
[Autodesk.AutoCAD.Runtime.CommandMethod("PrintAllXrefs")]
public List<string> GetDrawingReferences()
{
List<string> result = new List<string>();
//Get current document
Autodesk.AutoCAD.ApplicationServices.Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
//Get current database
Database db = doc.Database;
//Get current editor
Editor ed = doc.Editor;
//For debug print to editor only...
string name = null;
string fullname = null;
bool isnested = false;
//Get the first transaction to read the xref graph
using (Transaction tr = doc.TransactionManager.StartTransaction()) {
//Get the current document's xref graph
XrefGraph DocDbXrGraph = db.GetHostDwgXrefGraph(false);
//Loop through the nodes in the xref graph
for (int i = 0; i <= DocDbXrGraph.NumNodes - 1; i++) {
//Get the node
XrefGraphNode XrGraphNode = DocDbXrGraph.GetXrefNode(i);
//Only continue if the node contains items
if (i != 0) {
//Start another transaction to get extended information for the xref
TransactionManager tm = db.TransactionManager;
using (Transaction tr2 = tm.StartTransaction) {
//Get block table of the current document
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
//Get block table record for the xref
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(XrGraphNode.BlockTableRecordId, OpenMode.ForRead);
//Add xref to the list for returning, regardless of nested status
result.Add(btr.PathName);
//debug only:
name = btr.Name;
fullname = btr.PathName;
isnested = XrGraphNode.IsNested;
}
//Uncomment the following lines for extended debug
//With ed
//.WriteMessage("" & Chr(10) & "--------------------")
//.WriteMessage("" & Chr(10) & "Block Name: " + name)
//.WriteMessage("" & Chr(10) & "Full Name: " + fullname)
//.WriteMessage("" & Chr(10) & "Is Nested: " + isnested.ToString)
//End With
}
}
}
return result;
}
The next thing to do, I suppose, is to ensure that the xrefs are up-to-date and current in the drawing
-
James,
Thanks for the tip about 'db.ResolveXrefs(false, false)'. I was just updating my utility program that gets all the xref information I want, and I had to do this before I could get the in's and out's of the xref nodes.
-
Hi,
I was looking for a way to list all xrefs in a drawing (even nested), and searching some inspiration here and there and I found this one.
I tried to build one my own way and here's the result.
Thanks to T.Willey, mcarson, Glenn R and all others... for the the shared informations.
As I didn't find a way to convert a GraphNode (as returned by GraphNode.In) into an XrefGraphNode, I first 'copy' the XrefGraph in a GraphNodeCollection to be able to deal with index.
Any comments are welcome.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace XrefSample
{
public static class ListXref
{
[CommandMethod("XRLST")]
public static void GetXrefList()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
XrefGraph xrg = db.GetHostDwgXrefGraph(true);
GraphNodeCollection gnc = new GraphNodeCollection();
for (int i = 0; i < xrg.NumNodes; i++)
{
gnc.Add(xrg.GetXrefNode(i));
}
for (int i = 1; i < xrg.NumNodes; i++)
{
XrefGraphNode xrgn = xrg.GetXrefNode(i);
if (xrgn.IsNested)
{
for (int j = 0; j < xrgn.NumIn; j++)
{
XrefGraphNode parent = xrg.GetXrefNode(gnc.IndexOf(gnc[i].In(j)));
ed.WriteMessage("\n{0}|{1} : {2}", parent.Name, xrgn.Name, getStatus(xrgn));
}
}
else
{
ed.WriteMessage("\n{0} : {1}", xrgn.Name, getStatus(xrgn));
}
}
}
private static string getStatus(XrefGraphNode xrgn)
{
string result = string.Empty;
switch (xrgn.XrefStatus)
{
case XrefStatus.FileNotFound:
result = "File not found";
break;
case XrefStatus.Resolved:
result = "Resolved";
break;
case XrefStatus.Unloaded:
result = "Unloaded";
break;
case XrefStatus.Unreferenced:
result = "Unreferenced";
break;
case XrefStatus.Unresolved:
result = "Unresolved";
break;
}
return result;
}
}
}
Result for a sample drawing:
Theatre
| Equipement
| Perches
| Passerelles
| Plateau
Rotonde
| Mobilier
Detail
| Passerelles
Theatre : Resolved
Rotonde : Resolved
Rotonde|Mobilier : Resolved
Theatre|Plateau : Resolved
Theatre|Equipement : Unloaded
Equipement|Perches : Unreferenced
Equipement|Passerelles : Resolved
Detail|Passerelles : Resolved
Detail : Resolved
-
Another way (classical recursive process).
[CommandMethod("XRTREE")]
public static void XrefTree()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
getNestedXref(db, ed, string.Empty);
}
catch (System.Exception ex)
{
ed.WriteMessage("\nErreur: " + ex.Message);
}
}
private static void getNestedXref(Database db, Editor ed, string parent)
{
XrefGraph xrg = db.GetHostDwgXrefGraph(true);
for (int i = 1; i < xrg.NumNodes; i++)
{
XrefGraphNode xrgn = xrg.GetXrefNode(i);
if (!xrgn.IsNested)
{
ed.WriteMessage("\n{0}{1} ({2})", parent, xrgn.Name, getStatus(xrgn));
if (xrgn.XrefStatus == XrefStatus.Resolved)
getNestedXref(xrgn.Database, ed, parent + xrgn.Name + "|");
}
}
}
Théâtre (Resolved)
Théâtre|Plateau (Resolved)
Théâtre|Equipement (Resolved)
Théâtre|Equipement|Perches (Resolved)
Théâtre|Equipement|Passerelles (Resolved)
Rotonde (Resolved)
Rotonde|Mobilier (Resolved)
Detail (Resolved)
Detail|Passerelles (Resolved)
-
Again...
The recursive way allows to get the tree structure but using XrefGraphNode.Database doesn't allows to get an unresolved node children .
So I mixed the two previous ways, and write the result in an Xml file.
using System.Text;
using System.Xml;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace XrefSample
{
public class XrefToXml
{
[CommandMethod("XR2XML")]
public static void XrefListToXml()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
XrefGraph xrg = db.GetHostDwgXrefGraph(true);
using (GraphNodeCollection gnc = new GraphNodeCollection())
{
for (int i = 0; i < xrg.NumNodes; i++)
{
gnc.Add(xrg.GetXrefNode(i));
}
string dwgName = doc.Name;
string xmlName = dwgName.Substring(0, dwgName.LastIndexOf('.')) + ".xml";
XmlTextWriter writer = new XmlTextWriter(xmlName, Encoding.UTF8);
try
{
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
writer.WriteStartElement("host");
writer.WriteAttributeString("path", dwgName);
using (Transaction tr = db.TransactionManager.StartTransaction())
{
for (int i = 1; i < xrg.NumNodes; i++)
{
XrefGraphNode xrgn = xrg.GetXrefNode(i);
if (!xrgn.IsNested)
writeXmlElement(tr, writer, xrgn, xrg, gnc);
}
}
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
ed.WriteMessage("\nAutoCAD error: " + ex.Message + "\n" + ex.StackTrace);
}
catch (System.Exception ex)
{
ed.WriteMessage("\nSystem error: " + ex.Message + "\n" + ex.StackTrace);
}
finally
{
writer.Close();
}
}
}
private static void writeXmlElement(Transaction tr, XmlTextWriter writer, XrefGraphNode xrgn, XrefGraph xrg, GraphNodeCollection gnc)
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(xrgn.BlockTableRecordId, OpenMode.ForRead);
writer.WriteStartElement("xref");
writer.WriteAttributeString("path", btr.PathName);
writer.WriteAttributeString("status", getStatus(btr));
for (int i = 0; i < xrgn.NumOut; i++)
{
writeXmlElement(tr, writer, xrg.GetXrefNode(gnc.IndexOf(xrgn.Out(i))), xrg, gnc);
}
writer.WriteEndElement();
}
private static string getStatus(BlockTableRecord btr)
{
switch (btr.XrefStatus)
{
case XrefStatus.FileNotFound:
return "File not found";
case XrefStatus.Resolved:
return "Resolved";
case XrefStatus.Unloaded:
return "Unloaded";
case XrefStatus.Unreferenced:
return "Unreferenced";
default:
return "Unresolved";
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<host path="F:\DAO\Dessins\Theatre\Plan.dwg">
<xref path="F:\DAO\Dessins\Theatre\Rotonde.dwg" status="Resolved">
<xref path="F:\DAO\Dessins\Theatre\Mobilier.dwg" status="Resolved" />
</xref>
<xref path="F:\DAO\Dessins\Theatre\Theatre.DWG" status="Resolved">
<xref path="F:\DAO\Dessins\Theatre\Plateau.dwg" status="Resolved" />
<xref path="F:\DAO\Dessins\Theatre\Equipement.dwg" status="Unloaded">
<xref path="F:\DAO\Dessins\Theatre\Perches.dwg" status="Unreferenced" />
<xref path="F:\DAO\Dessins\Theatre\Passerelles.dwg" status="Resolved" />
</xref>
</xref>
<xref path="F:\DAO\Dessins\Theatre\Detail.dwg" status="Resolved">
<xref path="F:\DAO\Dessins\Theatre\Passerelles.dwg" status="Resolved" />
</xref>
</host>