找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 875|回复: 1

[分享] ObjectIdFilter

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-6-11 23:23:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
/// ObjectIdFilter.cs   Copyright (c)  2012  Tony Tanzillo

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

/// <summary>
///
/// ObjectIdFilter class
///
/// Used to efficiently do simple and complex filtering
/// of ObjectIds based on associated managed wrapper types.
///
/// This class helps to simplify Linq code that performs
/// complex filtering of ObjectIds based on the associated
/// managed wrapper type of each ObjectId.
///
/// An example:
///
///    BlockTableRecord btr = //.. (open some BlockTableRecord)
///   
///    // Get a filter that includes only entities
///    // whose managed wrappers are derived from
///    // AutoDesk.AutoCAD.DatabaseServices.Curve:
///   
///    ObjectIdFilter curveFilter = new ObjectIdFilter<Curve>();
///   
///    // Get an object that enumerates the ObjectIds
///    // of all Curve objects in the BlockTableRecord:
///   
///    var curveIds = btr.Cast<ObjectId>().Where( curveFilter.Predicate );
///   
///    // In AutoCAD 2013 or later, the above line can
///    // be reduced to:
///   
///    var curveIds = btr.Where( curveFilter.Predicate );
///   
///    // Additionally, in all AutoCAD releases, the
///    // GetObjectIds() method of the ObjectIdFilter
///    // class can be used to do the equivalent:
///   
///    var curveIds = curveFilter.GetObjectIds( btr );
///
/// Complex Filtering Criteria:
///
/// The ObjectIdFilter class as used above offers little
/// advantages over explicit testing of each ObjectId's
/// ObjectClass property with standard Linq methods, but
/// the ObjectIdFilter was actually created to simplify
/// a more-complicated problem, which involves filtering
/// against multiple types, both related and unrelated;
/// filtering against types derived from multiple types;
/// and being more-selective, by explicitly including or
/// excluding certain specified types individually.
///
/// For example, the following filter will include only
/// the ObjectIds of Lines, Arcs, and Polylines:
///
///    var curveSubSetFilter = new ObjectIdFilter(
///                  typeof( Line ),
///                  typeof( Arc ),
///                  typeof( Polyline )
///         );
///         
/// Overriding Criteria:
///
/// The ObjectIdFilter allows the programmer to override
/// criteria that includes or excludes all types derived
/// from a given type, to specifically include or exclude
/// one or more derived types, on a type-by-type basis.
///
/// This example includes all types of Dimensions except
/// for OrdinateDimensions using an overriding criteria:
///
///   // Define an ObjectIdFilter with the sole criteria
///   // that includes all types derived from Dimension:
///   
///   ObjectIdFilter dimfilter = new ObjectIdFilter<Dimension>();
///   
///   // Override the criteria that includes all types
///   // derived from Dimension, to exclude Ordinate
///   // dimensions:
///   
///   dimfilter[typeof(OrdinateDimension)] = false;
///   
/// Overriding criteria can also override other
/// overriding criteria.
///   
/// The next example uses an override on a filter that
/// includes all Curve types, to exclude Splines and all
/// types derived from Spline, and then overrides that
/// criteria to specifically include Helixes, which are
/// derived from Spline:
///
///   var myFilter = new ObjectIdFilter<Curve>();
///   
///   // allow/disallow types derived from those
///   // types that are explicitly-included or
///   // excluded:
///   
///   myFilter.ExactMatch = false;
///   
///   // Add an override that excludes Splines and
///   // all types derived from Spline:
///   
///   myFilter[typeof(Spline)] = false;
///   
///   // we then override the above override that excludes
///   // Spline and all derived types, to specifically
///   // include Helixes (which are derived from Spline):
///   
///   myFilter[typeof(Helix)] = true;
///   
/// The the above example defines a filter that
/// includes all Curves, including Helixes, but
/// not Splines or any other type derived from
/// Spline. and is functionally-equivalent to
/// this delegate:
///
/// bool IsCurveOrNotSplineExceptHelix( ObjectId id )
/// {
///    RXClass curveClass = RXClass.GetClass(typeof(Curve));
///    RXClass splineClass = RXClass.GetClass(typeof(Spline));
///    RXClass helixClass = RXClass.GetClass(typeof(Helix));
///   
///    RXClass objectClass = id.ObjectClass;
///   
///    return objectClass.IsDerivedFrom( curveClass )
///           && ( ! objectClass.IsDerivedFrom( splineClass )
///                  || objectClass.IsDerivedFrom( helixClass ) );
/// }
///
/// As unrealistic as it is, the above example serves to
/// demonstrate the degree of granularity that can easily
/// be achieved using the ObjectIdFilter with overriding
/// criteria.
///
/// This next example uses two overriding criteria to
/// include all Curve objects EXCEPT XLines and Rays:
///
///   var myFilter = new ObjectIdFilter<Curve>();
///   myFilter[typeof(XLine)] = false;
///   myFilter[typeof(Ray)] = false;
///   
/// The predicate generated by ObjectIdFilter in the
/// above example does what this delegate does:
///
/// bool IsCurveExceptXLineOrRay( ObjectId id )
/// {
///    RXClass curveClass = RXClass.GetClass(typeof(Curve));
///    RXClass rayClass = RXClass.GetClass(typeof(Ray));
///    RXClass xlineClass = RXClass.GetClass(typeof(XLine));
///   
///    RXClass objectClass = id.ObjectClass;
///    return objectClass.IsDerivedFrom( curveClass )
///           && objectClass != rayClass
///           && objectClass != xlineClass;
/// }
///
/// Note that the equivalent predicates are relatively-complex
/// in contrast to the ObjectIdFilter, and yet ObjectIdFilter
/// is as fast, and in some cases faster than the direct use
/// of hand-coded predicates when used with the Linq Where()
/// function.
///
/// Performance:
///
/// The performance of ObjectIdFilter is comparable to the
/// performance of explicit, hand-coded predicates in most
/// use cases, and can be faster in some, mainly those that
/// involve expensive predicates. The basic purpose of this
/// class is not to out-perform other methods of filtering,
/// but more for the purpose of simplifying the writing of
/// code that defines the criteria, and to support dynamic
/// composition of filters based on criteria that is unknown
/// at compile-time, and would otherwise require complicated
/// means to achieve.
///
/// </summary>

namespace Autodesk.AutoCAD.DatabaseServices
{
        public class ObjectIdFilter<T> : ObjectIdFilter
                where T : DBObject
        {
                public ObjectIdFilter( bool exact = false )
                        : base( exact, typeof( T ) )
                {
                }
        }

        public class ObjectIdFilter : ICollection<Type> // IDictionary<Type, bool> (work in progress)
        {
                bool exactMatch = false;
                Dictionary<Type, bool> types = null;
                Dictionary<IntPtr, Type> typemap = null;
                Dictionary<IntPtr, bool> cache = new Dictionary<IntPtr, bool>();
                RXClass rxclass = null;
                IntPtr rxclassPtr = IntPtr.Zero;
                IntPtr rootClass = RXClass.GetClass( typeof( DBObject ) ).MyParent.UnmanagedObject;
                bool validated = false;

                /// If only one Type is provided, exactMatch defaults
                /// to false. Otherwise, it defaults to true.

                public ObjectIdFilter( params Type[] items )
                        : this( defaultExactMatch( items ), items )
                {
                }

                /// <summary>
                /// If exactMatch is true, types derived from any of
                /// the specified types do not match.
                /// </summary>

                public ObjectIdFilter( bool exactMatch, params Type[] types )
                {
                        if( types == null || types.Length == 0 )
                                types = new Type[0];
                        else
                        {
                                if( !types.All( type => type.IsSubclassOf( typeof( DBObject ) ) ) )
                                        throw new ArgumentException( "Type must derive from DBObject" );
                        }
                        this.types = types.ToDictionary( t => t, t => true );
                        Invalidate();
                }

                Func<ObjectId, bool> predicate = null;

                public Func<ObjectId, bool> Predicate
                {
                        get
                        {
                                Update();
                                return this.predicate;
                        }
                }

                /// <summary>
                ///
                /// Indicates if types derived from types contained
                /// in the match set are treated the same as the base
                /// types in the match set.
                ///
                /// If true, derived types inherit the criteria of then
                /// nearest base type contained in the match set.  If
                /// multiple base types of a derived type are present in
                /// the match set, the derived type inherits the critera
                /// of the most-immediate base type.
                ///
                /// If false, derived types are treated as distinct types
                /// that must have an entry in the match set in order for
                /// the filter to explicitly include or exclude them.
                ///
                /// </summary>

                public bool ExactMatch
                {
                        get
                        {
                                return exactMatch;
                        }
                        set
                        {
                                if( value != exactMatch )
                                {
                                        exactMatch = value;
                                        Invalidate();
                                }
                        }
                }

                /// <summary>
                ///
                /// Adds a managed wrapper type to the filter
                /// that specifies that managed wrappers of the
                /// given type match the filter.
                ///
                /// If the ExactMatch property is false, all
                /// managed wrappers whose type is derived from
                /// the given type also match the filter.
                ///
                /// The given type must be a type derived from
                /// DBObject.
                ///
                /// </summary>

                public void Add( Type type )
                {
                        Add( type, true );
                }

                /// <summary>
                ///
                /// Adds a managed wrapper type to the filter
                /// and a value that specifies if managed wrappers
                /// of the given type match the filter.
                ///
                /// If the value of the include argument is true,
                /// managed wrappers of the specified type match
                /// the filter.
                ///
                /// If the value of the include argument is false,
                /// managed wrappers of the specified type do not
                /// match the filter.
                ///
                /// If the ExactMatch property is false, the include
                /// argument applies to all managed wrappers whose
                /// runtime type is the given type, or any type that
                /// is derived from the given type.
                ///
                /// The given type must be a type derived from DBObject.
                ///
                /// </summary>

                public void Add( Type type, bool include )
                {
                        if( type == null )
                                throw new ArgumentNullException( "type" );
                        if( types.ContainsKey( type ) )
                                throw new ArgumentException( "Specified type is already present" );
                        if( !type.IsSubclassOf( typeof( DBObject ) ) )
                                throw new ArgumentException( "Specified type must be derived from DBObject" );
                        types.Add( type, include );
                        Invalidate();
                }

                /// <summary>
                ///
                /// Removes the specied type from the filter set,
                /// if it contains the type.
                ///
                /// </summary>

                public bool Remove( Type type )
                {
                        if( type == null )
                                throw new ArgumentNullException( "type" );
                        if( types.Remove( type ) )
                        {
                                Invalidate();
                                return true;
                        }
                        return false;
                }

                /// <summary>
                ///
                /// Associates a value with a type key, indicating if
                /// ObjectIds whose managed wrapper types are instances
                /// of the given type (or a derived type if ExactMatch
                /// is false) match the filter.
                ///
                /// Pass true/false to include/exclude managed wrappers of
                /// the given type (and all derived types, if ExactMatch
                /// is false).
                ///
                /// If ExactMatch is false, ObjectIds whose managed
                /// wrapper types are derived from the specified type
                /// implicitly inherit the assigned value.
                ///
                /// To exclude a given type (and optionally, all derived
                /// types if ExactMatch = false) from the filter, pass
                /// false with the type.
                ///
                /// </summary>

                public bool this[Type type]
                {
                        get
                        {
                                bool result = false;
                                types.TryGetValue( type, out result );
                                return result;
                        }
                        set
                        {
                                bool current = false;
                                if( !types.TryGetValue( type, out current ) || current != value )
                                {
                                        types[type] = value;
                                        Invalidate();
                                }
                        }
                }

                /// <summary>
                ///
                /// Returns an object that enumerates all matching ObjectIds
                /// in the given BlockTableRecord.
                ///
                /// Note:
                ///
                /// In AutoCAD 2013 or later, this method results in an ambiguous
                /// match error in the compiler because in AutoCAD 2013 or later,
                /// the BlockTableRecord supports IEnumerable<ObjectId>, for which
                /// there is an overload of GetObjectIds() included below.
                ///
                /// So, this method can be commented out or removed when targeting
                /// AutoCAD 2013 or later. If you leave the method in you can avoid
                /// the compiler error by using Cast<ObjectId>().
                ///
                /// </summary>

                public IEnumerable<ObjectId> GetObjectIds( BlockTableRecord btr )
                {
                        Func<ObjectId, bool> func = this.Predicate;
                        foreach( ObjectId id in btr )
                        {
                                if( func( id ) )
                                        yield return id;
                        }
                }

                /// <summary>
                ///
                /// Returns an object that enumerates all matching
                /// ObjectIds in the given sequence.
                ///
                /// </summary>

                public IEnumerable<ObjectId> GetObjectIds( IEnumerable<ObjectId> source )
                {
                        if( source == null )
                                throw new ArgumentNullException( "source" );
                        return source.Where( this.Predicate );
                }

                /// <summary>
                ///
                /// Enumerate the matching ObjectIds contained in all
                /// BlockTableRecords whose ObjectIds are passed in the
                /// arguments. All BlockTableRecord ObjectIds must be
                /// from the same database.
                ///
                /// Requires an active transaction in the database
                /// which the BlockTableRecords are from.
                ///
                /// </summary>

                public IEnumerable<ObjectId> GetObjectIds( params ObjectId[] blockTableRecordIds )
                {
                        if( blockTableRecordIds == null )
                                throw new ArgumentNullException( "blockTableRecordIds" );
                        RXClass btrClass = RXClass.GetClass( typeof( BlockTableRecord ) );
                        if( !blockTableRecordIds.All( id => id.ObjectClass.IsDerivedFrom( btrClass ) ) )
                                throw new ArgumentException( "Requires the ObjectId of one or more BlockTableRecords" );
                        if( blockTableRecordIds.Length > 0 )
                        {
                                Transaction tr = blockTableRecordIds[0].Database.TransactionManager.TopTransaction;
                                if( tr == null )
                                        throw new Autodesk.AutoCAD.Runtime.Exception( ErrorStatus.NoActiveTransactions );
                                Func<ObjectId, bool> func = this.Predicate;
                                foreach( var btrId in blockTableRecordIds )
                                {
                                        BlockTableRecord btr = (BlockTableRecord) tr.GetObject( btrId, OpenMode.ForRead );
                                        foreach( ObjectId id in btr )
                                        {
                                                if( func( id ) )
                                                        yield return id;
                                        }
                                }
                        }
                }

                /// <summary>
                /// Debugging-only APIs
                /// </summary>

                [Flags]
                public enum MatchFlags
                {
                        Subclass = 0,
                        Exact = 1,
                        Multiple = 2,
                        Negated = 4
                }

                public int CacheCount
                {
                        get
                        {
                                return cache != null ? cache.Count : 0;
                        }
                }

                public MatchFlags MatchType
                {
                        get;
                        protected set;
                }

                ////////////////////////////////////////////////////////
                /// Dynamic Predicate Selection:
                ///
                /// One of the following five methods is returned as
                /// the value of the Predicate property, and is used
                /// to determine if an ObjectId matches the filter,
                /// depending on the number of types being matched
                /// against, and whether exact matching is used.

                ///////////////////////////////////////////////////////////
                /// Case 1: Used when only one Type is present in the
                /// match set, and exact matching is in use.
                ///
                /// Exact matching is used if it has been explicitly
                /// specified, or if the type(s) being filtered are
                /// not abstract, and there are no runtime classes
                /// derived from their associated runtime class.

                bool matchExact( ObjectId id )
                {
                        return id.ObjectClass.UnmanagedObject == rxclassPtr;
                }

                ///////////////////////////////////////////////////////////
                /// Case 2: Used when only one Type is present in the
                /// match set, exact matching is in use, and the type
                /// is specified to be excluded (e.g., everything but
                /// the specified type matches the filter).

                bool negatedMatchExact( ObjectId id )
                {
                        return id.ObjectClass.UnmanagedObject != rxclassPtr;
                }

                ///////////////////////////////////////////////////////////
                /// Case 3: Used when only one Type is present in the
                /// match set, and exact matching is not being used.

                bool match( ObjectId id )
                {
                        RXClass objclass = id.ObjectClass;
                        bool result;
                        if( !cache.TryGetValue( objclass.UnmanagedObject, out result ) )
                                result = cache[objclass.UnmanagedObject] = objclass.IsDerivedFrom( rxclass );
                        return result;
                }

                ///////////////////////////////////////////////////////////
                /// Case 4: Used when the match set contains multiple types
                /// and exact matching is used. A managed wrapper matches the
                /// filter if its runtime class is in the match set, and that
                /// type is specified to be included. Managed wrappers whose
                /// types are derived from types in the match set do not match.

                bool matchManyExact( ObjectId id )
                {
                        bool result = false;
                        cache.TryGetValue( id.ObjectClass.UnmanagedObject, out result );
                        return result;
                }

                ///////////////////////////////////////////////////////////
                /// Case 5: Used in the most-complex (and least-common)
                /// scenario: Matching aginst multiple types, and all
                /// of their derived types.
                ///
                /// In this scenario, a managed wrapper matches if its
                /// runtime type or any of its base types are contained
                /// in the match set and the type is included.
                ///
                /// While this code is relatively-expensive, it only
                /// needs to be called once for each distinct runtime
                /// class encountered in the set of ObjectIds that are
                /// being filtered. The result is cached and used for
                /// all subsequently-encountered instances of the same
                /// runtime class.
                ///
                /// This predicate can be significantly-faster than an
                /// equivalent hand-coded predicate, largely due to
                /// caching and reusing the result with all instances
                /// of the same runtime class.

                bool matchMany( ObjectId id )
                {
                        bool result;
                        if( !cache.TryGetValue( id.ObjectClass.UnmanagedObject, out result ) )
                        {
                                RXClass objectClass = id.ObjectClass;

                                /// Look in the match set for the nearest parent
                                /// runtime class, and if found, use its value:

                                RXClass parent = objectClass.MyParent;
                                IntPtr ptr = parent.UnmanagedObject;
                                while( ptr != rootClass && !typemap.ContainsKey( ptr ) )
                                {
                                        parent = parent.MyParent;
                                        ptr = parent.UnmanagedObject;
                                }
                                if( ptr != rootClass )
                                        result = cache[ptr];
                                cache[objectClass.UnmanagedObject] = result;
                        }
                        return result;
                }

                /// <summary>
                ///
                /// Assigned to the predicate when the instance has been
                /// invalidated. The use of the predicate will cause the
                /// cache to be rebuilt, and the match predicate to be
                /// recomputed and reassigned to the predicate.
                ///
                /// </summary>

                bool Invalid( ObjectId id )
                {
                        Update();
                        if( predicate == null || predicate == this.Invalid )
                                throw new InvalidOperationException( "Somthing is terribly wrong" );
                        return predicate( id );
                }

                /// <summary>
                ///
                /// Invalidates the filter and with that, any previously-
                /// obtained references to the Predicate property. This
                /// method generally does not have to be called by the
                /// user, because any change that is made to the filter
                /// will implicitly invalidate it.
                ///
                /// </summary>

                public void Invalidate()
                {
                        predicate = Invalid;
                        validated = false;
                }

                /// <summary>
                ///
                /// Updates the filter and invalidates the current
                /// predicate. If this method is called, any previously-
                /// obtained reference to the Predicate property is no
                /// longer valid and should be discarded or reassigned
                /// to the current value of that property after the call
                /// to this method returns.
                ///
                /// </summary>

                public void Update()
                {
                        if( validated )
                                return;
                        validated = true;
                        MatchType = 0;
                        if( types.Count == 0 )
                        {
                                predicate = id => false;
                                return;
                        }
                        typemap = types.Keys.ToDictionary( t => GetRXClassPtr( t ), t => t );
                        cache = types.ToDictionary( p => GetRXClassPtr( p.Key ), p => p.Value );
                        bool exact = GetMatchExact();
                        if( types.Count == 1 )
                        {
                                var pair = types.Single();
                                rxclass = GetRXClass( pair.Key );
                                rxclassPtr = rxclass.UnmanagedObject;
                                if( exact )
                                {
                                        if( pair.Value )
                                        {
                                                predicate = matchExact;
                                        }
                                        else
                                        {
                                                predicate = negatedMatchExact;
                                                MatchType |= MatchFlags.Negated;
                                        }
                                }
                                else
                                {
                                        predicate = match;
                                }
                        }
                        else
                        {
                                if( exact )
                                {
                                        predicate = matchManyExact;
                                }
                                else
                                {
                                        predicate = matchMany;
                                }
                                MatchType |= MatchFlags.Multiple;
                        }
                        if( exact )
                                MatchType |= MatchFlags.Exact;
                }

                /// <summary>
                /// Returns true if the given type can use exact matching
                /// </summary>

                bool GetMatchExact( Type type )
                {
                        if( type.IsAbstract )
                                return false;
                        IntPtr impobj = GetRXClass( type ).UnmanagedObject;
                        foreach( DictionaryEntry e in SystemObjects.ClassDictionary )
                        {
                                RXClass entry = ( (RXClass) e.Value ).MyParent;
                                if( entry != null && impobj == entry.UnmanagedObject )
                                        return false;
                        }
                        return true;
                }

                /// <summary>
                /// Returns true if all Types can use exact matching.
                /// </summary>

                bool GetMatchExact()
                {
                        if( types.Count == 0 )
                                return false;
                        if( exactMatch )
                                return true;
                        if( types.Count == 1 )
                                return GetMatchExact( types.Single().Key );
                        if( types.Keys.Any( type => type.IsAbstract ) )
                                return false;
                        foreach( DictionaryEntry e in SystemObjects.ClassDictionary )
                        {
                                RXClass entry = ( (RXClass) e.Value ).MyParent;
                                if( entry != null && typemap.ContainsKey( entry.UnmanagedObject ) )
                                        return false;
                        }
                        return true;
                }

                static IntPtr GetRXClassPtr( Type type, bool check = true )
                {
                        return GetRXClass( type, check ).UnmanagedObject;
                }

                static RXClass GetRXClass( Type type, bool check = true )
                {
                        if( type == null )
                                throw new ArgumentNullException( "type" );
                        if( !typeof( DBObject ).IsAssignableFrom( type ) )
                        {
                                if( check )
                                        throw new ArgumentException( "Requires a type derived from DBObject" );
                                return null;
                        }
                        RXClass result = RXClass.GetClass( type );
                        if( result == null && check )
                                throw new InvalidOperationException( "No runtime class found for type " + type.Name );
                        return result;
                }

                static bool defaultExactMatch( Type[] types )
                {
                        if( types == null )
                                return true;
                        else
                                return types.Length != 1;
                }

                /// ICollection<Type>

                public void Clear()
                {
                        types.Clear();
                        Invalidate();
                }

                public bool Contains( Type item )
                {
                        return types.ContainsKey( item );
                }

                public void CopyTo( Type[] array, int arrayIndex )
                {
                        types.Keys.CopyTo( array, arrayIndex );
                }

                public int Count
                {
                        get
                        {
                                return types.Count;
                        }
                }

                public bool IsReadOnly
                {
                        get
                        {
                                return false;
                        }
                }

                public IEnumerator<Type> GetEnumerator()
                {
                        return types.Keys.GetEnumerator();
                }

                IEnumerator IEnumerable.GetEnumerator()
                {
                        return this.GetEnumerator();
                }

                public static implicit operator Func<ObjectId, bool>( ObjectIdFilter filter )
                {
                        if( filter == null )
                                throw new ArgumentNullException( "right operand" );
                        return filter.Predicate;
                }
        }

}
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 859个

财富等级: 财运亨通

 楼主| 发表于 2014-6-11 23:24:10 | 显示全部楼层
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using System.Diagnostics;

namespace Autodesk.AutoCAD.DatabaseServices
{
        public static class ObjectIdFilterTests
        {
                /// <summary>
                /// Examples and test code for ObjectIdFilter.
                ///
                /// These example uses of ObjectIdFilter are tested
                /// against equivalent conventional code that performs
                /// the same operation, to verify that the results are
                /// consistent and equivalent and to compare relative
                /// performance of the ObjectIdFilter and manual code.
                ///
                /// Using these tests reuires a drawing with a significant
                /// number of objects of each type that is dealt with in
                /// each of the tests. The test drawing that was used to
                /// develop these tests contained ~250,000 entities that
                /// were comprised of about 12 different types, all of
                /// which are operated on by one or more tests.
                ///
                /// </summary>
               
                [CommandMethod( "IDFILTER1", CommandFlags.Redraw | CommandFlags.UsePickSet )]
                public static void FilterTest1()
                {
                        /// A filter that includes all Curve objects:
                        var filter = new ObjectIdFilter<Curve>();
                        MeasureFilter( filter );
                        /// Compare to simple delegate
                        MeasurePredicate<Curve>();

                        /// A filter that includes all PolyLines:
                        var filter2 = new ObjectIdFilter<Polyline>();
                        MeasureFilter( filter2 );
                        /// Compare to simple delegate
                        MeasurePredicate<Polyline>();

                        /// A filter that includes all Dimension objects:
                        var filter3 = new ObjectIdFilter<Dimension>();
                        MeasureFilter( filter3, false );
                        /// Compare to simple delegate
                        MeasurePredicate<Dimension>();
                }

                [CommandMethod( "IDFILTER2", CommandFlags.Redraw | CommandFlags.UsePickSet )]
                public static void FilterTest2()
                {
                        /// Get a filter that includes only
                        /// Line, Arc, Spline, and Polyline entities:
                       
                        var filter = new ObjectIdFilter(
                                typeof( Polyline ),
                                typeof( Arc ),
                                typeof( Line ),
                                typeof( Spline )
                        );

                        MeasureFilter( filter );

                        /// Compare the filter's execution time and result
                        /// to that of a hand-coded predicate that performs
                        /// the equvalent operation:

                        MeasurePredicate( IsLineArcPolylineOrSpline );
                }

                [CommandMethod( "IDFILTER3", CommandFlags.Redraw | CommandFlags.UsePickSet )]
                public static void FilterTest3()
                {
                        Document doc = Application.DocumentManager.MdiActiveDocument;
                        Editor ed = doc.Editor;
                        try
                        {
                                /// A filter that includes the ObjectIds of
                                /// all Curve types EXCEPT XLines and Rays:

                                ObjectIdFilter filter = curveWithoutXLinesOrRays;
                                if( filter == null )
                                {
                                        filter = new ObjectIdFilter<Curve>();
                                        filter[typeof( Xline )] = false;
                                        filter[typeof( Ray )] = false;
                                        curveWithoutXLinesOrRays = filter;
                                }

                                MeasureFilter( filter );

                                /// Compare the filter's execution time and result
                                /// to that of a hand-coded predicate that performs
                                /// the equvalent operation:

                                MeasurePredicate( IsCurveExceptXLineOrRay );
                        }
                        catch( System.Exception ex )
                        {
                                ed.WriteMessage( ex.ToString() );
                                throw ex;
                        }
                }

                /// <summary>
                /// Test re-use of filter (not recommended)
                /// </summary>
                static ObjectIdFilter curveWithoutXLinesOrRays = null;

                [CommandMethod( "IDFILTER4", CommandFlags.Redraw | CommandFlags.UsePickSet )]
                public static void FilterTest4()
                {
                        /// A filter that includes DBText and MText, but not
                        /// derived types (e.g., no AttributeDefinitions):

                        var filter = new ObjectIdFilter( typeof( DBText ), typeof( MText ) );

                        // No derived types:
                        filter.ExactMatch = true;

                        MeasureFilter( filter );

                        MeasurePredicate( IsTextOrMtext );
                }

                [CommandMethod( "IDFILTER" )]
                public static void IDFilterCommand()
                {
                        FilterTest1();
                        FilterTest2();
                        FilterTest3();
                        FilterTest4();
                }


                /// <summary>
                /// Hand-coded predicates and supporting variables
                /// that perform the equivalent of what some of the
                /// ObjectIdFilters defined above do, for testing
                /// and performance comparision purposes:
                /// </summary>

                static RXClass circleClass = RXClass.GetClass( typeof( Circle ) );
                static RXClass ellipseClass = RXClass.GetClass( typeof( Ellipse ) );
                static RXClass curveClass = RXClass.GetClass( typeof( Curve ) );
                static RXClass lineClass = RXClass.GetClass( typeof( Line ) );
                static RXClass arcClass = RXClass.GetClass( typeof( Arc ) );
                static RXClass splineClass = RXClass.GetClass( typeof( Spline ) );
                static RXClass polyLineClass = RXClass.GetClass( typeof( Polyline ) );
                static RXClass xlineClass = RXClass.GetClass( typeof( Xline ) );
                static RXClass rayClass = RXClass.GetClass( typeof( Ray ) );
                static RXClass dbTextClass = RXClass.GetClass( typeof( DBText ) );
                static RXClass mTextClass = RXClass.GetClass( typeof( MText ) );

                static bool IsLineArcPolylineOrSpline( ObjectId id )
                {
                        RXClass objectClass = id.ObjectClass;
                        return objectClass.IsDerivedFrom( lineClass )
                                || objectClass.IsDerivedFrom( arcClass )
                                || objectClass.IsDerivedFrom( polyLineClass )
                                || objectClass.IsDerivedFrom( splineClass );
                }

                /// <summary>
                /// Technically-incorrect, because it doesn't account
                /// for potential custom objects whose runtime classes
                /// derive from XLine and/or Ray, which as rare as that
                /// may be, is still possible.
                /// </summary>
                ///
                //static bool IsCurveExceptCircleOrEllipse( ObjectId id )
                //{
                //   RXClass rxclass = id.ObjectClass;
                //   return rxclass.IsDerivedFrom( curveClass )
                //      && rxclass != xlineClass
                //      && rxclass != rayClass;
                //}

                /// Technically-correct, without checking to see if
                /// there are runtime classes derived from XLine or
                /// Ray, before iteration (allowing a simple equality
                /// comparision verses a call to IsDerivedFrom()):
                ///
                /// Interestingly, because of the boxing/unboxing
                /// operation that DisposableWrapper's == operator
                /// leads to 8), a call to IsDerivedFrom() can be
                /// as fast or faster than an equality comparision.
               
                static bool IsCurveExceptXLineOrRay( ObjectId id )
                {
                        RXClass rxclass = id.ObjectClass;
                        return rxclass.IsDerivedFrom( curveClass )
                                && !rxclass.IsDerivedFrom( xlineClass )
                                && !rxclass.IsDerivedFrom( rayClass );
                }

                /// <summary>
                /// This is an 'exact' match, as per the
                /// equivalent filter it is compared with.
                /// </summary>
                static bool IsTextOrMtext( ObjectId id )
                {
                        RXClass rxclass = id.ObjectClass;
                        return rxclass == mTextClass || rxclass == dbTextClass;
                }

                /// Functions for testing results and measuring execution
                /// time of the above ObjectIdFilters and the equivalent
                /// hand-coded predicates:

                /// <summary>
                /// Measures the time required to filter on a single
                /// managed wrapper type using a predicate that calls
                /// the associated runtime class' IsDerivedFrom() to
                /// test each ObjectId.
                /// </summary>

                static void MeasurePredicate<T>()
                {
                        RXClass rxclass = RXClass.GetClass( typeof( T ) );
                        MeasurePredicate(
                                id => id.ObjectClass.IsDerivedFrom( rxclass ),
                                string.Format( "id => id.ObjectClass.IsDerivedFrom( {0} )",
                                        rxclass.Name ) );
                }

                /// <summary>
                /// Fastest possible execution of predicate-based
                /// id filtering, avoiding Enumerable.Cast<ObjectId>();
                /// </summary>
                /// <param name="predicate"></param>

                static void MeasurePredicate( Func<ObjectId, bool> predicate, string name = null )
                {
                        Document doc = Application.DocumentManager.MdiActiveDocument;
                        Database db = doc.Database;
                        Editor ed = doc.Editor;
                        try
                        {
                                using( Transaction tr = doc.TransactionManager.StartTransaction() )
                                {
                                        BlockTableRecord model = (BlockTableRecord)
                                                tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId( db ), OpenMode.ForRead );
                                        ObjectId item;
                                        int count = 0;
                                        Stopwatch st = Stopwatch.StartNew();
                                        foreach( ObjectId id in model )
                                        {
                                                if( predicate( id ) )
                                                {
                                                        ++count;
                                                        item = id;
                                                }
                                        }
                                        st.Stop();
                                        ed.WriteMessage( "\n---------------------------------------------------------------" );
                                        if( string.IsNullOrEmpty( name ) )
                                        {
                                                ed.WriteMessage( "\nWhere( id => {0}( id ) ):\n   time: {1}  Count: {2}\n",
                                                        predicate.Method.Name, st.ElapsedMilliseconds, count );
                                        }
                                        else
                                        {
                                                ed.WriteMessage( "\nWhere( {0} ):\n   time: {1}  Count: {2}\n",
                                                        name, st.ElapsedMilliseconds, count );
                                        }
                                        tr.Commit();
                                }
                        }
                        catch( System.Exception ex )
                        {
                                ed.WriteMessage( ex.ToString() );
                                throw ex;
                        }
                }

                static double MeasureFilter( ObjectIdFilter filter, bool select = false )
                {
                        Document doc = Application.DocumentManager.MdiActiveDocument;
                        Database db = doc.Database;
                        Editor ed = doc.Editor;
                        try
                        {
                                using( Transaction tr = doc.TransactionManager.StartTransaction() )
                                {
                                        BlockTableRecord model = (BlockTableRecord)
                                                tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId( db ), OpenMode.ForRead );
                                        long count = 0;
                                        Stopwatch st = Stopwatch.StartNew();
                                        var func = filter.Predicate;
                                        ObjectId current;
                                        foreach( ObjectId id in model )
                                        {
                                                if( func( id ) )
                                                {
                                                        current = id;
                                                        ++count;
                                                }
                                        }
                                        st.Stop();
                                        var time = st.ElapsedMilliseconds;
                                        if( select )
                                                ed.SetImpliedSelection( filter.GetObjectIds( model ).ToArray() );
                                        ed.WriteMessage( "\n===============================================================" );
                                        ed.WriteMessage( "\nFilter<{0}>:",
                                                string.Join( ",",
                                                        filter.Select(
                                                                t => string.Format( "{0}={1}", t.Name, filter[t] ) ) ) );
                                        ed.WriteMessage( "\n   Time: {0} Count: {1} Match: {2} Cache: {3}",
                                                time, count, filter.MatchType, filter.CacheCount );
                                        ed.WriteMessage( "\n   Predicate: {0}", filter.Predicate.Method.Name );
                                        tr.Commit();
                                        return time;
                                }
                        }
                        catch( System.Exception ex )
                        {
                                ed.WriteMessage( ex.ToString() );
                                throw ex;
                        }
                }
        }

}
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-11-17 22:29 , Processed in 0.198661 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表