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

optimize Insert Block Cad to Current Drawing by net

13 REPLIES 13
SOLVED
Reply
Message 1 of 14
nguyenxuanvung
822 Views, 13 Replies

optimize Insert Block Cad to Current Drawing by net

I am currently developing an application that requires the insertion of blocks into an open drawing in AutoCAD. To enhance the performance of the application, I would like to preload block files into a Dictionary  at the start of the program. This way, I can quickly retrieve the necessary blocks when needed without having to read the files again.

Could you please advise on the best practices for loading block definitions into a dictionary in AutoCAD .NET? Specifically, I am looking for guidance on:

  1. The optimal way to read block files and store their Object Id in a dictionary.
  2. Any recommended methods or classes within the AutoCAD API that facilitate this process.
  3. Suggestions for handling any potential exceptions or errors that may arise during this loading process.

Thank you for your assistance. I look forward to your valuable insights.

Labels (1)
13 REPLIES 13
Message 2 of 14

I wouldn't consider what you are trying to do is "optimizing".

 

If your intension is to make sure all block definitions that MIGHT BE USED in your app's workflow exit in the drawing, then I do not see there would be noticeable differences between bringing all block definitions in at beginning of the app, or bring them in the middle on demand. Actually the latter might be more efficient if these is case when only some of the blocks are needed in particular workflow.

 

Also, using a Dictionary to store block definition's ObjectId is redundant, completely not necessary: BlockTable does it for you.

 

The code you attached (you should post the code using the "</>" button) does not make things clearer:

 

Are the dwg files your code loop through from a directory block drawing? or drawing that contains many block definitions. For the former, you use Database.Insert() to bring the block drawing into the current drawing as block definition; for the latter, you use WLockCloneObjects() to bring one or more block definition in the source drawing into the current drawing at once.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 14

Your optimization has nothing to do with storing block ObjectIds keyed to their names in a dictionary. If there is some optimization, it is pre-inserting blocks from external drawing files. The only thing the dictionary does is eliminate the need to open the block table to get the ObjectId of a block from its name, which only allows you to avoid a line or two of code needed to open the block table.

 

So the question becomes, what if not all of the blocks that are pre-loaded are ultimately needed? In that case, you have overhead from pre-loading that you wouldn't have when loading blocks on-demand.

 

If you decide against pre-loading blocks, then something that may be useful is to store the the source .DWG file paths keyed to the corresponding block names in a dictionary (something I've done in the past), to make insertion of blocks from files (if needed) simpler.

 

 

Message 4 of 14

my application where users can insert blocks into their drawings by clicking on buttons.

The process is as follows:

When a user clicks a button, the program uses a predefined path to search for the corresponding .dwg file based on the button's name (each dwg file is one dynamic block)
The program then inserts the block into the current drawing at a point chosen by the user.
Currently, this process involves searching the directory containing the .dwg files each time a button is clicked.

 

I am concerned about the efficiency of this approach, especially if I want to upgrade the program to handle a list of blocks (e.g., 1000 blocks) to be inserted with their respective coordinates.

In such a case, the program would need to search the directory for each block, which I believe is not optimal.

 

Could you please suggest a more efficient method? I have not fully understood the block table approach you previously mentioned.

public class BlockCadConfig
{
    public const string PathBlockCad = @".\Blocks\";
   public string Pattern { get; set; } = "*.dwg";
    public Document Document { get; set; }
    private Database _database;
    private string pathFile;
    public Dictionary<string, ObjectId> BlocksObjectID { get; private set; } = new Dictionary<string, ObjectId>();

    public BlockCadConfig( DuplicateRecordCloning cloning=default)
    {
        string assemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        pathFile = Path.GetFullPath(Path.Combine(assemblyPath, PathBlockCad));
        Document = Application.DocumentManager.MdiActiveDocument;
        Transaction tr=Document.TransactionManager.StartTransaction();
        _database = Document.Database;
        //BlocksObjectID = GetBlocksObjectID(tr);
    }

    public  ObjectId GetBlocksObjectID(Transaction tr)

    {
       
        if (_database is null)
            throw new ArgumentNullException(nameof(_database));

        string[] cadFiles = Directory.GetFiles(pathFile, Pattern);
        foreach (string cadFile in cadFiles)
        {
            string blockname = Path.GetFileNameWithoutExtension(cadFile);
            var blockTable = (BlockTable)tr.GetObject(_database.BlockTableId, OpenMode.ForRead);

            var targetDb = HostApplicationServices.WorkingDatabase;
            var ids = new ObjectIdCollection();
            var bt = default(BlockTable);
            using (var tmpDb = new Database(false, true))
            {
                tmpDb.ReadDwgFile(cadFile, FileOpenMode.OpenForReadAndAllShare, true, null);
                using (var trn = tmpDb.TransactionManager.StartTransaction())
                {
                    bt = (BlockTable)trn.GetObject(tmpDb.BlockTableId, OpenMode.ForRead);
                    if (bt.Has(blockname))
                    {
                        ids.Add(bt[blockname]);
                    }
                    trn.Commit();
                }
                if (ids.Count == 1)
                {
                    var mapping = new IdMapping();
                    targetDb.WblockCloneObjects(ids, blockTable.ObjectId, mapping, DuplicateRecordCloning.Replace, false);
                    if (blockTable.Has(blockname))
                    {
                        return blockTable[blockname];
                    }
                }
            }
        }
        return default(ObjectId);
    }

autocad insertblock question.png 

Message 5 of 14

Thank you for your previous suggestion.

I understand that I can create a JSON file to store the name of each block along with the corresponding path to the .dwg file. I believe this will help improve the performance of my application slightly.

However, I am concerned about the efficiency when I pass a list of 1000 items, each containing a block name and an insert point. I am unsure if AutoCAD will handle this operation efficiently.

Could you please provide further advice or suggestions on this matter?

Message 6 of 14
kdub_nz
in reply to: nguyenxuanvung

@nguyenxuanvung 

Is your plan to 'load' the blocks each time the application is run ??

 

Perhaps, just for edification, you could write a couple of time-testable methods to actually determine the advantage to be gained from each option.

Personally as a user, I'd prefer to have a small 'delay' when I insert a block from a "predefined path " than to have a more significant 'delay' when the app is initially loaded ( I assume your app would be demand loaded ) or worse still, each time the app is run.

Keep in mind that even if you (as a developer) assume the block definitions are loaded, each insert routine should check that the reference is in the BlockTable . . .  

 

I'm interested in what you believe your users consider "excessive" time from the image press to the completed insertion of the block.

 

Regards,

 

added:

Your comments describe two completely different procedures


@nguyenxuanvung wrote:

When a user clicks a button, the program uses a predefined path to search for the corresponding .dwg file based on the button's name (each dwg file is one dynamic block)
The program then inserts the block into the current drawing at a point chosen by the user.


and . . 

 


@nguyenxuanvung wrote:

. . . .  I want to upgrade the program to handle a list of blocks (e.g., 1000 blocks) to be inserted with their respective coordinates.

In such a case, the program would need to search the directory for each block, which I believe is not optimal.


With these alternatives you may require two different options for eficiency.

Perhaps re-read message 3 from @ActivistInvestor 


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.
Sometimes the question is more important than the answer.

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

Message 7 of 14
cuongtk2
in reply to: nguyenxuanvung

Button của bạn được khai báo thủ công hay phát sinh tự động. Nếu khai báo thủ công thì việc lưu trữ vào Dictionary là vô ích, vì bạn chỉ cần khai báo file thư viện cho button click . Nếu nó là phát sinh tự động thì chỉ cần tạo class để binding image và file dwg là được.

Message 8 of 14
nguyenxuanvung
in reply to: kdub_nz

Thank you for your suggestion, i want to build a solution to multi user can work on a project, each user work on other drawing, but graphic and db must the same,  I m interested in performan, because if you just click butom one by one it’s ok, but if you want to show other finished, you must reload from db to your drawing to see final work, my app worked at the moment, but performance not good, so i’m finding other way to input a list block into autocad

Message 9 of 14
nguyenxuanvung
in reply to: cuongtk2

Em cảm ơn anh đã gợi ý, buttom của em đang được tạo 1 cách tự động, nhưng theo nhóm chức năng, nghĩa là 1 button đại diện cho mỗi nhóm block, khi nhấn nút và chọn điểm trên màn hình sẽ trả ra đúng tên block tương ứng, sau đó chương trình sẽ tìm được file dwg tương ứng để insert,  tuy nhiên, trong nhiều trường hợp việc insert block được diễn ra tự động, dữ liệu nhận về là 1 list block, kèm theo point insert vào trong cad, thì  e đang thấy chương trình có hiệu năng ko tốt, em muốn có tên block là cad ngay lập tức có thể có sẵn dữ liệu để insert vào file cad đang mở.  Giả sử nếu em binding các buttom trên thì cũng chỉ binding được nhóm block tương ứng với nút đó, e vẫn đang tìm cách để tối ưu việc này. Như bác Norman gợi ý, e sẽ thử tạo ra 1 file json tương ứng để trả về đường dẫn file cad, nếu có ý tưởng hoặc cách làm tốt hơn, anh có thể chi sẻ cho em biết với ah!

Message 10 of 14
kdub_nz
in reply to: nguyenxuanvung

 

Perhaps this should have been part of your first post  ??

 


@nguyenxuanvung wrote:  (translated )

Thank you for your suggestion, my button is being created automatically, but according to function group, meaning 1 button represents each block group, when pressing the button and selecting a point on the screen, the correct name will be returned. the corresponding block, then the program will find the corresponding dwg file to insert,  however, in many cases inserting the block is done automatically, the data received is a list of blocks, accompanied by the insertion point into the cad , then  I'm seeing that the program's performance is not good. I want to have the block name CAD so I can immediately have data available to insert into the open CAD file.Suppose if I bind the above buttons, I can only bind the block group corresponding to that button. Is there a better way to optimize the display?


 


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.
Sometimes the question is more important than the answer.

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

Message 11 of 14
nguyenxuanvung
in reply to: kdub_nz

yes, if user click one by one button to insert block, it’s ok because they dont see any delay. But with other function must insert a list block cad about 1000 block. It’s not good, because program will delay some minute. So I m looking for a solution can insert many block cad in current cad working.

Message 12 of 14
kdub_nz
in reply to: nguyenxuanvung

Which AutoCAD version are you building for ?

 

And how unique will the block names be in the list o blockName : insertPoint ?  ie how many name repeats ?

 

If the  Blocks are dynamic, won't you need to provide additional information for the inserts ???

where is that stored ?

 


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.
Sometimes the question is more important than the answer.

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

Message 13 of 14
nguyenxuanvung
in reply to: kdub_nz

Yes, you’re correct, my app base on Autocad 2020 or higher .my block is dynamic block, my list to insert to current auto include. : cadblockname+ infomation of dynamic dimention+point insert. That’s mean each dynamic block is inserted autocad have full information to set for dynamic block. Could you please give me some advice to do it better,   
current my flow is each item in list, i find path file dynamic block=> insert to current cad=> set dynamic attribute.     My list to input dynamic block, have many item same block name and dynamic attribute

Message 14 of 14
kdub_nz
in reply to: nguyenxuanvung

This methodology has worked for me in the past :

 

Create a master drawing for each of your component types. The drawing will contain all the blocks for each type.

If the Master block is not in the blockTable of your working drawing add it programmatically.

 

Then you don't need to import each individual block, nor will you need to test if the block is available.

 

This saves a few clock ticks and is easy to modify/update.

 

Regards,

 

 

 


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.
Sometimes the question is more important than the answer.

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

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

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report