博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
过滤动态块
阅读量:4497 次
发布时间:2019-06-08

本文共 5844 字,大约阅读时间需要 19 分钟。

Creating a selection filter that finds dynamic blocks in AutoCAD using .NET

 An interesting question came in via email from Rob Outman. He’s interested in applying a selection filter when the user selects dynamic blocks. This is straightforward for unmodified dynamic blocks – just as with standard blocks, you can filter on the block name very easily – but it works less well on dynamic blocks whose properties have been modified at an instance level.

 
Essentially what happens is this: if you select a block reference to a dynamic block in the AutoCAD editor and then use (for example) the Properties window to edit some of the custom properties associated with that block, the block definition gets duplicated as an anonymous block – with the modified properties, of course – and the reference gets updated to point to that. If you LIST the block reference, you can see that it still mentions the originating block by name, so it’s clear some connection still exists between the two block definitions, at the very least.
 
Listing the properties of a modified dynamic block reference
 
This makes it a little difficult to use a SelectionFilter to look for these BlockReference objects, as their associated BlockTableRecord has a name such as “*U24” rather than the name being searched for.
 
The answer to this riddle was actually reasonably straightforward, in the end. Using the very handy ArxDbg sample, it was easy to find out that the modified block definition contains XData linking back to the original – under the AcDbBlockRepBTag app name there’s an entry containing its handle – which we can use to compile a list of the (anonymous) names of modified blocks for which to look.
 
ArxDbg showing the XData linking modified dynamic blocks to their originals
 
We can then create a conditional SelectionFilter – with an “or” clause listing each of these names – and use that to find any block meeting the condition.
 
Here’s the C# code that does all this:
 
using Autodesk.AutoCAD.ApplicationServices;
 
using Autodesk.AutoCAD.Runtime;
 
using Autodesk.AutoCAD.DatabaseServices;
 
using Autodesk.AutoCAD.EditorInput;
 
using System.Collections.Generic;
 

namespace EntitySelection
 
{
 
  public class Commands
 
  {
 
    [CommandMethod("SDB")]
 
    static public void SelectDynamicBlocks()
 
    {
 
      var doc = Application.DocumentManager.MdiActiveDocument;
 
      var ed = doc.Editor;
 

      var pso =
 
        new PromptStringOptions(
 
          "\nName of dynamic block to search for"
 
        );
 
      pso.AllowSpaces = true;
 

      var pr = ed.GetString(pso);
 

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

      string blkName = pr.StringResult;
 

      List<string> blkNames = new List<string>();
 
      blkNames.Add(blkName);
 

      var tr = doc.TransactionManager.StartTransaction();
 
      using (tr)
 
      {
 
        var bt =
 
          (BlockTable)tr.GetObject(
 
            doc.Database.BlockTableId,
 
            OpenMode.ForRead
 
          );
 

        // Start by getting the handle of our block, if it exists
 

        if (!bt.Has(blkName))
 
        {
 
          ed.WriteMessage(
 
            "\nCannot find block called \"{0}\".", blkName
 
          );
 
          return;
 
        }
 

        var btr =
 
          (BlockTableRecord)tr.GetObject(
 
            bt[blkName], OpenMode.ForRead
 
          );
 

        var blkHand = btr.Handle;
 

        foreach (var bid in bt)
 
        {
 
          // We'll check each block in turn, to see if it has
 
          // XData pointing to our original block definition
 

          var btr2 =
 
            (BlockTableRecord)tr.GetObject(bid, OpenMode.ForRead);
 

          // Only check blocks that don't share the name :-)
 

          if (btr2.Name != blkName)
 
          {
 
            // And only check blocks with XData
 

            var xdata = btr2.XData;
 
            if (xdata != null)
 
            {
 
              // Get the XData as an array of TypeValues and loop
 
              // through it
 

              var tvs = xdata.AsArray();
 
              for (int i=0; i < tvs.Length; i++)
 
              {
 
                // The first value should be the RegAppName
 

                var tv = tvs;
 
                if (
 
                  tv.TypeCode == (int)DxfCode.ExtendedDataRegAppName
 
                )
 
                {
 
                  // If it's the one we care about...
 

                  if ((string)tv.Value == "AcDbBlockRepBTag")
 
                  {
 
                    // ... then loop through until we find a
 
                    // handle matching our blocks or otherwise
 
                    // another RegAppName
 

                    for (int j = i + 1; j < tvs.Length; j++)
 
                    {
 
                      tv = tvs[j];
 
                      if (
 
                        tv.TypeCode ==
 
                          (int)DxfCode.ExtendedDataRegAppName
 
                      )
 
                      {
 
                        // If we have another RegAppName, then
 
                        // we'll break out of this for loop and
 
                        // let the outer loop have a chance to
 
                        // process this section
 

                        i = j - 1;
 
                        break;
 
                      }
 

                      if (
 
                        tv.TypeCode ==
 
                          (int)DxfCode.ExtendedDataHandle
 
                      )
 
                      {
 
                        // If we have a matching handle...
 

                        if ((string)tv.Value == blkHand.ToString())
 
                        {
 
                          // ... then we can add the block's name
 
                          // to the list and break from both loops
 
                          // (which we do by setting the outer index
 
                          // to the end)
 

                          blkNames.Add(btr2.Name);
 
                          i = tvs.Length - 1;
 
                          break;
 
                        }
 
                      }
 
                    }
 
                  }
 
                }
 
              }
 
            }
 
          }
 
        }
 

        tr.Commit();
 
      }
 

      // Build a conditional filter list so that only
 
      // entities with the specified properties are
 
      // selected
 

      SelectionFilter sf =
 
        new SelectionFilter(CreateFilterListForBlocks(blkNames));
 
      PromptSelectionResult psr = ed.SelectAll(sf);
 

      ed.WriteMessage(
 
        "\nFound {0} entit{1}.",
 
        psr.Value.Count,
 
        (psr.Value.Count == 1 ? "y" : "ies")
 
      );
 
    }
 

    private static TypedValue[] CreateFilterListForBlocks(
 
      List<string> blkNames
 
    )
 
    {
 
      // If we don't have any block names, return null
 

      if (blkNames.Count == 0)
 
        return null;
 

      // If we only have one, return an array of a single value
 

      if (blkNames.Count == 1)
 
        return new TypedValue[] {
 
          new TypedValue(
 
            (int)DxfCode.BlockName,
 
           blkNames[0]
 
          )
 
        };
 

      // We have more than one block names to search for...
 

      // Create a list big enough for our block names plus
 
      // the containing "or" operators
 

      List<TypedValue> tvl =
 
        new List<TypedValue>(blkNames.Count + 2);
 

      // Add the initial operator
 

      tvl.Add(
 
        new TypedValue(
 
          (int)DxfCode.Operator,
 
          "<or"
 
        )
 
      );
 

      // Add an entry for each block name, prefixing the
 
      // anonymous block names with a reverse apostrophe
 

      foreach (var blkName in blkNames)
 
      {
 
        tvl.Add(
 
          new TypedValue(
 
            (int)DxfCode.BlockName,
 
            (blkName.StartsWith("*") ? "`" + blkName : blkName)
 
          )
 
        );
 
      }
 

      // Add the final operator
 

      tvl.Add(
 
        new TypedValue(
 
          (int)DxfCode.Operator,
 
          "or>"
 
        )
 
      );
 

      // Return an array from the list
 

      return tvl.ToArray();
 
    }
 
  }
 
}

 

转载于:https://www.cnblogs.com/swtool/p/3832396.html

你可能感兴趣的文章
HDU 1709 The Balance
查看>>
2016/7/7 设置wamp2.5 mysql密码 重点是mysql版本
查看>>
简介几种负载均衡原理
查看>>
micropython logging文档
查看>>
Webform(分页、组合查询)
查看>>
Foundation - NSDate
查看>>
geatpy - 遗传和进化算法相关算子的库函数(python)
查看>>
iOS 线程安全
查看>>
mysql 分组之后统计记录条数
查看>>
New STL Algorithms That Will Make A More Productive Developer
查看>>
js 对象 浅拷贝 和 深拷贝
查看>>
初识 python
查看>>
PCL Examples
查看>>
spring boot
查看>>
浏览器URL传参最大长度问题
查看>>
学习进度条
查看>>
Linux crontab 定时任务详解
查看>>
string成员函数
查看>>
onSaveInstanceState()方法问题
查看>>
[转]CocoaChina上一位工程师整理的开发经验(非常nice)
查看>>