coyotte Posté(e) le 4 septembre 2020 Posté(e) le 4 septembre 2020 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.netPlugins pour AutoCAD
(gile) Posté(e) le 5 septembre 2020 Posté(e) le 5 septembre 2020 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
coyotte Posté(e) le 6 septembre 2020 Auteur Posté(e) le 6 septembre 2020 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.netPlugins pour AutoCAD
(gile) Posté(e) le 6 septembre 2020 Posté(e) le 6 septembre 2020 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
coyotte Posté(e) le 6 septembre 2020 Auteur Posté(e) le 6 septembre 2020 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.netPlugins pour AutoCAD
(gile) Posté(e) le 6 septembre 2020 Posté(e) le 6 septembre 2020 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
coyotte Posté(e) le 7 septembre 2020 Auteur Posté(e) le 7 septembre 2020 Merci Gile, cela semble être tout à fait ce que je cherchais. http://www.carpetdiem.netPlugins pour AutoCAD
Messages recommandés
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 compteSe connecter
Vous avez déjà un compte ? Connectez-vous ici.
Connectez-vous maintenant