Author Topic: Burst in .Net  (Read 6677 times)

0 Members and 1 Guest are viewing this topic.

pedroantonio

  • Guest
Burst in .Net
« on: February 04, 2011, 03:47:01 PM »
Anybody knows how to do in .net what Burst command do from command line?

Basically, I wanna code 'burst' command in .net...

LE3

  • Guest
Re: Burst in .Net
« Reply #1 on: February 04, 2011, 03:55:42 PM »

pedroantonio

  • Guest
Re: Burst in .Net
« Reply #2 on: February 05, 2011, 05:28:46 PM »
thanks... that's better then just start ;)

kaefer

  • Guest
Re: Burst in .Net
« Reply #3 on: February 06, 2011, 12:26:57 PM »
Here - could be a good start:
http://www.theswamp.org/index.php?topic=18383.0

Thanks, Luis.

That was the real thing.

What got me was the renamed TextStyle property. It got me thinking too: if I bring in the customary Reflection hack to support both AutoCAD versions before and after the rename, that would be useful also for the transfer of the relevant properties. There's not much room for improvement anywhere else: May I humbly suggest to recurse on the BlockReferences instead of their ObjectIds, and to guard the explode from non-uniformly scaled blocks?  And do we have to dispose an Entity we just erased from the Database?

Cheers, Thorsten

Code: [Select]
// Based on LE 2007-08-25 http://www.theswamp.org/index.php?topic=18383.msg224681#msg224681

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

namespace SuperBurst
{
    public class SuperBurstCmd
    {
        static string[] PropsToCopy = new string[]{
            "VerticalMode",
            "HorizontalMode",
            "Position",
            "Normal",
            "Rotation",
            "Height",
            "WidthFactor",
            "Thickness",
            "TextStyle" , "TextStyleId",
            "TextString",
            "Oblique",
            "AlignmentPoint" };

        static void tryCopyProp(object target, object source, string p)
        {
            try {
                object value = source.GetType().GetProperty(p).GetValue(source, null);
                target.GetType().GetProperty(p).SetValue(target, value, null);
            } catch {}
        }
        static void copyProps(object target, object source, string[] names)
        {
            foreach (string name in names) tryCopyProp(target, source, name);
        }
        static int deepExplode(
            Database db,
            Transaction tr,
            BlockTableRecord cspace,
            BlockReference block )
        {
            foreach (ObjectId oid in block.AttributeCollection)
            {
                AttributeReference att = (AttributeReference)tr.GetObject(oid, OpenMode.ForRead, false);
                DBText txt = new DBText();
                txt.SetDatabaseDefaults(db);
                txt.AdjustAlignment(db);
                copyProps(txt, att, PropsToCopy);

                int cindex = att.ColorIndex;
                if (cindex == 0)                        // use block layer color, block layer
                    copyProps(txt, block, new string[]{ "Color", "Layer" });
                else if (cindex == 256)                 // use attribute color, attribute layer
                    copyProps(txt, att, new string[]{ "Color", "Layer" });
                else if (cindex > 0 && cindex < 256)    // use color index, attribute layer
                    copyProps(txt, att, new string[]{ "ColorIndex", "Layer" });
                cspace.AppendEntity(txt);
                tr.AddNewlyCreatedDBObject(txt, true);
            }
            int numberOfBlocks = 1;
            using (DBObjectCollection entitySet = new DBObjectCollection())
            {
                try
                {
                    block.Explode(entitySet);
                }
                catch
                {
                    numberOfBlocks = 0;
                    entitySet.Clear();
                }
                foreach (Entity ent in entitySet)
                {
                    AttributeDefinition ad = ent as AttributeDefinition;
                    if (ad != null) continue;

                    if (ent.ColorIndex == 0)
                        copyProps(ent, block, new string[] { "Color", "Layer" });
                    cspace.AppendEntity(ent);
                    tr.AddNewlyCreatedDBObject(ent, true);

                    BlockReference br = ent as BlockReference;
                    if (br == null) continue;
                    numberOfBlocks += deepExplode(db, tr, cspace, br);
                }
            }
            block.UpgradeOpen();
            block.Erase();
            return numberOfBlocks;
        }
        static int superBurst(SelectionSet sset)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            int numberOfBlocks = 0;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord cspace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite, false);
                foreach(SelectedObject so in sset)
                {
                    BlockReference br = (BlockReference)tr.GetObject(so.ObjectId, OpenMode.ForRead, false);
                    numberOfBlocks += deepExplode(db, tr, cspace, br);
                }
                tr.Commit();
            }
            return numberOfBlocks;
        }
        [CommandMethod("SUPERBURST", CommandFlags.UsePickSet)]
        static public void superBurstCmd()
        {
            Editor ed = acApp.DocumentManager.MdiActiveDocument.Editor;
            ed.WriteMessage("\nSelect block(s) for SuperBurst...");
           
            TypedValue[] filterValue = new TypedValue[1] { new TypedValue((int)DxfCode.Start, "INSERT") };
            PromptSelectionResult res = ed.GetSelection(new SelectionFilter(filterValue));
            if (res.Status == PromptStatus.OK && res.Value.Count > 0)
            {
                int numberOfBlocks = superBurst(res.Value);
                ed.WriteMessage("\nNumber of block(s) exploded [{0}] ", numberOfBlocks);
            }
        }
    }
}

LE3

  • Guest
Re: Burst in .Net
« Reply #4 on: February 06, 2011, 01:35:17 PM »
Hi Thorsten,

That was some of my early C# code, when I was learning the language (not that I know much or better nowadays).

I recall (back then and today) that one have to call Dispose(); as soon you are done using the object especially if the object will remain in the scope during a long operation, once Erase(); it is called it can be sent to dispose... or simple leave it to be out of scope and let c# call the destructor - in my case there was also the use of the using statement, that did not knew much about the usage - where the dispose will be called automatically... per my search on all my c# code, I only used dispose after an erase in two old commands.

Cheers, Thorsten

Glenn R

  • Guest
Re: Burst in .Net
« Reply #5 on: February 07, 2011, 06:57:01 AM »
Calling erase on a dbase resident entity just flips a bit, so I wouldn't be calling Dispose() on it myself as it's still dbase resident until a save operation, then there's always the undo command as well :D

LE3

  • Guest
Re: Burst in .Net
« Reply #6 on: February 07, 2011, 03:35:14 PM »
And do we have to dispose an Entity we just erased from the Database?

Do what Glenn R. does:
http://www.theswamp.org/index.php?topic=36986.msg420059#msg420059

Been following that on any latest code. :)

About the non-uniform (IsUniscaledOrtho()) - recall reading something about it or did it from arx, will double check, Burst (expresstools) command can explode those blocks, but since that command only works for not nested (explode) they might be using ExplodeToOwnerSpace()... and can't be use on a non resident block... umm...
« Last Edit: February 07, 2011, 03:43:21 PM by LE »

dan.glassman

  • Guest
Re: Burst in .Net
« Reply #7 on: February 07, 2011, 06:24:51 PM »
I've been reading this thread with interest, and was baffled at the lack of a better/easier way to do a .NET "MATCHPROP".  I've done the "manual" route any number of times, too.  Finally came up with this today, which uses the protocol extension classes that make "MATCHPROP" tick.  

Code: [Select]
public enum MatchPropFlags  //dbmatch.h
{
    ColorFlag = 0x1,
    LayerFlag = 0x2,
    LtypeFlag = 0x4,
    ThicknessFlag = 0x8,
    LtscaleFlag = 0x10,
    TextFlag = 0x20,
    DimensionFlag = 0x40,
    HatchFlag = 0x80,
    LweightFlag = 0x100,
    PlotstylenameFlag = 0x200,
    PolylineFlag = 0x400,
    ViewportFlag = 0x800,
    TableFlag = 0x1000,
    MaterialFlag = 0x2000,
    ShadowDisplayFlag = 0x4000,
    MultileaderFlag = 0x8000,
    TransparencyFlag = 0x10000,
    SetAllFlagsOn = 0x1FFFF,
};

[CommandMethod("mymatch")]
public void MyMatchProp()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;

    PromptEntityResult per1 = ed.GetEntity("Pick the source ent: ");
    PromptEntityResult per2 = ed.GetEntity("Pick the dest ent: ");

    using (Transaction t = doc.Database.TransactionManager.StartTransaction())
    {
        Entity src = t.GetObject(per1.ObjectId, OpenMode.ForRead) as Entity;
        Entity dest = t.GetObject(per2.ObjectId, OpenMode.ForWrite) as Entity;
        MatchProps(src, dest);
        t.Commit();
    }
}

public void MatchProps(Entity src, Entity dest)
{
    // make sure we have acmatch.arx
    HostApplicationServices.Current.LoadApplication("AcadMatch",
        ApplicationLoadReasons.OnLoadRequest, false, false);

    IntPtr _propertyMatcher = IntPtr.Zero;
    RXClass srcClass = src.GetRXClass();
    RXClass destClass = dest.GetRXClass();

    if (srcClass.IsDerivedFrom(destClass) || destClass.IsDerivedFrom(srcClass))
    {
        // Unmanaged AcDbMatchProperties protocol extension class specific to dest entity
        _propertyMatcher = dest.QueryX(RXClass.GetClass(typeof(MatchProperties)));
    }
    else
    {
        // Unmanaged generic AcDbMatchProperties protocol extension class
        _propertyMatcher = RXClass.GetClass(typeof(Entity)).QueryX(RXClass.GetClass(typeof(MatchProperties)));
    }
    if (_propertyMatcher == IntPtr.Zero) return;

    using (MatchProperties propertymatcher = MatchProperties.Create(_propertyMatcher, false) as MatchProperties)
    {
        int matchFlags = (int)MatchPropFlags.SetAllFlagsOn;
        propertymatcher.CopyProperties(src, dest, matchFlags);
    }            
}


« Last Edit: February 07, 2011, 06:50:22 PM by dan.glassman »

kaefer

  • Guest
Re: Burst in .Net
« Reply #8 on: February 07, 2011, 09:04:06 PM »
I've been reading this thread with interest, and was baffled at the lack of a better/easier way to do a .NET "MATCHPROP".  I've done the "manual" route any number of times, too.  Finally came up with this today, which uses the protocol extension classes that make "MATCHPROP" tick.  

Wow. There are still places of outstanding natural beauty to discover.

Well, back to the trodden paths through the wasteland. Did anyone notice the TypeDescriptionProvider attributes sprinkled all over the DatabaseServices namespace? Let's suppose the properties exposed aren't readonly and are not in the default as well as the "Geometry"
Category, could then we try to copy their values between Entites?

Code: [Select]
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Runtime

type acApp = Autodesk.AutoCAD.ApplicationServices.Application

let pdfiltered (o: obj) =
    System.ComponentModel.TypeDescriptor.GetProperties o
    |> Seq.cast<System.ComponentModel.PropertyDescriptor>
    |> Seq.filter
        (fun prop ->
            not prop.IsReadOnly &&
            prop.Category <> "Misc" &&
            prop.Category <> "Geometry" )

[<CommandMethod "mymatch">]
let myMatchProp() =
    let doc = acApp.DocumentManager.MdiActiveDocument
    let ed = doc.Editor
    let per1 = ed.GetEntity "Pick the source ent: "
    if per1.Status = PromptStatus.OK then
        let per2 = ed.GetEntity "Pick the dest ent: "
        if per2.Status = PromptStatus.OK then
            use tr = doc.Database.TransactionManager.StartTransaction()
            let src = tr.GetObject(per1.ObjectId, OpenMode.ForRead) :?> Entity
            let dest = tr.GetObject(per2.ObjectId, OpenMode.ForWrite) :?> Entity
           
            pdfiltered dest
            |> Seq.append (pdfiltered src)
            |> Seq.groupBy (fun prop -> prop.Name)
            |> Seq.map (snd >> Seq.toList)
            |> Seq.iter
                (function
                    | sp::dp::_ ->
                        try
                            dp.SetValue(dest, sp.GetValue src)
                            ed.WriteMessage("\n{0} ({1}) ", sp.Name, sp.Category)
                        with ex ->
                            ed.WriteMessage(
                                "\nSkipped: {0} ({1}), {2} ",
                                sp.Name, sp.Category, ex.Message)
                    | _ -> () )
            tr.Commit()


dan.glassman

  • Guest
Re: Burst in .Net
« Reply #9 on: February 09, 2011, 10:05:19 PM »
Quote
Did anyone notice the TypeDescriptionProvider attributes sprinkled all over the DatabaseServices namespace? Let's suppose the properties exposed aren't readonly and are not in the default as well as the "Geometry"
Category, could then we try to copy their values between Entities?

I...only just learned [from you] that they were there to be noticed.  I don't spend a lot of time in the Object Browser, and while I had it installed I don't think I've actually used Reflector before, which is where I now see them. 

I didn't know such introspective methods were available in .Net -- thanks for the lesson!

-drg

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Burst in .Net
« Reply #10 on: February 09, 2011, 10:36:40 PM »
Have not tested any of your code. So this issue might be addressed or not even a issue

If you create a block with a couple of Attributes on different visibiltiy states and use AutoCAD burst command it will show all attributes.

I did something in the past and just checked for IsHidden. Have a Client who is notoriuos for that

dan.glassman

  • Guest
Re: Burst in .Net
« Reply #11 on: February 09, 2011, 11:13:48 PM »
I don't know enough lisp to point out the bug in ET's "burst", yet.  But SuperBurst does not have that bug.

-drg

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Burst in .Net
« Reply #12 on: February 09, 2011, 11:20:06 PM »
I don't know enough lisp to point out the bug in ET's "burst", yet.  But SuperBurst does not have that bug.

-drg

I guess that is one of the reasons that make it Super

kaefer

  • Guest
Re: Burst in .Net
« Reply #13 on: February 10, 2011, 02:57:57 AM »
I didn't know such introspective methods were available in .Net -- thanks for the lesson!

Guess it' s more a lesson on how not to do it.

Unfortunately, there are  quite a few cases that would have to be excluded explicitly, Position for one.
Code: [Select]
    public class MatchPropCmd
    {
        static Dictionary<string, PropertyDescriptor> pdfiltered (object o)
        {
            Dictionary<string, PropertyDescriptor> pds = new Dictionary<string, PropertyDescriptor>();
            foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(o))
            {
                string name = pd.Name;
                if (!pd.IsReadOnly &&
                    pd.Category != "Misc" &&
                    pd.Category != "Geometry" &&
                    name != "XData" &&
                    name != "HasSaveVersionOverride" &&
                    name != "Position" &&
                    name != "DimLinePoint" &&
                    name != "XLine1Point" &&
                    name != "XLine1Point" &&
                    !pds.ContainsKey(name)) pds.Add(name, pd);
            }
            return pds;
        }
        [CommandMethod("mymatch")]
        public void MyMatchProp()
        {
            Editor ed = acApp.DocumentManager.MdiActiveDocument.Editor;
            Database db = acApp.DocumentManager.MdiActiveDocument.Database;

            PromptEntityResult per1 = ed.GetEntity("Pick the source ent: ");
            if (per1.Status != PromptStatus.OK) return;
            PromptEntityResult per2 = ed.GetEntity("Pick the dest ent: ");
            if (per2.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                Entity src = (Entity)tr.GetObject(per1.ObjectId, OpenMode.ForRead);
                Entity dest = (Entity)tr.GetObject(per2.ObjectId, OpenMode.ForWrite);
                Dictionary<string, PropertyDescriptor> destprops = pdfiltered(dest);
                foreach( KeyValuePair<string, PropertyDescriptor> srcprops in pdfiltered(src))
                {
                    if (destprops.ContainsKey(srcprops.Key))
                    {
                        try
                        {           
                            destprops[srcprops.Key].SetValue(dest, srcprops.Value.GetValue(src));
                            ed.WriteMessage("\n{0} ({1}) ", srcprops.Key, srcprops.Value.Category);
                        }
                        catch (System.Exception ex)
                        {
                            ed.WriteMessage(
                                "\nSkipped: {0} ({1}), {2} ",
                                srcprops.Key, srcprops.Value.Category, ex.Message);
                        }
                    }
                }
                tr.Commit();
            }
        }
    }