.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Dynamic Block Geometry Invisible Or Black After Cloned

7 REPLIES 7
SOLVED
Reply
Message 1 of 8
kbrown
1103 Views, 7 Replies

Dynamic Block Geometry Invisible Or Black After Cloned

When I use the following code to clone dynamic blocks to a different drawing database, the blocks in the destination drawing are either invisible or their geometry is black where the color is set by layer (block geometry with explicit color assigned is drawn correctly). I've confirmed that the layers the source blocks are assigned to in the source drawing exist and have the same color in the destination drawing prior to cloning.

 

Here is the code responsible for cloning the blocks:

 

Using maps As New IdMapping()
                Dim cloned As Boolean = False
                Dim clones As New ObjectIdCollection()
                Using lock As DocumentLock = destDocument.LockDocument()
                    Using srcTran As Transaction = sourceDocument.TransactionManager.StartTransaction()
                        Using destTran As Transaction = destDocument.TransactionManager.StartTransaction()
                            Try
                                sourceDocument.Database.WblockCloneObjects(sourceObjs, destDocument.Database.CurrentSpaceId, maps, DuplicateRecordCloning.Replace, False)
                                For Each clId As IdPair In maps
                                    If clId.IsPrimary AndAlso clId.IsCloned Then clones.Add(clId.Value)
                                Next
                                destTran.Commit()
                                cloned = True
                            Catch ex As System.Exception
                                destTran.Abort()
                                cloned = False
                            End Try
                        End Using
                    End Using
                End Using

 

 

Here is the result in the destination drawing:

 

acadclonedblockblack.PNG

 

Here is what the blocks should look like:

 

acadclonedblock.PNG

 

The color is defined in the layer these blocks are assigned to. If I save the drawing containing the cloned blocks, close it, then open it, the color is correct. Also, sometimes the blocks in the destination drawing are completely invisible until I select them, then they have the same black geometry issue after selection. 

 

I've tried regen and UpdateScreen to no effect. However, if I use the LAYER command and freeze/unfreeze the layers these blocks are assigned to, their color is rendered correctly after. I'm sorry if my terminology is off; I do not use AutoCAD, I've just been developing plugins.

 

Thanks in advance for any advice,

Kevin

7 REPLIES 7
Message 2 of 8
moogalm
in reply to: kbrown

Can you please share sample drawing , at my end I'm not able to reproduce the behavior.

 

Steps I Followed.

  1. Created a simple dynamic block
  2. Assigned color 'By Layer'
  3. After clone from source database, when I insert in current dwg , block takes the color of the active layer,which is correct.

 

 public void ImportBlocks()
    {
        DocumentCollection dm = Application.DocumentManager;
        Editor ed = dm.MdiActiveDocument.Editor;
        Database destDb = dm.MdiActiveDocument.Database;
        Database sourceDb = new Database(false, true);
        string sourceFileName;
        try
        {
            sourceFileName = "C:\\Users\\moogalm\\Documents\\CustomerData\\Test_DynMicBlock.dwg";
            sourceDb.ReadDwgFile(sourceFileName, System.IO.FileShare.Read, true, "");
            ObjectIdCollection blockIds = new ObjectIdCollection();
            Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = sourceDb.TransactionManager;
            using (Transaction myT = tm.StartTransaction())
            {
                BlockTable bt = (BlockTable)tm.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, false);
                foreach (ObjectId btrId in bt)
                {
                    BlockTableRecord btr = (BlockTableRecord)tm.GetObject(btrId, OpenMode.ForRead, false);
                    if ( !btr.IsLayout) blockIds.Add(btrId);
                    btr.Dispose();
                }
            }
            IdMapping mapping = new IdMapping();
            sourceDb.WblockCloneObjects(blockIds, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
            ed.WriteMessage("\nCopied " + blockIds.Count.ToString() + " block definitions from " + sourceFileName + " to the current drawing.");
        }
        catch (Autodesk.AutoCAD.Runtime.Exception ex)
        {
            ed.WriteMessage("\nError during copy: " + ex.Message);
        }
        sourceDb.Dispose();
    }

 Attached DWG, I used.

 

 

Note: Don't share any confidential data.

Message 3 of 8
kbrown
in reply to: moogalm

I've attached a project which can be used to reproduce the results. In the project directory there are 3 drawing files. I included BCC250.dwg, which just includes the definition of the dynamic block used in the other two drawings in case you need it.

 

To reproduce, open SourceDrawing.dwg and DestDrawing.dwg. Make SourceDrawing the active drawing and run the command TestCommand defined in the plugin. Select the only block instance in the SourceDrawing when prompted to, then hit enter. The resulting geometry in DestDrawing is not black as it is when I use my actual plugin, but it is neither the color of the active layer nor is it the color assigned to the layer (Layer1) created by my AddLayer method, which the block in the dest drawing is assigned to if you click on it.

 

If you remove the call to AddLayer, the block is invisible in the DestDrawing. I had to take code from various places in my actual plugin and paste it all into this project to reproduce.

 

Thanks,

Kevin

Message 4 of 8
moogalm
in reply to: kbrown

Hi ,

 

This because your are cloning to current space ,

sourceDocument.Database.WblockCloneObjects(sourceO​bjs, destDocument.Database.CurrentSpaceId, maps, DuplicateRecordCloning.Replace, False)

 

You need to use ,BlockTable as container not Current Space. Use destDocument.Database.BlockTableId

 

Now definations are cloned to blocktable container, and you can  "INSERT" to get the block reference with color of active layer. No need to add layer in your code ,layer is created by wblockclone api in the dest drawing.

 

wblockclone API is very lowleve functionality just does what it name implies , we need to explicit implement to get correct colors on all entities as of source block using IdMapping api , I have written similar functionality some time back for draworder ,where drawing order is put incorrectly in destination database,this is just for an idea , we need to write on similar line.

http://adndevblog.typepad.com/autocad/2014/11/preserving-draworder-of-entities-while-wblockcloning-t...

 

I will update you if I can find a sample or will try to write one to get corrrect colors as of source block.

 

 

Message 5 of 8
kbrown
in reply to: moogalm

This change (using destDocument.Database.BlockTableID) made matters worse. I'm guessing you mean for me to insert after cloning? Remember, these are dynamic blocks. Are you saying I need to load the dynamic block definitions for the block references I intend to copy using clone, then manually create the references myself, transforming each block reference and setting the properties of each dynamic block reference? 

Message 6 of 8
moogalm
in reply to: kbrown

Hi ,

 

Sorry If I'm not clear.I think I might have digressed the topic.

 

You are cloning dynamic block reference and I'm talking about cloning dynamic block defination.

 

Generally for dynamic blocks we prefer cloning block definations and programattically inserting and apply neccessary changes , I know this is pathetic idea,this we do because dynamic blocks have anonymous references and behavior of cloning dynamic block refernece is unexpected .

 

Nonetheless I'm pursuing your idea i.e. cloning references not defination and working on it .I will get back to you.

 

 

 

Message 7 of 8
moogalm
in reply to: moogalm

Thanks to you ,

"If I save the drawing containing the cloned blocks, close it, then open it, the color is correct." this led  me to revisit your code and checked on without opening source drawing i.e just reading source drawing and cloning dynamic blockreferene to current drawing.

It worked out.

 

Code Sample:

[CommandMethod("WBCLONEToCurrent")]
    public void WBCLONEToCurrent()
    {
        DocumentCollection dm = Application.DocumentManager;
        Editor ed = dm.MdiActiveDocument.Editor;
        Database destDb = dm.MdiActiveDocument.Database;
        Database sourceDb = new Database(false, true);
        string sourceFileName;
        try
        {
            sourceFileName = "C:\\Users\\moogalm\\Documents\\CustomerData\\DynamicBlock.dwg";
            sourceDb.ReadDwgFile(sourceFileName, System.IO.FileShare.Read, true, "");
            ObjectIdCollection blockIds = new ObjectIdCollection();
            Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = sourceDb.TransactionManager;
            using (Transaction myT = tm.StartTransaction())
            {
                /*Handle of your Dynamic block reference*/
                Handle handle = new Handle(0x215);
                ObjectId brefId = ObjectId.Null;
                sourceDb.TryGetObjectId(handle,out brefId);
                blockIds.Add(brefId);
               

                
            }
            IdMapping mapping = new IdMapping();
            destDb.WblockCloneObjects(blockIds, destDb.CurrentSpaceId, mapping, DuplicateRecordCloning.Replace, false);
           
        }
        catch (Autodesk.AutoCAD.Runtime.Exception ex)
        {
            ed.WriteMessage("\nError during copy: " + ex.Message);
        }
        sourceDb.Dispose();
    }

 So to get it work done in your case when source drawing and destination drawing are opened in acad, we need to

1. Select entities in the current document and collect objetIds
2. Make the destination drawing as the current document
3. Call TransactionManager.QueueForGraphicsFlush() to queue for a graphic flush
4. Use Database.WblockCloneObjects()to copy the entities to this current document

 Sample code :

/*When switching documents you need to be in session mode.*/
    [CommandMethod("WBCLONE", CommandFlags.Session)]
     public void TestWBCLONE() {
	DocumentCollection docs = Application.DocumentManager;
	Document doc = docs.MdiActiveDocument;
	Database db = doc.Database;
	Editor Ed = doc.Editor;
	Document destDoc = null;
	foreach(Document tmpDoc in docs)
    {
		destDoc = tmpDoc;
	}
	try {
		PromptEntityResult entRes = Ed.GetEntity("Select Bref");
		if (entRes.Status != PromptStatus.OK) {
			return;
		}
		ObjectIdCollection objIds = new ObjectIdCollection();
		
        /*add bref id */
		objIds.Add(entRes.ObjectId);

        /*This is the trick  we need to make destination document as active one*/
		Database destdb = destDoc.Database;
		docs.MdiActiveDocument = destDoc;
		using(DocumentLock docLock = destDoc.LockDocument())
        {
			using(Transaction trans = destdb.TransactionManager.StartTransaction()) {
                /*
                 Please note that you need to set the destination document as the current document to use TransactionManager.QueueForGraphicsFlush() 
                 * otherwise you will get an expectation. Also please lock/unlock the document appropriately.*/
				trans.TransactionManager.QueueForGraphicsFlush();
		        IdMapping iMap = new IdMapping();
				db.WblockCloneObjects(objIds, destdb.CurrentSpaceId, iMap, DuplicateRecordCloning.Ignore, false);
				trans.Commit();
			}
		}
	}
    catch (System.Exception ex)
    {
		
	}
}

 

IMHO ,

The wblock clone operation  use object filing to clone an object. A new object is created, which will be the clone. Next, the original object is filed out to memory using dwgOut(). Finally, the data is filed into the new cloned object using dwgIn().

While processing the dwgOut() and dwgIn() operations the wblock clone engines identify all the references they have to process (clone/copy and translate) as the destination drawing is not yet active , filing part might be missing in hierarchy of cloning mechanism  ,hence you're finding bref to be dissappeared or grey out in the destination drawing, and same explains why we 're able to see when we close and reopen the destination drawing.

 

Thanks,

 

Message 8 of 8
kbrown
in reply to: moogalm

Thank you Madhukar, this does seem to fix the issue. One thing I noticed is that because I was running a modal command I needed to set

Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.DocumentActivationEnabled = True before setting MdiActiveDocument to the destination document to which the entities are copied.

 

I need to do some additional testing, but this seems to be the solution to my issue. Thanks again.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost