Stripping block information/details for customer use

S7RM7RPR
Advocate
Advocate

Stripping block information/details for customer use

S7RM7RPR
Advocate
Advocate

I've just spent the last 2 years formatting a pile of new title blocks and borders and details for use on customer outline drawings. The detail blocks in specific are the problem. Right now they are set up with visibility states allowing the user to select from dozens of options. This however becomes a problem if and when we send the AutoCAD file to the customer because now the customer can see all of the different options they have available to them. No, we can't stop sending the .dwg file for "reasons".

 

Btw, all of the below is done via .NET with AutoCAD 2018. Yes, we've considered macros however we're concerned that the .NET code will run faster than the macro which obviously wouldn't work out well.

 

My initial solution was to go through and explode the relevant blocks when the drafter finishes the design and uploads it to our document management system. The visibility states will produce only the chosen detail, however I totally forgot some of the details use attributes - exploding the block displays the attribute instead of text in the attribute.

 

My second solution that I spent the last 4 days scrambling to figure out how to use the "burst" command instead of explode. Burst does the same thing, however it automatically preserves the text in any attributes. The problem now is that it is preserving the text in all of the attributes, regardless of the visibility state.. So I'm ending up with a dozen random placeholder texts for a detail that doesn't need it.

 

So, my question. Does anyone have any thoughts as to how to tackle this? Bottom line, the final .dwg file needs to have specific details that do not have all the potential options. The final details do not need to be blocks - if there's a detail revision the drafter will just insert a fresh block.

0 Likes
Reply
Accepted solutions (1)
695 Views
6 Replies
Replies (6)

_gile
Mentor
Mentor

Hi,

 

What about using the BlockReference.ConvertToStaticblock() method.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes

S7RM7RPR
Advocate
Advocate

Hadn't considered converting to a static block, I'll have to test it out and see how it interacts with the visibility states

0 Likes

norman.yuan
Mentor
Mentor

I think your solution would be a combination of your custom processing to the blocks + "BURST" command. I assume the "unwanted" information is all held by attributes with Visibility dynamic property set to invisible in a dynamic block.

 

So, before you code call "Burst" command, you need to remove all the AttributeReferences having their Visible property set to false because of the dynamic visibility state. Yes, Dynamic visibility state change does not cause a block reference's attributes being added/removed to the block references. It simply change the Entity (Attributereference)'s Visible property (true or false).

 

So, before calling "Burst" command, you simply need code to examine each attribute reference in the target block, if its Visible property is false, you can erase it. At the end, the block referenece would only have the attributes that show in current dynamic visibility state left and they are ready for "Burst". But wait, actually, you no not need to do the "burst" any more, unless you also care not showing the dynamic properties of your blocks. That is, after the "notvisible" attributes being erased, when use select a visibility state to show different attributes, they simply not there any more. Note, I am sure you know Entity/AttributeRefernce's "Visible" property is different from AttributeReference's "Invisible" property: the former is the one being set by dynamic visibility state.

 

You might not need code sample for such a straightforward and simple solution, but since I wrote actual code to make sure what I said works, I post it here anyway:

 

using System.Text;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(AttVisibilityInDynBlk.MyCommands))]

namespace AttVisibilityInDynBlk
{
    public class MyCommands
    {
        [CommandMethod("AttVisibility")]
        public static void TestAttVisibility()
        {
            var dwg = CadApp.DocumentManager.MdiActiveDocument;
            var ed = dwg.Editor;

            try
            {
                var blkId = SelectBlock(ed);
                if (!blkId.IsNull)
                {
                    //var msg = TestBlock(blkId);
                    var msg = TestBlock(blkId, true);
                    ed.WriteMessage(msg);
                }
                else
                {
                    ed.WriteMessage("\n*Cancel*");
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage("\nError:\n{0}.", ex.Message);
            }
            finally
            {
                Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
            }
        }

        private static ObjectId SelectBlock(Editor ed)
        {
            var opt = new PromptEntityOptions(
                "\nSelect a block:");
            opt.SetRejectMessage("\nI*nvalid: not a block!");
            opt.AddAllowedClass(typeof(BlockReference), true);

            var res = ed.GetEntity(opt);
            if (res.Status == PromptStatus.OK)
            {
                return res.ObjectId;
            }
            else
            {
                return ObjectId.Null;
            }
        }

        private static string TestBlock(ObjectId blkId, bool removeInvisible = false)
        {
            var text = new StringBuilder();
            using (var tran = blkId.Database.TransactionManager.StartTransaction())
            {
                var blk = (BlockReference)tran.GetObject(blkId, OpenMode.ForRead);
                if (!blk.IsDynamicBlock)
                {
                    text.Append("\nNo a dynamic block!");
                }
                else
                {
                    if (blk.AttributeCollection.Count==0)
                    {
                        text.Append("\nThe block does not have attribute.");
                    }
                    else
                    {
                        foreach (ObjectId id in blk.AttributeCollection)
                        {
                            var att = (AttributeReference)tran.GetObject(id, OpenMode.ForRead);
                            string txt = $"\nAttribute \"{att.Tag}\" - dynamic visibility: {(att.Visible ? "VISIBLE" : "NOT VISIBLE")}";
                            text.Append(txt);

                            if (removeInvisible && !att.Visible)
                            {
                                att.UpgradeOpen();
                                att.Erase(true);
                            }
                        }
                    }
                }
                tran.Commit();
            }

            return text.ToString();
        }
    } 
}

HTH

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes

S7RM7RPR
Advocate
Advocate

Looks like you put a lot of thought into that! It looks like it's actually fairly ideal. I might still have to use burst after though to get rid of the block tables just to avoid extra questions from the customers. I'll work on it the next couple days and keep you all updated

0 Likes

Anonymous
Not applicable
Accepted solution

Hello,

 

The easiest way to fulfill your requirement is converting your dynamic block to a static block.

 

But you must keep in mind that you will lose all the visibility states and the attributes . You will only have the attributes in the current visibility state.

 

You must select the desired visibility state and then convert you dynamic block to static block using the "acadBlockReference.ConvertToStaticBlock()" method where it will ask for a new name for the static block. Your existing dynamic block will be converted into a new static block in your model space.

0 Likes

S7RM7RPR
Advocate
Advocate

Converting to a static block appears to work perfectly. Annoyingly simple solution!

So for reference, here is the final code. Note that for my purposes, I identify the blocks to be converted by adding a custom parameter called "explode". This way it is entirely dynamic regardless of how many and what blocks are used on the drawing.

 

Editor ed = AutoCad.Application.DocumentManager.MdiActiveDocument.Editor;
AutoCad.Document acDoc = AutoCad.Application.DocumentManager.MdiActiveDocument;

Database acCurDb = acDoc.Database;

ObjectIdCollection objIdColl = BlockReferenceInModelSpace(ed);
List<ObjectId> listOfIDS = new List<ObjectId>();

acDoc.LockDocument();

using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
foreach (ObjectId objId in objIdColl)
{
//get the object
Entity ent = acTrans.GetObject(objId, OpenMode.ForWrite) as Entity;
if (ent is BlockReference)
{
//casting block reference
BlockReference br = ent as BlockReference;
if (br.IsDynamicBlock)
{
DynamicBlockReferencePropertyCollection props = br.DynamicBlockReferencePropertyCollection;

foreach (DynamicBlockReferenceProperty prop in props)
{
if (prop.PropertyName.ToUpper() == "EXPLODE")
{
br.ConvertToStaticBlock();
}
}
}
}
}
acTrans.Commit();
MessageBox.Show("Blocks exploded." + "\n" + "Note: if another detail is required, the detail block will need to be re-inserted");
}

0 Likes