TheSwamp

Code Red => .NET => Topic started by: LE on December 19, 2006, 12:15:03 PM

Title: Something about Xref functions...
Post by: LE on December 19, 2006, 12:15:03 PM
I kept learning as I can all about this C# stuff, not much, but I am, at least trying.... he he

Here is a tryout to convert an attach xref to overlay - without luck of course, it is something I never tried on objectARX by the way... and also, there is no single sample anywhere (I think).

Code: [Select]
[CommandMethod("ATOVERLAY")]
public void attachTooverlay()
{
    Document doc = acadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    //PromptEntityOptions prOpt = new PromptEntityOptions("\nSelect Xref: ");
    //prOpt.SetRejectMessage("\nNot an Xref!");
    //prOpt.AddAllowedClass(typeof(BlockReference), true);
    //PromptEntityResult rs = ed.GetEntity(prOpt);
    PromptEntityResult res = ed.GetEntity("\nSelect xref: ");
    if (res.Status != PromptStatus.OK) return;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        BlockReference blkRef = tr.GetObject(res.ObjectId, OpenMode.ForWrite, false) as BlockReference;
        if (blkRef != null)
        {
            BlockTableRecord blkRec = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
            if (blkRec.IsFromOverlayReference == false)
            {
                //db.DetachXref(blkRec.ObjectId);
                //db.ResolveXrefs(true, true);

                string fileName, blockName;
                fileName = blkRec.PathName;
                blockName = blkRec.Name;
                ed.WriteMessage("\nPath: " + fileName);
                ed.WriteMessage("\nBlockname: " + blockName);
                ObjectId xrefId = db.OverlayXref(fileName, blockName);
                if (xrefId.IsValid == true)
                    ed.WriteMessage("\nIs a valid object id...");
                else
                    ed.WriteMessage("\nNo valid object id...");

                db.ResolveXrefs(true, true);
            }
        }
        tr.Commit();
    }
}

Since the OverlayXref() returns an ID.... what I should do with it?  or to make it work.... I tried first to detach the xref (it does that) but when I try to tun the overlay part... nothing.... nada.... niep.... nil

Thanks!
Title: Re: Something about Xref functions...
Post by: LE on December 19, 2006, 04:04:24 PM
Here is my try using ARX and is working, still is a function in progress - mostly the undefined block message requires to get fix.... Will kept trying with the C# code...

Code: [Select]
static void changeToOverlay (void)
{
ads_name ename;
ads_point pt;
AcDbObjectId xrefBlkId;
AcDbDatabase* pDb = NULL;
pDb = acdbHostApplicationServices()->workingDatabase();
if (acedEntSel(_T("\nSelect an Xref: "), ename, pt) != RTNORM) return;
if (acdbGetObjectId (xrefBlkId, ename) != Acad::eOk) return;
AcDbObjectPointer<AcDbBlockReference> pRef (xrefBlkId, AcDb::kForWrite);
if (pRef.openStatus() != Acad::eOk) return;
//acutPrintf(_T("\nBlockReference open..."));
AcDbBlockTableRecordPointer pBtr (pRef->blockTableRecord(), AcDb::kForWrite);
if (pBtr.openStatus() != Acad::eOk) return;
//acutPrintf(_T("\nBlockTableRecord open..."));

ACHAR *pFilename;
if (pBtr->pathName(pFilename) != Acad::eOk) return;
acutPrintf(_T("\nPath: %s"), pFilename);

ACHAR *pBlockName;
if (pBtr->getName (pBlockName) != Acad::eOk) return;
acutPrintf(_T("\nBlockname: %s"), pBlockName);

pBtr->close(); // no needed anymore

if (acedXrefDetach(pBlockName) != Acad::eOk) return;
acutPrintf(_T("\nDetaching block..."));

pRef->recordGraphicsModified();

if (acedXrefOverlay(pFilename, pBlockName) != Acad::eOk) return;
acutPrintf(_T("\nChanging to overlay..."));

pRef->recordGraphicsModified();
}
Title: Re: Something about Xref functions...
Post by: T.Willey on December 19, 2006, 04:49:51 PM
So the only way it to detach it, and reattach it as an overlay in both languages?  I was hoping that it would be some function that would just switch it.  I didn't see a way in C# when I looked, but was hoping you would find one Luis.  Thanks for keeping us posted.
Title: Re: Something about Xref functions...
Post by: LE on December 19, 2006, 05:26:21 PM
So the only way it to detach it, and reattach it as an overlay in both languages?  I was hoping that it would be some function that would just switch it.  I didn't see a way in C# when I looked, but was hoping you would find one Luis.  Thanks for keeping us posted.

That's how I was able to make it work, but just the ARX code... the C# nope...
Title: Re: Something about Xref functions...
Post by: Alexander Rivilis on December 21, 2006, 12:45:45 PM
P/Invoke? http://discussion.autodesk.com/thread.jspa?messageID=5206856
Title: Re: Something about Xref functions...
Post by: LE on December 21, 2006, 01:27:27 PM
P/Invoke? http://discussion.autodesk.com/thread.jspa?messageID=5206856

Thank you Alexander;

I saw the code, thanks.

If I use my attachTooverlay() function, it is returning and ID of a new TableRecord no?.... what are we supposed to do with that?
Now, if I first detach the xref, and then tried to run the overlay method, it does not work.... why?
Title: Re: Something about Xref functions...
Post by: LE on December 21, 2006, 01:42:02 PM
This is the latest code I have for that function....

Code: [Select]
        [CommandMethod("OVERLAY")]
        public void attachTooverlay()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            PromptEntityResult res = ed.GetEntity("\nSelect xref: ");
            if (res.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ObjectId objId = res.ObjectId;
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                DBObject dbObj = tr.GetObject(objId, OpenMode.ForRead);
                BlockReference blkRef = dbObj as BlockReference;
                if (blkRef != null)
                {
                    BlockTableRecord blkDef = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
                    if (blkDef.IsFromOverlayReference == false)
                    {
                        string fileName, blockName;
                        fileName = blkDef.PathName;
                        blockName = blkDef.Name;
                        ed.WriteMessage("\nPath: " + fileName);
                        ed.WriteMessage("\nBlockname: " + blockName);
                        doc.LockDocument();
                        ObjectId xrefId = db.OverlayXref(fileName, blockName);
                    }
                }

                tr.Commit();
            }
        }
Title: Re: Something about Xref functions...
Post by: LE on December 21, 2006, 01:48:29 PM
And I tried also, to implement it with ObjectARX.... but was not possible :-(

OverlayXref() is a wrap of acdbOverlayXref()

Note: the below code, does not work....
Code: [Select]
static void changeToOverlay1 (void)
{
Acad::ErrorStatus es = Acad::eOk;
AcDbDatabase* pDb = NULL;
pDb = acdbHostApplicationServices()->workingDatabase();
if (!pDb) return;
ads_name ename;
ads_point pt;
if (acedEntSel(_T("\nSelect Xref: "), ename, pt) != RTNORM) return;
AcDbObjectId id = AcDbObjectId::kNull;
acdbGetObjectId(id, ename);
if (id == AcDbObjectId::kNull) return;
AcDbBlockReference *pRef = NULL;
if (acdbOpenAcDbObject((AcDbObject *&)pRef, id, AcDb::kForWrite) != Acad::eOk) return;
if (!pRef->isKindOf(AcDbBlockReference::desc()))
{
pRef->close();
return;
}
AcDbBlockTableRecord *pRec = NULL;
if (acdbOpenAcDbObject((AcDbObject*&)pRec, pRef->blockTableRecord(), AcDb::kForWrite) == Acad::eOk)
{
AcDbObjectId xrefBlkId;
ACHAR *pFilename, *pBlockName = _T("XREF1"); // falta definir el blocktable de pBlockname y hacer lock el dibujo

AcDbObjectId curSpaceId = pDb->currentSpaceId(); //acdbCurDwg()->currentSpaceId();


AcDbBlockTable *pBlockTable;
pDb->getSymbolTable(pBlockTable, AcDb::kForWrite);

AcDbObjectId pOutputId;
AcDbBlockTableRecord *pBlkRec = NULL;
if (acdbOpenObject(pBlkRec,curSpaceId,AcDb::kForWrite) == Acad::eOk)
{
AcDbBlockReference *pBlkRef = new AcDbBlockReference;

pBlkRec->appendAcDbEntity(pOutputId, pBlkRef);

pBlkRec->setName(_T("XREF1"));
pBlkRec->close();
pBlkRef->close();
}

if (pRec->pathName(pFilename) == Acad::eOk)
{
if (acdbOverlayXref(pDb, pFilename, pBlockName, xrefBlkId) == Acad::eOk)
acutPrintf(_T("\nDone..."));
}
pRec->close();
}
pRef->close();

//acdbOverlayXref()
//acdbAttachXref()
}
Title: Re: Something about Xref functions...
Post by: LE on December 21, 2006, 08:38:27 PM
Here is the function working now... it does not update the nice icon on the palette, but... :)

Code: [Select]
        [CommandMethod("OVERLAY")]
        public void attachTooverlay()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            PromptEntityResult res = ed.GetEntity("\nSelect xref: ");
            if (res.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ObjectId objId = res.ObjectId;
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                DBObject dbObj = tr.GetObject(objId, OpenMode.ForRead);
                BlockReference blkRef = dbObj as BlockReference;
                if (blkRef != null)
                {
                    BlockTableRecord blkDef = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
                    if (blkDef.IsFromOverlayReference == false)
                    {
                        db.DetachXref(blkDef.ObjectId);

                        string fileName, blockName;
                        fileName = blkDef.PathName;
                        blockName = blkDef.Name;
                        ed.WriteMessage("\nPath: " + fileName);
                        ed.WriteMessage("\nBlockname: " + blockName);
                        doc.LockDocument();
                        ObjectId xrefId = db.OverlayXref(fileName, blockName);

                        BlockTableRecord blkRec = (BlockTableRecord)tr.GetObject(xrefId, OpenMode.ForRead);
                        BlockTableRecord BTR = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        BlockReference newBlkRef;
                        newBlkRef = new BlockReference(Point3d.Origin, blkRec.ObjectId);
                        BTR.AppendEntity(newBlkRef);
                        tr.AddNewlyCreatedDBObject(newBlkRef, true);

                        db.ResolveXrefs(true, true);

                    }
                }
                tr.Commit();
            }
        }

HTH
Title: Re: Something about Xref functions...
Post by: Kerry on December 22, 2006, 01:36:03 AM
Hi Luis,
I'm running past and can't really stop ... :-)

Are you sure you are using the
doc.LockDocument();
correctly ...

I thought it was only needed for commands in the application context
... and required the return value saved so that it could be disposed later.

ie

DocumentLock docLock = doc.LockDocument();
// bla, bla
docLock.Dispose();


... but I may be misunderstanding ....

/// regards, kwb
Title: Re: Something about Xref functions...
Post by: Kerry on December 22, 2006, 05:45:30 AM
... or if needed, perhaps wrap the DocumentLock in a using statement block .... ?


wish I had time to play. !!
Title: Re: Something about Xref functions...
Post by: LE on December 22, 2006, 11:18:21 AM
... or if needed, perhaps wrap the DocumentLock in a using statement block .... ?


wish I had time to play. !!

Hi Kerry;

Actually is not needed, because of the using  block... I forgot to remove it, it was part of previous tryouts, as you know in the objectarx acdbOverlayXref() function, they recommend to provide the locking, but as I understood in C# we can take advantage of using, as it is here, but wait for the masters to comfirm it.

I know how you feel.... :)


Thanks!
Title: Re: Something about Xref functions...
Post by: cadpro on November 02, 2008, 08:01:03 AM
Is there a way to get the xrefs in the drawing that are inserted into the layout, and then chage them to overlay?
Title: Re: Something about Xref functions...
Post by: sinc on November 02, 2008, 10:10:27 AM
The document lock should be unnecessary, since you are in a command method.

If you were to use it, though, you should remember the lock, and dispose of it when you no longer need the lock, as in Kerry's post.
Title: Re: Something about Xref functions...
Post by: cadpro on November 02, 2008, 11:12:53 PM
I would like to know whether I could loop through the layout entities and get the xrefs inserted in the layout only, rather than selecting.

Thanks
Title: Re: Something about Xref functions...
Post by: Alexander Rivilis on November 03, 2008, 01:07:04 AM
Each Layout has property Autodesk.AutoCAD.DatabaseServices.Layout.BlockTableRecordId
Open BlockTableRecord with this Id and iterate it.
Title: Re: Something about Xref functions...
Post by: cadpro on November 04, 2008, 02:04:09 AM
The code given in this thread does not change the attached xrefs to overlayed if it is inserted in multiple layouts. Any solution to this issue?
Title: Re: Something about Xref functions...
Post by: Bryco on November 12, 2008, 12:34:11 AM
Luis I've added a bit to your code and this seems to work.
The array is the only way I could figure out how to do it, as I didn't want to do the whole mum, dad, orphan thing (Get,set).
I would cringe at using object in vba but I don't know if that is costly in C#.
Xclip is something I'll have to learn next.
If you have a better way please let me know.

Code: [Select]
        [CommandMethod("OVERLAY")]
        public void attachTooverlay()
        {
            Document doc =acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            PromptEntityOptions peo = new PromptEntityOptions("\nSelect xref: ");
            peo.SetRejectMessage("Must be an x-ref");
            peo.AddAllowedClass(typeof(BlockReference), true);

            PromptEntityResult res = ed.GetEntity(peo);
            if (res.Status != PromptStatus.OK) return;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {               
                BlockReference br = tr.GetObject
                    (res.ObjectId, OpenMode.ForWrite) as BlockReference;
                BlockTableRecord btr = tr.GetObject
                    (br.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
                if (!btr.IsFromExternalReference)
                {
                    MessageBox.Show("not an x-ref");
                    return;
                }
                if (btr.IsFromOverlayReference) return;

                XrefStatus xstatus=btr.XrefStatus;
                BlockScaling bs=btr.BlockScaling;
                bool bLoaded=btr.IsUnloaded;   
                UnitsValue uv = btr.Units;
                string fileName =btr.PathName;
                string blockName = btr.Name;

                ObjectIdCollection ids = btr.GetBlockReferenceIds(true, true);
                int ct = ids.Count;
                object[][] ob =new object[ct][];

                for (int i = 0; i < ct; i++)
                {
                    BlockReference xref = tr.GetObject
                        (ids[i], OpenMode.ForRead) as BlockReference;
                    BlockTableRecord xtr = tr.GetObject(
                        xref.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
                    ob[i] = new object[7];
                    ob[i][0] = xref.Position;
                    ob[i][ 1] = xref.Rotation;
                    ob[i][ 2] = xref.Layer;
                    ob[i][ 3] = xref.ColorIndex;
                    ob[i][ 4] = xref.ScaleFactors;
                    ob[i][5] = xref.OwnerId;
                    ob[i][6] = xref.Normal;
                   //db.XclipFrame
   
                    xref.UpgradeOpen();
                    xref.Erase();

                }
                db.DetachXref(btr.Id);


                for (int i = 0; i < ct; i++)
                {
                    using(Transaction tr2=db.TransactionManager.StartTransaction())
                    {
                        ObjectId xrefId = db.OverlayXref(fileName, blockName);
                        btr = (BlockTableRecord)tr2.GetObject(xrefId, OpenMode.ForWrite);
                        BlockTableRecord space = (BlockTableRecord)tr2.GetObject(
                            (ObjectId)ob[i][5], OpenMode.ForWrite);
                        br = new BlockReference((Point3d)ob[i][0], btr.ObjectId);
                        br.Rotation = (double)ob[i][1];
                        br.Layer = (string)ob[i][2];   
                        br.ColorIndex = (int)ob[i][3];
                        br.ScaleFactors=(Scale3d) ob[i][4];
                        br.Normal = (Vector3d)ob[i][6];
                        space.AppendEntity(br);
                        tr.AddNewlyCreatedDBObject(br, true);
                        db.ResolveXrefs(true, true);
                        tr2.Commit();
                    }   
                }


                tr.Commit();
            }
        }//end attachTooverlay
Title: Re: Something about Xref functions...
Post by: T.Willey on November 12, 2008, 01:05:22 AM
Can't think of another way to do it right now, but with Lisp the xclip information is store within the extension dictionary, so I would figure its the same with .Net, but haven't looked into it yet.  Here is the Lisp code to get the xclip information.]

Code: [Select]
(defun GetSpatialFilter (ename / Data Dict tempDict)
    ; Get the xclip boundry
   
    (if
        (and
            (setq Data (entget ename))
            (setq Dict (cdr (assoc 360 Data)))
            (setq tempDict (dictsearch Dict "ACAD_FILTER"))
            (setq tempDict (dictsearch (cdr (assoc -1 tempDict)) "SPATIAL"))
        )
        (cons '(0 . "SPATIAL_FILTER") (member (assoc 100 tempDict) tempDict))
    )
)
Title: Re: Something about Xref functions...
Post by: Bryco on November 15, 2008, 03:25:35 PM
Well this took a while, I was messing with xrecords when I shouldn't have bothered. Tim I don't know lisp but it looks like your lisp is looking for a dictionary within a dictionary (rather than an xrecord within a dictionary). I still can't figure out how to copyfrom or make the new dictionary=the old dictionary (this doesn't work maybe because the old dictionary is being deleted), there should be a more direct way than below.


Code: [Select]
        [CommandMethod("OVERLAY")]
        public void attachTooverlay()
        {
            Document doc =acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            PromptEntityOptions peo = new PromptEntityOptions("\nSelect xref: ");
            peo.SetRejectMessage("Must be an x-ref");
            peo.AddAllowedClass(typeof(BlockReference), true);

            PromptEntityResult res = ed.GetEntity(peo);
            if (res.Status != PromptStatus.OK) return;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {               
                BlockReference br = tr.GetObject
                    (res.ObjectId, OpenMode.ForWrite) as BlockReference;
                BlockTableRecord btr = tr.GetObject
                    (br.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
                if (!btr.IsFromExternalReference)
                {
                    MessageBox.Show("not an x-ref");
                    return;
                }
                if (btr.IsFromOverlayReference) return;

                XrefStatus xstatus=btr.XrefStatus;
                BlockScaling bs=btr.BlockScaling;
                bool bLoaded=btr.IsUnloaded;   
                UnitsValue uv = btr.Units;
                string fileName =btr.PathName;
                string blockName = btr.Name;

                ObjectIdCollection ids = btr.GetBlockReferenceIds(true, true);
                int ct = ids.Count;
                object[][] ob =new object[ct][];

                for (int i = 0; i < ct; i++)
                {
                    BlockReference xref = tr.GetObject
                        (ids[i], OpenMode.ForRead) as BlockReference;
                    BlockTableRecord xtr = tr.GetObject(
                        xref.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
                    ob[i] = new object[8];
                    ob[i][0] = xref.Position;
                    ob[i][ 1] = xref.Rotation;
                    ob[i][ 2] = xref.Layer;
                    ob[i][ 3] = xref.ColorIndex;
                    ob[i][ 4] = xref.ScaleFactors;
                    ob[i][5] = xref.OwnerId;
                    ob[i][6] = xref.Normal;
                    ob[i][7] = xref.ExtensionDictionary;

                    ObjectId xclipId = xref.ExtensionDictionary;
                    xref.UpgradeOpen();
                    xref.Erase();
                    xref.DowngradeOpen();
                }
                db.DetachXref(btr.Id);

                ObjectId xrefId = db.OverlayXref(fileName, blockName);
                for (int i = 0; i < ct; i++)
                {

                    btr = (BlockTableRecord)tr.GetObject(xrefId, OpenMode.ForWrite);
                    BlockTableRecord space = (BlockTableRecord)tr.GetObject(
                        (ObjectId)ob[i][5], OpenMode.ForWrite);
                    br = new BlockReference((Point3d)ob[i][0], btr.ObjectId);
                    br.Rotation = (double)ob[i][1];
                    br.Layer = (string)ob[i][2];   
                    br.ColorIndex = (int)ob[i][3];
                    br.ScaleFactors=(Scale3d) ob[i][4];
                    br.Normal = (Vector3d)ob[i][6];
                    ObjectId xclipId =(ObjectId) ob[i][7];
                    space.AppendEntity(br);
                    tr.AddNewlyCreatedDBObject(br, true);
                    if (! xclipId.IsNull)
                    {
                        br.CreateExtensionDictionary();
                        DBDictionary XclipDic = tr.GetObject
                            (br.ExtensionDictionary,OpenMode.ForWrite) as DBDictionary;

                        DBDictionary dic = tr.GetObject(xclipId, OpenMode.ForRead) as DBDictionary;       
                        DBDictionary FilterDic = tr.GetObject
                            (dic.GetAt("ACAD_FILTER"), OpenMode.ForRead) as DBDictionary;                       
                        DBDictionary nd = new DBDictionary();
                        foreach (DictionaryEntry de in FilterDic)
                        {
                            nd.SetAt((string)de.Key, tr.GetObject((ObjectId) de.Value,OpenMode.ForWrite ) as DBObject);
                        }

                        XclipDic.SetAt("ACAD_FILTER", nd);
                        tr.AddNewlyCreatedDBObject(nd, true);

                    }
                }

                db.ResolveXrefs(true, true);
                tr.Commit();
             
            }
        }//end attachTooverlay
Title: Re: Something about Xref functions...
Post by: Bryco on November 15, 2008, 03:27:52 PM
Cadpro did this work for you?
Title: Re: Something about Xref functions...
Post by: cadpro on November 16, 2008, 05:20:16 AM
Cadpro did this work for you?

This works fine. But I need to overlay all attached xrefs inserted in layouts, without picking each xref. How do I go about it?

Thanks
Title: Re: Something about Xref functions...
Post by: Spike Wilbury on November 16, 2008, 10:19:32 AM
Cadpro did this work for you?

This works fine. But I need to overlay all attached xrefs inserted in layouts, without picking each xref. How do I go about it?

Thanks

Have you done any code?
Title: Re: Something about Xref functions...
Post by: Spike Wilbury on November 16, 2008, 10:46:25 AM
Luis I've added a bit to your code and this seems to work.
The array is the only way I could figure out how to do it, as I didn't want to do the whole mum, dad, orphan thing (Get,set).
I would cringe at using object in vba but I don't know if that is costly in C#.
Xclip is something I'll have to learn next.
If you have a better way please let me know.


Hi Bryco,

I just noticed your message.... I have been doing all of my code in C++/ARX - no time to play with C#, as soon I can, I will try to participate with some coding... if possible.

Cheers!
Title: Re: Something about Xref functions...
Post by: Bryco on November 16, 2008, 07:46:44 PM
Hi Luis, no problem, I think I've taken that code far enough, of course I didn't give it any rigorous testing so it may be crap.
Also didn't try nested clips.
Title: Re: Something about Xref functions...
Post by: T.Willey on November 17, 2008, 11:16:28 AM
I'll see what I can do when I have some time.  I haven't really copied anything dictionary with C# yet, so it would be a good learning exercise.
Title: Re: Something about Xref functions...
Post by: Bryco on November 17, 2008, 02:38:39 PM
Looking forward to seeing your findings Tim
Title: Re: Something about Xref functions...
Post by: T.Willey on November 17, 2008, 07:47:04 PM
This is all I had time for today.  Not sure if I will be able to get to it tomorrow, and I didn't test this, but it should show you want the process is that I'm thinking of going.  Hope it helps.  The idea was to use a test drawing with only one xref in it, and is inserted as many times as you want, and has an xclip associated with it ( which is the SpatialFilter object ).

Code: [Select]
public void TestXrefXClip {

DBDictionary tempDict;
ObjectId tempId;

Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
Database Db = Doc.Database;
Editor Ed = Doc.Editor;
using ( Transaction Trans = Db.TransactionManager.StartTransaction() ) {
XrefGraph XrGph = Db.GetHostDwgXrefGraph(false);
XrefGraphNode XrNode = XrGph.GetXrefNode( 1 ) as XrefGraphNode;
BlockTableRecord BlkTblRec = Trans.GetObject( XrNode.BlockTableRecordId, OpenMode.ForRead ) as BlockTableRecord;
foreach ( ObjectId objId in BlkTblRec.GetBlockReferenceIds( true, true ) ) {
BlockReference BlkRef = Trans.GetObject( objId, OpenMode.ForRead ) as BlockReference;
tempDict = Trans.GetObject( BlkRef.ExtensionDictionary, OpenMode.ForRead ) as DBDictionary;
tempId = tempDict.GetAt( "ACAD_FILTER" ) as ObjectId;
if ( tempId == ObjectId.Null )
return;
tempDict = Trans.GetObject( tempId, OpenMode.ForRead ) as DBDictionary;
tempId = tempDict.GetAt( "SPATIAL" ) as ObjectId;
if ( tempId == ObjectId.Null )
return;
SpatialFilter SpFtr = Trans.GetObject( tempId, OpenMode.ForRead ) as SpatialFilter;
}
}
}
Title: Re: Something about Xref functions...
Post by: Bryco on November 18, 2008, 10:58:19 PM
Tim I had got that far ( the thing works) but I couldn't make the new dic=the old dic and get it to take.
Title: Re: Something about Xref functions...
Post by: cadpro on November 19, 2008, 01:37:58 AM
This is all I had time for today.  Not sure if I will be able to get to it tomorrow, and I didn't test this, but it should show you want the process is that I'm thinking of going.  Hope it helps.  The idea was to use a test drawing with only one xref in it, and is inserted as many times as you want, and has an xclip associated with it ( which is the SpatialFilter object ).

Code: [Select]
public void TestXrefXClip {

DBDictionary tempDict;
ObjectId tempId;

Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
Database Db = Doc.Database;
Editor Ed = Doc.Editor;
using ( Transaction Trans = Db.TransactionManager.StartTransaction() ) {
XrefGraph XrGph = Db.GetHostDwgXrefGraph(false);
XrefGraphNode XrNode = XrGph.GetXrefNode( 1 ) as XrefGraphNode;
BlockTableRecord BlkTblRec = Trans.GetObject( XrNode.BlockTableRecordId, OpenMode.ForRead ) as BlockTableRecord;
foreach ( ObjectId objId in BlkTblRec.GetBlockReferenceIds( true, true ) ) {
BlockReference BlkRef = Trans.GetObject( objId, OpenMode.ForRead ) as BlockReference;
tempDict = Trans.GetObject( BlkRef.ExtensionDictionary, OpenMode.ForRead ) as DBDictionary;
tempId = tempDict.GetAt( "ACAD_FILTER" ) as ObjectId;
if ( tempId == ObjectId.Null )
return;
tempDict = Trans.GetObject( tempId, OpenMode.ForRead ) as DBDictionary;
tempId = tempDict.GetAt( "SPATIAL" ) as ObjectId;
if ( tempId == ObjectId.Null )
return;
SpatialFilter SpFtr = Trans.GetObject( tempId, OpenMode.ForRead ) as SpatialFilter;
}
}
}

I did not understand a word.  :cry:

My code to loop through the xrefs.

     
Code: [Select]
BlockTable bt=tr.GetObject(db.BlockTableId,OpenMode.ForRead,false) as BlockTable;

                foreach (ObjectId btrId in bt)
                {
                    BlockTableRecord btr=tr.GetObject(btrId,OpenMode.ForRead,false) as BlockTableRecord;

                    ObjectIdCollection blkRefIds = btr.GetBlockReferenceIds(true, false);

                    foreach (ObjectId blkRefId in blkRefIds)
                    {
                        BlockReference blkRef = tr.GetObject(blkRefId, OpenMode.ForRead, false) as BlockReference;
                        MessageBox.Show(blkRef.Name.ToString());
                    }
                }

But how do I filter the xrefs inserted in layouts?

Thanks
Title: Re: Something about Xref functions...
Post by: Bryco on November 19, 2008, 09:41:37 AM
http://www.theswamp.org/index.php?topic=14465.msg174209#msg174209
Title: Re: Something about Xref functions...
Post by: T.Willey on November 19, 2008, 10:58:45 AM
Tim I had got that far ( the thing works) but I couldn't make the new dic=the old dic and get it to take.
I don't know if I will have time to play today, but I would think that you would have to clone the first item that the new entity doesn't have; mean if there is not extension dictionary, then clone that, but if that is there and the acad filters dictionary isn't there, then clone that.  If I have time to play, which would be cool, I'll see what I can do.
Title: Re: Something about Xref functions...
Post by: cadpro on November 20, 2008, 12:01:46 AM
http://www.theswamp.org/index.php?topic=14465.msg174209#msg174209

I know how to loop through the layouts. But how do I get to the blocks in the layouts? And I think the code that I posted in the previous post is fair enough to loop through the xrefs in the drawing. Of these, is there a way to find out if the xref in inserted in model or layout?
Title: Re: Something about Xref functions...
Post by: It's Alive! on November 20, 2008, 01:39:10 AM
http://www.theswamp.org/index.php?topic=14465.msg174209#msg174209

I know how to loop through the layouts. But how do I get to the blocks in the layouts? And I think the code that I posted in the previous post is fair enough to loop through the xrefs in the drawing. Of these, is there a way to find out if the xref in inserted in model or layout?

Alexander Rivilis gave you the answer here http://www.theswamp.org/index.php?topic=14068.msg309109#msg309109


Title: Re: Something about Xref functions...
Post by: Bryco on November 20, 2008, 02:56:04 AM
And another way is to use the blockid
BlockReference br = tr.GetObject
                    (TheBlockreference.ObjectId, OpenMode.ForWrite) as BlockReference;
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                if(br.BlockId==bt[BlockTableRecord.ModelSpace])
                    msg="modelspace";
                else
                    msg="paperspace";
                    MessageBox.Show(msg);
Title: Re: Something about Xref functions...
Post by: It's Alive! on November 20, 2008, 03:45:01 AM
Code: [Select]
namespace ExecMethod
{
  public class Commands
  {
    [CommandMethod("doit")]
    public static void doit()
    {
      AcEd.Editor editor = AcAp.Application.DocumentManager.MdiActiveDocument.Editor;
      try
      {
        AcDb.Database database = HostApplicationServices.WorkingDatabase;
        AcDb.TransactionManager transactionManager = database.TransactionManager;
        using (AcDb.Transaction transaction = transactionManager.StartTransaction())
        {

          DBDictionary LayoutDictionary = transaction.GetObject
            (database.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;

          foreach (AcDb.DBDictionaryEntry entry in LayoutDictionary)
          {
            if (!entry.Key.Equals("Model"))
            {

              AcDb.Layout layout = transaction.GetObject
                (entry.Value, OpenMode.ForRead) as AcDb.Layout;

              AcDb.BlockTableRecord blockTableRecord = transaction.GetObject
                (layout.BlockTableRecordId, OpenMode.ForRead) as AcDb.BlockTableRecord;

              foreach (AcDb.ObjectId objectId in blockTableRecord)
              {
                AcDb.BlockReference blockReference = transaction.GetObject
                              (objectId, OpenMode.ForRead) as AcDb.BlockReference;

                if (blockReference != null)
                {
                  editor.WriteMessage("\nBlockReference found {0} in layout {1}", 
                                                  blockReference.ObjectId, entry.Key);
                }
              }
            }
          }
        }
      }
      catch (System.Exception ex)
      {
       editor.WriteMessage("\n" + ex.Message);
      }
    }
  }
}
Title: Re: Something about Xref functions...
Post by: T.Willey on November 20, 2008, 01:54:27 PM
Tim I had got that far ( the thing works) but I couldn't make the new dic=the old dic and get it to take.
I don't know if I will have time to play today, but I would think that you would have to clone the first item that the new entity doesn't have; mean if there is not extension dictionary, then clone that, but if that is there and the acad filters dictionary isn't there, then clone that.  If I have time to play, which would be cool, I'll see what I can do.

This is what I came up with.  It reports that is worked, the message box shows object id numbers for the new dictionary and spatial object, but it won't update the xref with the xclip.  I don't think I will have anymore time today to play, but this is what I got so far.  Two new xrefs in a drawing.  Xclip'ed one, then run the command.

Code: [Select]
[CommandMethod( "TestCopyXClip" )]
public void TestCopyXClip() {
PromptEntityResult per;
ObjectId tempId;

Document Doc = acadApp.DocumentManager.MdiActiveDocument;
Database Db = Doc.Database;
Editor Ed = Doc.Editor;
using ( Transaction Trans = Db.TransactionManager.StartTransaction() ) {
per = Ed.GetEntity( "Select xref to copy xclip to: " );
Entity ToEnt = Trans.GetObject( per.ObjectId, OpenMode.ForWrite ) as Entity;

per = Ed.GetEntity( "Select xref to copy xclip from: " );
Entity FromEnt = Trans.GetObject( per.ObjectId, OpenMode.ForRead ) as Entity;

DBDictionary xDictFrom = Trans.GetObject( FromEnt.ExtensionDictionary, OpenMode.ForRead ) as DBDictionary;
tempId = xDictFrom.GetAt( "ACAD_FILTER" );
DBDictionary FltDict = Trans.GetObject( tempId, OpenMode.ForRead ) as DBDictionary;

ToEnt.CreateExtensionDictionary();
DBDictionary xDictTo = Trans.GetObject( ToEnt.ExtensionDictionary, OpenMode.ForWrite ) as DBDictionary;
IdMapping iMap = new IdMapping();
DBDictionary nFltDict = FltDict.DeepClone( xDictTo, iMap, true ) as DBDictionary;
xDictTo.SetAt( "ACAD_FILTER", nFltDict );
try {
tempId = xDictTo.GetAt( "ACAD_FILTER" );
MessageBox.Show( tempId.ToString() );
tempId = nFltDict.GetAt( "SPATIAL" );
MessageBox.Show( tempId.ToString() );
}
catch ( System.Exception e ) { MessageBox.Show( e.Message + Environment.NewLine + e.StackTrace ); }
Trans.Commit();
}
}
Title: Re: Something about Xref functions...
Post by: T.Willey on November 20, 2008, 01:59:42 PM
If you want to see what space the xref is inserted in, then just step through all the ObjectId's in the ObjectIdCollection returned by GetBlockReferenceIds method of the BlockTableRecord associated with the xref.  You can get the BlockTableRecord of the OwnerId of the BlockReference, and then see if it's a layout, and if so which layout it is in.

So of my code ( I would do it differently now, but don't have time right now ).  btr = BlockTableRecord of the Xref.

Code: [Select]
ObjectIdCollection ObjIdCol = (ObjectIdCollection)btr.GetBlockReferenceIds(true, true);
for (int j = 0; j < ObjIdCol.Count; ++j) {
    ObjectId ObjId = ObjIdCol[j];
    BlockReference BlkRef = (BlockReference)Trans.GetObject(ObjId, OpenMode.ForRead);
    BlockTableRecord tempbtr = (BlockTableRecord)Trans.GetObject(BlkRef.OwnerId, OpenMode.ForRead);
    if (tempbtr.IsLayout)
        Layout templo = (Layout)Trans.GetObject(tempbtr.LayoutId, OpenMode.ForRead);
}

Title: Re: Something about Xref functions...
Post by: Bryco on November 20, 2008, 06:20:58 PM
Tim does  db.DeepCloneObjects do any better?
I'll look tonight. When I made the new dic=olddic it also reported everything is ok.
Title: Re: Something about Xref functions...
Post by: T.Willey on November 20, 2008, 06:26:25 PM
Tim does  db.DeepCloneObjects do any better?
Not with my testing Bryco.  I'm still trying some stuff, but nothing good is happening.

I'll look tonight. When I made the new dic=olddic it also reported everything is ok.
Sounds good.  Hope you have better luck than I am.
Title: Re: Something about Xref functions...
Post by: T.Willey on November 20, 2008, 07:03:46 PM
I have put in a request for help with ADN.  Lets see how helpful they are this time.  *Not getting my hopes up too high.*
Title: Re: Something about Xref functions...
Post by: kdub on November 20, 2008, 07:33:51 PM
Tim,
You could also send an email to Kean Walmsley .. he may follow up the ADN request ..
Title: Re: Something about Xref functions...
Post by: T.Willey on November 20, 2008, 07:41:34 PM
Tim,
You could also send an email to Kean Walmsley .. he may follow up the ADN request ..
Good idea Kerry.  I'll see if they send anything out tomorrow.
Title: Re: Something about Xref functions...
Post by: Bryco on November 20, 2008, 11:59:54 PM
Well Tim DeepClone seems to be the GO.
Both a regen and a AddNewlyCreatedDBObject are required to make it work.
SetAt must add it to the database.
So I guess the answer is a new dictionary is requied.

Code: [Select]
[CommandMethod("TestCopyXClip")]


public void TestCopyXClip()
{
    PromptEntityResult per;
    ObjectId tempId;

    Document Doc = acadApp.DocumentManager.MdiActiveDocument;
    Database Db = Doc.Database;
    Editor Ed = Doc.Editor;
    using (Transaction Trans = Db.TransactionManager.StartTransaction())
    {
        per = Ed.GetEntity("Select xref to copy xclip to: ");
        Entity ToEnt = Trans.GetObject(per.ObjectId, OpenMode.ForWrite) as Entity;
       

        per = Ed.GetEntity("Select xref to copy xclip from: ");
        Entity FromEnt = Trans.GetObject(per.ObjectId, OpenMode.ForRead) as Entity;

        DBDictionary xDictFrom = Trans.GetObject(FromEnt.ExtensionDictionary, OpenMode.ForRead) as DBDictionary;
        tempId = xDictFrom.GetAt("ACAD_FILTER");
        DBDictionary FltDict = Trans.GetObject(tempId, OpenMode.ForRead) as DBDictionary;
        ObjectId xclipId = ToEnt.ExtensionDictionary;
        if(xclipId.IsNull)ToEnt.CreateExtensionDictionary();
       
        DBDictionary xDictTo = Trans.GetObject(ToEnt.ExtensionDictionary, OpenMode.ForWrite) as DBDictionary;
        IdMapping iMap = new IdMapping();
        DBDictionary nFltDict = FltDict.DeepClone(xDictTo, iMap, true) as DBDictionary;
        xDictTo.SetAt("ACAD_FILTER", nFltDict);

        Trans.AddNewlyCreatedDBObject(nFltDict, true);
        Db.ResolveXrefs(true, true);
        Ed.Regen();
        Trans.Commit();
    }
}
Title: Re: Something about Xref functions...
Post by: T.Willey on November 21, 2008, 11:14:19 AM
Well Tim DeepClone seems to be the GO.
Both a regen and a AddNewlyCreatedDBObject are required to make it work.
SetAt must add it to the database.
So I guess the answer is a new dictionary is requied.

<snip>

Good catch Bryco!  It didn't even occur to me to use AddNewlyCreatedDBObject, but not it seems so simple.   :oops:  Thanks for posting that.  I was loosing my mine here, not being able to understand why it wasn't working.  I have some more complete code here.  Let me update it per this, and I'll post it.
Title: Re: Something about Xref functions...
Post by: T.Willey on November 21, 2008, 11:35:54 AM
Here is one that will work if it does / doesn't have an xclip already.

Code: [Select]
[CommandMethod( "TestCopyXClip" )]
public void TestCopyXClip() {
PromptEntityResult per;
ObjectId tempId;
DBDictionary nFltDict;

Document Doc = acadApp.DocumentManager.MdiActiveDocument;
Database Db = Doc.Database;
Editor Ed = Doc.Editor;

using ( Transaction Trans = Db.TransactionManager.StartTransaction() ) {
per = Ed.GetEntity( "\n Select xref to copy xclip from: " );
Entity FromEnt = Trans.GetObject( per.ObjectId, OpenMode.ForRead ) as Entity;

per = Ed.GetEntity( "\n Select xref to copy xclip to: " );
Entity ToEnt = Trans.GetObject( per.ObjectId, OpenMode.ForRead ) as Entity;

DBDictionary xDictFrom = Trans.GetObject( FromEnt.ExtensionDictionary, OpenMode.ForRead ) as DBDictionary;
tempId = xDictFrom.GetAt( "ACAD_FILTER" );
DBDictionary FltDict = Trans.GetObject( tempId, OpenMode.ForRead ) as DBDictionary;
tempId = FltDict.GetAt( "SPATIAL" );
SpatialFilter SptFlt = Trans.GetObject( tempId, OpenMode.ForRead ) as SpatialFilter;

if ( ToEnt.ExtensionDictionary == ObjectId.Null ) {
ToEnt.UpgradeOpen();
ToEnt.CreateExtensionDictionary();
ToEnt.DowngradeOpen();
}
DBDictionary xDictTo = Trans.GetObject( ToEnt.ExtensionDictionary, OpenMode.ForRead ) as DBDictionary;
if ( xDictTo.Contains( "ACAD_FILTER" ) ) {
tempId = xDictTo.GetAt( "ACAD_FILTER" );
nFltDict = Trans.GetObject( tempId, OpenMode.ForWrite ) as DBDictionary;
if ( nFltDict.Contains( "SPATIAL" ) )
nFltDict.Remove( "SPATIAL" );
SpatialFilter nSptFlt = SptFlt.DeepClone( nFltDict, new IdMapping(), true ) as SpatialFilter;
nFltDict.SetAt( "SPATIAL", nSptFlt );
Trans.AddNewlyCreatedDBObject( nSptFlt, true );
}
else {
xDictTo.UpgradeOpen();
nFltDict = FltDict.DeepClone( xDictTo, new IdMapping(), true ) as DBDictionary;
xDictTo.SetAt( "ACAD_FILTER", nFltDict );
Trans.AddNewlyCreatedDBObject( nFltDict, true );
}
Db.ResolveXrefs( true, true );
//Ed.Regen();
Trans.Commit();
}
}
Title: Re: Something about Xref functions...
Post by: Kerry on November 21, 2008, 06:24:07 PM

Nice job guys.
isn't it fun working at the bleeding edge :)
 .. but somehow satisfyng!


Title: Re: Something about Xref functions...
Post by: T.Willey on November 21, 2008, 06:29:31 PM

Nice job guys.
isn't it fun working at the bleeding edge :)
 .. but somehow satisfyng!

Yea, but I was getting very frustrated when it wouldn't stick.  Stupid simple single command missing.
Title: Re: Something about Xref functions...
Post by: Kerry on November 21, 2008, 06:31:23 PM
Tim,
just a note on convention.
usually variable names begin with a lowercase letter.
while this makes absolutely no difference to the compiler, personally I find it helps when visually scanning code if this (convention) is follwed consistently.
Title: Re: Something about Xref functions...
Post by: T.Willey on November 21, 2008, 07:04:57 PM
Tim,
just a note on convention.
usually variable names begin with a lowercase letter.
while this makes absolutely no difference to the compiler, personally I find it helps when visually scanning code if this (convention) is follwed consistently.

I agree.  If this was code I was going to use I would rewrite it, or at least rename the variables.  I was just happy to get it working, so I didn't want to have to do anymore with it than I did today.   :wink:
Title: Re: Something about Xref functions...
Post by: Bryco on November 22, 2008, 12:07:35 AM
Quote
isn't it fun working at the bleeding edge
Kerry I'm surprised at how often a search for something new to me ends up at your code.
I don't know how you start with so little info and end up with the right stuff.