.NET

.NET

Reply
Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 11 of 19 (238 Views)

Re: Will the best code reviewer please stand up

03-06-2013 08:01 PM in reply to: BlackBox_

BlackBoxCAD wrote:

 

Now that that's out of the way, I am correct in that (logically) it is better to perform this task on a valid SelectionSet, rather than iterating the BlockTable, no?

 

Cheers!

 

Edit to add:

 

"Third, you are not modifying the WIPEOUT objects in the selection, and don't need to open them in the first place, because they are all WIPEOUT objects."

 

The code I posted (never mind the duplication of work) _did_ modify the Wipeout entities (not express tools text masks, WIpeouts)... My test was performed on a line drawn with a Wipeout drawn over the top such that part of the line was no longer visible. The code (albeit innefficiently) correctly moved the Wipeout(s) to the back so that the line was fully visible.

 

If I've misunderstood your point, please clarify.


On the first question, if you're working in the drawing editor and operating on objects in the current space, then it makes sense to use SelectAll() with a filter. Of course, sometimes we want our code to work with databases that aren't open in the editor, which precludes using object selection or selection filtering, and requires that we iterate over BlockTableRecord objects directly and operate on those objects of interest, as Alex's code does. So, the answer is 'It depends".

 

In the code you posted, the WIPEOUT objects are not modified. You are opening them with OpenMode.ForRead.

 

To modify the draw order of an object, you don't have to modify the object, only the DrawOrderTable.

 

Distinguished Mentor
BlackBox_
Posts: 785
Registered: ‎02-25-2013
Message 12 of 19 (233 Views)

Re: Will the best code reviewer please stand up

03-06-2013 08:12 PM in reply to: DiningPhilosopher

To the first point; I fully understand this... Been using ObjectDBX (LISP) for years. I fully agree.

 

To the second part, many thanks for the clarification... First time in the draw order water; greatly appreciate the education.

 

Cheers!



"Potential has a shelf life." - Margaret Atwood


Autodesk Exchange Apps ~ Autoloader ~ AutoCAD Security


AutoCAD® 2014, and Civil 3D® 2014 Certified Professional ~ Autodesk® Authorized Developer

Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 13 of 19 (231 Views)

Re: Will the best code reviewer please stand up

03-06-2013 08:39 PM in reply to: BlackBox_

One minor problem with the sample I posted, is that SelectAll() selects objects in both model and paper space, which is a problem since the code is operating only on the DrawOrderTable of the current space.

 

Here's the corrected version that gets around that problem:

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;

namespace Autodesk.AutoCAD.ApplicationServices.MyExtensions
{
   public static class WipeOutOrderExample
   {
      [CommandMethod( "WIPEOUTORDER" )]
      public static void WipeoutOrderCommand()
      {
         Document doc = Application.DocumentManager.MdiActiveDocument;
         Editor ed = doc.Editor;

         using( Transaction tr = doc.Database.TransactionManager.StartTransaction() )
         {

            BlockTableRecord btr = (BlockTableRecord)
               tr.GetObject( doc.Database.CurrentSpaceId, OpenMode.ForRead );
               
            Layout layout = (Layout) tr.GetObject( btr.LayoutId, OpenMode.ForRead );

            TypedValue[] array = new TypedValue[] {
               new TypedValue( 0, "WIPEOUT" ),
               new TypedValue( 410, layout.LayoutName ) 
            };

            PromptSelectionResult psr = ed.SelectAll( new SelectionFilter( array ) );

            if( psr.Status != PromptStatus.OK || psr.Value == null || psr.Value.Count == 0 )
            {
               ed.WriteMessage( "\nNo WIPEOUT objects found in current space." );
               tr.Commit();
               return;
            }

            ed.WriteMessage( "\n{0} WIPEOUTs found,", psr.Value.Count );
            PromptKeywordOptions pko = new PromptKeywordOptions( "\nMove to Top or Bottom?" );
            pko.Keywords.Add( "Top" );
            pko.Keywords.Add( "Bottom" );
            pko.Keywords.Default = "Bottom";
            PromptResult pr = ed.GetKeywords( pko );
            if( pr.Status != PromptStatus.OK )
            {
               tr.Commit();
               return;
            }

            bool top = pr.StringResult == "Top";

            ObjectIdCollection ids = new ObjectIdCollection( psr.Value.GetObjectIds() );

            DrawOrderTable dot = (DrawOrderTable)
               tr.GetObject( btr.DrawOrderTableId, OpenMode.ForWrite );

            if( top )
               dot.MoveToTop( ids );
            else
               dot.MoveToBottom( ids );

            tr.Commit();
            doc.Editor.WriteMessage( "Modified draw order of {0} WIPEOUTs", ids.Count );
         }
      }
   }
}

 

Moderator
Alexander.Rivilis
Posts: 1,451
Registered: ‎04-09-2008
Message 14 of 19 (224 Views)

Re: Will the best code reviewer please stand up

03-06-2013 10:19 PM in reply to: BlackBox_

BlackBoxCAD wrote:
Why iterate the entire BlockTable, when one could iterate a simple SelectionSet?

In addition to  Tony (DiningPhilosopher)  posts, I would like say that with SelectionSet you can not select entities within the block definition. So if you have to process ALL wipeouts in Database - you have to iterate the entire BlockTable (there is another way, but it looks more like a hack).


Пожалуйста не забывайте про Утвердить в качестве решения! Утвердить в качестве решения и Give Kudos!Баллы
Please remember to Accept Solution! Accept as Solution and Give Kudos!Kudos

Valued Mentor
jeff
Posts: 338
Registered: ‎05-12-2009
Message 15 of 19 (197 Views)

Re: Will the best code reviewer please stand up

03-07-2013 05:51 PM in reply to: area51visitor

First off I am far from the best code reviewer and secondly it is easier for my to type sitting down instead of standing up.

 

No need to open everything for write.

 

For a little info on casting,

 

You have your explicit cast -> (string)word.....

which will try to cast and either succeed or throw an InvalidCastException.

 

If you look at the 'is' operator in IL it tries the explicit cast then compares result with null.

The  'as' operator will return null instead of throwing an InvalidCastException.

So the is operator tries the cast and if it succeeds it throws away the casted result and returns true and then turn around and  cast it again, but with as operator it preserves it or returns null.

Depending on how the 'as' operator is used you can  prevent yourself from knowing if it was a failed cast or from passing a null value as the argument.

 

Some of the guys put wipeouts inside alot of their block definitions and use them for covering up objects under the "open areas" of a block insertion(A example is like a keyed not in a busy area with a wipeout under circle or hexagon and attribute).

 

I do not know what causes it and just pops up here and there, but for some reason the wipeout makes it way up to the front and starts covering up the entites in the block definition.

 

Obviously Alex and Tony know better than i do but I do not see how using SelectAll is any better especially in this case.

Do you guys perfer calling SelectAll or iterating yourself? 

I thought it was more efficient and flexible to iterate and filter yourself instead of SelectAll which has to do the same thing?

In this case the only object being open for write is the DrawOrderTable so no benefit of filtering for entities on locked layers, and where you are not asking user for a selection,

would you guys just iterate yourself?

 

 

 

You can also find your answers @ TheSwamp
Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 16 of 19 (186 Views)

Re: Will the best code reviewer please stand up

03-07-2013 08:55 PM in reply to: jeff

If you need to move wipeouts in any block or all blocks, there's no choice.

 

The code I posted was simply to show a more-efficient version of what BlockBox posted, to illustrate the comments I had on that. But, what that code does could be done by one line of LISP.

Distinguished Mentor
BlackBox_
Posts: 785
Registered: ‎02-25-2013
Message 17 of 19 (182 Views)

Re: Will the best code reviewer please stand up

03-07-2013 10:00 PM in reply to: DiningPhilosopher

I really appreciate the discussion, and the clarifying of different points of view (i.e., how others utilize wipeouts, etc.)... Very informative, and prompts me to factor in other considerations when developing for myself, or attempting to help others.

 

This has been very educational, gentlemen - Cheers!



"Potential has a shelf life." - Margaret Atwood


Autodesk Exchange Apps ~ Autoloader ~ AutoCAD Security


AutoCAD® 2014, and Civil 3D® 2014 Certified Professional ~ Autodesk® Authorized Developer

Valued Mentor
jeff
Posts: 338
Registered: ‎05-12-2009
Message 18 of 19 (175 Views)

Re: Will the best code reviewer please stand up

03-07-2013 11:30 PM in reply to: BlackBox_

I gotcha there Tony I just meant in general if you had to filter entites within the current space and were not prompting for user to select which method you perfered using SelectAll or iterating yourself.

 

 

Dug up what I had laying around for personal use that I put in certain projects until I figure out if it is useful or how to bettter implement it.

 

Thanks again to Tony as it uses ideas expressed by him and from code examples he has posted.

 

        [CommandMethod("WipeOutToBack")]
        public void WipeOutToBack()
        {
            using (Transaction trx = Doc.TransactionManager.StartTransaction())
            {
                BlockTable bt = Db.BlockTable();
                var blks = bt.GetBlockTableRecords().LocallyDefinedBlocks();

                foreach (BlockTableRecord btr in blks)
                {
                    ObjectId[] idArr = btr.GetObjectIds<Wipeout>().ToArray();
                    ObjectIdCollection ids = new ObjectIdCollection(idArr);
                    if (ids.Count > 0)
                    {
                        DrawOrderTable dot = btr.DrawOrderTableId.GetDBObject<DrawOrderTable>(OpenMode.ForWrite);
                        dot.MoveToBottom(ids);
                    }
                }

                trx.Commit();
            }

            Ed.Regen();
        }

 Extenion methods should be self-explainatory except for maybe ones below

 

public static IEnumerable<ObjectId> GetObjectIds<T>(this BlockTableRecord btr) where T : Entity
        {
            IntPtr impobj = RXClass.GetClass(typeof(T)).UnmanagedObject;
            foreach (ObjectId id in btr)
            {
                if (id.ObjectClass.UnmanagedObject == impobj)
                {
                    yield return id;
                }
            }
        }

        /// <summary>
        /// Author: Tony Tanzillo
        /// Source: http://www.theswamp.org/index.php?topic=41311.msg464529#msg464529
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<BlockTableRecord> UserDefinedBlocks(this IEnumerable<BlockTableRecord> source)
        {
            return source.Where(btr =>
                !(
                btr.IsDependent ||
                btr.IsAnonymous ||
                btr.IsFromExternalReference ||
                btr.IsFromOverlayReference ||
                btr.IsLayout ||
                btr.IsAProxy
                )
                );
        }

        /// <summary>
        /// Author: Tony Tanzillo
        /// Source: http://www.theswamp.org/index.php?topic=41311.msg464529#msg464529
        /// Use instead of UserDefinedBlocks when anonymous blocks are needed
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<BlockTableRecord> LocallyDefinedBlocks(this IEnumerable<BlockTableRecord> source)
        {
            return source.Where(btr =>
                !(
                btr.IsDependent ||
                btr.IsFromExternalReference ||
                btr.IsFromOverlayReference ||
                btr.IsLayout ||
                btr.IsAProxy
                )
                );
        }

 

You can also find your answers @ TheSwamp
Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 19 of 19 (153 Views)

Re: Will the best code reviewer please stand up

03-08-2013 04:30 PM in reply to: jeff

I would use a SelectionSet with filtering when working on drawings open in the editor, but I would separate that from the code that does the work, so that it could be used with both an array of ObjectIds from SelectionGet.GetObjectIds(), or from the IEnumerator of a BlockTableRecord.

 

So, with the various LINQ extension methods I use, like GetObjects<T>( this IEnumerable<ObjectId>, ...), I can operate on a sequence of ObjectIds that come from a SelectionSet's GetObjectIds() method, or from BlockTableRecord.Cast<ObjectId>().

 

The important things for me are, separation, separation, and separation. I keep the code that operationes on DBObjects seperate from the code that produces them.

 

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Do you have 60 seconds to spare? The Autodesk Community Team is revamping our site ranking system and we want your feedback! Please click here to launch the 5 question survey. As always your input is greatly appreciated.