/// Excerpts from AcDbLinq.cs Copyright (c) 2008-2013 Tony Tanzillo
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Internal;
using System.Collections;
namespace Autodesk.AutoCAD.DatabaseServices
{
public static class AcDbLinqExtensions
{
/// <summary>
///
/// Returns an object that enumerates all references
/// to all blocks whose names match the given wildcard
/// pattern, open for read.
///
/// Requires an active transaction (NOT an OpenCloseTransaction)
///
/// </summary>
///
public static IEnumerable<BlockReference> GetBlockReferences(
this Database database,
string pattern )
{
if( string.IsNullOrWhiteSpace( pattern ) )
throw new ArgumentException( "Requires a wildcard pattern" );
if( database == null )
throw new ArgumentNullException( "database" );
Transaction tr = database.TransactionManager.TopTransaction;
if( tr == null )
throw new Autodesk.AutoCAD.Runtime.Exception(
ErrorStatus.NoActiveTransactions );
BlockTable blockTable = (BlockTable)
tr.GetObject( database.BlockTableId, OpenMode.ForRead );
return blockTable.Cast<ObjectId>()
.GetObjects<BlockTableRecord>()
.Where( btr => Utils.WcMatchEx( btr.Name, pattern, true ) )
.SelectMany( btr => btr.GetBlockReferences() );
}
/// <summary>
/// Gets an object that enumerates all references to the given
/// BlockTableRecord, including references to anonymous dynamic
/// BlockTableRecords, open for read.
/// </summary>
public static IEnumerable<BlockReference> GetBlockReferences(
this BlockTableRecord btr,
OpenMode mode = OpenMode.ForRead,
bool directOnly = true )
{
if( btr == null )
throw new ArgumentNullException( "btr" );
var tr = btr.Database.TransactionManager.TopTransaction;
if( tr == null )
throw new InvalidOperationException( "No transaction" );
var ids = btr.GetBlockReferenceIds( directOnly, true );
int cnt = ids.Count;
for( int i = 0; i < cnt; i++ )
{
yield return (BlockReference)
tr.GetObject( ids[i], mode, false, false );
}
if( btr.IsDynamicBlock )
{
BlockTableRecord btr2 = null;
var blockIds = btr.GetAnonymousBlockIds();
cnt = blockIds.Count;
for( int i = 0; i < cnt; i++ )
{
btr2 = (BlockTableRecord) tr.GetObject( blockIds[i],
OpenMode.ForRead, false, false );
ids = btr2.GetBlockReferenceIds( directOnly, true );
int cnt2 = ids.Count;
for( int j = 0; j < cnt2; j++ )
{
yield return (BlockReference)
tr.GetObject( ids[j], mode, false, false );
}
}
}
}
/// <summary>
/// The one, but not only GetObjects<T> (abridged), with due credits
/// to Jeff H, kaefer, Gile, et. al.
///
/// Returns an object that enumerates all instances of the
/// given generic argument type, opened accoring to the given
/// parameters.
/// </summary>
public static IEnumerable<T> GetObjects<T>(
this IEnumerable<ObjectId> ids,
OpenMode mode = OpenMode.ForRead,
bool openErased = false,
bool forceOpenOnLockedLayers = false ) where T : DBObject
{
if( ids.Any() )
{
TransactionManager tm = ids.First().Database.TransactionManager;
RXClass rxclass = RXClass.GetClass( typeof( T ) );
if( typeof( T ) == typeof( DBObject ) )
{
foreach( ObjectId id in ids )
{
yield return (T) tm.GetObject( id, mode, openErased,
forceOpenOnLockedLayers );
}
}
else if( rxclass.GetHasChildren() )
{
foreach( ObjectId id in ids )
{
if( id.ObjectClass.IsDerivedFrom( rxclass ) )
yield return (T) tm.GetObject( id, mode, openErased,
forceOpenOnLockedLayers );
}
}
else
{
foreach( ObjectId id in ids )
{
if( id.ObjectClass == rxclass )
yield return (T) tm.GetObject( id, mode, openErased,
forceOpenOnLockedLayers );
}
}
}
}
// Returns true if at least one RXClass is derived from
// the given RXClass:
public static bool GetHasChildren( this RXClass rxclass )
{
foreach( DictionaryEntry e in SystemObjects.ClassDictionary )
{
if( rxclass == ( (RXClass) e.Value ).MyParent )
return true;
}
return false;
}
}
}
RXClass rxc = RXClass.GetClass(typeof(BlockReference));
return btr.Cast<ObjectId>()
.Where(id => id.ObjectClass == rxc)
.Select(id => (BlockReference)id.GetObject(OpenMode.ForRead))
.Where(br =>
(br.IsDynamicBlock ?
((BlockTableRecord)br.DynamicBlockTableRecord.GetObject(OpenMode.ForRead)).Name :
br.Name) == pattern);;
static class Extensions
{
public static T GetObject<T>(this ObjectId id) where T : DBObject
{
return (T)id.GetObject(OpenMode.ForRead);
}
public static IEnumerable<T> GetObjects<T>(this SymbolTable source) where T : SymbolTableRecord
{
foreach (ObjectId id in source)
yield return (T)id.GetObject(OpenMode.ForRead);
}
public static IEnumerable<BlockReference> GetBlockReferences(this BlockTableRecord btr, ObjectId ownerId)
{
return btr.GetStaticReferences(ownerId)
.Concat(btr.GetAnonymousBlockIds()
.Cast<ObjectId>()
.SelectMany(id => id.GetObject<BlockTableRecord>().GetStaticReferences(ownerId)));
}
public static IEnumerable<BlockReference> GetBlockReferences(this Database db, string pattern, ObjectId ownerId)
{
return db.BlockTableId
.GetObject<BlockTable>()
.GetObjects<BlockTableRecord>()
.Where(btr => Autodesk.AutoCAD.Internal.Utils.WcMatch(btr.Name, pattern))
.SelectMany(btr => btr.GetBlockReferences(ownerId));
}
static IEnumerable<BlockReference> GetStaticReferences(this BlockTableRecord btr, ObjectId ownerId)
{
return btr.GetBlockReferenceIds(true, false)
.Cast<ObjectId>()
.Select(id => id.GetObject<BlockReference>())
.Where(br => br.OwnerId == ownerId);
}
}