CadXP: Blocs imbriqués - CadXP

Aller au contenu

Page 1 sur 1
  • Vous ne pouvez pas commencer un sujet
  • Vous ne pouvez pas répondre à ce sujet

Blocs imbriqués

#1 L'utilisateur est hors-ligne   coyotte 

  • ceinture verte
  • Groupe : Membres
  • Messages : 83
  • Inscrit(e) : 13-septembre 05

Posté 04 septembre 2020 - 14:59

Bonjour,

Une petite question sur les blocs.

Il y a t'il un moyen de lister les blocs d'un plan en excluant tous les blocs qui font partie d'un autre bloc ou d'une référence externe.

Merci par avance.

Cordialement.
http://www.carpetdiem.net
Plugins pour AutoCAD
0

#2 L'utilisateur est hors-ligne   (gile) 

  • ceinture rouge et blanche 8em dan
  • Groupe : Moderateurs
  • Messages : 11 424
  • Inscrit(e) : 02-septembre 05

Posté 05 septembre 2020 - 11:33

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 -
Développements sur mesure pour AutoCAD
Image IPB
0

#3 L'utilisateur est hors-ligne   coyotte 

  • ceinture verte
  • Groupe : Membres
  • Messages : 83
  • Inscrit(e) : 13-septembre 05

Posté 06 septembre 2020 - 08:49

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
0

#4 L'utilisateur est hors-ligne   (gile) 

  • ceinture rouge et blanche 8em dan
  • Groupe : Moderateurs
  • Messages : 11 424
  • Inscrit(e) : 02-septembre 05

Posté 06 septembre 2020 - 10:59

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 -
Développements sur mesure pour AutoCAD
Image IPB
0

#5 L'utilisateur est hors-ligne   coyotte 

  • ceinture verte
  • Groupe : Membres
  • Messages : 83
  • Inscrit(e) : 13-septembre 05

Posté 06 septembre 2020 - 12:10

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
0

#6 L'utilisateur est hors-ligne   (gile) 

  • ceinture rouge et blanche 8em dan
  • Groupe : Moderateurs
  • Messages : 11 424
  • Inscrit(e) : 02-septembre 05

Posté 06 septembre 2020 - 14:44

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 -
Développements sur mesure pour AutoCAD
Image IPB
0

#7 L'utilisateur est hors-ligne   coyotte 

  • ceinture verte
  • Groupe : Membres
  • Messages : 83
  • Inscrit(e) : 13-septembre 05

Posté 07 septembre 2020 - 07:11

Merci Gile,

cela semble être tout à fait ce que je cherchais.
http://www.carpetdiem.net
Plugins pour AutoCAD
0

Partager ce sujet :


Page 1 sur 1
  • Vous ne pouvez pas commencer un sujet
  • Vous ne pouvez pas répondre à ce sujet

1 utilisateur(s) en train de lire ce sujet
0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)