Author Topic: Copy items from xref to current drawing, by window  (Read 3700 times)

0 Members and 1 Guest are viewing this topic.

T.Willey

  • Needs a day job
  • Posts: 5251
Copy items from xref to current drawing, by window
« on: April 12, 2011, 04:01:32 PM »
I have a proof of concept code that works pretty much, but don't really know if it can be coded to work in all circumstances.  So I'm asking more for ideas of how others envision this working.

I have gone two ways, and chosen to just clone the items in the current drawing for the selection process, instead of bringing them in from the xref's database.  This way it doesn't leave as much clutter in the drawing, but it doesn't work for dimensions ( maybe others entities also ), as it leaves a bunch of corrupted block definitions within the drawing after the code has been run.  It seems pretty fast, with just a single, non-nested, xref.

Don't judge the code too hard.  It isn't a finished project, and I'm not sure that it is going to go this way or not.  :-)

Thanks!

Code: [Select]
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;

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

using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace XrefSuite
{
/// <summary>
/// Description of CopyNestedWindow.
/// </summary>
public partial class CopyNestedWindow : Form
{
private const string tempLayName = "tempLayerForCopyXrefEntities";
public CopyNestedWindow()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();

//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
[CommandMethod( "testcnw", CommandFlags.Session )]
public void Main()
{
Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
Database Db = Doc.Database;
Editor Ed = Doc.Editor;
XrefGraph XrGph = Db.GetHostDwgXrefGraph( false );
if ( XrGph.NumNodes <= 1 ) return;
Dictionary< ObjectId, Handle > Dict = new Dictionary<ObjectId, Handle>();
List<ObjectId> XrList = new List<ObjectId>();
LayerTableRecord ltr;
BlockTableRecord btr = null;
ObjectIdCollection LayIdCol = new ObjectIdCollection();

using ( Doc.LockDocument() ) {
using ( Transaction Trans = Db.TransactionManager.StartTransaction() ) {
BlockTableRecord CurSpace = Trans.GetObject( Db.CurrentSpaceId, OpenMode.ForWrite ) as BlockTableRecord;
LayerTable LayTbl = Trans.GetObject( Db.LayerTableId, OpenMode.ForRead ) as LayerTable;
LinetypeTable LtTbl = Trans.GetObject( Db.LinetypeTableId, OpenMode.ForRead ) as LinetypeTable;
ObjectId tempLayId = XrUtilities.GetTableRecord( LayTbl, tempLayName );

if ( tempLayId.IsNull ) {
ltr = new LayerTableRecord();
ltr.Name = tempLayName;
if ( !LayTbl.IsWriteEnabled ) LayTbl.UpgradeOpen();
LayTbl.Add( ltr );
Trans.AddNewlyCreatedDBObject( ltr, true );
LayTbl.DowngradeOpen();
tempLayId = ltr.ObjectId;
}
for ( int i = 1; i < XrGph.NumNodes; i++ ) {
XrefGraphNode XrNode = XrGph.GetXrefNode( i );
btr = Trans.GetObject( XrNode.BlockTableRecordId, OpenMode.ForRead ) as BlockTableRecord;
ObjectIdCollection InsIdCol = btr.GetBlockReferenceIds( true, true );
if ( InsIdCol.Count == 0 ) continue;
ObjectIdCollection CopyIdCol = new ObjectIdCollection();
foreach ( ObjectId id in btr ) {
if ( id.IsErased ) continue;
Entity Ent = Trans.GetObject( id, OpenMode.ForRead ) as Entity;
if ( !Ent.Visible ) continue;
ltr = Trans.GetObject( Ent.LayerId, OpenMode.ForRead ) as LayerTableRecord;
if ( ltr.IsFrozen || ltr.IsOff ) continue;
CopyIdCol.Add( id );
}
foreach ( ObjectId id in InsIdCol ) {
BlockReference BlkRef = Trans.GetObject( id, OpenMode.ForRead ) as BlockReference;
if ( BlkRef == null ) continue;
if ( !BlkRef.Visible ) continue;
if ( BlkRef.OwnerId != Db.CurrentSpaceId ) continue;
XrList.Add( id );
foreach ( ObjectId tempId in CopyIdCol ) {
Entity Ent = Trans.GetObject( tempId, OpenMode.ForRead ) as Entity;
if ( Ent is Dimension ) continue;
object Obj = Ent.Clone();
Entity tempEnt = Obj as Entity;
if ( tempEnt == null ) continue;
ltr = Trans.GetObject( Ent.LayerId, OpenMode.ForRead ) as LayerTableRecord;
tempEnt.LayerId = tempLayId;
tempEnt.Color = Ent.EntityColor.ColorMethod == Autodesk.AutoCAD.Colors.ColorMethod.ByLayer ? ltr.Color : Ent.Color;
tempEnt.LinetypeId = Ent.Linetype == "ByLayer" ? ltr.LinetypeObjectId : Ent.LinetypeId;
tempEnt.TransformBy( BlkRef.BlockTransform );
CurSpace.AppendEntity( tempEnt );
Trans.AddNewlyCreatedDBObject( tempEnt, true );
Dict.Add( tempEnt.ObjectId, tempId.Handle );
if ( tempEnt is BlockReference ) {
BlockReference tempBlkRef = tempEnt as BlockReference;
foreach ( ObjectId attId in tempBlkRef.AttributeCollection ) {
Ent = Trans.GetObject( attId, OpenMode.ForWrite ) as Entity;
Ent.Color = tempEnt.Color;
Ent.LayerId = tempLayId;
Ent.Linetype = "Continuous";
Dict.Add( attId, attId.Handle );
}
}
}
if ( !BlkRef.IsWriteEnabled ) BlkRef.UpgradeOpen();
BlkRef.Visible = false;
BlkRef.DowngradeOpen();
}
}
Trans.TransactionManager.QueueForGraphicsFlush();
DocumentLock XrLock = null;
Document XrDoc;
Database XrDb = XrUtilities.GetXrefDatabase( btr.PathName, Db, out XrDoc );
if ( XrDoc != null ) XrLock = XrDoc.LockDocument();
ObjectIdCollection IdCol = new ObjectIdCollection();
PromptSelectionResult psr = Ed.GetSelection();
if ( psr.Status != PromptStatus.OK ) return;
foreach ( ObjectId id in psr.Value.GetObjectIds() ) {
if ( Dict.ContainsKey( id ) ) IdCol.Add( XrDb.GetObjectId( false, Dict[ id ], 0 ) );
}
foreach ( KeyValuePair<ObjectId, Handle> kvp in Dict ) {
DBObject dbo = Trans.GetObject( kvp.Key, OpenMode.ForWrite ) as DBObject;
dbo.Erase();
}
foreach ( ObjectId id in XrList ) {
Entity Ent = Trans.GetObject( id, OpenMode.ForWrite ) as Entity;
Ent.Visible = true;
}
LayIdCol = XrUtilities.UnlockEntityLayers( IdCol, XrDb );
Db.WblockCloneObjects( IdCol, Db.CurrentSpaceId, new IdMapping(), DuplicateRecordCloning.Ignore, false );
XrUtilities.LockLayers( LayIdCol, XrDb );
if ( XrLock == null ) XrDb.Dispose();
else XrLock.Dispose();
ltr = Trans.GetObject( LayTbl[ tempLayName ], OpenMode.ForWrite ) as LayerTableRecord;
ltr.Erase();
Trans.Commit();
}
}
}
}
}

Code: [Select]
public static ObjectIdCollection UnlockEntityLayers ( ObjectIdCollection objIdCol, Database db )
{
ObjectIdCollection LayIdCol = new ObjectIdCollection();
using ( Transaction Trans = db.TransactionManager.StartTransaction() )
{
foreach ( ObjectId id in objIdCol )
{
Entity Ent = Trans.GetObject( id, OpenMode.ForRead ) as Entity;
LayerTableRecord LayTblRec = Trans.GetObject( Ent.LayerId, OpenMode.ForRead ) as LayerTableRecord;
if ( LayTblRec.IsLocked )
{
LayTblRec.UpgradeOpen();
LayTblRec.IsLocked = false;
LayIdCol.Add( LayTblRec.ObjectId );
LayTblRec.DowngradeOpen();
}
}
}
return LayIdCol;
}
public static void LockLayers ( ObjectIdCollection layIdCol, Database db )
{
using ( Transaction Trans = db.TransactionManager.StartTransaction() )
{
foreach ( ObjectId id in layIdCol )
{
LayerTableRecord LayTblRec = Trans.GetObject( id, OpenMode.ForWrite ) as LayerTableRecord;
LayTblRec.IsLocked = true;
LayTblRec.DowngradeOpen();
}
}
}
Tim

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

Please think about donating if this post helped you.

Jeff H

  • Needs a day job
  • Posts: 6151
Re: Copy items from xref to current drawing, by window
« Reply #1 on: April 12, 2011, 05:27:18 PM »
Any reason for using Clone() instead of DeepClone()?

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Copy items from xref to current drawing, by window
« Reply #2 on: April 12, 2011, 05:29:20 PM »
Nope.  I saw clone used before, and didn't think about using something else.  I'll do some research on DeepClone, and see what I find.  Thanks Jeff.
Tim

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

Please think about donating if this post helped you.

Jeff H

  • Needs a day job
  • Posts: 6151
Re: Copy items from xref to current drawing, by window
« Reply #3 on: April 12, 2011, 05:31:33 PM »
Have not tested or tried but using DeepClone() might resolve the issues with Dimensions etc....


T.Willey

  • Needs a day job
  • Posts: 5251
Re: Copy items from xref to current drawing, by window
« Reply #4 on: April 12, 2011, 06:00:54 PM »
DeepClone sounded like a good thing, but it didn't work either.  It seemed to cause more problems also, which I think has to do with that I really only want a shallow clone, as I only want it to look good; doesn't have to be good.  That is why I copy the actually items with  WBlockClone later in the code.
Tim

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

Please think about donating if this post helped you.

chobo

  • Newt
  • Posts: 24
Re: Copy items from xref to current drawing, by window
« Reply #5 on: June 09, 2011, 12:35:20 AM »
Please, share your XrUtilities.GetXrefDatabase function

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Copy items from xref to current drawing, by window
« Reply #6 on: June 09, 2011, 10:07:03 AM »
Code: [Select]
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

public static Document GetDocumentFrom ( DocumentCollection docCol, string name )
{
foreach ( Document doc in docCol ) {
if ( string.Compare( name, doc.Name, true ) == 0 )
return doc;
}
return null;
}
public static Database GetXrefDatabase ( string xrPath, Database db, out Document doc )
{
doc = GetDocumentFrom( AcadApp.DocumentManager, xrPath );
if ( doc != null ) return doc.Database;

Database Db = new Database( false, true );
string FoundAtPath = HostApplicationServices.Current.FindFile( xrPath, db, FindFileHint.XRefDrawing );
if ( string.IsNullOrEmpty( FoundAtPath ) ) return null;
Db.ReadDwgFile( FoundAtPath, System.IO.FileShare.ReadWrite, true, null );
return Db;
}
Tim

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

Please think about donating if this post helped you.

chobo

  • Newt
  • Posts: 24
Re: Copy items from xref to current drawing, by window
« Reply #7 on: June 09, 2011, 10:50:50 AM »
T.Willey, Thank you for sharing ~  :-)