Aller au contenu

Blocs imbriqués


coyotte

Messages recommandés

Salut,

 

Un exemple utilisant un jeu de sélection (suppose que le dessin est ouvert dans l'éditeur):

public static Dictionary<string, int> BlockCount(Document doc)
{
   var db = doc.Database;
   var ed = doc.Editor;
   var result = new Dictionary<string, int>();
   var filter = new SelectionFilter(new[] { new TypedValue(0, "INSERT") });
   var selection = ed.SelectAll(filter);
   if (selection.Status == PromptStatus.OK)
   {
       using (var tr = db.TransactionManager.StartOpenCloseTransaction())
       {
           foreach (var refId in selection.Value.GetObjectIds())
           {
               var br = (BlockReference)tr.GetObject(refId, OpenMode.ForRead);
               var btr = (BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead);
               if (!btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && !btr.IsDependent)
               {
                   string name = btr.Name;
                   if (result.ContainsKey(name))
                   {
                       result[name]++;
                   }
                   else
                   {
                       result.Add(name, 1);
                   }
               }
           }
           tr.Commit();
       }
   }
   return result;
}

 

Un autre utilisant uniquement la base de données du dessin :

public static Dictionary<string, int> BlockCount(Database db)
{
   var result = new Dictionary<string, int>();
   using (var tr = db.TransactionManager.StartOpenCloseTransaction())
   {
       var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
       foreach (ObjectId id in bt)
       {
           var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
           if (!btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && !btr.IsDependent)
           {
               foreach (ObjectId refId in btr.GetBlockReferenceIds(true, false))
               {
                   var br = (BlockReference)tr.GetObject(refId, OpenMode.ForRead);
                   var owner = (BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead);
                   if (owner.IsLayout)
                   {
                       string name = ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name;
                       if (result.ContainsKey(name))
                       {
                           result[name]++;
                       }
                       else
                       {
                           result.Add(name, 1);
                       }
                   }
               }
           }
       }
       tr.Commit();
   }
   return result;
}

 

Le même en utilisant une requête LINQ:

public static Dictionary<string, int> BlockCount(Database db)
{
   using (var tr = db.TransactionManager.StartOpenCloseTransaction())
   {
       return ((BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead))
           .Cast<ObjectId>()
           .Select(id => (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead))
           .Where(btr => !btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && !btr.IsDependent)
           .SelectMany(btr => (btr.GetBlockReferenceIds(true, false)).Cast<ObjectId>())
           .Select(refId => (BlockReference)tr.GetObject(refId, OpenMode.ForRead))
           .Where(br => ((BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead)).IsLayout)
           .GroupBy(br => ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name)
           .ToDictionary(gr => gr.Key, gr => gr.Count());
   }
}

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Merci Gile pour cette réponse ultra rapide et fonctionnelle.

 

Mon soucis est le suivant.

 

Ta fonction ne marche qu'à la condition que les blocs soit insérés dans le plan.

 

Mais existe t'il une solution pour parcourir l'ensemble de la database.blocktableid et savoir si chaque blocktablerecord rempli les conditions, à savoir si c'est bloc de premier rang (non inclus dans un autre bloc ou une référence externe).

 

Désolé de n'avoir pas été plus précis dans précédente question.

 

Cordialement.

http://www.carpetdiem.net

Plugins pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

La table des blocs contient toutes les définitions de bloc qu'ils soient imbriqués ou non.

Par exemple si une définition de bloc 'A' contient une référence de bloc 'B', la table des blocs contient aussi la définition de bloc 'B'. Les blocs 'A' et 'B' sont donc tous les deux "de premier rang" (ils peuvent être insérés séparément.

 

Si je comprends bien, ce que tu cherches à faire, c'est collecter uniquement les définitions de bloc qui ne sont pas référencées par une autre définition de bloc.

Pour ça, tu peux faire une liste de toutes les définitions de bloc qui ne sont ni une présentation, ni une xref, puis parcourir toutes les définitions de cette liste pour chercher une référence de bloc et pour chaque référence trouvée, supprimer sa définition de la liste.

 

        public static string[] GetFirstLevelBlocks(Database db)
       {
           using (var tr = db.TransactionManager.StartOpenCloseTransaction())
           {
               var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
               // toutes les définitions (sauf layout et xref)
               var btrs = new HashSet<BlockTableRecord>(
                   bt
                   .Cast<ObjectId>()
                   .Select(id => (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead))
                   .Where(btr => !btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && !btr.IsDependent));
               // toutes les définitions imbriquées
               var nested = new HashSet<BlockTableRecord>(
                   btrs
                   .SelectMany(btr => btr.Cast<ObjectId>())
                   .Where(id => id.ObjectClass.DxfName == "INSERT")
                   .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
                   .Select(br => (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead)));
               // soustraction des blocs imbriqués
               btrs.ExceptWith(nested);
               return btrs.Select(btr => btr.Name).ToArray();
           }
       }

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Re bonjour Gile,

 

Ce que je cherche à faire va encore plus loin.

 

Si je reprend ton exemple.

 

Le bloc A contient contient un bloc B.

 

Le bloc B n'est jamais insérer dans l'espace objet de mon plan en tant que bloc B.

 

Un bloc C est défini dans une référence externe mais jamais en tant que bloc C dans l'espace objet de mon plan.

 

Comment faire pour les blocs B et C n'apparaissent pas dans ma liste.

 

Cordialement.

http://www.carpetdiem.net

Plugins pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Le bloc 'A' contient 'B' et 'C', la xref 'X' contient 'X|D', seuls 'B' et 'X' sont directement insérés dans l'espace objet. La liste contient 'A' (non imbriqué) et 'B' (imbriqué et inséré dans un espace).

 

        public static string[] GetFirstLevelBlocks(Database db)
       {
           using (var tr = db.TransactionManager.StartOpenCloseTransaction())
           {
               // fonction locale qui évalue si un bloc est inséré dans un espace
               bool isInserted(BlockTableRecord btr) =>
                   btr
                   .GetBlockReferenceIds(true, false)
                   .Cast<ObjectId>()
                   .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
                   .Any(br => ((BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead)).IsLayout);

               var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

               // toutes les définitions (sauf layout, xref et bloc dépendant d'une xref)
               var btrs = new HashSet<BlockTableRecord>(
                   bt
                   .Cast<ObjectId>()
                   .Select(id => (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead))
                   .Where(btr => !btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && ! btr.IsDependent));

               // toutes les définitions imbriquées non directement insérées dans un espace
               var nested = new HashSet<BlockTableRecord>(
                   btrs
                   .SelectMany(btr => btr.Cast<ObjectId>())
                   .Where(id => id.ObjectClass.DxfName == "INSERT")
                   .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
                   .Select(br => (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead))
                   .Where(btr => !isInserted(btr)));

               // soustraction des blocs imbriqués
               btrs.ExceptWith(nested);
               return btrs.Select(btr => btr.Name).ToArray();
           }
       }

 

Si ça ne répond pas à ta demande, essaye de formuler sans aucune équivoque ce que tu veux obtenir et le boulot sera quasiment fait, tu n'auras qu'à retranscrire cet algorithme en code.

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité