Author Topic: Isolate Objects - Block Being Disobediant  (Read 5450 times)

0 Members and 1 Guest are viewing this topic.

Hugh_Compton

  • Guest
Isolate Objects - Block Being Disobediant
« on: October 27, 2008, 12:25:34 PM »

I have a routine for Isolating selected objects.  It works fine BUT not on blocks.  If I try to use it on a block the block will disappear.  can anyone help?

<CommandMethod("isom")> _
    Public Sub objectsIsolate()
        Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
        Dim db As Database = HostApplicationServices.WorkingDatabase
        Dim tm As Autodesk.AutoCAD.ApplicationServices.TransactionManager = db.TransactionManager
        Dim ss As SelectionSet
        Dim ent As Entity = Nothing

        Dim trans As Transaction = tm.StartTransaction()

        Try
            Dim bt As BlockTable = tm.GetObject(db.BlockTableId, OpenMode.ForRead, False)
            Dim btr As BlockTableRecord = tm.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead, False, True)

            'Get objectIds from user selection
            Dim prmptSSopt As New PromptSelectionOptions()
            prmptSSopt.PrepareOptionalDetails = True
            prmptSSopt.RejectObjectsOnLockedLayers = False
            prmptSSopt.MessageForAdding = "Select objects to isolate: " + vbNewLine

            Dim ssRes As PromptSelectionResult = ed.GetSelection(prmptSSopt)

            If Not ssRes.Status = PromptStatus.OK Then Exit Sub
            ss = ssRes.Value

            'make an array of objectIds from the user's selection set
            Dim objIds() As ObjectId = ss.GetObjectIds()

            'Make everything visible = false
            For Each id As ObjectId In btr 'For Each id In drawing
                ent = CType(trans.GetObject(id, OpenMode.ForWrite, False), Entity)
                ent.Visible = False
            Next

            'Make Users selection visible
            For Each objId As ObjectId In objIds
                ent = CType(trans.GetObject(objId, OpenMode.ForWrite, False, True), Entity)
                ent.Visible = True
            Next

        Catch ex As System.Exception
            MsgBox(ex.Message, MsgBoxStyle.Information, "Error in Isolate")
        Finally
            trans.Commit()
            trans.Dispose()
        End Try
    End Sub

Glenn R

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #1 on: October 27, 2008, 12:38:11 PM »
Test drawing?

Hugh_Compton

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #2 on: October 27, 2008, 12:43:46 PM »
OK, I've attached one....the cylinder is a block.....the circle is a circle entity.....

Glenn R

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #3 on: October 27, 2008, 04:46:45 PM »
Uhhh...why are you using an objects Visible property to isolate it?

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Isolate Objects - Block Being Disobediant
« Reply #4 on: October 27, 2008, 04:51:10 PM »
Uhhh...why are you using an objects Visible property to isolate it?
That is how I have done it in Lisp without problems.  Is there a better way?
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Hugh_Compton

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #5 on: October 28, 2008, 04:37:48 AM »
By Isolate I mean make only the objects that a user selects will be visible in the application's window.  I believe it has something to do with getting the objectIds of objects within the block.  I thought it might be a common problem so have posted it here.  I am still investigating and will post a solution if I find one.

Glenn R

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #6 on: October 28, 2008, 06:23:01 AM »
I for one would definitely not be doing it this way for several reasons:

1. If your program fails, you need code to get back the objects turned off.
2. Confusing to the user as they would use layers.
3. Use layers instead.

If you must continue down this route, try separating the loop to turn the selected objects visible out into it's own transaction and see what happens with that as an initial step.

Glenn R

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #7 on: October 28, 2008, 06:24:51 AM »
You also don't mention:

Visual Studio version
.NET Framework version
AutoCAD version

Glenn R

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #8 on: October 28, 2008, 07:01:53 AM »
The below works for me on your test drawing on the cylinder. I am using AutoCAD 2009, Visual C# 2008 Express and .Net Framework 3.5:

Code: [Select]
[CommandMethod("MakeInvisible", CommandFlags.NoPaperSpace)]
        public static void MakeInvisibleCommand()
        {
            PromptSelectionOptions pso = new PromptSelectionOptions();
            pso.RejectObjectsOnLockedLayers = false;
            pso.MessageForAdding = "Select objects to isolate: ";
            pso.MessageForRemoval = "Select objects to remove: ";

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

            // ask the question
            PromptSelectionResult psr = ed.GetSelection(pso);
            if (psr.Status != PromptStatus.OK)
                return;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord modelspaceBTR = tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead, false) as BlockTableRecord;
                if (modelspaceBTR == null)
                {
                    return;
                }

                foreach (ObjectId btrId in modelspaceBTR)
                {
                    Entity modelspaceEnt = tr.GetObject(btrId, OpenMode.ForWrite, false) as Entity;
                    if (modelspaceEnt == null)
                    {
                        continue;
                    }

                    modelspaceEnt.Visible = false;
                }

                ObjectId[] selectedIds = psr.Value.GetObjectIds();

                foreach (ObjectId selectedId in selectedIds)
                {
                    Entity modelspaceEnt = tr.GetObject(selectedId, OpenMode.ForWrite, false) as Entity;
                    if (modelspaceEnt == null)
                    {
                        continue;
                    }

                    modelspaceEnt.Visible = true;
                }
               
                tr.Commit();
            }
        }


It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8738
  • AKA Daniel
Re: Isolate Objects - Block Being Disobediant
« Reply #9 on: October 28, 2008, 07:32:49 AM »
interesting, prmptSSopt.PrepareOptionalDetails = true;  was the problem  :-o

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8738
  • AKA Daniel
Re: Isolate Objects - Block Being Disobediant
« Reply #10 on: October 28, 2008, 07:35:54 AM »
here is another approach

Code: [Select]
CommandMethod("doit")]
    static public void doit()
    {
      Editor ed = AcAp.Application.DocumentManager.MdiActiveDocument.Editor;
      Database db = HostApplicationServices.WorkingDatabase;
      try
      {
        PromptSelectionOptions prmptSSopt = new PromptSelectionOptions();
        //prmptSSopt.PrepareOptionalDetails = true;
        prmptSSopt.RejectObjectsOnLockedLayers = false;
        prmptSSopt.MessageForAdding = "\nSelect objects to isolate: ";
        PromptSelectionResult ssRes = ed.GetSelection(prmptSSopt);

        if (ssRes.Status != PromptStatus.OK)
          return;

        SelectionSet ss = ssRes.Value;

        List<ObjectId> ids = new List<ObjectId>(ss.GetObjectIds());

        AcDb.TransactionManager manager = db.TransactionManager;
        using (Transaction transaction = manager.StartTransaction())
        {
          BlockTableRecord btr = transaction.GetObject
            (SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead) as BlockTableRecord;

          foreach (ObjectId id in btr)
          {
            Entity ent = transaction.GetObject(id, OpenMode.ForWrite) as Entity;
            if (ent != null && !(ids.Contains(id)))
            {
              ent.Visible = false;
            }
          }
          transaction.Commit();
        }
      }
      catch (System.Exception ex)
      {
        ed.WriteMessage("\n" + ex.Message);
        ed.WriteMessage("\n" + ex.StackTrace);
      }
    }


Glenn R

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #11 on: October 28, 2008, 07:36:03 AM »
More than likely as it sets the ':N' option of acedSSGet.
That was pretty much my only difference to the original code Dan.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8738
  • AKA Daniel
Re: Isolate Objects - Block Being Disobediant
« Reply #12 on: October 28, 2008, 07:37:21 AM »
Thanks master Glenn, this one had me stumped to. PS do you know the ARX equivalent of prmptSSopt.PrepareOptionalDetails?

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8738
  • AKA Daniel
Re: Isolate Objects - Block Being Disobediant
« Reply #13 on: October 28, 2008, 07:37:41 AM »
 :lol:

Glenn R

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #14 on: October 28, 2008, 07:38:56 AM »
Does the above explain it Dan? :)

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8738
  • AKA Daniel
Re: Isolate Objects - Block Being Disobediant
« Reply #15 on: October 28, 2008, 07:41:55 AM »
Does the above explain it Dan? :)

Yes sir, thank you!!!

Code: [Select]
static void CRPDArxIterate_doit(void)
  {
    Acad::ErrorStatus es;
    long ssLength = 0;

    ads_name sel,ent;
    AcDbObjectId objId, entId, tableRecordId;
    AcDbObjectIdArray ids;

    TCHAR* prompt[] = {_T("\nSelect Objects: "), _T("\nRemove Objects: ")};
    TCHAR* mode = _T(":N:$"); //<<<<----------------------------

    if (acedSSGet(mode, prompt, NULL, NULL, sel) != RTNORM) {
      return;
    }

    if (acedSSLength(sel, &ssLength) != RTNORM || ssLength == 0) {
      acedSSFree(sel);
      return;
    }

    for (long i = 0; i < ssLength; i++){
      acedSSName(sel, i, ent);
      acdbGetObjectId(objId, ent);
      ids.append(objId);
    }

    AcDbDatabase *pDatabase = acdbHostApplicationServices()->workingDatabase();

    //++-- Delete me!
    AcDbBlockTableIterator *pBlockTableIterator = NULL;
    AcDbBlockTableRecordIterator *pBlockTableRecordIterator = NULL;

    AcDbBlockTablePointer pBlockTable(pDatabase,AcDb::kForRead);
    pBlockTable->newIterator(pBlockTableIterator);

    for (pBlockTableIterator->start();
        !pBlockTableIterator->done();
         pBlockTableIterator->step())
    {
      pBlockTableIterator->getRecordId(tableRecordId);
      AcDbBlockTableRecordPointer pTableRecord(tableRecordId,AcDb::kForRead);
      if (es == Acad::eOk)
      {
        AcDbBlockTableRecordIterator *pBlockTableRecordIterator = NULL;
        pTableRecord->newIterator(pBlockTableRecordIterator);

        for (pBlockTableRecordIterator->start();
            !pBlockTableRecordIterator->done();
             pBlockTableRecordIterator->step())
        {
          es = pBlockTableRecordIterator->getEntityId(entId);
          if(!ids.contains(entId) && es == Acad::eOk)
          {
            AcDbEntityPointer pEnt(entId,AcDb::kForWrite,Adesk::kFalse);
            pEnt->setVisibility(kInvisible);
          }
        }
      }
    }
    delete pBlockTableIterator;
    delete pBlockTableRecordIterator;
    acedSSFree(sel);
  }

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8738
  • AKA Daniel
Re: Isolate Objects - Block Being Disobediant
« Reply #16 on: October 28, 2008, 07:47:23 AM »
Quote
":N"
This mode option will cause a subsequent call to acedSSNameX() to provide additional information about container blocks and transformation matrices for any entities selected during the acedSSGet() operation. The additional information will only be available for entities selected via graphical selection methods such as Window, Crossing, point pick, etc.


Hugh_Compton

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #17 on: October 28, 2008, 08:01:02 AM »
Hi Glenn

Your routine works brilliantly...I'm not sure what the difference is yet between yours and mine - I'm going to have to look closely. Thanks! :)

Just out of interest as to why I'm doing this....I'm an ACA user - part of ACA is the ability to isolate / hide / show entities (some of my most common day to day commands).  

It works great but I am trying to make a utility to save visibility states (for instance I might have one state where Pumps are isolated so I can call this 'Pumps Only' and quickly get them in view for working on).  
Using Hide & Isolate in ACA is great but we can't save 'states' i.e. to get only the pumps visible I would have to isolate them each time.  

Visual Studio - 2005 Pro (have 2008 but not using yet)
.Net Framework (sorry, never look at this! using windows XP 64 Pro with all updates)
ACA 2009 / (ACAD 2009 for other users in my company)


TonyT

  • Guest
Re: Isolate Objects - Block Being Disobediant
« Reply #18 on: October 29, 2008, 10:53:57 PM »
Code: [Select]
static void CRPDArxIterate_doit(void)
  {

    <snip>

    for (long i = 0; i < ssLength; i++){
      acedSSName(sel, i, ent);
      acdbGetObjectId(objId, ent);
      ids.append(objId);
    }

    <snip>

  }


Tip:

Instead of the above, you can just do this:

Code: [Select]

     AcDbObjectIdArray ids = acedGetCurrentSelectionSet();




It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8738
  • AKA Daniel
Re: Isolate Objects - Block Being Disobediant
« Reply #19 on: October 30, 2008, 12:08:43 AM »
Wonderful! I actually did a search for something like this. The ODA’s DRX SDK has a nice SelectionSet class
with a method that returns an ObjectIdArray. I knew there had to be a better way in ARX.  8-)

Thanks Tony!