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

Insert a dwg into the current drawing

5 REPLIES 5
SOLVED
Reply
Message 1 of 6
bsaidiDG51
589 Views, 5 Replies

Insert a dwg into the current drawing

My main purpose is to replace all blocks named "8x11Materiel" in my current drawing with the drawing "C:/8x11Materiel.dwg".

So I made a code that deleted all blocks "8x11Materiel", stored their positions, and purged all purgeable items of the drawing. But when it comes to inserting the drawing "C:/8x11Materiel.dwg" at the stored positions, I'm not able to produce or find a code that works.

I found out how to do it using AutoLisp using the following line: (command "insert" "C:/8x11Materiel.dwg" '(0 0) 1 1 ""), but in C# it seems to be more complicated.

 

Thank you in advance for your time.

 

My current code just in case you need a bit more context: 

moderator edit: Put code into code window. Please use the </> button.

 

private readonly List<Point3d> _deletedBlockPositions = new List<Point3d>(); // Global list to store deleted block positions
private readonly List<Scale3d> _deletedBlockScaleFactors = new List<Scale3d>(); // Global list to store deleted block scale factors

[CommandMethod("Replace8x11MaterielBlocks")]
public void Replace8x11MaterielBlocks()
{

Document doc = Application.DocumentManager.MdiActiveDocument;

if (doc == null)
{
Application.ShowAlertDialog("No active document found.");
return;
}

Database db = doc.Database;
Editor editor = doc.Editor;

using (Transaction transaction = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)transaction.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord modelSpace = (BlockTableRecord)transaction.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

// Process all entities in the model space
foreach (ObjectId objId in modelSpace)
{
ProcessEntity(transaction, objId); // Deletes 8x11MaterielBlocks
}

// Commit the transaction
transaction.Commit();
}

// Now, purge the block definitions
using (Transaction purgeTransaction = db.TransactionManager.StartTransaction())
{
BlockTable blockTable = (BlockTable)purgeTransaction.GetObject(db.BlockTableId, OpenMode.ForRead);

foreach (ObjectId objId in blockTable)
{
PurgeEntity(purgeTransaction, objId); // Purge all purgeable entities
}

purgeTransaction.Commit();
}


// ADD CODE HERE THAT WOULD INSERT THE DWG FOUND IN filePath IN THE POSITIONS STORED IN _deletedBlockPositions
string filePath = "C:\\8x11Materiel.dwg";

}


private void ProcessEntity(Transaction tr, ObjectId entityId)
{
Entity entity = tr.GetObject(entityId, OpenMode.ForWrite) as Entity;

if (entity is BlockReference blkRef)
{
if (blkRef.Name == "8x11Materiel")
{
_deletedBlockPositions.Add(blkRef.Position);
_deletedBlockScaleFactors.Add(blkRef.ScaleFactors);
blkRef.Erase();
// No need to process further, as we're done with the attributes
return;
}

var blockTableRecord = tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;

// Recursively process the entities within the block
foreach (ObjectId nestedEntityId in blockTableRecord)
{
ProcessEntity(tr, nestedEntityId);
}
}
}


private static void PurgeEntity(Transaction tr, ObjectId entityId)
{
if (entityId.ObjectClass.Name == "AcDbBlockTableRecord")
{
BlockTableRecord blockTableRecord = tr.GetObject(entityId, OpenMode.ForRead) as BlockTableRecord;

if (blockTableRecord.IsAnonymous || blockTableRecord.IsLayout || blockTableRecord.Name == "*Model_Space" || blockTableRecord.Name == "*Paper_Space")
{
// Don't purge special block table records
return;
}

// Check if the block is empty (no block references)
if (blockTableRecord.GetBlockReferenceIds(true, true).Count == 0)
{
blockTableRecord.UpgradeOpen();
blockTableRecord.Erase();
}
}
}

 

 

 

5 REPLIES 5
Message 2 of 6
norman.yuan
in reply to: bsaidiDG51

Let's see if I understand your issue correctly (since we are Acad .NET API programmers, when referring "block", make sure only use "block" while there is no confusion between block definition and block reference, otherwise always use "BlockReference/block reference" and "BlockTableRecord/block definition"):

 

You have a block definition "8x11Materiel" in current drawing, with many block references of it inserted. Now, you have an UPDATED block drawing, which redefines/updates to block definition. You want all the block references in the current drawing to be the references of new block definition, while their insertion position remain unchanged.

 

If that is the task you need to do, then it is rather simple: no need to erase all the block references, then purge the block definition, then insert the new/updated block definition, then insert block references in remembered location. No, there is no need to do these tedious work at all. The only thing you need to do is to update the block definition.

 

If the "8x11Materiel.dwg" is a block drawing, then you only need to call Database.Insert() to bring the new block definition with the same block name into the current drawing. This would effectively update the existing block definition with the same block name in the current drawing; in turn, the block references would be automatically updated (you would need to call Editor.Regen() if you want to see the change visually right away).

 

If the source drawing contains multiple block definitions, then you would use Database.WblockCloneObjects() to bring the needed new block definition into current drawing (using DuplicateRecordCloning.Replace argument).

 

It looks to me that you only need to use Database.Insert() to get the job done, only in a few lines of code (not tested, but you get the idea):

[CommandMethod("UpdateBlk")]
public void UpdateBlock()
{
   var doc=Application.DocumentManager.MdiActiveDocument;
   var ed=doc.Editor;
   var db=doc.Database;

   var blkFile="c:\\temp\\8X11Material.dwg"
   var blkName=System.IO.Path.GetFileNameWithoutExtension(blkFile);

   // read the block file into a database
   using (var sourceDb=new Database(false, true))
   {
     sourceDb.ReadDwgFromFile(blkFile, FileOpenModeReadAndAllShare, false, null);
     db.Insert(blkName, sourceDb, false)
   }
   ed.Regen();
}

 

 

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 6
kdub_nz
in reply to: bsaidiDG51

@bsaidiDG51 ,  @Et al

Please use the 'Insert/Edit code sample' button when posting code.

kdub_nz_1-1697751112295.png

 

 

Regards,


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.

class keyThumper<T> : Lazy<T>;      another  Swamper

Message 4 of 6
bsaidiDG51
in reply to: norman.yuan

Yes, you correctly understood my issue.

Now when I try your code, it works only for the "physical/visual" aspect of the block (like an mtext change or a removed line), but for the attributes of the block no change takes place. The block that I try to insert has different attribute definitions than the ones existing in the drawing (additional attributes and some attributes with a different tag). So when the program inserts the new block definition, the visual aspect of the block gets updated but it keeps the same attributes as the blocks that were "replaced".

Thank you again for your time.

 

The used code:

[CommandMethod("UpdateBlk")]
public void UpdateBlock()
{
    var doc = Application.DocumentManager.MdiActiveDocument;
    var ed = doc.Editor;
    var db = doc.Database;

    var blkFile = "C:\\8x11Materiel.dwg";
    var blkName = System.IO.Path.GetFileNameWithoutExtension(blkFile);

    // read the block file into a database
    using (var sourceDb = new Database(false, true))
    {
        sourceDb.ReadDwgFile(blkFile, FileOpenMode.OpenForReadAndAllShare, false, null);
        db.Insert(blkName, sourceDb, false);
    }
    ed.Regen();
}

 

Message 5 of 6
norman.yuan
in reply to: bsaidiDG51

In your original post, you did not mention the block reference has attributes, nor the code in your post indicate that. 

 

I assume you fully understand that when you say attribute, it is the AttributeReference(s) that are created with AttributeDefinition in the block definition as TEMPLATE,AFTER a BlockReference is created, and they ONLY BELONG TO the block reference. 

 

So, after you inserted new/updated block definition into the current drawing, which results in all the block references of it being updated GEOMETRICALLY/VISUALLY (such as color/linetype/layer of the element entities in the block definition), HOWEVER, it does not update block references' attributes because the block definition has now knowledge of the AttributeReferences of the block reference. It is up to you to decide what to do with the AttributeReferences. You could run the ExpressTool's ATTSYC command to reset attributes of the block references due to block definition update, if the new block definition has the same set of attributes defined in it.

 

But since you say the new block definition has different attribute defined, then, you need to handle this with your own code after the new bock definition is brought into the drawing:

 

1. find and loop through all BlockReferences of the block;

2. For each BlockReference, you can simply erase all the AttributeReferences

3. Recreate AttributeRefernces according to newly updated block definition (BlockTableRecord) (I assume you do know how to create AttributeReference based on a block definition).

 

Norman Yuan

Drive CAD With Code

EESignature

Message 6 of 6
Ed.Jobe
in reply to: norman.yuan

I have a solution for changing title blocks that is similar to what you want to do. 

Ed


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
How to post your code.

EESignature

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

Post to forums  

Forma Design Contest


AutoCAD Beta