乐筑天下

搜索
欢迎各位开发者和用户入驻本平台 尊重版权,从我做起,拒绝盗版,拒绝倒卖 签到、发布资源、邀请好友注册,可以获得银币 请注意保管好自己的密码,避免账户资金被盗
查看: 49|回复: 1

Kean-An automatic numbering system for AutoCAD blocks using .NET

[复制链接]

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-15 15:05:00 | 显示全部楼层 |阅读模式
三、一个图块的自动计数系统
May 07, 2008
An automatic numbering system for  blocks using .NET - Part 1
I had this interesting request come in by email:
I have a problem where I have a block I need to insert into several parts of a drawing. The block has three attributes, 1. Point number, 2. Level, and 3. Code.
I would like to do the following;
1. be able to select objects in a drawing and have it insert the block and autosnap to circle centres, and auto number each point number attribute.
2. be able to manually select points which are automatically numbered.
3. it should remember the last point number.
4. have the option to renumber points if changes are made i could renumber all the points.
5. be able to extract the points & attributes, point number, x position, y position, level, & code to a comma delimited file.
The request was more for guidance than for custom development services, but I thought the topic was of general-enough interest to be worth spending some time working on.
Over the next few posts I'm going to serialize the implementation I put together, in more-or-less the order in which I implemented it. If further related enhancement requests come in - as comments or by email - then I'll do what I can to incorporate them into the solution (no guarantees, though :-).
Today's post looks at the first two items: automatic numbering of selected circles and manual selection of points that also get numbered.
During these posts (and in the code), I'll refer to these numbered blocks as "bubbles", as this implementation could be used to implement automatically numbered bubble (or balloon) dimensions. As you'll see in the next few posts, though, I've tried to keep the core number management implementation as independent as possible, so it could be used to manage a numbered list of any type of AutoCAD entity.
So, here's the initial C# code:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.EditorInput;
  5. using Autodesk.AutoCAD.Geometry;
  6. using System.Collections.Generic;
  7. namespace AutoNumberedBubbles
  8. {
  9.   public class Commands : IExtensionApplication
  10.   {
  11.     // Strings identifying the block
  12.     // and the attribute name to use
  13.     const string blockName = "BUBBLE";
  14.     const string attbName = "NUMBER";
  15.     // In this version, just use a simple
  16.     // integer to take care of the numbering
  17.     private int m_bulletNumber = 0;
  18.     // Constructor
  19.     public Commands()
  20.     {
  21.     }
  22.     // Functions called on initialization & termination
  23.     public void Initialize()
  24.     {
  25.       try
  26.       {
  27.         Document doc =
  28.           Application.DocumentManager.MdiActiveDocument;
  29.         Editor ed = doc.Editor;
  30.         ed.WriteMessage(
  31.           "\nBAP  Create bubbles at points" +
  32.           "\nBIC  Create bubbles at the center of circles"
  33.         );
  34.       }
  35.       catch
  36.       { }
  37.     }
  38.     public void Terminate()
  39.     {
  40.     }
  41.     // Command to create bubbles at points selected
  42.     // by the user - loops until cancelled
  43.     [CommandMethod("BAP")]
  44.     public void BubblesAtPoints()
  45.     {
  46.       Document doc =
  47.         Application.DocumentManager.MdiActiveDocument;
  48.       Database db = doc.Database;
  49.       Editor ed = doc.Editor;
  50.       Autodesk.AutoCAD.ApplicationServices.
  51.       TransactionManager tm =
  52.         doc.TransactionManager;
  53.       Transaction tr =
  54.         tm.StartTransaction();
  55.       using (tr)
  56.       {
  57.         // Get the information about the block
  58.         // and attribute definitions we care about
  59.         BlockTableRecord ms;
  60.         ObjectId blockId;
  61.         AttributeDefinition ad;
  62.         List other;
  63.         if (GetBlock(
  64.               db, tr, out ms, out blockId
  65.           ))
  66.         {
  67.           GetBlockAttributes(
  68.             tr, blockId, out ad, out other
  69.           );
  70.           // By default the modelspace is returned to
  71.           // us in read-only state
  72.           ms.UpgradeOpen();
  73.           // Loop until cancelled
  74.           bool finished = false;
  75.           while (!finished)
  76.           {
  77.             PromptPointOptions ppo =
  78.               new PromptPointOptions("\nSelect point: ");
  79.             ppo.AllowNone = true;
  80.             PromptPointResult ppr =
  81.               ed.GetPoint(ppo);
  82.             if (ppr.Status != PromptStatus.OK)
  83.               finished = true;
  84.             else
  85.               // Call a function to create our bubble
  86.               CreateNumberedBubbleAtPoint(
  87.                 db, ms, tr, ppr.Value,
  88.                 blockId, ad, other
  89.               );
  90.             tm.QueueForGraphicsFlush();
  91.             tm.FlushGraphics();
  92.           }
  93.         }
  94.         tr.Commit();
  95.       }
  96.     }
  97.     // Command to create a bubble at the center of
  98.     // each of the selected circles
  99.     [CommandMethod("BIC")]
  100.     public void BubblesInCircles()
  101.     {
  102.       Document doc =
  103.         Application.DocumentManager.MdiActiveDocument;
  104.       Database db = doc.Database;
  105.       Editor ed = doc.Editor;
  106.       // Allow the user to select circles
  107.       TypedValue[] tvs =
  108.         new TypedValue[1] {
  109.             new TypedValue(
  110.               (int)DxfCode.Start,
  111.               "CIRCLE"
  112.             )
  113.           };
  114.       SelectionFilter sf =
  115.         new SelectionFilter(tvs);
  116.       PromptSelectionResult psr =
  117.         ed.GetSelection(sf);
  118.       if (psr.Status == PromptStatus.OK &&
  119.           psr.Value.Count > 0)
  120.       {
  121.         Transaction tr =
  122.           db.TransactionManager.StartTransaction();
  123.         using (tr)
  124.         {
  125.           // Get the information about the block
  126.           // and attribute definitions we care about
  127.           BlockTableRecord ms;
  128.           ObjectId blockId;
  129.           AttributeDefinition ad;
  130.           List other;
  131.           if (GetBlock(
  132.                 db, tr, out ms, out blockId
  133.             ))
  134.           {
  135.             GetBlockAttributes(
  136.               tr, blockId, out ad, out other
  137.             );
  138.             // By default the modelspace is returned to
  139.             // us in read-only state
  140.             ms.UpgradeOpen();
  141.             foreach (SelectedObject o in psr.Value)
  142.             {
  143.               // For each circle in the selected list...
  144.               DBObject obj =
  145.                 tr.GetObject(o.ObjectId, OpenMode.ForRead);
  146.               Circle c = obj as Circle;
  147.               if (c == null)
  148.                 ed.WriteMessage(
  149.                   "\nObject selected is not a circle."
  150.                 );
  151.               else
  152.                 // Call our numbering function, passing the
  153.                 // center of the circle
  154.                 CreateNumberedBubbleAtPoint(
  155.                   db, ms, tr, c.Center,
  156.                   blockId, ad, other
  157.                 );
  158.             }
  159.           }
  160.           tr.Commit();
  161.         }
  162.       }
  163.     }
  164.     // Internal helper function to open and retrieve
  165.     // the model-space and the block def we care about
  166.     private bool
  167.       GetBlock(
  168.         Database db,
  169.         Transaction tr,
  170.         out BlockTableRecord ms,
  171.         out ObjectId blockId
  172.       )
  173.     {
  174.       BlockTable bt =
  175.         (BlockTable)tr.GetObject(
  176.           db.BlockTableId,
  177.           OpenMode.ForRead
  178.         );
  179.       if (!bt.Has(blockName))
  180.       {
  181.         Document doc =
  182.           Application.DocumentManager.MdiActiveDocument;
  183.         Editor ed = doc.Editor;
  184.         ed.WriteMessage(
  185.           "\nCannot find block definition "" +
  186.           blockName +
  187.           "" in the current drawing."
  188.         );
  189.         blockId = ObjectId.Null;
  190.         ms = null;
  191.         return false;
  192.       }
  193.       ms =
  194.         (BlockTableRecord)tr.GetObject(
  195.           bt[BlockTableRecord.ModelSpace],
  196.           OpenMode.ForRead
  197.         );
  198.       blockId = bt[blockName];
  199.       return true;
  200.     }
  201.     // Internal helper function to retrieve
  202.     // attribute info from our block
  203.     // (we return the main attribute def
  204.     // and then all the "others")
  205.     private void
  206.       GetBlockAttributes(
  207.         Transaction tr,
  208.         ObjectId blockId,
  209.         out AttributeDefinition ad,
  210.         out List other
  211.       )
  212.     {
  213.       BlockTableRecord blk =
  214.         (BlockTableRecord)tr.GetObject(
  215.           blockId,
  216.           OpenMode.ForRead
  217.         );
  218.       ad = null;
  219.       other =
  220.         new List();
  221.       foreach (ObjectId attId in blk)
  222.       {
  223.         DBObject obj =
  224.           (DBObject)tr.GetObject(
  225.             attId,
  226.             OpenMode.ForRead
  227.           );
  228.         AttributeDefinition ad2 =
  229.           obj as AttributeDefinition;
  230.         if (ad2 != null)
  231.         {
  232.           if (ad2.Tag == attbName)
  233.           {
  234.             if (ad2.Constant)
  235.             {
  236.               Document doc =
  237.                 Application.DocumentManager.MdiActiveDocument;
  238.               Editor ed = doc.Editor;
  239.               ed.WriteMessage(
  240.                 "\nAttribute to change is constant!"
  241.               );
  242.             }
  243.             else
  244.               ad = ad2;
  245.           }
  246.           else
  247.             if (!ad2.Constant)
  248.               other.Add(ad2);
  249.         }
  250.       }
  251.     }
  252.     // Internal helper function to create a bubble
  253.     // at a particular point
  254.     private Entity
  255.       CreateNumberedBubbleAtPoint(
  256.         Database db,
  257.         BlockTableRecord btr,
  258.         Transaction tr,
  259.         Point3d pt,
  260.         ObjectId blockId,
  261.         AttributeDefinition ad,
  262.         List other
  263.       )
  264.     {
  265.       //  Create a new block reference
  266.       BlockReference br =
  267.         new BlockReference(pt, blockId);
  268.       // Add it to the database
  269.       br.SetDatabaseDefaults();
  270.       ObjectId blockRefId = btr.AppendEntity(br);
  271.       tr.AddNewlyCreatedDBObject(br, true);
  272.       // Create an attribute reference for our main
  273.       // attribute definition (where we'll put the
  274.       // bubble's number)
  275.       AttributeReference ar =
  276.         new AttributeReference();
  277.       // Add it to the database, and set its position, etc.
  278.       ar.SetDatabaseDefaults();
  279.       ar.SetAttributeFromBlock(ad, br.BlockTransform);
  280.       ar.Position =
  281.         ad.Position.TransformBy(br.BlockTransform);
  282.       ar.Tag = ad.Tag;
  283.       // Set the bubble's number
  284.       int bubbleNumber =
  285.         ++m_bulletNumber;
  286.       ar.TextString = bubbleNumber.ToString();
  287.       ar.AdjustAlignment(db);
  288.       // Add the attribute to the block reference
  289.       br.AttributeCollection.AppendAttribute(ar);
  290.       tr.AddNewlyCreatedDBObject(ar, true);
  291.       // Now we add attribute references for the
  292.       // other attribute definitions
  293.       foreach (AttributeDefinition ad2 in other)
  294.       {
  295.         AttributeReference ar2 =
  296.           new AttributeReference();
  297.         ar2.SetAttributeFromBlock(ad2, br.BlockTransform);
  298.         ar2.Position =
  299.           ad2.Position.TransformBy(br.BlockTransform);
  300.         ar2.Tag = ad2.Tag;
  301.         ar2.TextString = ad2.TextString;
  302.         ar2.AdjustAlignment(db);
  303.         br.AttributeCollection.AppendAttribute(ar2);
  304.         tr.AddNewlyCreatedDBObject(ar2, true);
  305.       }
  306.       return br;
  307.     }
  308.   }
  309. }
You can see only two commands have been implemented, for now: BAP (Bubbles At Points) and BIC (Bubbles In Circles). These commands will create bubbles in increasing order, starting at 1. For now there's nothing in the application to allow the numbering to continue when you reload the drawing - it will start again at 1, for now.
Here's a base drawing containing some circles (which you can download from here):
Here's what happens when we run the BIC command, selecting each of the circles, going from left to right:
And here's what happens after we run the BAP command, selecting a number of points at random:
In the next post we'll add some intelligence to the numbering system, by adding a class to take care of a lot of the hard work for us. We'll then implement some commands to use this class to get more control over the numbering.
回复

使用道具 举报

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-15 15:17:00 | 显示全部楼层
May 12, 2008
An automatic numbering system for AutoCAD blocks using .NET - Part 3
In the last post we introduced some additional features to the original post in this series. In this post we take advantage of - and further extend - those features, by allowing deletion, movement and compaction of the numbered objects.
Here's the modified C# code:[code]using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System.Collections.Generic;namespace AutoNumberedBubbles
{
  public class Commands : IExtensionApplication
  {
    // Strings identifying the block
    // and the attribute name to use    const string blockName = "BUBBLE";
    const string attbName = "NUMBER";    // We will use a separate object to
    // manage our numbering, and maintain a
    // "base" index (the start of the list)    private NumberedObjectManager m_nom;
    private int m_baseNumber = 0;    // Constructor    public Commands()
    {
      m_nom = new NumberedObjectManager();
    }    // Functions called on initialization & termination    public void Initialize()
    {
      try
      {
        Document doc =
          Application.DocumentManager.MdiActiveDocument;
        Editor ed = doc.Editor;        ed.WriteMessage(
          "\nLNS  Load numbering settings by analyzing the current drawing" +
          "\nDMP  Print internal numbering information" +
          "\nBAP  Create bubbles at points" +
          "\nBIC  Create bubbles at the center of circles" +
          "\nMB   Move a bubble in the list" +
          "\nDB   Delete a bubble" +
          "\nRBS  Reorder the bubbles, to close gaps caused by deletion" +
          "\nHLB  Highlight a particular bubble"
        );
      }
      catch
      { }
    }    public void Terminate()
    {
    }    // Command to extract and display information
    // about the internal numbering    [CommandMethod("DMP")]
    public void DumpNumberingInformation()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;
      m_nom.DumpInfo(ed);
    }    // Command to analyze the current document and
    // understand which indeces have been used and
    // which are currently free    [CommandMethod("LNS")]
    public void LoadNumberingSettings()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;      // We need to clear any internal state
      // already collected      m_nom.Clear();
      m_baseNumber = 0;      // Select all the blocks in the current drawing      TypedValue[] tvs =
        new TypedValue[1] {
            new TypedValue(
              (int)DxfCode.Start,
              "INSERT"
            )
          };
      SelectionFilter sf =
        new SelectionFilter(tvs);      PromptSelectionResult psr =
        ed.SelectAll(sf);      // If it succeeded and we have some blocks...      if (psr.Status == PromptStatus.OK &&
          psr.Value.Count > 0)
      {
        Transaction tr =
          db.TransactionManager.StartTransaction();
        using (tr)
        {
          // First get the modelspace and the ID
          // of the block for which we're searching          BlockTableRecord ms;
          ObjectId blockId;          if (GetBlock(
                db, tr, out ms, out blockId
             ))
          {
            // For each block reference in the drawing...            foreach (SelectedObject o in psr.Value)
            {
              DBObject obj =
                tr.GetObject(o.ObjectId, OpenMode.ForRead);
              BlockReference br = obj as BlockReference;
              if (br != null)
              {
                // If it's the one we care about...                if (br.BlockTableRecord == blockId)
                {
                  // Check its attribute references...                  int pos = -1;
                  AttributeCollection ac =
                    br.AttributeCollection;                  foreach (ObjectId id in ac)
                  {
                    DBObject obj2 =
                      tr.GetObject(id, OpenMode.ForRead);
                    AttributeReference ar =
                      obj2 as AttributeReference;                    // When we find the attribute
                    // we care about...                    if (ar.Tag == attbName)
                    {
                      try
                      {
                        // Attempt to extract the number from
                        // the text string property... use a
                        // try-catch block just in case it is
                        // non-numeric                        pos =
                          int.Parse(ar.TextString);                        // Add the object at the appropriate
                        // index                        m_nom.NumberObject(
                          o.ObjectId, pos, false
                        );
                      }
                      catch { }
                    }
                  }
                }
              }
            }
          }
          tr.Commit();
        }        // Once we have analyzed all the block references...        int start = m_nom.GetLowerBound(true);        // If the first index is non-zero, ask the user if
        // they want to rebase the list to begin at the
        // current start position        if (start > 0)
        {
          ed.WriteMessage(
            "\nLowest index is {0}. ",
            start
          );
          PromptKeywordOptions pko =
            new PromptKeywordOptions(
              "Make this the start of the list?"
            );
          pko.AllowNone = true;
          pko.Keywords.Add("Yes");
          pko.Keywords.Add("No");
          pko.Keywords.Default = "Yes";          PromptResult pkr =
            ed.GetKeywords(pko);          if (pkr.Status == PromptStatus.OK)
          {
            if (pkr.StringResult == "Yes")
            {
              // We store our own base number
              // (the object used to manage objects
              // always uses zero-based indeces)              m_baseNumber = start;
              m_nom.RebaseList(m_baseNumber);
            }
          }
        }
      }
    }
   
    // Command to create bubbles at points selected
    // by the user - loops until cancelled    [CommandMethod("BAP")]
    public void BubblesAtPoints()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;
      Autodesk.AutoCAD.ApplicationServices.
      TransactionManager tm =
        doc.TransactionManager;      Transaction tr =
        tm.StartTransaction();
      using (tr)
      {
        // Get the information about the block
        // and attribute definitions we care about        BlockTableRecord ms;
        ObjectId blockId;
        AttributeDefinition ad;
        List other;        if (GetBlock(
              db, tr, out ms, out blockId
           ))
        {
          GetBlockAttributes(
            tr, blockId, out ad, out other
          );          // By default the modelspace is returned to
          // us in read-only state          ms.UpgradeOpen();          // Loop until cancelled          bool finished = false;
          while (!finished)
          {
            PromptPointOptions ppo =
              new PromptPointOptions("\nSelect point: ");
            ppo.AllowNone = true;            PromptPointResult ppr =
              ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
              finished = true;
            else
              // Call a function to create our bubble
              CreateNumberedBubbleAtPoint(
                db, ms, tr, ppr.Value,
                blockId, ad, other
              );
            tm.QueueForGraphicsFlush();
            tm.FlushGraphics();
          }
        }
        tr.Commit();
      }
    }    // Command to create a bubble at the center of
    // each of the selected circles    [CommandMethod("BIC")]
    public void BubblesInCircles()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;      // Allow the user to select circles      TypedValue[] tvs =
        new TypedValue[1] {
            new TypedValue(
              (int)DxfCode.Start,
              "CIRCLE"
            )
          };
      SelectionFilter sf =
        new SelectionFilter(tvs);      PromptSelectionResult psr =
        ed.GetSelection(sf);      if (psr.Status == PromptStatus.OK &&
          psr.Value.Count > 0)
      {
        Transaction tr =
          db.TransactionManager.StartTransaction();
        using (tr)
        {
          // Get the information about the block
          // and attribute definitions we care about          BlockTableRecord ms;
          ObjectId blockId;
          AttributeDefinition ad;
          List other;          if (GetBlock(
                db, tr, out ms, out blockId
             ))
          {
            GetBlockAttributes(
              tr, blockId, out ad, out other
            );            // By default the modelspace is returned to
            // us in read-only state            ms.UpgradeOpen();            foreach (SelectedObject o in psr.Value)
            {
              // For each circle in the selected list...              DBObject obj =
                tr.GetObject(o.ObjectId, OpenMode.ForRead);
              Circle c = obj as Circle;
              if (c == null)
                ed.WriteMessage(
                  "\nObject selected is not a circle."
                );
              else
                // Call our numbering function, passing the
                // center of the circle
                CreateNumberedBubbleAtPoint(
                  db, ms, tr, c.Center,
                  blockId, ad, other
                );
            }
          }
          tr.Commit();
        }
      }
    }    // Command to delete a particular bubble
    // selected by its index    [CommandMethod("MB")]
    public void MoveBubble()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;      // Use a helper function to select a valid bubble index      int pos =
        GetBubbleNumber(
          ed,
          "\nEnter number of bubble to move: "
        );      if (pos >= m_baseNumber)
      {
        int from = pos - m_baseNumber;        pos =
          GetBubbleNumber(
            ed,
            "\nEnter destination position: "
          );        if (pos >= m_baseNumber)
        {
          int to = pos - m_baseNumber;          ObjectIdCollection ids =
            m_nom.MoveObject(from, to);          RenumberBubbles(doc.Database, ids);
        }
      }
    }    // Command to delete a particular bubbler,
    // selected by its index    [CommandMethod("DB")]
    public void DeleteBubble()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;      // Use a helper function to select a valid bubble index      int pos =
        GetBubbleNumber(
          ed,
          "\nEnter number of bubble to erase: "
        );      if (pos >= m_baseNumber)
      {
        // Remove the object from the internal list
        // (this returns the ObjectId stored for it,
        // which we can then use to erase the entity)        ObjectId id =
          m_nom.RemoveObject(pos - m_baseNumber);
        Transaction tr =
          db.TransactionManager.StartTransaction();
        using (tr)
        {
          DBObject obj =
            tr.GetObject(id, OpenMode.ForWrite);
          obj.Erase();
          tr.Commit();
        }
      }
    }    // Command to reorder all the bubbles in the drawing,
    // closing all the gaps between numbers but maintaining
    // the current numbering order    [CommandMethod("RBS")]
    public void ReorderBubbles()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;      // Re-order the bubbles - the IDs returned are
      // of the objects that need to be renumbered      ObjectIdCollection ids =
        m_nom.ReorderObjects();      RenumberBubbles(doc.Database, ids);
    }    // Command to highlight a particular bubble    [CommandMethod("HLB")]
    public void HighlightBubble()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;      // Use our function to select a valid bubble index      int pos =
        GetBubbleNumber(
          ed,
          "\nEnter number of bubble to highlight: "
        );      if (pos >= m_baseNumber)
      {
        Transaction tr =
          db.TransactionManager.StartTransaction();
        using (tr)
        {
          // Get the ObjectId from the index...          ObjectId id =
            m_nom.GetObjectId(pos - m_baseNumber);          if (id == ObjectId.Null)
          {
            ed.WriteMessage(
              "\nNumber is not currently used -" +
              " nothing to highlight."
            );
            return;
          }          // And then open & highlight the entity          Entity ent =
            (Entity)tr.GetObject(
              id,
              OpenMode.ForRead
            );
          ent.Highlight();
          tr.Commit();
        }
      }
    }    // Internal helper function to open and retrieve
    // the model-space and the block def we care about    private bool
      GetBlock(
        Database db,
        Transaction tr,
        out BlockTableRecord ms,
        out ObjectId blockId
      )
    {
      BlockTable bt =
        (BlockTable)tr.GetObject(
          db.BlockTableId,
          OpenMode.ForRead
        );      if (!bt.Has(blockName))
      {
        Document doc =
          Application.DocumentManager.MdiActiveDocument;
        Editor ed = doc.Editor;
        ed.WriteMessage(
          "\nCannot find block definition "" +
          blockName +
          "" in the current drawing."
        );        blockId = ObjectId.Null;
        ms = null;
        return false;
      }      ms =
        (BlockTableRecord)tr.GetObject(
          bt[BlockTableRecord.ModelSpace],
          OpenMode.ForRead
        );      blockId = bt[blockName];      return true;
    }    // Internal helper function to retrieve
    // attribute info from our block
    // (we return the main attribute def
    // and then all the "others")    private void
      GetBlockAttributes(
        Transaction tr,
        ObjectId blockId,
        out AttributeDefinition ad,
        out List other
      )
    {
      BlockTableRecord blk =
        (BlockTableRecord)tr.GetObject(
          blockId,
          OpenMode.ForRead
        );      ad = null;
      other =
        new List();      foreach (ObjectId attId in blk)
      {
        DBObject obj =
          (DBObject)tr.GetObject(
            attId,
            OpenMode.ForRead
          );
        AttributeDefinition ad2 =
          obj as AttributeDefinition;        if (ad2 != null)
        {
          if (ad2.Tag == attbName)
          {
            if (ad2.Constant)
            {
              Document doc =
                Application.DocumentManager.MdiActiveDocument;
              Editor ed = doc.Editor;              ed.WriteMessage(
                "\nAttribute to change is constant!"
              );
            }
            else
              ad = ad2;
          }
          else
            if (!ad2.Constant)
              other.Add(ad2);
        }
      }
    }    // Internal helper function to create a bubble
    // at a particular point    private Entity
      CreateNumberedBubbleAtPoint(
        Database db,
        BlockTableRecord btr,
        Transaction tr,
        Point3d pt,
        ObjectId blockId,
        AttributeDefinition ad,
        List other
      )
    {
      //  Create a new block reference      BlockReference br =
        new BlockReference(pt, blockId);      // Add it to the database      br.SetDatabaseDefaults();
      ObjectId blockRefId = btr.AppendEntity(br);
      tr.AddNewlyCreatedDBObject(br, true);      // Create an attribute reference for our main
      // attribute definition (where we'll put the
      // bubble's number)      AttributeReference ar =
        new AttributeReference();      // Add it to the database, and set its position, etc.      ar.SetDatabaseDefaults();
      ar.SetAttributeFromBlock(ad, br.BlockTransform);
      ar.Position =
        ad.Position.TransformBy(br.BlockTransform);
      ar.Tag = ad.Tag;      // Set the bubble's number      int bubbleNumber =
        m_baseNumber +
        m_nom.NextObjectNumber(blockRefId);      ar.TextString = bubbleNumber.ToString();
      ar.AdjustAlignment(db);      // Add the attribute to the block reference      br.AttributeCollection.AppendAttribute(ar);
      tr.AddNewlyCreatedDBObject(ar, true);      // Now we add attribute references for the
      // other attribute definitions      foreach (AttributeDefinition ad2 in other)
      {
        AttributeReference ar2 =
          new AttributeReference();        ar2.SetAttributeFromBlock(ad2, br.BlockTransform);
        ar2.Position =
          ad2.Position.TransformBy(br.BlockTransform);
        ar2.Tag = ad2.Tag;
        ar2.TextString = ad2.TextString;
        ar2.AdjustAlignment(db);        br.AttributeCollection.AppendAttribute(ar2);
        tr.AddNewlyCreatedDBObject(ar2, true);
      }
      return br;
    }    // Internal helper function to have the user
    // select a valid bubble index    private int
      GetBubbleNumber(
        Editor ed,
        string prompt
      )
    {
      int upper = m_nom.GetUpperBound();
      if (upper  m_ids;
    private List[i] m_free;    // Constructor    public NumberedObjectManager()
    {
      m_ids =
        new List();      m_free =
        new List[i]();
    }    // Clear the internal lists    public void Clear()
    {
      m_ids.Clear();
      m_free.Clear();
    }    // Return the first entry in the ObjectId list
    // (specify "true" if you want to skip
    // any null object IDs)    public int GetLowerBound(bool ignoreNull)
    {
      if (ignoreNull)
        // Define an in-line predicate to check
        // whether an ObjectId is null
        return
          m_ids.FindIndex(
            delegate(ObjectId id)
            {
              return id != ObjectId.Null;
            }
          );
      else
        return 0;
    }    // Return the last entry in the ObjectId list    public int GetUpperBound()
    {
      return m_ids.Count - 1;
    }    // Store the specified ObjectId in the next
    // available location in the list, and return
    // what that is    public int NextObjectNumber(ObjectId id)
    {
      int pos;
      if (m_free.Count > 0)
      {
        // Get the first free position, then remove
        // it from the "free" list        pos = m_free[0];
        m_free.RemoveAt(0);
        m_ids[pos] = id;
      }
      else
      {
        // There are no free slots (gaps in the numbering)
        // so we append it to the list        pos = m_ids.Count;
        m_ids.Add(id);
      }
      return pos;
    }    // Go through the list of objects and close any gaps
    // by shuffling the list down (easy, as we're using a
    // List rather than an array)    public ObjectIdCollection ReorderObjects()
    {
      // Create a collection of ObjectIds we'll return
      // for the caller to go and update
      // (so the renumbering will gets reflected
      // in the objects themselves)      ObjectIdCollection ids =
        new ObjectIdCollection();      // We'll go through the "free" list backwards,
      // to allow any changes made to the list of
      // objects to not affect what we're doing      List[i] rev =
        new List[i](m_free);
      rev.Reverse();      foreach (int pos in rev)
      {
        // First we remove the object at the "free"
        // position (in theory this should be set to
        // ObjectId.Null, as the slot has been marked
        // as blank)        m_ids.RemoveAt(pos);        // Now we go through and add the IDs of any
        // affected objects to the list to return        for (int i = pos; i  0)
      {
        ed.WriteMessage("\nIdx ObjectId");        int index = 0;
        foreach (ObjectId id in m_ids)
          ed.WriteMessage("\n{0} {1}", index++, id);
      }      if (m_free.Count > 0)
      {
        ed.WriteMessage("\n\nFree list: ");        foreach (int pos in m_free)
          ed.WriteMessage("{0} ", pos);
      }
    }    // Remove the initial n items from the list    public void RebaseList(int start)
    {
      // First we remove the ObjectIds      for (int i=0; i 复制代码As you can see, we've ended up with a few free slots in our list (and you'll note you need to add our "base number" (1) to get to the visible number). Here's the state of the drawing at this point:
Now let's try MB:复制代码This results in the item in internal slot 6 being moved to internal slot 1 (remember that base number :-) and the objects between being shuffled along. Here's what's on the screen at this point:
And finally we'll compact the list - removing those four free slots - with our RBS command:复制代码And here's how that looks:
I don't currently have any further enhancements planned for this application. Feel free to post a comment or send me an email if there's a particular direction in which you'd like to see it go. For instance, is it interesting to see support for prefixes/suffixes...?
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

  • 微信公众平台

  • 扫描访问手机版

  • 点击图片下载手机App

QQ|关于我们|小黑屋|乐筑天下 繁体中文

GMT+8, 2025-3-14 02:11 , Processed in 3.825033 second(s), 57 queries .

© 2020-2025 乐筑天下

联系客服 关注微信 帮助中心 下载APP 返回顶部 返回列表