Author Topic: Xref Tools  (Read 11936 times)

0 Members and 1 Guest are viewing this topic.

Chuck Gabriel

  • Guest
Xref Tools
« on: July 09, 2008, 01:57:32 PM »
I thought somebody else might find this useful, plus I thought it might elicit some comments I can learn from.

Code: [Select]
using System;
using System.IO;
using System.Text;

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;

using ofdFlags = Autodesk.AutoCAD.Windows.OpenFileDialog.OpenFileDialogFlags;

[assembly: ExtensionApplication(typeof(cgabriel.XrefTools))]
[assembly: CommandClass(typeof(cgabriel.XrefTools))]

namespace cgabriel
{
    public class XrefTools : IExtensionApplication
    {
        #region ExtensionAppImplementation

        public void Initialize() { }
        public void Terminate() { }

        #endregion

        #region Helpers

        public delegate void ProcessSingleXref(BlockTableRecord btr);

        public delegate void ProcessMultipleXrefs(ObjectIdCollection xrefIds);

        public static void detachXref(BlockTableRecord btr)
        {
            Application.DocumentManager.MdiActiveDocument.Database.DetachXref(btr.ObjectId);
        }

        public static void openXref(BlockTableRecord btr)
        {
            string xrefPath = btr.PathName;
            if (xrefPath.Contains("..\\"))
            {
                string hostPath =
                    Application.DocumentManager.MdiActiveDocument.Database.Filename;
                Directory.SetCurrentDirectory(Path.GetDirectoryName(hostPath));
                xrefPath = Path.GetFullPath(xrefPath);
            }
            if (!File.Exists(xrefPath)) return;
            Document doc = Application.DocumentManager.Open(xrefPath, false);
            if (doc.IsReadOnly)
            {
                System.Windows.Forms.MessageBox.Show(
                    doc.Name + " opened in read-only mode.",
                    "OpenXrefs",
                    System.Windows.Forms.MessageBoxButtons.OK,
                    System.Windows.Forms.MessageBoxIcon.Warning);
            }
        }

        public static void bindXrefs(ObjectIdCollection xrefIds)
        {
            Application.DocumentManager.MdiActiveDocument.Database.BindXrefs(xrefIds, false);
        }

        public static void reloadXrefs(ObjectIdCollection xrefIds)
        {
            Application.DocumentManager.MdiActiveDocument.Database.ReloadXrefs(xrefIds);
        }

        public static void unloadXrefs(ObjectIdCollection xrefIds)
        {
            Application.DocumentManager.MdiActiveDocument.Database.UnloadXrefs(xrefIds);
        }

        public static void processXrefs(string promptMessage, ProcessSingleXref process)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            TypedValue[] filterList = { new TypedValue(0, "INSERT") };
            ed.WriteMessage(promptMessage);
            PromptSelectionResult result = ed.GetSelection(new SelectionFilter(filterList));
            if (result.Status != PromptStatus.OK) return;

            ObjectId[] ids = result.Value.GetObjectIds();
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ObjectIdCollection xrefIds = new ObjectIdCollection();
                foreach (ObjectId id in ids)
                {
                    BlockReference blockRef = (BlockReference)tr.GetObject(id, OpenMode.ForRead, false, true);
                    ObjectId bId = blockRef.BlockTableRecord;
                    if (!xrefIds.Contains(bId))
                    {
                        xrefIds.Add(bId);
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bId, OpenMode.ForRead);
                        if (btr.IsFromExternalReference)
                            process(btr);
                    }
                }
                tr.Commit();
            }
        }

        public static void processXrefs(string promptMessage, ProcessMultipleXrefs process)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            TypedValue[] filterList = { new TypedValue(0, "INSERT") };
            ed.WriteMessage(promptMessage);
            PromptSelectionResult result = ed.GetSelection(new SelectionFilter(filterList));
            if (result.Status != PromptStatus.OK) return;

            ObjectId[] ids = result.Value.GetObjectIds();
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ObjectIdCollection blockIds = new ObjectIdCollection();
                foreach (ObjectId id in ids)
                {
                    BlockReference blockRef = (BlockReference)tr.GetObject(id, OpenMode.ForRead, false, true);
                    blockIds.Add(blockRef.BlockTableRecord);
                }
                ObjectIdCollection xrefIds = filterXrefIds(blockIds);
                if (xrefIds.Count != 0)
                    process(xrefIds);
                tr.Commit();
            }
        }

        public static void attachXrefs(string[] fileNames)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            Array.Sort(fileNames);
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            double dimscale = db.Dimscale;
            foreach (string fileName in fileNames)
            {
                PromptPointOptions options = new PromptPointOptions("Pick insertion point for " + fileName + ": ");
                options.AllowNone = false;
                PromptPointResult pt = ed.GetPoint(options);
                if (pt.Status != PromptStatus.OK) continue;

                double xrefScale = getDwgScale(fileName);
                double scaleFactor = dimscale / xrefScale;
                using (Transaction tr = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction())
                {
                    ObjectId xrefId = db.AttachXref(fileName, Path.GetFileNameWithoutExtension(fileName));
                    BlockReference blockRef = new BlockReference(pt.Value, xrefId);
                    BlockTableRecord layoutBlock = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    blockRef.ScaleFactors = new Scale3d(scaleFactor, scaleFactor, scaleFactor);
                    blockRef.Layer = "0";
                    layoutBlock.AppendEntity(blockRef);
                    tr.AddNewlyCreatedDBObject(blockRef, true);
                    tr.Commit();
                }
            }
        }

        public static double getDwgScale(string fileName)
        {
            using (Database db = new Database(false, true))
            {
                db.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, false, string.Empty);
                return db.Dimscale;
            }
        }

        public static ObjectIdCollection filterXrefIds(ObjectIdCollection blockIds)
        {
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            ObjectIdCollection xrefIds = new ObjectIdCollection();
            foreach (ObjectId bId in blockIds)
            {
                if (!xrefIds.Contains(bId))
                {
                    BlockTableRecord btr = (BlockTableRecord)bId.GetObject(OpenMode.ForRead);
                    if (btr.IsFromExternalReference)
                        xrefIds.Add(bId);
                }
            }
            return xrefIds;
        }

        #endregion

        #region Commands

        [CommandMethod("XrefTools", "AttachXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefAttach()
        {
            string initFolder = Application.DocumentManager.MdiActiveDocument.Database.Filename.ToUpper();
            if (initFolder.Contains("PLOT"))
            {
                initFolder = initFolder.Replace("-PLOT.DWG", "");
                initFolder = initFolder.Replace("PLOT\\", "");
                if (!Directory.Exists(initFolder))
                    initFolder = Application.DocumentManager.MdiActiveDocument.Database.Filename;
            }

            ofdFlags flags = ofdFlags.DefaultIsFolder | ofdFlags.AllowMultiple;
            OpenFileDialog dlg = new OpenFileDialog("Select Drawings to Attach", initFolder, "dwg", "Select Xrefs", flags);
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                attachXrefs(dlg.GetFilenames());
        }

        [CommandMethod("XrefTools", "BindXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefBind()
        {
            processXrefs("\nSelect xrefs to bind: ", XrefTools.bindXrefs);
        }

        [CommandMethod("XrefTools", "DetachXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefDetach()
        {
            processXrefs("\nSelect xrefs to detach: ", XrefTools.detachXref);
        }

        [CommandMethod("XrefTools", "OpenXrefs", CommandFlags.Session)]
        public static void XrefOpen()
        {
            processXrefs("\nSelect xrefs to open: ", XrefTools.openXref);
        }

        [CommandMethod("XrefTools", "ReloadXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefReload()
        {
            processXrefs("\nSelect xrefs to reload: ", XrefTools.reloadXrefs);
        }

        [CommandMethod("XrefTools", "ReloadAllXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefReloadAll()
        {
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable blockTbl = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                ObjectIdCollection blockIds = new ObjectIdCollection();
                foreach (ObjectId bId in blockTbl)
                    blockIds.Add(bId);
                ObjectIdCollection xrefIds = filterXrefIds(blockIds);
                if (xrefIds.Count != 0)
                    db.ReloadXrefs(xrefIds);
                tr.Commit();
            }
        }

        [CommandMethod("XrefTools", "UnloadXrefs", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void XrefUnload()
        {
            processXrefs("\nSelect xrefs to unload: ", XrefTools.unloadXrefs);
        }

        #endregion

    }
}

FengK

  • Guest
Re: Xref Tools
« Reply #1 on: July 09, 2008, 02:50:48 PM »
Thanks Chuck. I got an error when trying to compile it:

The name 'FileOpenMode' does not exist in the current context (CS0103)

Do I need to reference other dll's besides acmgd.dll and acdbmgd.dll?


Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #2 on: July 09, 2008, 02:53:48 PM »
Thanks Chuck. I got an error when trying to compile it:

The name 'FileOpenMode' does not exist in the current context (CS0103)

Do I need to reference other dll's besides acmgd.dll and acdbmgd.dll?

Sorry.  I guess I should have mentioned that this was coded against the AutoCAD 2009 .NET API and that a reference to System.Windows.Forms is also required.

Thanks for taking a look at it, by the way.
« Last Edit: July 09, 2008, 02:57:37 PM by Chuck Gabriel »

FengK

  • Guest
Re: Xref Tools
« Reply #3 on: July 09, 2008, 04:13:40 PM »
Sorry.  I guess I should have mentioned that this was coded against the AutoCAD 2009 .NET API and that a reference to System.Windows.Forms is also required.

Do you mean the code won't work with earlier releases of AutoCAD? (I tested it with AutoCAD 2008). Btw, I did reference System.Windows.Forms.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #4 on: July 09, 2008, 10:47:41 PM »
Sorry.  I guess I should have mentioned that this was coded against the AutoCAD 2009 .NET API and that a reference to System.Windows.Forms is also required.

Do you mean the code won't work with earlier releases of AutoCAD? (I tested it with AutoCAD 2008). Btw, I did reference System.Windows.Forms.

It uses at least one feature that I know doesn't exist in AutoCAD 2007.

Code: [Select]
db.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, false, string.Empty);

That particular overload of ReadDwgFile doesn't exist in the 2007 API.  I'm not sure about 2008.
« Last Edit: July 10, 2008, 08:30:36 AM by Chuck Gabriel »

FengK

  • Guest
Re: Xref Tools
« Reply #5 on: July 10, 2008, 01:14:41 AM »
That particular overload of ReadDwgFile doesn't exist in the 2007 API.  I'm not sure about 2008.

My guess is it doesn't exist in AutoCAD 2008 either. I'll confirm it tomorrow. Thanks.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #6 on: July 10, 2008, 06:37:47 AM »
Here is what I've used in the past.  This overload is deprecated according to the 2009 docs.

Code: [Select]
db.ReadDwgFile(fileName, System.IO.FileShare.Read, false, string.Empty);

FengK

  • Guest
Re: Xref Tools
« Reply #7 on: July 10, 2008, 01:18:13 PM »
Here is what I've used in the past.  This overload is deprecated according to the 2009 docs.
Code: [Select]
db.ReadDwgFile(fileName, System.IO.FileShare.Read, false, string.Empty);

This works with AutoCAD 2008. And the original overloaded version does not seem to available in 2008. Attached is from acad_mgd.chm for version 2008.

The OpenXrefs command doesn't seem to do anything.

Thanks Chuck.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #8 on: July 10, 2008, 02:25:38 PM »
Attached is from acad_mgd.chm for version 2008.

I know there has been a lot of grumbling about 2009, but I will say this.  The documentation for the managed API is a lot better in 2009.

The OpenXrefs command doesn't seem to do anything.

Are your xrefs relative-pathed by any chance?  I ask because the following line might cause it to to seem like a no-op if I've gotten my path resolution code wrong:

Code: [Select]
if (!File.Exists(xrefPath)) return;

I can't remember whether I ever actually got around to testing this bit:

Code: [Select]
if (xrefPath.Contains("..\\"))
{
  string hostPath =
    Application.DocumentManager.MdiActiveDocument.Database.Filename;
  Directory.SetCurrentDirectory(Path.GetDirectoryName(hostPath));
  xrefPath = Path.GetFullPath(xrefPath);
}

Thanks again for looking at it Kelie.
« Last Edit: July 10, 2008, 02:35:06 PM by Chuck Gabriel »

FengK

  • Guest
Re: Xref Tools
« Reply #9 on: July 10, 2008, 09:33:29 PM »
Are your xrefs relative-pathed by any chance?  I ask because the following line might cause it to to seem like a no-op if I've gotten my path resolution code wrong:

Yes. I prefer using relative paths.

I can't remember whether I ever actually got around to testing this bit:

Code: [Select]
if (xrefPath.Contains("..\\"))

Change "..\\" to ".\\" fixes the problem.

Thanks again for looking at it Kelie.
My pleasure. You've done the hard work and I get to learn a little bit of C#.

Glenn R

  • Guest
Re: Xref Tools
« Reply #10 on: July 11, 2008, 04:36:18 AM »
Hey Chuck,

Nice stuff - especially the relative path resolution. Can you try your bind function on the drawings I posted in this thread and see what happens please?

Cheers,
Glenn.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #11 on: July 11, 2008, 07:12:54 AM »
Change "..\\" to ".\\" fixes the problem.

I should have thought of that.  Thanks for the tip.


Hey Chuck,

Nice stuff - especially the relative path resolution. Can you try your bind function on the drawings I posted in this thread and see what happens please?

Cheers,
Glenn.

I'll try it when I get home.

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #12 on: July 11, 2008, 10:36:12 AM »
I'll try it when I get home.

I just realized I'm not going to be able to do this.  The function I used isn't available in 2007 and my trial of 2009 has expired.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8706
  • AKA Daniel
Re: Xref Tools
« Reply #13 on: July 12, 2008, 02:26:07 PM »
You do very nice programming Chuck!
The only thing I might consider changing is, the function filterXrefIds()  assigns the variable ‘Database db’ that’s not used. 

Chuck Gabriel

  • Guest
Re: Xref Tools
« Reply #14 on: July 12, 2008, 02:44:47 PM »
You do very nice programming Chuck!

Thanks.

The only thing I might consider changing is, the function filterXrefIds()  assigns the variable ‘Database db’ that’s not used. 

I wonder where I was planning on going with that.  Thanks for pointing it out.