Author Topic: Revising Color of selected entities - implementing code from others-failing. :-(  (Read 1993 times)

0 Members and 1 Guest are viewing this topic.

Yosso

  • Newt
  • Posts: 36
I've been trying to learn C#, so when one of our CAD power users had a request for a small utility program, I thought it might be an good project for learning..

I started with the code posted by Mr. Walmsey at  http://through-the-interface.typepad.com/through_the_interface/2007/02/changing_the_co.html

Adapted to suit my application, where objects on certain layers are changed to another color to facilitate faded plotting. I'm checking for dimension, as the color of the lines will be different than the text.  Also going through the attributes to revise the color of the text.

Had the routine working perfectly, until the user stated that he/she would like to be able to select certain objects and not just do a complete fade of all the objects...sigh.

Code for Fading:

Code: [Select]
private int ChangeNestedEntitiesToColor(ObjectId btrId, Boolean Fade)
        {
            int changedCount = 0;

            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            Transaction tr = doc.TransactionManager.StartTransaction();
            using (tr)
            {
                LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
                foreach (ObjectId entId in btr)
                {
                    Entity ent = tr.GetObject(entId, OpenMode.ForRead) as Entity;
                    if (ent != null)
                    {
                        BlockReference br = ent as BlockReference;
                        if (br != null)
                        {
                            //Check for attributes for calling the recursive routine
                            foreach (ObjectId arId in br.AttributeCollection)
                            {
                                DBObject obj = tr.GetObject(arId,OpenMode.ForRead);
                                AttributeReference ar = obj as AttributeReference;
                                if (ar != null)
                                {
                                    if (ar.Color.ColorIndex == 256 && Fade)
                                    {
                                        obj.UpgradeOpen();
                                        ar.Color = Color.FromColorIndex(ColorMethod.ByAci, 7);
                                        obj.DowngradeOpen();
                                    }
                                    else
                                    {
                                        obj.UpgradeOpen();
                                        ar.Color = Color.FromColorIndex(ColorMethod.ByAci, 256);
                                        obj.DowngradeOpen ();
                                    }
                                }
                            }
                            changedCount += ChangeNestedEntitiesToColor(br.BlockTableRecord, Fade);
                        }
                        else
                        {
                            changedCount++;
                            //Entity is only open for read - Upgrade time.
                            ent.UpgradeOpen();

                            //Loop thru the color arrays
                            for (int i = 0; i < intBoldClr.GetUpperBound(0); i++)
                            {
                                //Get layertable record to verify the layer color
                                LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(lt[ent.Layer], OpenMode.ForWrite);
                                //
                                if (ltr.Color.ColorIndex == intBoldClr[i] && Fade)
                                {
                                    ent.Color = Color.FromColorIndex(ColorMethod.ByAci, intFadeClr[i]);
                                }
                                if (ltr.Color.ColorIndex == intBoldClr[i] && !Fade)
                                {
                                    ent.Color = Color.FromColorIndex(ColorMethod.ByAci, 256);
                                }
                            }
                            //Check for a dimension entity
                            if (ent.Id.ObjectClass.DxfName == "DIMENSION")
                            {
                                Dimension entDim = ent as Dimension;
                                if (Fade)
                                { entDim.Dimclrt = Color.FromColorIndex(ColorMethod.ByAci, 7); }
                                if (!Fade)
                                { entDim.Dimclrt = Color.FromColorIndex(ColorMethod.ByAci, 11); }
                            }
                            ent.DowngradeOpen();
                        }
                    }
                }
                tr.Commit();
            }
            return changedCount;
        }


Code for selecting objects:

Code: [Select]
    public class FadeCommands
    {
        //Arrays for the color revisions
        short[] intBoldClr = { 1, 2, 3, 6, 10, 11, 12, 14 };
        short[] intFadeClr = { 7, 115, 115, 223, 223, 7, 254, 255 };

        //Selection set code example from Fixo
        //http://www.acadnetwork.com/index.php?PHPSESSID=370b206819c63b95da71b0dc03b7263c&topic=236.0

        [CommandMethod("CF")]

        public void ColorFade()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            PromptSelectionOptions pso = new PromptSelectionOptions();
            int count = 0;

            // Create transaction to operate on the selection set
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
            pso.MessageForAdding = "\nSelect Items to fade: ";
            pso.MessageForRemoval = "\nSelect Items to remove from selection: ";
            pso.RejectObjectsOnLockedLayers = false;

            PromptSelectionResult psr = ed.GetSelection(pso);
            SelectionSet sso = psr.Value;

            if (psr.Status != PromptStatus.OK)
                return;
           
            // Let's hope something was selected...
            if (psr.Value.Count == 0) return; // If not, then return

                ObjectId msId;

                foreach (SelectedObject so in sso)
                {
                    //Cast Object into Entity
                    Entity ent = (Entity)tr.GetObject(so.ObjectId, OpenMode.ForRead);
                    msId = ent.ObjectId;

                    count += ChangeNestedEntitiesToColor(msId, true);
                }

// Not needed, but quicker than aborting
             tr.Commit();
            }
        ed.Regen();
        ed.WriteMessage("\nColor fade added to {0} entit{1}.", count, count == 1 ? "y" : "ies");
        }

Now I'm getting an "InvalidCastException was unhandled by user code" error at the line below.

Code: [Select]
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);

If I pick a block, then there error stating that we were unable to cast....

Quote
Unable to cast object of type 'Autodesk.AutoCAD.DatabaseServices.BlockReference' to type 'Autodesk.AutoCAD.DatabaseServices.BlockTableRecord'

If I pick multiple items, then the first item selected will not be converted, so on and so forth.

I'm missing something critical in the entire scheme of the AutoCAD API, I've got Jerry Winters VB.net book (somewhat helpful) and Tom Nelson's more recent C# short "book".  Which was more helpful than the Winter's book. 

Still not catching on.  :embarrassed:

So...any hints or tips?

Thank you in advance.

Mike

n.yuan

  • Bull Frog
  • Posts: 348
The ObjectId you passed to function "ChangeNestedEntitiesToColor()" is the ObjectId of an Entity (line, circle, Blockreference...), while it seems that the function expects an ObjectId of a block definition (BlockTableRecord). That is why the error.

Assume the function is correct (e.g. it needs a BlockTableRecord's ObjectId to work with), then you must pass in an ObjectId of BlockTablerecord, not an Entity. As matter of fact, BlockTableRecord is not selectable (not directly).

You need to do it this way:

1. Get a SelectionSet as you did, but better yet, you may want to use a selection filter to only select blocks (BlockReference, that is). This way, anything in the SelectionSet is a BlockReference;

2. Looping through the selected entities (BlkockReference), for each BlockReference, you find its block definition's ObjectId (ObjectId of a BlockTableRecord. Since it is possible several BlockReferneces may be based on the same BlockTableRecord, you better end up with a list/collection of ObjectId of BlockTableRecords.

3. Then loop through the collection of ObjectIds of BlockTableRecord with the function "Change....()"

Yosso

  • Newt
  • Posts: 36
N. Yuan,

I'm needing to select all types of object, blocks, entities, text - could be anything or nothing.

That being said, I did some further research today and found another post by Mr. Walmsley where he provides an example of looping though a selection set.  Going to try his approach tomorrow morning before work, when I can "code" during non-billable hours.

http://through-the-interface.typepad.com/through_the_interface/2010/08/changing-the-layer-or-color-of-a-nested-entity-using-net.html

Thank you again for your assistance.

M.

Yosso

  • Newt
  • Posts: 36
Found another post by an Autodesk blogger regarding converting a selection set to a block, so I tried that approach.

http://adndevblog.typepad.com/autocad/2012/07/creating-block-from-selection-set.html

Code: [Select]
   [CommandMethod("CF")]

        public void ColorFade()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            PromptSelectionOptions pso = new PromptSelectionOptions();
            int count = 0;
           
            // Expansion Plans for Code: (9/10/14)
            // Call selection set routine to allow user to either select objects or
            // simply select all objects in the document - perhaps allow MS or PS
            // First Choice - Select Objects
            // Second Choice - All MS objects
            // Third Choice - All PS objects
            // Fourth Choice - Everything in PS and MS
     
            pso.MessageForAdding = "\nSelect Items to fade: ";
            pso.MessageForRemoval = "\nSelect Items to remove from selection: ";
            pso.RejectObjectsOnLockedLayers = false;

            PromptSelectionResult psr = ed.GetSelection(pso);
            SelectionSet sso = psr.Value;

            if (psr.Status != PromptStatus.OK)
                return;
           
            // Let's hope something was selected...
            if (psr.Value.Count == 0) return; // If not, then return

            //Create an array to hold the object id's of the selected objects
                ObjectId[] ids = psr.Value.GetObjectIds();
                ObjectId blockId = ObjectId.Null;

            //Add a block table with the name "fadeawayblock"
            string strFadeBlock = "fadeawayblock";

            //Transaction tr starts right now...
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

                if (!bt.Has(strFadeBlock))
                {
                    bt.UpgradeOpen();
                    //Create new block
                    BlockTableRecord record = new BlockTableRecord();
                    record.Name = strFadeBlock;
                    bt.Add(record);
                    tr.AddNewlyCreatedDBObject(record, true);
                }
                blockId = bt[strFadeBlock];
            tr.Commit();
            }
            //Copy the selected entities to the block using Deepclone.
            ObjectIdCollection collection = new ObjectIdCollection(ids);
            IdMapping mapping = new IdMapping();
            db.DeepCloneObjects(collection, blockId, mapping, false);
           
            count += ChangeNestedEntitiesToColor(blockId , true);
     
                ed.Regen();
                ed.WriteMessage("\nColor fade added to {0} entit{1}.", count, count == 1 ? "y" : "ies");
        }

I'm going with the old "selection set convert to a block" trick.  Seems to be working, now just need user feedback. :-)

Mike