找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1858|回复: 0

[分享] Fixing block draw-order in AutoCAD drawings exported by SmartSketch

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-6-6 22:32:41 | 显示全部楼层 |阅读模式

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

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

×
Fixing block draw-order in AutoCAD drawings exported by SmartSketch using .NET  Here’s a question I received recently from Dustin Vest, who works as a PDMS administrator at Fluor:
I am having a problem with Intergraph’s SmartSketch dwg files it exports... I found some code on your site that got me into the blocks, but I can’t seem to change the draworder of entities within the block. SmartPlant 3D exports all the symbols as blocks but with wipeouts on top of the rest of the block.
Dustin provided some code that was very nearly working – it really didn’t need much work to get it in shape – and has kindly allowed me to share it, here.
The below C# code defines a WTB command (for “WipeoutsToBottom” – it’s not a new Internet swearcronym ;-) that moves any wipeouts to the bottom of the selected block (or of all blocks in the drawing if the user hits Enter).

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

namespace BlockFixer
{
  public class Commands
  {
    [CommandMethod("WTB")]
    public static void WipeoutsToBottom()
    {
      var doc = Application.DocumentManager.MdiActiveDocument;
      var ed = doc.Editor;
      var db = doc.Database;

      try
      {
        // Ask the user to select a block or None for "all"

        var peo =
          new PromptEntityOptions("\nSelect block to fix <all>");
        peo.SetRejectMessage("Must be a block.");
        peo.AddAllowedClass(typeof(BlockReference), false);
        peo.AllowNone = true;

        var per = ed.GetEntity(peo);

        if (
          per.Status != PromptStatus.OK &&
          per.Status != PromptStatus.None
        )
          return;

        // If the user hit enter, run on all blocks in the drawing

        bool allBlocks = per.Status == PromptStatus.None;

        using (var tr = db.TransactionManager.StartTransaction())
        {
          var toProcess = new ObjectIdCollection();
          if (allBlocks)
          {
            var bt =
              (BlockTable)tr.GetObject(
                db.BlockTableId, OpenMode.ForRead
              );

            // Collect all the non-layout blocks in the drawing

            foreach (ObjectId btrId in bt)
            {
              var btr =
                (BlockTableRecord)tr.GetObject(
                  btrId, OpenMode.ForRead
                );
              if (!btr.IsLayout)
              {
                toProcess.Add(btrId);
              }
            }
          }
          else
          {
            // A specific block was selected, let's open it

            var brId = per.ObjectId;
            var br =
              (BlockReference)tr.GetObject(brId, OpenMode.ForRead);

            // Collect the ID of its underlying block definition

            toProcess.Add(br.BlockTableRecord);
          }

          var brIds = MoveWipeoutsToBottom(tr, toProcess);
          var count = toProcess.Count;

          // Open each of the returned block references and
          // request that they be redrawn

          foreach (ObjectId brId in brIds)
          {
            var br =
              (BlockReference)tr.GetObject(brId, OpenMode.ForWrite);

            // We want to redraw a specific block, so let's modify a
            // property on the selected block reference

            // We might also have called this method:
            // br.RecordGraphicsModified(true);
            // but setting a property works better with undo

            br.Visible = br.Visible;
          }

          // Report the number of blocks modified (after
          // being filtered by MoveWipeoutsToBottom())

          ed.WriteMessage(
            "\nModified {0} block definition{1}.",
            count, count == 1 ? "" : "s"
          );

          // Commit the transaction

          tr.Commit();
        }
      }
      catch (Autodesk.AutoCAD.Runtime.Exception e)
      {
        doc.Editor.WriteMessage(
        "\nException: {0}", e.Message
        );
      }
    }

    // Move the wipeouts to the bottom of the specified
    // block definitions

    private static ObjectIdCollection MoveWipeoutsToBottom(
      Transaction tr, ObjectIdCollection ids
    )
    {
      // The IDs of any block references we find
      // to return to the call for updating

      var brIds = new ObjectIdCollection();

      // We only need to get this once

      var wc = RXClass.GetClass(typeof(Wipeout));

      // Take a copy of the IDs passed in, as we'll modify the
      // original list for the caller to use

      var btrIds = new ObjectId[ids.Count];
      ids.CopyTo(btrIds, 0);

      // Loop through the blocks passed in, opening each one

      foreach (var btrId in btrIds)
      {
        var btr =
          (BlockTableRecord)tr.GetObject(
            btrId, OpenMode.ForWrite
          );

        // Collect the wipeouts in the block

        var wipeouts = new ObjectIdCollection();
        foreach (ObjectId id in btr)
        {
          var ent = (Entity)tr.GetObject(id, OpenMode.ForRead);
          if (ent.GetRXClass().IsDerivedFrom(wc))
          {
            wipeouts.Add(id);
          }
        }

        // Move the collected wipeouts to the bottom

        if (wipeouts.Count > 0)
        {
          // Modify the draw order table, if we have wipepouts

          var dot =
            (DrawOrderTable)tr.GetObject(
              btr.DrawOrderTableId, OpenMode.ForWrite
            );
          dot.MoveToBottom(wipeouts);

          // Collect the block references to this block, to pass
          // back to the calling function for updating

          var btrBrIds = btr.GetBlockReferenceIds(false, false);
          foreach (ObjectId btrBrId in btrBrIds)
          {
            brIds.Add(btrBrId);
          }
        }
        else
        {
          ids.Remove(btrId);
        }
      }
      return brIds;
    }
  }
}

The code is a bit longer than I had originally expected as I decided that, rather than relying on Editor.Regen() to reflect the changes to the drawing, it would be cleaner to modify each block reference in turn in order to force their graphics to be refreshed.
We’re not actually making a change to each block reference, but it’s not enough to just open them for write. The classic approach, here, would be to call RecordGraphicsModified(true) on each object, but I’ve actually found that making a property modification (even if to the same value) leads to undo working better – it forces a redraw even on undo. So I’ve chosen to set the Visible property of each block reference to the current value of the Visible property – I’m sure you’ll agree that’s as innocuous a modification as you can get. :-)
The function that checks each block for wipeouts and then modifies the draw order now collects the block references to these blocks and returns them to the caller. It’s clear that calling Regen() would have been simpler (i.e. taking fewer lines of code), but it would have exhibited similar behaviour to calling RecordGraphicsModified() with respect to undo. So while it takes more code, this approach is ultimately cleaner and works better, too.
Dustin has tried the application and tells me it works well for him – and it works well on the drawings Dustin provided for me to test with – but, beyond that, as I don’t personally use SmartSketch I have to take his word for it. If any other SmartSketch users who’ve hit this particular problem are able to give this a test, it’d be great to get some feedback in the comments.


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

本版积分规则

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

GMT+8, 2024-12-23 09:56 , Processed in 0.410355 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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