找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 2241|回复: 0

[分享] Creating an AutoCAD group

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-6-7 00:43:19 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
Creating an AutoCAD group using .NET  In the last post we looked at some code to define a block and insert it into the model-space of an AutoCAD drawing. Today we’re going to look at creating a group.
Before we dive into the code, it’s worth taking a quick look at the difference between a block and a group, to understand the differences between these two container/aggregator objects. I know that much of this information is available elsewhere, but hey – I’m on a roll, so I request your forbearance.
Let’s start with looking at the top-level structure of an AutoCAD Database (which is equivalent to a DWG file):
0.jpg
On the left of the above image we have a number of symbol tables. Symbol tables are the “traditional” container for data in an AutoCAD drawing, and have been in the format since the 80s (i.e. the dawn of time, from a PC technology perspective :-). Symbol tables store the names of objects within the objects themselves, which means you need to open the contained objects (symbol table records) to discover what they’re called.
The containers on the right, based on dictionaries (the DBDictionary class in .NET), are the more modern container inside DWGs. Dictionaries are like lookup tables: the entries – while sequentially accessible – are stored against a unique name, which means they’re more efficient if you need to identify a particular named entry.
Blocks are implemented via symbol tables, as they pre-date the introduction of dictionaries. Blocks are really about structuring content for repeated use, although – having said that – they’re also the mechanism used for external references, which are clearly not used repeatedly within a particular drawing.
Let’s take a look at the drawing structure we created in the last post: we created a new block definition called “Square” and then created a block reference in the model-space pointing to that block definition.
1.jpg
We can have multiple block references pointing to the same block definition, and if we change the contents of the block definition this will impact the various references.
Now let’s look at groups: as a more recently introduced mechanism, these are implemented using dictionaries. There’s a specific Group Dictionary that contains all the group objects in a drawing, and these, in turn, refer to sets of entities in the model-space (or paper-space, for that matter).
2.jpg
Groups collect entities together – and can be nested (but non-overlapping), just like blocks – but the individual elements retain the ability to be modified independently.
After groups were first implemented (back in R13, maybe? I forget…), I recall there were performance issues, and – in all honestly – I haven’t used them very heavily myself, over the years. I’d be curious to hear from this blog’s readership if anyone has experiences they wish to share: I would hope either that the initial performance problems have been resolved or that I’m misremembering and they work just fine for people.
Anyway, that’s it for the brief overview of blocks vs. groups: here’s the updated C# code that introduces a CG command to create a group.
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;

namespace CollectionCreation
{
  public class Commands
  {
    [CommandMethod("CB")]
    public void CreateBlock()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;

      Transaction tr =
        db.TransactionManager.StartTransaction();
      using (tr)
      {
        // Get the block table from the drawing

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

        // Check the block name, to see whether it's
        // already in use

        PromptStringOptions pso =
          new PromptStringOptions(
            "\nEnter new block name: "
          );
        pso.AllowSpaces = true;

        // A variable for the block's name

        string blkName = "";

        do
        {
          PromptResult pr = ed.GetString(pso);

          // Just return if the user cancelled
          // (will abort the transaction as we drop out of the using
          // statement's scope)

          if (pr.Status != PromptStatus.OK)
            return;

          try
          {
            // Validate the provided symbol table name

            SymbolUtilityServices.ValidateSymbolName(
              pr.StringResult,
              false
            );

            // Only set the block name if it isn't in use

            if (bt.Has(pr.StringResult))
              ed.WriteMessage(
                "\nA block with this name already exists."
              );
            else
              blkName = pr.StringResult;
          }
          catch
          {
            // An exception has been thrown, indicating the
            // name is invalid

            ed.WriteMessage(
              "\nInvalid block name."
            );
          }

        } while (blkName == "");

        // Create our new block table record...

        BlockTableRecord btr = new BlockTableRecord();

        // ... and set its properties

        btr.Name = blkName;

        // Add the new block to the block table

        bt.UpgradeOpen();
        ObjectId btrId = bt.Add(btr);
        tr.AddNewlyCreatedDBObject(btr, true);

        // Add some lines to the block to form a square
        // (the entities belong directly to the block)

        DBObjectCollection ents = SquareOfLines(5);
        foreach (Entity ent in ents)
        {
          btr.AppendEntity(ent);
          tr.AddNewlyCreatedDBObject(ent, true);
        }

        // Add a block reference to the model space

        BlockTableRecord ms =
          (BlockTableRecord)tr.GetObject(
            bt[BlockTableRecord.ModelSpace],
            OpenMode.ForWrite
          );

        BlockReference br =
          new BlockReference(Point3d.Origin, btrId);

        ms.AppendEntity(br);
        tr.AddNewlyCreatedDBObject(br, true);

        // Commit the transaction

        tr.Commit();

        // Report what we've done

        ed.WriteMessage(
          "\nCreated block named \"{0}\" containing {1} entities.",
          blkName, ents.Count
        );
      }
    }

    [CommandMethod("CG")]
    public void CreateGroup()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;

      Transaction tr =
        db.TransactionManager.StartTransaction();
      using (tr)
      {
        // Get the group dictionary from the drawing

        DBDictionary gd =
          (DBDictionary)tr.GetObject(
            db.GroupDictionaryId,
            OpenMode.ForRead
          );

        // Check the group name, to see whether it's
        // already in use

        PromptStringOptions pso =
          new PromptStringOptions(
            "\nEnter new group name: "
          );
        pso.AllowSpaces = true;

        // A variable for the group's name

        string grpName = "";

        do
        {
          PromptResult pr = ed.GetString(pso);

          // Just return if the user cancelled
          // (will abort the transaction as we drop out of the using
          // statement's scope)

          if (pr.Status != PromptStatus.OK)
            return;

          try
          {
            // Validate the provided symbol table name

            SymbolUtilityServices.ValidateSymbolName(
              pr.StringResult,
              false
            );

            // Only set the block name if it isn't in use

            if (gd.Contains(pr.StringResult))
              ed.WriteMessage(
                "\nA group with this name already exists."
              );
            else
              grpName = pr.StringResult;
          }
          catch
          {
            // An exception has been thrown, indicating the
            // name is invalid

            ed.WriteMessage(
              "\nInvalid group name."
            );
          }

        } while (grpName == "");

        // Create our new group...

        Group grp = new Group("Test group", true);

        // Add the new group to the dictionary

        gd.UpgradeOpen();
        ObjectId grpId = gd.SetAt(grpName, grp);
        tr.AddNewlyCreatedDBObject(grp, true);

        // Open the model-space

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

        BlockTableRecord ms =
          (BlockTableRecord)tr.GetObject(
            bt[BlockTableRecord.ModelSpace],
            OpenMode.ForWrite
          );

        // Add some lines to the group to form a square
        // (the entities belong to the model-space)

        ObjectIdCollection ids = new ObjectIdCollection();

        DBObjectCollection ents = SquareOfLines(8);
        foreach (Entity ent in ents)
        {
          ObjectId id = ms.AppendEntity(ent);
          ids.Add(id);
          tr.AddNewlyCreatedDBObject(ent, true);
        }

        grp.InsertAt(0, ids);

        // Commit the transaction

        tr.Commit();

        // Report what we've done

        ed.WriteMessage(
          "\nCreated group named \"{0}\" containing {1} entities.",
          grpName, ents.Count
        );
      }
    }

    private DBObjectCollection SquareOfLines(double size)
    {
      // A function to generate a set of entities for our block

      DBObjectCollection ents = new DBObjectCollection();
      Point3d[] pts =
          { new Point3d(-size, -size, 0),
            new Point3d(size, -size, 0),
            new Point3d(size, size, 0),
            new Point3d(-size, size, 0)
          };
      int max = pts.GetUpperBound(0);

      for (int i = 0; i <= max; i++)
      {
        int j = (i == max ? 0 : i + 1);
        Line ln = new Line(pts, pts[j]);
        ents.Add(ln);
      }
      return ents;
    }
  }
}

  The CG command allows us to create a group, just as the CB command created a block. We can even run them one after the other, using the same name (because one will use the name as a unique ID into the block table, the other into the group dictionary). And as the resultant squares are of different sizes, it should be obvious when the respective commands have done their work.
Command: CG
Enter new group name: Square
Created group named "Square" containing 4 entities.



论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-12-23 00:48 , Processed in 0.410005 second(s), 34 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表