Aller au contenu

Extraction de références de blocs et de leurs attributs


Messages recommandés

Bonjour

 

Je dois concevoir une application capable de récupérer les informations (attributs) contenues dans les blocs insérés dans le dessin Autocad (je ne suis pas utilisateur d'Autocad à la base).

 

Je suis sous Autocad 2011 et Visual studio 2010, je ne peux pas installer ObjectARX, donc pour tester mon appli je dois la compiler puis la charger dans Autocad à chaque fois donc pas évident à débuguer.

 

J'ai beaucoup de mal à comprendre la hiérarchie des blocs (BlockTable, BlockTableRecord, BlockReference) et leur mode de construction.

 

J'ai malgré tout réussi à extraire les références de bloc avec le code suivant (récupéré sur ce forum) :

 

        Private Function GetBlockReference(ByVal db As Database, ByVal ed As Editor) As ObjectIdCollection
           Dim result As New ObjectIdCollection
           Using tr As Transaction = db.TransactionManager.StartTransaction()
               Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)

               For Each id As ObjectId In bt

                   Dim btrA As BlockTableRecord = DirectCast(id.GetObject(OpenMode.ForRead), BlockTableRecord)

                   Dim btr As BlockTableRecord = DirectCast(tr.GetObject(bt(btrA.Name), OpenMode.ForRead), BlockTableRecord)
                   GetRefs(btr, result, ed)
                   For Each anonId As ObjectId In btr.GetAnonymousBlockIds()
                       Dim anonBtr As BlockTableRecord = DirectCast(tr.GetObject(anonId, OpenMode.ForRead), BlockTableRecord)
                       GetRefs(anonBtr, result, ed)
                   Next

               Next

           End Using
           Return result
       End Function

       Private Sub GetRefs(ByVal btr As BlockTableRecord, ByVal ids As ObjectIdCollection, ByVal ed As Editor)
           For Each id As ObjectId In btr.GetBlockReferenceIds(True, False)
               Dim br As BlockReference = DirectCast(id.GetObject(OpenMode.ForRead), BlockReference)
               Dim owner As BlockTableRecord = DirectCast(br.OwnerId.GetObject(OpenMode.ForRead), BlockTableRecord)
               If owner.IsLayout Then
                   ids.Add(br.Id)

                   ed.WriteMessage("   Ref = " + br.Name + " " + owner.Name + " " + vbCrLf)

               End If
           Next
       End Sub

 

Ce qui sort pour le dessin testé :

 

Début de l'extraction
  Ref = TRIPODE *Paper_Space
  Ref = EDTOLE *Model_Space
  Ref = EDTOLE *Model_Space
  Ref = EDTOLE *Model_Space
  Ref = ESTOLE *Model_Space
  Ref = _Cartouche *Model_Space
  Ref = EDCASE *Model_Space
Succès de l'extraction

 

Questions :

 

  1. le bout de code ci-dessus est-il bien indiqués si l'on veut récupérer toutes les références de blocs insérés dans le dessin ?
  2. Comment accéder aux informations contenues dans les attributs ?

 

Pour infos, les blocs insérés peuvent être des blocs dynamiques.

 

Merci

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

la table des blocs (BlockTable) est la collection qui contient tous les objets BlockTableRecord du dessin, à savoir l'espace objet, les espaces papier, les définitions de bloc et les références externes. Un objet BlockReference est une référence à une définition de bloc insérée dans une BlockTableRecord (qui peut être un espace ou une définition de bloc).

Les définitions de blocs peuvent contenir des définitions d'attribut (AttributeDefinition). Quand c'est le cas, les références de ces blocs contiennent autant de référence d'attributs (AttributeReference) qui ont chacune une propriété Tag pour l'étiquette de l'attribut et une propriété TextString pour la valeur de l'attribut

 

1. Oui le code retourne bien toutes les références mais on peut faire plus simple (ce code était prévue pour récupérer les références de bloc suivant un nom.

 

2. Les objets BlockReference ont une propriété AttributeCollection qui contient les ObjectId des attributs de cette référence de bloc.

 

Un exemple simple qui utilise une classe BlockAttribute avec deux propriétés: Name pour le nom du bloc (de type String) et Attributes pour les attributs (de type Dictionary).

 

using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace GetAttributesSample
{
   public class Commands
   {
       [CommandMethod("Test")]
       public void Test()
       {
           Document doc = AcAp.DocumentManager.MdiActiveDocument;
           Database db = doc.Database;
           Editor ed = doc.Editor;
           foreach (BlockAttribute blkAtt in GetBlockAttributes(db))
           {
               ed.WriteMessage("\n" + blkAtt.ToString());
           }
       }

       private List<BlockAttribute> GetBlockAttributes(Database db)
       {
           List<BlockAttribute> result = new List<BlockAttribute>();
           using (Transaction tr = db.TransactionManager.StartTransaction())
           {
               BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
               foreach (ObjectId id in bt)
               {
                   BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
                   if (!(btr.IsAProxy || btr.IsFromExternalReference || btr.IsLayout))
                   {
                       foreach (ObjectId brId in btr.GetBlockReferenceIds(true, false))
                       {
                           BlockReference br = (BlockReference)brId.GetObject(OpenMode.ForRead);
                           BlockTableRecord owner = (BlockTableRecord)br.OwnerId.GetObject(OpenMode.ForRead);
                           if (owner.IsLayout)
                               result.Add(new BlockAttribute(br));
                       }
                   }
               }
           }
           return result;
       }
   }

   public class BlockAttribute
   {
       private string _name;
       private Dictionary<string, string> _atts;
       private Transaction _tr;

       public string Name
       {
           get { return _name; }
       }

       public Dictionary<string, string> Attributes
       {
           get { return _atts; }
       }

       public string this[string key]
       {
           get { return _atts[key.ToUpper()]; }
       }

       public BlockAttribute(BlockReference br)
       {
           Document doc = AcAp.DocumentManager.MdiActiveDocument;
           using (_tr = doc.TransactionManager.StartTransaction())
           {
               SetProperties(br);
           }
       }

       public BlockAttribute(ObjectId id)
       {
           Document doc = AcAp.DocumentManager.MdiActiveDocument;
           using (_tr = doc.TransactionManager.StartTransaction())
           {
               SetProperties(_tr.GetObject(id, OpenMode.ForRead) as BlockReference);
           }
       }

       public override string ToString()
       {
           if (_atts != null && _atts.Count > 0)
               return string.Format("{0}: {1}",
                   _name,
                   _atts.Select(a => string.Format("{0}={1}", a.Key, a.Value))
                       .Aggregate((a, B) => string.Format("{0}; {1}", a, B)));
           return _name;
       }

       private void SetProperties(BlockReference br)
       {
           if (br == null) return;
           if (br.IsDynamicBlock)
           {
               BlockTableRecord btr = (BlockTableRecord)_tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead);
               _name = btr.Name;
           }
           else
               _name = br.Name;
           _atts = new Dictionary<string, string>();
           foreach (ObjectId id in br.AttributeCollection)
           {
               AttributeReference att = (AttributeReference)_tr.GetObject(id, OpenMode.ForRead);
               _atts.Add(att.Tag.ToUpper(), att.TextString);
           }
       }
   }
}

 

Tu trouveras un exemple plus complet pour une extraction d'attributs utilisant un DataTable où les blocs sont regroupés par noms et valeurs d'attributs identiques ici.

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

Lien vers le commentaire
Partager sur d’autres sites

L'extraction des blocs et de leur attributs fonctionne bien, merci.

 

j'ai une nouvelle question peut-être simple mais je n'ai pas trouvé de solution.

 

Est-il possible de récupérer les dimensions d'une référence de block ? tel que :

 

http://img15.hostingpics.net/pics/657125dim.png

 

Merci

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

Oui, si ce que tu cherches correspond à l'emprise rectangulaire de bloc suivant les axes X et Y (BoundingBox).

Ces dimension peuvent être différentes pour des références d'un même bloc suivant qu'elles ont subit une rotation ou des changement d'échelle.

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

namespace BoundingBoxSample
{
   public class Commands
   {
       [CommandMethod("Test")]
       public void Test()
       {
           Document doc = Application.DocumentManager.MdiActiveDocument;
           Database db = doc.Database;
           Editor ed = doc.Editor;
           PromptEntityOptions peo = new PromptEntityOptions("\nSélectionnez un bloc: ");
           peo.SetRejectMessage("Objet non valide.");
           peo.AddAllowedClass(typeof(BlockReference), true);
           PromptEntityResult per = ed.GetEntity(peo);
           if (per.Status != PromptStatus.OK) return;
               double width, height;
           using (Transaction tr = db.TransactionManager.StartTransaction())
           {
               BlockReference br = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForRead);
               GetExtentsDimensions(br, out width, out height);
               tr.Commit();
           }
           ed.WriteMessage("\nLargeur = {0}\nHauteur = {1}", width, height);
       }

       private void GetExtentsDimensions(BlockReference br, out double width, out double height)
       {
           Extents3d ext = br.GeometricExtents;
           width = ext.MaxPoint.X - ext.MinPoint.X;
           height = ext.MaxPoint.Y - ext.MinPoint.Y;
       }
   }
}

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é