qq1254582201 发表于 3 天前

【转载】CAD多重引线相关内容转载合集

本帖最后由 qq1254582201 于 2025-4-16 16:04 编辑

MLeader text that reflects MLeaderStyle settings


这是一个基于现有MLeaderStyle创建MLeader的简短代码片段。为了使MLeader的文本正确地遵循对MLeaderStyle所做的任何更改,有必要克隆MLeaderStyle。DefaultText并将其用作MLeader的文本。在不依赖DefaultText的情况下创建新的多行文字可能会导致文本不反映以后对MLeaderStyle所做的任何更改。
public void MLTestMethod()
{
    Editor ed = default(Editor);
    ed = Application.DocumentManager.MdiActiveDocument.Editor;

    PromptPointResult ppr1 = default(PromptPointResult);
    ppr1 = ed.GetPoint(
      new PromptPointOptions("Select start point"));

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

    PromptPointResult ppr2 = default(PromptPointResult);
    ppr2 = ed.GetPoint(
            new PromptPointOptions("Select end point"));
    if (ppr2.Status != PromptStatus.OK)
      return;

    Database db = HostApplicationServices.WorkingDatabase;

    ObjectId myMLeaderId = ObjectId.Null;
    using (Transaction trans
                = db.TransactionManager.StartTransaction())
    {
      ObjectId myleaderStyleId = db.MLeaderstyle;
      MLeaderStyle mlstyle
            = trans.GetObject(myleaderStyleId,
                        OpenMode.ForRead) as MLeaderStyle;

      using (MLeader myMLeader = new MLeader())
      {
            myMLeader.SetDatabaseDefaults();
            myMLeader.PostMLeaderToDb(db);
            myMLeaderId = myMLeader.ObjectId;
            myMLeader.MLeaderStyle = db.MLeaderstyle;

            int leaderIndex = myMLeader.AddLeader();
            int leaderLineIndex
                = myMLeader.AddLeaderLine(leaderIndex);
            myMLeader.AddFirstVertex(
                        leaderLineIndex, ppr1.Value);
            myMLeader.AddLastVertex(
                        leaderLineIndex, ppr2.Value);

            MText myMText
                = mlstyle.DefaultMText.Clone() as MText;
            if (myMText != null)
            {
                myMText.SetContentsRtf("Autodesk");
                myMLeader.MText = myMText;
            }
      }
      trans.Commit();
    }
}


qq1254582201 发表于 3 天前

AutoCAD .NET: MultiLeader (MLeader) Jig 4 – Jigging Block with AttributeWe provided various jig implementations before, either using EntityJig or DrawJig, either from scratch or with the assistance of the Entity Jigger or Draw Jigger of AcadNetAddinWizard(Pro).We demonstrated how to jig a MultiLeader programmatically through an arrow location and a single landing location using AutoCAD .NET and C#. We also showed how to jig multiple landing locations. We presented last time how to jig block content instead of the default MText content. In this post, we are going to extend the jig to support any blocks having attributes defined. This will make the MLeaderJigger more flexible and useful since the block content will likely change from one case to another in the real design world.Here we go.#region Namespaces

using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.Drawing;
using System.IO;

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

using MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application;
using MgdAcDocument = Autodesk.AutoCAD.ApplicationServices.Document;
using AcWindowsNS = Autodesk.AutoCAD.Windows;

#endregion

namespace AcadNetCSharp
{
    public class MLeaderJigger4 : EntityJig
    {
      #region Fields

      private const string BlockName = "tagAtt";
      public static string TagContent = "";

      public int mCurJigFactorIndex = 1;// Jig Factor Index

      public Autodesk.AutoCAD.Geometry.Point3d mArrowLocation; // Jig Factor #1
      public Autodesk.AutoCAD.Geometry.Point3d mLandingLocation; // Jig Factor #2

      #endregion

      #region Constructors

      public MLeaderJigger4(MLeader ent)
            : base(ent)
      {
            Entity.SetDatabaseDefaults();

            Entity.ContentType = ContentType.BlockContent;

            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                Entity.BlockContentId = bt;
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(Entity.BlockContentId, OpenMode.ForWrite);
                if (btr.HasAttributeDefinitions)
                {
                  foreach (ObjectId id in btr)
                  {
                        DBObject obj = tr.GetObject(id, OpenMode.ForRead);
                        if (obj is AttributeDefinition)
                        {
                            AttributeDefinition ad = obj as AttributeDefinition;
                            AttributeReference ar = new AttributeReference();
                            ar.SetAttributeFromBlock(ad, Matrix3d.Displacement(Entity.BlockPosition - Point3d.Origin));
                            ar.TextString = TagContent;

                            Entity.SetBlockAttribute(id, ar);
                        }
                  }
                }

                tr.Commit();
            }

            Entity.EnableDogleg = true;
            Entity.EnableLanding = true;
            Entity.EnableFrameText = false;

            Entity.AddLeaderLine(mLandingLocation);
            Entity.SetFirstVertex(0, mArrowLocation);

            Entity.TransformBy(UCS);
      }

      #endregion

      #region Properties

      private Editor Editor
      {
            get
            {
                return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
            }
      }

      private Matrix3d UCS
      {
            get
            {
                return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem;
            }
      }

      #endregion

      #region Overrides

      public new MLeader Entity// Overload the Entity property for convenience.
      {
            get
            {
                return base.Entity as MLeader;
            }
      }

      protected override bool Update()
      {

            switch (mCurJigFactorIndex)
            {
                case 1:
                  Entity.SetFirstVertex(0, mArrowLocation);
                  Entity.SetLastVertex(0, mArrowLocation);

                  break;
                case 2:
                  Entity.SetLastVertex(0, mLandingLocation);

                  break;

                default:
                  return false;
            }

            return true;
      }

      protected override SamplerStatus Sampler(JigPrompts prompts)
      {
            switch (mCurJigFactorIndex)
            {
                case 1:
                  JigPromptPointOptions prOptions1 = new JigPromptPointOptions("\nArrow Location:");
                  // Set properties such as UseBasePoint and BasePoint of the prompt options object if necessary here.
                  prOptions1.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect | UserInputControls.UseBasePointElevation;
                  PromptPointResult prResult1 = prompts.AcquirePoint(prOptions1);
                  if (prResult1.Status == PromptStatus.Cancel && prResult1.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult1.Value.Equals(mArrowLocation))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mArrowLocation = prResult1.Value;
                        return SamplerStatus.OK;
                  }
                case 2:
                  JigPromptPointOptions prOptions2 = new JigPromptPointOptions("\nLanding Location:");
                  // Set properties such as UseBasePoint and BasePoint of the prompt options object if necessary here.
                  prOptions2.UseBasePoint = true;
                  prOptions2.BasePoint = mArrowLocation;
                  prOptions2.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect | UserInputControls.UseBasePointElevation;
                  PromptPointResult prResult2 = prompts.AcquirePoint(prOptions2);
                  if (prResult2.Status == PromptStatus.Cancel && prResult2.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult2.Value.Equals(mLandingLocation))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mLandingLocation = prResult2.Value;
                        return SamplerStatus.OK;
                  }

                default:
                  break;
            }

            return SamplerStatus.OK;
      }



      #endregion

      #region Methods to Call

      public static MLeader Jig()
      {
            MLeaderJigger4 jigger = null;
            try
            {
                jigger = new MLeaderJigger4(new MLeader());
                PromptResult pr;
                do
                {
                  pr = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.Drag(jigger);
                  if (pr.Status == PromptStatus.Keyword)
                  {
                        // Keyword handling code

                  }
                  else
                  {
                        jigger.mCurJigFactorIndex++;
                  }
                } while (pr.Status != PromptStatus.Cancel && pr.Status != PromptStatus.Error && jigger.mCurJigFactorIndex <= 2);

                if (pr.Status == PromptStatus.Cancel || pr.Status == PromptStatus.Error)
                {
                  if (jigger != null && jigger.Entity != null)
                        jigger.Entity.Dispose();

                  return null;
                }
            
                return jigger.Entity;
            }
            catch(System.Exception ex)
            {
                MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());

                if (jigger != null && jigger.Entity != null)
                  jigger.Entity.Dispose();

                return null;
            }
      }

      #endregion

      #region Test Commands

      
      public static void TestMLeaderJigger4_Method()
      {
            try
            {
                TagContent = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.GetString("\nTag: ").StringResult;
                Entity jigEnt = MLeaderJigger4.Jig();
                if (jigEnt != null)
                {
                  Database db = HostApplicationServices.WorkingDatabase;
                  using (Transaction tr = db.TransactionManager.StartTransaction())
                  {
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        btr.AppendEntity(jigEnt);
                        tr.AddNewlyCreatedDBObject(jigEnt, true);
                        tr.Commit();
                  }
                }
            }
            catch (System.Exception ex)
            {
                MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
            }
      }

      #endregion
    }
}

The workflow and output may look like the following:
https://spiderinnet1.typepad.com/.a/6a0153928ee38e970b01bb084d0f02970d-800wi

As can be seen, the block attribute value (tag) is collected first so that the tag with the exact string value can be jigged nicely along with the arrow, leader line, and standing line. The UCS is still perfectly honored. Before running the jig test code, please make sure a block named “tagAtt” exists and it has at least a block attribute defined. The block attribute can have any tag name. If multiple block attributes defined, all of them will have the value as input at the beginning of the jigging.


qq1254582201 发表于 3 天前

AutoCAD .NET: Jig MultiLeader (MLeader) Using EntityJig and C#We provided various jig implementations before, either using EntityJig or DrawJig, either from scratch or with the assistance of the Entity Jigger or Draw Jigger of AcadNetAddinWizard(Pro).
Recently, Damyan requested a jig for MultiLeader. Since the MultiLeader is becoming more and more popular, we think it’s worth of another post to demonstrate how to jig a MultiLeader programmatically using AutoCAD .NET and C#.Here we go.#region Namespaces

using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.Drawing;
using System.IO;

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

using MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application;
using MgdAcDocument = Autodesk.AutoCAD.ApplicationServices.Document;
using AcWindowsNS = Autodesk.AutoCAD.Windows;

#endregion

namespace AcadNetCSharp
{
    public class MLeaderJigger : EntityJig
    {
      #region Fields

      public int mCurJigFactorIndex = 1;// Jig Factor Index

      public Autodesk.AutoCAD.Geometry.Point3d mArrowLocation; // Jig Factor #1
      public Autodesk.AutoCAD.Geometry.Point3d mTextLocation; // Jig Factor #2
      public string mMText; // Jig Factor #3


      #endregion

      #region Constructors

      public MLeaderJigger(MLeader ent)
            : base(ent)
      {
            Entity.SetDatabaseDefaults();
            
            Entity.ContentType = ContentType.MTextContent;
            Entity.MText = new MText();
            Entity.MText.SetDatabaseDefaults();

            Entity.EnableDogleg = true;
            Entity.EnableLanding = true;
            Entity.EnableFrameText = false;

            Entity.AddLeaderLine(mTextLocation);
            Entity.SetFirstVertex(0, mArrowLocation);

            Entity.TransformBy(UCS);
      }

      #endregion

      #region Properties

      private Editor Editor
      {
            get
            {
                return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
            }
      }

      private Matrix3d UCS
      {
            get
            {
                return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem;
            }
      }

      #endregion

      #region Overrides

      public new MLeader Entity// Overload the Entity property for convenience.
      {
            get
            {
                return base.Entity as MLeader;
            }
      }

      protected override bool Update()
      {

            switch (mCurJigFactorIndex)
            {
                case 1:
                  Entity.SetFirstVertex(0, mArrowLocation);
                  Entity.SetLastVertex(0, mArrowLocation);

                  break;
                case 2:
                  Entity.SetLastVertex(0, mTextLocation);

                  break;
                case 3:
                  Entity.MText.Contents = mMText;

                  break;

                default:
                  return false;
            }

            return true;
      }

      protected override SamplerStatus Sampler(JigPrompts prompts)
      {
            switch (mCurJigFactorIndex)
            {
                case 1:
                  JigPromptPointOptions prOptions1 = new JigPromptPointOptions("\nArrow Location:");
                  // Set properties such as UseBasePoint and BasePoint of the prompt options object if necessary here.
                  prOptions1.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect | UserInputControls.UseBasePointElevation;
                  PromptPointResult prResult1 = prompts.AcquirePoint(prOptions1);
                  if (prResult1.Status == PromptStatus.Cancel && prResult1.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult1.Value.Equals(mArrowLocation))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mArrowLocation = prResult1.Value;
                        return SamplerStatus.OK;
                  }
                case 2:
                  JigPromptPointOptions prOptions2 = new JigPromptPointOptions("\nLanding Location:");
                  // Set properties such as UseBasePoint and BasePoint of the prompt options object if necessary here.
                  prOptions2.UseBasePoint = true;
                  prOptions2.BasePoint = mArrowLocation;
                  prOptions2.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect | UserInputControls.UseBasePointElevation;
                  PromptPointResult prResult2 = prompts.AcquirePoint(prOptions2);
                  if (prResult2.Status == PromptStatus.Cancel && prResult2.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult2.Value.Equals(mTextLocation))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mTextLocation = prResult2.Value;
                        return SamplerStatus.OK;
                  }
                case 3:
                  JigPromptStringOptions prOptions3 = new JigPromptStringOptions("\nText Content:");
                  // Set properties such as UseBasePoint and BasePoint of the prompt options object if necessary here.
                  prOptions3.UserInputControls = UserInputControls.AcceptOtherInputString;
                  PromptResult prResult3 = prompts.AcquireString(prOptions3);
                  if (prResult3.Status == PromptStatus.Cancel && prResult3.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult3.StringResult.Equals(mMText))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mMText = prResult3.StringResult;
                        return SamplerStatus.OK;
                  }

                default:
                  break;
            }

            return SamplerStatus.OK;
      }



      #endregion

      #region Methods to Call

      public static MLeader Jig()
      {
            MLeaderJigger jigger = null;
            try
            {
                jigger = new MLeaderJigger(new MLeader());
                PromptResult pr;
                do
                {
                  pr = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.Drag(jigger);
                  if (pr.Status == PromptStatus.Keyword)
                  {
                        // Keyword handling code

                  }
                  else
                  {
                        jigger.mCurJigFactorIndex++;
                  }
                } while (pr.Status != PromptStatus.Cancel && pr.Status != PromptStatus.Error && jigger.mCurJigFactorIndex <= 3);

                if (pr.Status == PromptStatus.Cancel || pr.Status == PromptStatus.Error)
                {
                  if (jigger != null && jigger.Entity != null)
                        jigger.Entity.Dispose();

                  return null;
                }
                else
                {
                  MText text = new MText();
                  text.Contents = jigger.mMText;
                  text.TransformBy(jigger.UCS);
                  jigger.Entity.MText = text;
                  return jigger.Entity;
                }
            }
            catch
            {
                if (jigger != null && jigger.Entity != null)
                  jigger.Entity.Dispose();

                return null;
            }
      }

      #endregion

      #region Test Commands

      
      public static void TestMLeaderJigger_Method()
      {
            try
            {
                Entity jigEnt = MLeaderJigger.Jig();
                if (jigEnt != null)
                {
                  Database db = HostApplicationServices.WorkingDatabase;
                  using (Transaction tr = db.TransactionManager.StartTransaction())
                  {
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        btr.AppendEntity(jigEnt);
                        tr.AddNewlyCreatedDBObject(jigEnt, true);
                        tr.Commit();
                  }
                }
            }
            catch (System.Exception ex)
            {
                MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
            }
      }

      #endregion
    }
}

The workflow and output may look like the following:

https://spiderinnet1.typepad.com/.a/6a0153928ee38e970b01bb0843d943970d-800wi
As can be seen, it follows almost exactly the same default jigging steps that the AutoCAD native MLeader command does. In addition, UCS is honored perfectly. From coding perspective, the Entity Jigger of AcadNetAddinWizardPro was used to set up the jigging framework to save time and effort.


qq1254582201 发表于 3 天前

AutoCAD .NET: MultiLeader (MLeader) Jig 2 – Jigging Multiple Landing PointsWe provided various jig implementations before, either using EntityJig or DrawJig, either from scratch or with the assistance of the Entity Jigger or Draw Jigger of AcadNetAddinWizard(Pro).We demonstrated previously how to jig a MultiLeader programmatically through an arrow location and a single landing location using AutoCAD .NET and C#. In this post, let’s see how to jig multiple landing locations by modifying the previous MultiLeader (MLeader) Jig a little bit.Here we go.#region Namespaces

using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.Drawing;
using System.IO;

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

using MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application;
using MgdAcDocument = Autodesk.AutoCAD.ApplicationServices.Document;
using AcWindowsNS = Autodesk.AutoCAD.Windows;

#endregion

namespace AcadNetCSharp
{
    public class MLeaderJigger2 : EntityJig
    {
      #region Fields

      public int mCurJigFactorIndex = 1;// Jig Factor Index

      public Autodesk.AutoCAD.Geometry.Point3d mArrowLocation; // Jig Factor #1
      public Autodesk.AutoCAD.Geometry.Point3d mTextLocation; // Jig Factor #2

      #endregion

      #region Constructors

      public MLeaderJigger2(MLeader ent)
            : base(ent)
      {
            Entity.SetDatabaseDefaults();
            
            Entity.ContentType = ContentType.MTextContent;
            Entity.MText = new MText();
            Entity.MText.SetDatabaseDefaults();

            Entity.EnableDogleg = true;
            Entity.EnableLanding = true;
            Entity.EnableFrameText = false;

            Entity.AddLeaderLine(mTextLocation);
            Entity.SetFirstVertex(0, mArrowLocation);

            Entity.TransformBy(UCS);
      }

      #endregion

      #region Properties

      private Editor Editor
      {
            get
            {
                return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
            }
      }

      private Matrix3d UCS
      {
            get
            {
                return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem;
            }
      }

      #endregion

      #region Overrides

      public new MLeader Entity// Overload the Entity property for convenience.
      {
            get
            {
                return base.Entity as MLeader;
            }
      }

      protected override bool Update()
      {

            switch (mCurJigFactorIndex)
            {
                case 1:
                  Entity.SetFirstVertex(0, mArrowLocation);
                  Entity.SetLastVertex(0, mArrowLocation);

                  break;
                case 2:
                default:
                  Entity.SetLastVertex(0, mTextLocation);

                  break;
            }

            return true;
      }

      protected override SamplerStatus Sampler(JigPrompts prompts)
      {
            switch (mCurJigFactorIndex)
            {
                case 1:
                  JigPromptPointOptions prOptions1 = new JigPromptPointOptions("\nArrow Location:");
                  // Set properties such as UseBasePoint and BasePoint of the prompt options object if necessary here.
                  prOptions1.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect | UserInputControls.UseBasePointElevation;
                  PromptPointResult prResult1 = prompts.AcquirePoint(prOptions1);
                  if (prResult1.Status == PromptStatus.Cancel && prResult1.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult1.Value.Equals(mArrowLocation))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mArrowLocation = prResult1.Value;
                        return SamplerStatus.OK;
                  }
                case 2:
                default:
                  JigPromptPointOptions prOptions2 = new JigPromptPointOptions("\nLanding Location:");
                  prOptions2.Keywords.Add("Done");
                  prOptions2.UseBasePoint = true;
                  prOptions2.BasePoint = mTextLocation == Point3d.Origin ? mArrowLocation : mTextLocation;
                  prOptions2.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect | UserInputControls.UseBasePointElevation;
                  PromptPointResult prResult2 = prompts.AcquirePoint(prOptions2);
                  if (prResult2.Status == PromptStatus.Cancel && prResult2.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult2.Value.Equals(mTextLocation))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mTextLocation = prResult2.Value;
                        return SamplerStatus.OK;
                  }

            }
      }


      #endregion

      #region Methods to Call

      public static MLeader Jig()
      {
            MLeaderJigger2 jigger = null;
            try
            {
                jigger = new MLeaderJigger2(new MLeader());
                PromptResult pr;
                do
                {
                  pr = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.Drag(jigger);
                  if (pr.Status == PromptStatus.Keyword)
                  {
                        // Keyword handling code
                        if(pr.StringResult == "Done")
                        {
                            break;
                        }
                  }
                  else
                  {
                        jigger.mCurJigFactorIndex++;
                        if (jigger.mCurJigFactorIndex > 2)
                            jigger.Entity.AddLastVertex(0, jigger.mTextLocation);
                  }
                } while (pr.Status != PromptStatus.Cancel && pr.Status != PromptStatus.Error );

                if (pr.Status == PromptStatus.Cancel || pr.Status == PromptStatus.Error)
                {
                  if (jigger != null && jigger.Entity != null)
                        jigger.Entity.Dispose();

                  return null;
                }
                else
                {
                  PromptResult prLabel = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.GetString("Label: ");
                  MText text = new MText();
                  text.Contents = prLabel.StringResult;
                  text.TransformBy(jigger.UCS);
                  jigger.Entity.MText = text;
                  return jigger.Entity;
                }
            }
            catch
            {
                if (jigger != null && jigger.Entity != null)
                  jigger.Entity.Dispose();

                return null;
            }
      }

      #endregion

      #region Test Commands

      
      public static void TestMLeaderJigger2_Method()
      {
            try
            {
                Entity jigEnt = MLeaderJigger2.Jig();
                if (jigEnt != null)
                {
                  Database db = HostApplicationServices.WorkingDatabase;
                  using (Transaction tr = db.TransactionManager.StartTransaction())
                  {
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        btr.AppendEntity(jigEnt);
                        tr.AddNewlyCreatedDBObject(jigEnt, true);
                        tr.Commit();
                  }
                }
            }
            catch (System.Exception ex)
            {
                MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
            }
      }

      #endregion
    }
}

The workflow and output may look like the following:
https://spiderinnet1.typepad.com/.a/6a0153928ee38e970b01bb08482d0a970d-800wi

As can be seen, as many as landing locations can be dragged this time by the same single Multileader (MLeader) Jig. UCS is also honored perfectly. From coding perspective, the MLeaderJigger version 2 was updated a bit from the MLeaderJigger version 1 as introduced before, whose fundamental jigging framework was set up by the Entity Jigger of AcadNetAddinWizardPro .


qq1254582201 发表于 3 天前

How to create MLeader objects in .Net?

Below are two samples that illustrates MLeader creation in C#:The first creates a MLeader with a MText content:
[CommandMethod("netTextMLeader"public static void netTextMLeader(){    Document doc = Application.DocumentManager.MdiActiveDocument;    Database db = doc.Database;    Editor ed = doc.Editor;     using (Transaction Tx = db.TransactionManager.StartTransaction())    {      BlockTable table = Tx.GetObject(            db.BlockTableId,            OpenMode.ForRead)                as BlockTable;       BlockTableRecord model = Tx.GetObject(            table[BlockTableRecord.ModelSpace],            OpenMode.ForWrite)                as BlockTableRecord;       MLeader leader = new MLeader();      leader.SetDatabaseDefaults();       leader.ContentType = ContentType.MTextContent;         MText mText = new MText();      mText.SetDatabaseDefaults();      mText.Width = 100;      mText.Height = 50;      mText.SetContentsRtf("MLeader");      mText.Location = new Point3d(4, 2, 0);       leader.MText = mText;       int idx = leader.AddLeaderLine(new Point3d(1, 1, 0));      leader.AddFirstVertex(idx, new Point3d(0, 0, 0));       model.AppendEntity(leader);      Tx.AddNewlyCreatedDBObject(leader, true);       Tx.Commit();    }}
The second creates a MLeader with a Block content. It also handles the case where the MLeader block contains attributes and set them to a default value:
[CommandMethod("netBlockMLeader"public static void netBlockMLeader(){    Document doc = Application.DocumentManager.MdiActiveDocument;    Database db = doc.Database;    Editor ed = doc.Editor;     using (Transaction Tx = db.TransactionManager.StartTransaction())    {      BlockTable table = Tx.GetObject(            db.BlockTableId,            OpenMode.ForRead)                as BlockTable;       BlockTableRecord model = Tx.GetObject(            table[BlockTableRecord.ModelSpace],            OpenMode.ForWrite)                as BlockTableRecord;       if (!table.Has("BlkLeader"))      {            ed.WriteMessage(                "\nYou need to define a \"BlkLeader\" first...");            return;      }       MLeader leader = new MLeader();      leader.SetDatabaseDefaults();       leader.ContentType = ContentType.BlockContent;       leader.BlockContentId = table["BlkLeader"];      leader.BlockPosition = new Point3d(4, 2, 0);       int idx = leader.AddLeaderLine(new Point3d(1, 1, 0));      leader.AddFirstVertex(idx, new Point3d(0, 0, 0));       //Handle Block Attributes      int AttNumber = 0;      BlockTableRecord blkLeader = Tx.GetObject(            leader.BlockContentId,            OpenMode.ForRead)                as BlockTableRecord;       //Doesn't take in consideration oLeader.BlockRotation      Matrix3d Transfo = Matrix3d.Displacement(            leader.BlockPosition.GetAsVector());       foreach (ObjectId blkEntId in blkLeader)      {            AttributeDefinition AttributeDef = Tx.GetObject(                blkEntId,                OpenMode.ForRead)                  as AttributeDefinition;             if (AttributeDef != null)            {                AttributeReference AttributeRef =                  new AttributeReference();                 AttributeRef.SetAttributeFromBlock(                  AttributeDef,                  Transfo);                 AttributeRef.Position =                  AttributeDef.Position.TransformBy(Transfo);                 AttributeRef.TextString = "Attrib #" + (++AttNumber);                 leader.SetBlockAttribute(blkEntId, AttributeRef);            }      }       model.AppendEntity(leader);      Tx.AddNewlyCreatedDBObject(leader, true);       Tx.Commit();    }}


qq1254582201 发表于 3 天前

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

namespace LeaderCreation
{
    public class Commands
    {
      public void CreateLeader()
      {
            Document activeDoc = Application.DocumentManager.MdiActiveDocument;
            Database db = activeDoc.Database;
            Editor ed = activeDoc.Editor;

            PromptPointResult ppr1 = ed.GetPoint("\nSpecify leaderarrowhead location");

            if (ppr1.Status != PromptStatus.OK)
            {
                return;
            }

            Point3d startPoint = ppr1.Value;
            PromptPointOptions ppo = new PromptPointOptions("\nSpecify leader landing location");
            ppo.BasePoint = startPoint;
            ppo.UseBasePoint = true;
            PromptPointResult ppr2 = ed.GetPoint(ppo);

            if (ppr2.Status != PromptStatus.OK)
            {
                return;
            }

            Point3d endPoint = ppr2.Value;
            string blockText = "Autodesk";

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);

                MLeader ml = new MLeader();
                ml.SetDatabaseDefaults();

                int leaderNumber = ml.AddLeader();
                int leaderLineNum = ml.AddLeaderLine(leaderNumber);
                ml.AddFirstVertex(leaderLineNum, startPoint);
                ml.AddLastVertex(leaderLineNum, endPoint);

                MText mt = new MText();
                mt.Contents = blockText;

                double direction = 1.0;
                if ((endPoint - startPoint).DotProduct(Vector3d.XAxis) < 0.0)
                {
                  direction = -1.0;
                }

                ml.SetDogleg(leaderNumber, Vector3d.XAxis.MultiplyBy(direction));
                ml.MText = mt;

                btr.UpgradeOpen();
                btr.AppendEntity(ml);

                tr.AddNewlyCreatedDBObject(ml, true);
                tr.Commit();
            }
      }
    }
}设置多重引线文字左边还是右边

qq1254582201 发表于 3 天前

本帖最后由 qq1254582201 于 2025-4-16 16:04 编辑

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using 创建多重引线;



namespace 创建多重引线
{
    public class Class1
    {
      
      public static void DrawMleader()
      {
            var MLStyleId = CreateMleaderStyle("xuguang");
            //获取当前数据库
            var acDoc = Application.DocumentManager.MdiActiveDocument;
            var acCurDb = acDoc.Database;
            //启动事务
            using (var acTrans = acCurDb.TransactionManager.StartTransaction())
            {
                //以读模式打开块表
                var acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;

                //以写模式打开块表记录模型空间
                var acBlkTblRec = acTrans.GetObject(acBlkTbl,
                  OpenMode.ForWrite) as BlockTableRecord;

                var pMLeader = new MLeader();
                pMLeader.SetDatabaseDefaults();
                pMLeader.MLeaderStyle = MLStyleId;
                var pos = new Point3d(200, 200, 200);
                var posTmp = new Point3d(220, 220, 0);
                var sn = pMLeader.AddLeaderLine(pos);
                pMLeader.AddFirstVertex(sn, pos);
                pMLeader.SetFirstVertex(sn, pos);
                pMLeader.SetLastVertex(sn, posTmp);

                //创建多行文字(MText)注释
                var pMtext = new MText();
                pMtext.Contents = "创建多重引线";
                pMtext.TextHeight = 3;
                pMtext.TextStyleId = acCurDb.Textstyle;

                pMtext.Location = posTmp;
                pMLeader.MText = pMtext;
            
                //添加新对象到模型空间,记录事务
                acBlkTblRec.AppendEntity(pMLeader);
                acTrans.AddNewlyCreatedDBObject(pMLeader, true);

                //提交修改,回收内存
                acTrans.Commit();
            }
            acDoc.Editor.Regen();
      }

      private static ObjectId CreateMleaderStyle(string MlName)
      {
            var acDoc = Application.DocumentManager.MdiActiveDocument;
            var db = HostApplicationServices.WorkingDatabase;

            using (var acTrans = acDoc.TransactionManager.StartTransaction())
            {
                var DbDictionary = acTrans.GetObject(db.MLeaderStyleDictionaryId, OpenMode.ForWrite) as DBDictionary;
                //获取所有样式
                if (DbDictionary.Contains(MlName))
                {
                  return DbDictionary.GetAt(MlName);
                }
                var newMleadStyle = new MLeaderStyle();
                newMleadStyle.TextAlignAlwaysLeft = true;
                newMleadStyle.Annotative = AnnotativeStates.True;
                newMleadStyle.DrawMLeaderOrderType = DrawMLeaderOrderType.DrawLeaderFirst;
                newMleadStyle.TextAttachmentType = TextAttachmentType.AttachmentMiddle; //Text连接方式
                newMleadStyle.TextAttachmentDirection = TextAttachmentDirection.AttachmentHorizontal; //文字水平排列
                newMleadStyle.TextAlignmentType = TextAlignmentType.CenterAlignment; //Text排列方式
                newMleadStyle.LeaderLineColor =
                  Color.FromColorIndex(ColorMethod.ByLayer, 256);
                newMleadStyle.LeaderLineType = LeaderType.StraightLeader;
                newMleadStyle.ContentType = ContentType.MTextContent;
                newMleadStyle.ArrowSize = 3.0; //箭头大小
                newMleadStyle.BreakSize = 0.6; //基线打断大小
                newMleadStyle.DoglegLength = 1.25; //基线距离
                newMleadStyle.EnableLanding = true;
                newMleadStyle.EnableDogleg = true; //显示基线
                newMleadStyle.EnableFrameText = true; //显示文本框
                newMleadStyle.LandingGap = 1; //基线间隙
                newMleadStyle.MaxLeaderSegmentsPoints = 2; //最大引线点数
                newMleadStyle.TextStyleId = acDoc.Database.Textstyle; //文字样式
                newMleadStyle.TextHeight = 3.0;
                newMleadStyle.PostMLeaderStyleToDb(db, MlName);
                newMleadStyle.DowngradeOpen();
                acTrans.Commit();
                return newMleadStyle.ObjectId;
            }
      }
    }
}
多重引线样式的创建

qq1254582201 发表于 3 天前

揭秘 DXF:LEADER 和 MULTILEADER 实施说明
[*]介绍
[*]我的实现

[*]领导
[*]钩线
[*]样 条
[*]LEADER 是传统的

[*]多重引线
[*]信息来源
[*]结构
[*]实体句柄
[*]几何学
[*]计算狗腿/着陆
[*]休息

[*]内容
[*]文本内容
[*]阻止内容

[*]颜色
[*]挤压件 (OCS)

介绍作为我在开源地理空间数据抽象库 (GDAL) 中开发 DXF 驱动程序的工作的一部分,我的任务是实现对引导元素的支持。对于不熟悉 CAD 的人来说,引线本质上是从文本标签或符号发出的箭头,用于指出绘图的某些重要方面。https://atlight.github.io/formats/images/leader-demo.pngAutoCAD 提供了两种不同类型的引线对象:
[*]“经典”LEADER 实体从早期开始就是 AutoCAD 的一部分,并且与 DIMENSION 实体有很多共同之处,包括通用的样式基础结构(DIMSTYLE 和替代系统)。DXF 规范中 LEADER 的文档相当全面;请参阅以下部分。
[*]AutoCAD 2008 中引入了 MULTILEADER 图元,AutoCAD 用户可能更熟悉的是 MLEADER(命令的名称)。你可以把它想象成 MTEXT、INSERT、ATTRIB 和 LWPOLYLINE 的奇怪组合,上面倒了足够多的秘诀,以至于你永远不确定发生了什么。MULTILEADER 是记录最严重的 DXF 实体之一;DXF 规范中的描述几乎毫无用处。有关如何在项目中实现它的一些提示,请参阅下文。
我希望这些旨在补充 DXF 规范的注释能够帮助那些需要以编程方式与 DXF 格式交互但 AutoCAD 知识有限,甚至可能无法访问该软件的人。我假设对 DXF 格式有基本的了解。我的实现这是我为 GDAL/OGR 开发的 DXF LEADER 和 MULTILEADER 转换器的 C++ 代码。即使您完全不熟悉 OGR 或 GDAL,阅读大部分代码也应该不会太难。这是一个演示 DXF 文件,其中包含各种不同的 LEADER 和 MULTILEADER 对象,您可以使用它来测试您的实现。领导LEADER 实体表示一个箭头,由一个或多个顶点(或样条曲线拟合点)和一个箭头组成。LEADER 附加到的标签或其他内容存储为单独的实体,不是 LEADER 本身的一部分。如上所述,LEADER 与 DIMENSION 共享其样式基础架构。要正确设置这些实体的样式,请从所选维度样式的样式属性开始,然后应用实体本身指示的任何覆盖。DXF 规范提供了一个示例。与 DIMENSION 的庞大复杂性相比,渲染一个简单的 LEADER 实体很容易。它只是通过直线段连接顶点并在末尾附加箭头的问题(在大多数情况下)。唯一的困难是 “hook line” 功能,如下一节所述。钩线如果将 DIMTAD 标注样式特性(AutoCAD 的“特性”窗格中的“文本位置垂直”)设置为“居中”(0) 以外的任何值,则引出线将延伸到文本的下方。此扩展称为 “钩线”。https://atlight.github.io/formats/images/leader-dimtad.png不幸的是,此钩线的端点未存储在 DXF 文件中。我们必须使用 (211,221,231) 方向向量、存储在组码 41 中的文本宽度以及组码 74 中的 “flip” 布尔值来计算它。用伪代码编写的计算如下( 代表 “group code”):gcif ( DIMTAD != 0 && gc73 == 0 && gc41 > 0 && count(vertices) >= 2 ){    directionVector = (gc211, gc221, gc231) or (1.0, 0.0, 0.0) if the group codes are not present    if ( gc74 == 1 )      directionVector = -directionVector      lastVertex = the last (gc10, gc20, gc30) present      vertices.append( lastVertex + ( DIMGAP * DIMSCALE + gc41 ) * directionVector )}当组代码 74 为 1 时,此代码翻转方向向量,这与 DXF 规范似乎所说的相反。我认为规范在这一点上是错误的,因为它与 AutoCAD 的行为不匹配。样 条您可能还想知道如何渲染样条引线。DXF 文档提到,当组代码 72 设置为 1 时,LEADER 将呈现为样条曲线,但它没有提供任何详细信息。据我所知,配方是这样的:
[*]LEADER 的“顶点”被视为 3 阶样条曲线的等权重拟合点。
[*]样条是周期性的,但不是平面或闭合的。
[*]拟合容差为 0。
[*]起点和终点切线方向是当引线以“线”模式渲染时,引线的第一条和最后一条线段(包括钩线,如果有)的运行方向。
[*]如果存在箭头,则最终拟合点似乎位于箭头的后面。DXF 数据中没有给出这一点,因此您必须想出一种方法来解决它。我决定在我的实现中忽略这个细节,只使用给定的最终顶点作为最后一个拟合点。
请记住,顶点被视为拟合点。在 DXF 格式的其他位置,样条曲线是从控制点生成的,因此您可能需要调整逻辑。LEADER 是传统的Autodesk 似乎非常坚定地将 LEADER 和 QLEADER 视为遗留功能。LEADER 用户文档建议用户切换到 MLEADER 工作流,并且默认的 AutoCAD 工具栏不包含用于插入 LEADER 的按钮。现实情况是,除非您能让所有用户将他们的图纸保存到 2008 年之前的 DXF 版本,否则您将需要在 DXF 阅读器中支持 MULTILEADER。多重引线这就是乐趣开始的地方。MULTILEADER 与 LEADER 在许多重要方面有所不同:
[*]MULTILEADER 与 DIMENSION 或 LEADER 完全无关。特别是,他们不使用 DIMSTYLE 基础设施。有一个称为 MLEADERSTYLE 的并行样式系统,但是如果只需要读取 DXF 文件而不编写它们,则可以放心地忽略它。这是因为,与 LEADER 不同,在 LEADER 中仅将样式替代存储在图元中,而所有样式特性都存储在 MULTILEADER 图元本身中。
[*]MULTILEADER 的内容(文字标签或块)使用合并到 MULTILEADER 图元中的组码进行描述,而不是作为其自己的单独图元存储。这在概念上类似于 DIMENSION 合并维度文本的方式。
[*]MULTILEADER 可以有零条或多条引线,并分组为零条、一条或两条引线。样式属性将应用于所有引出线;例如,不能用不同的颜色设置引线的样式。
https://atlight.github.io/formats/images/mleader-parts-annot.png
[*]MULTILEADER 引线具有“dogleg”(在 AutoCAD UI 中称为“平台”),而不是 LEADER“钩线”,它本质上是引线在到达内容之前的常见最后段。
[*]DXF 规范中的文档令人震惊。当 AutoCAD 的 DXF 编写器实际输出名称 MULTILEADER 时,它将实体称为“MLEADER”时,它就开始了一个不吉利的开始,并且从未真正从那里开始。
信息来源DXF 等级库只是查找 MULTILEADER 信息的地方之一。您还应该查看 AcDbMLeader 的 ObjectARX 文档,AcDbMLeader 是 AutoCAD 内部用于表示 MULTILEADER 的 C++ 类。MULTILEADER 的 DXF 表示本质上是该类中数据的分支,比其他实体要多得多,因此本文档特别有价值。例如,AcDbMLeader::leaderLineType() 上的页面指出,此函数将引线类型作为 AcDbMLeaderStyle::LeaderType 值返回。从该枚举的值中,我们现在知道如何解释常见的组码 170!DWG 格式的 Open Design Alliance 逆向工程,第 19.4.46 节和 19.4.83 节,充当方便的交叉引用。DWG 和 DXF 格式在结构上非常相似,因此 ODA DWG 规范会尽可能引用 DXF 组代码。尽管版权声明相当严厉,但您不太可能使用该文档,以免引起版权问题。结构DXF 规范中完全缺少对 MULTILEADER 图元结构方式的描述。它由 30 个组代码划分为多个部分,这些组代码始终具有下面给出的文本值:...            // common group codes300CONTEXT_DATA{...            // context data group codes302LEADER{    ...          // leader group codes (referred to as "Leader Node" in the DXF spec)    304    LEADER_LINE{      ...      // leader line group codes    305    }    304    LEADER_LINE{      ...      // leader line group codes    305    }    ...          // further leader group codes303}302LEADER{    ...          // leader group codes with leader line section(s)303}...            // further context data group codes301}...            // further common group codes可以有零个或多个引线或引线部分。组代码具有不同的含义,具体取决于它们出现在哪个部分(DXF 规范正确地理解了这一点)。实体句柄MULTILEADER 图元通过其控标(而不是其名称)来引用其他 DXF 对象。甚至文本样式和 ATTDEF 实体(在其他实体中始终按名称引用)也由其句柄引用。常用组代码 342、344 和 330 以及上下文数据组代码 340 和 341 都是句柄引用。几何学MULTILEADER 中有三种类型的顶点:
[*]构成引线的普通顶点,由引线部分中的 (10,20,30) 组代码序列给出。
[*]引线的着陆点,由 leader 部分中的 (10,20,30) 组代码给出。
[*]您必须计算的 dogleg 终端节点 -- 请参阅下文。
https://atlight.github.io/formats/images/mleader-vertex-types-annot.png根据公共组码 170 的值,MULTILEADER 可以是直 (1)、样条曲线 (2) 或“无”(0)。直线渲染只涉及连接每条引线的相关顶点并提供一个狗腿形,在中断处中断线条。样条线渲染的完成方式与 LEADER 相同(见上文)。“None” 表示根本不呈现 leader - 只显示内容 (text or block)。计算狗腿/着陆与 LEADER 一样,必须执行一些计算才能找到整个几何。这涉及确定是否需要绘制狗腿,如果需要,则计算狗腿的端点。狗腿端点简单地计算为着陆点 +(狗腿长度 * 狗腿方向向量)。对于 MULTILEADER 中的特定引线,如果满足以下条件,则会绘制狗腿形:
[*]MULTILEADER 启用了狗腿形(公共组代码 291 为非零),并且
[*]MULTILEADER 是直的(公共组码 170 为 1),并且
[*]狗腿长度(领导组代码 40)为非零,并且
[*]狗腿方向向量(导流组代码 (11,21,31))不是零向量。
如果未绘制狗腿形,则仍必须计算狗形端点,因为在这种情况下,将忽略着陆点,而牵引线将在狗腿形端点处终止。https://atlight.github.io/formats/images/mleader-dogleg-on-off-annot.png休息可以“断开”直 MULTILEADER 引线,以避免与图形中的其他线条相交。每个打断(在 AutoCAD 命令中也称为 DIMBREAK)都存储为一对点。换行符(线条中的间隙)从第一个点开始,到第二个点结束。https://atlight.github.io/formats/images/mleader-break-crop.png位于折点 n 和折点 n + 1 之间的中断存储在引出线部分中折点 n 之后。引线组代码 (11,21,31) 给出起点,代码 (12,22,32) 给出终点。11,21,31,12,22,32 序列对引导线特定段中的每个中断重复。dogleg 中的中断将作为 leader 部分的一部分进行存储。中断的开始由领导组代码 (12,22,32) 给出,结束由 (13,23,33) 给出,可以以相同的方式重复。在样条曲线 MULTILEADER 中不使用打断。内容公共组代码 172 确定 MULTILEADER 是具有文本内容 (2)、块内容 (1) 还是无内容 (0)。文本内容在 AutoCAD 中,MULTILEADER 的文字内容在内部表示为属于该类的 (MTEXT) 数据成员。尽管组代码不同,但您很有可能能够在 MTEXT 和 MLEADER 的实现之间共享代码。AcDbMTextAcDbMLeader文本锚定在上下文数据组代码 (12,22,32) 给定的点,对应于 MTEXT 组代码 (10,20,30)。如果相同的值同时出现在公共数据部分和上下文数据部分(例如,文本颜色),则 AutoCAD 将使用上下文数据部分中给定的值。阻止内容MULTILEADER 的内容可以是块参照,而不是文字。公共组代码 344 存储BLOCK_RECORD的句柄。渲染器应将此块插入上下文数据组代码 (15,25,35) 给定的位置。DXF 规范在上下文数据部分(模块法线方向、模块缩放和模块旋转)中列出了一些其他参数,这些参数被解释为 INSERT。在 AutoCAD 中似乎没有办法为多重引线设置特定的块颜色,因此我不知道 93 是做什么用的。组码 47 出现 16 次,给出某种矩阵。由于最后四个值似乎总是为零,因此我假设这是一个 3D 仿射变换,但目前尚不清楚为什么在旋转、缩放和平移也独立存在时提供此矩阵。在我的实现中,我选择忽略这个矩阵,因为我认为它仅在图片中存在拉伸时才有用,并且我暂时不希望支持 MULTILEADER 的拉伸。与普通 INSERT 图元相比,块属性在 MULTILEADER 图元中的存储方式截然不同。相关 ATTDEF 的句柄(不是名称)在公共组代码 330 中给出,后跟索引 (177)、某种类型的“宽度”(44) 和属性的值 (302)。根据需要重复此四个代码序列。如果您正在编写 DXF 转换器,那么您很可能已经选择去除 ATTDEF 实体;显然,您需要重新考虑这一点,以便可以渲染 MULTILEADER 块属性。我在 GDAL 中的大量 MULTILEADER 代码被用于处理块属性。这似乎是一个次要且无关紧要的功能,但正确实现它实际上非常重要 - 经常会看到 MULTILEADERs,它由括在圆圈中的引线标签(例如,键号)组成。它总是被构造成一个块,其中包含一个圆圈和一个 ATTDEF,用于需要将文本替换为的标签。颜色MULTILEADER 的整体颜色以通常的方式存储(公共部分中的 62/440 组代码)。但开发人员似乎对其他颜色值感到懒惰,例如常见的组代码 91。作为 AcDbEntityColor 类一部分的联合的原始值作为有符号的 32 位整数直接写入 DXF。例如,这意味着 ByBlock 不再是熟悉的 0,而是 -1056964608 (0xC1000000)。RGBM挤压件 (OCS)拉伸,也称为对象坐标系 (OCS),是我尚未探讨的 MULTILEADER 实体的一个方面。如果有人已经弄清楚这些如何用于 MULTILEADER,请随时针对此站点提交问题或拉取请求。

qq1254582201 发表于 3 天前

Demystifying DXF: LEADER and MULTILEADER implementation notes
[*]Introduction
[*]My implementation

[*]LEADER
[*]The hook line
[*]Splines
[*]LEADERs are legacy

[*]MULTILEADER
[*]Sources of information
[*]Structure
[*]Entity handles
[*]Geometry
[*]Calculating the dogleg/landing
[*]Breaks

[*]Content
[*]Text content
[*]Block content

[*]Colors
[*]Extrusions (OCS)

IntroductionAs part of my work on the DXF driver in the open-source Geospatial Data Abstraction Library (GDAL), I was tasked with the job of implementing support for leader elements.For those unfamiliar with CAD, leaders are essentially arrows emanating from a text label or symbol, serving to point out some important aspect of the drawing.https://atlight.github.io/formats/images/leader-demo.pngAutoCAD offers two different kinds of leader objects:
[*]The "classic" LEADER entity has been part of AutoCAD since the early days, and shares a lot in common with the DIMENSION entity, including a common styling infrastructure (DIMSTYLE and the override system). The documentation for LEADER in the DXF specification is reasonably comprehensive; see the section below.
[*]The MULTILEADER entity, perhaps better known to AutoCAD users as MLEADER (the name of the command), was introduced in AutoCAD 2008. You can conceptualise it as a strange combination of MTEXT, INSERT, ATTRIB and LWPOLYLINE with enough secret sauce poured on top that you're never really quite sure what's going on. MULTILEADER is one of the worst-documented DXF entities; the description in the DXF spec is next to useless. See below for some tips on how to get it implemented in your project.
I hope these notes, which are intended to supplement the DXF specification, will help those who need to interact with the DXF format programmatically but have limited AutoCAD knowledge, or possibly even no access to the software. I assume a basic level of familiarity with the DXF format.My implementationHere is the C++ code of the DXF LEADER and MULTILEADER translator that I developed for GDAL/OGR. It should not be too difficult to read most of that code even if you're completely unfamiliar with OGR or GDAL. And here is a demo DXF file with all kinds of different LEADER and MULTILEADER objects which you can use to test your implementation.LEADERThe LEADER entity represents an arrow, made up of one or more vertices (or spline fit points) and an arrowhead. The label or other content to which the LEADER is attached is stored as a separate entity, and is not part of the LEADER itself.As noted above, LEADER shares its styling infrastructure with DIMENSION. To style these entities correctly, you begin with the styling properties of the selected dimension style, then apply any overrides indicated in the entity itself. The DXF spec provides an example.Compared to the sprawling complexity of DIMENSION, rendering a simple LEADER entity is easy. It is simply a matter of connecting the vertices by straight line segments and attaching an arrowhead at the end (in most cases). The only difficulty is the "hook line" feature, described in the following section.The hook lineIf the DIMTAD dimension style property ("Text pos vert" in AutoCAD's Properties pane) is set to anything other than "Centered" (0), the leader line extends beneath the text. This extension is known as a "hook line".https://atlight.github.io/formats/images/leader-dimtad.pngUnfortunately, the endpoint of this hook line is not stored in the DXF file. We have to calculate it using the (211,221,231) direction vector, the text width stored in group code 41, and a "flip" boolean in group code 74. The calculation, written in pseudocode, is as follows ( stands for "group code"):gcif ( DIMTAD != 0 && gc73 == 0 && gc41 > 0 && count(vertices) >= 2 ){    directionVector = (gc211, gc221, gc231) or (1.0, 0.0, 0.0) if the group codes are not present    if ( gc74 == 1 )      directionVector = -directionVector      lastVertex = the last (gc10, gc20, gc30) present      vertices.append( lastVertex + ( DIMGAP * DIMSCALE + gc41 ) * directionVector )}This code flips the direction vector when group code 74 is 1, contrary to what the DXF spec appears to say. I assume the spec is wrong on this, since it doesn't match AutoCAD's behaviour.SplinesYou might also wonder how to render spline LEADERs. The DXF documentation mentions that LEADERs are rendered as splines when group code 72 is set to 1, but it doesn't give any detail.As far as I can tell, the recipe is like this:
[*]The "vertices" of the LEADER are treated as equally-weighted fit points of a degree 3 spline.
[*]The spline is periodic but not planar or closed.
[*]The fit tolerance is 0.
[*]The start and end tangent directions are the directions in which the first and last line segment of the leader (including the hook line, if any) would run if the leader was rendered in "line" mode.
[*]If an arrowhead is present, the final fit point seems to be located at the back of the arrowhead. This point is not given in the DXF data, so you would have to come up with a way to work it out. I decided to ignore this detail in my implementation and just use the given final vertex as the last fit point.
Bear in mind that the vertices are treated as fit points. Elsewhere in the DXF format, splines are generated from control points, so you may need to adjust your logic.LEADERs are legacyAutodesk seems to be very firmly treating LEADER and QLEADER as a legacy feature. The LEADER user documentation recommends that users switch to the MLEADER workflow, and the default AutoCAD toolbars do not contain a button to insert a LEADER. The reality is, unless you can get all your users to downsave their drawings to pre-2008 DXF versions, you are going to need MULTILEADER support in your DXF reader.MULTILEADERThis is where the fun begins. MULTILEADERs differ from LEADERs in a number of important ways:
[*]MULTILEADERs have nothing to do with DIMENSIONs or LEADERs at all. In particular, they don't use the DIMSTYLE infrastructure. There is a parallel styling system known as MLEADERSTYLE, but if you only need to read DXF files and not write them, you can safely ignore it. This is because, unlike LEADER where only style overrides are stored in the entity, all the styling properties are stored in the MULTILEADER entity itself.
[*]The content of the MULTILEADER (the text label or block) is described using group codes incorporated into the MULTILEADER entity, rather than being stored as its own separate entity. This is conceptually similar to how DIMENSIONs incorporate the dimension text.
[*]MULTILEADERs can have zero or more leader lines, grouped into zero, one or two leaders. Styling properties are applied to all leader lines; for example, it's not possible to style leader lines in different colours.
https://atlight.github.io/formats/images/mleader-parts-annot.png
[*]Instead of the LEADER "hook line", MULTILEADER leaders have a "dogleg" (referred to as a "landing" in the AutoCAD UI), which is essentially the common final segment of the leader before it reaches the content.
[*]The documentation in the DXF spec is appalling. It gets off to an inauspicious start when it refers to the entity as "MLEADER" when AutoCAD's DXF writer actually outputs the name MULTILEADER, and it never really improves from there.
Sources of informationThe DXF spec is only one place to look for information on MULTILEADER.You should also look at the ObjectARX documentation for AcDbMLeader, the C++ class used internally by AutoCAD to represent MULTILEADERs. The DXF representation of MULTILEADER is essentially a spewing-out of the data in this class, much more so than for other entities, so this documentation is especially valuable. For example, the page on AcDbMLeader::leaderLineType() states that this function returns the leader line type as a AcDbMLeaderStyle::LeaderType value. From the values of that enum, we now know how to interpret common group code 170!The Open Design Alliance reverse-engineer of the DWG format, sections 19.4.46 and 19.4.83, acts as a handy cross-reference. The DWG and DXF formats are so similar in structure that the ODA DWG spec references the DXF group codes where it can. Although the copyright statement is rather stern, you are unlikely to use the document to the extent that copyright becomes a concern.StructureTotally missing from the DXF spec is a description of the way the MULTILEADER entity is structured. It is divided into sections by 30x group codes, which always have the text values given below:...            // common group codes300CONTEXT_DATA{...            // context data group codes302LEADER{    ...          // leader group codes (referred to as "Leader Node" in the DXF spec)    304    LEADER_LINE{      ...      // leader line group codes    305    }    304    LEADER_LINE{      ...      // leader line group codes    305    }    ...          // further leader group codes303}302LEADER{    ...          // leader group codes with leader line section(s)303}...            // further context data group codes301}...            // further common group codesThere could be zero or more leader or leader line sections. Group codes have different meanings depending on the section they appear in (the DXF spec got this bit right).Entity handlesThe MULTILEADER entity refers to other DXF objects by their handle, not by their name. Even text styles and ATTDEF entities, which are always referred to by name in other entities, are referenced by their handle. Common group codes 342, 344 and 330, and context data group codes 340 and 341, are all handle references.GeometryThere are three types of vertices in a MULTILEADER:
[*]The ordinary vertices that make up the leader line, given by a sequence of (10,20,30) group codes in the leader line section.
[*]The landing point of the leader, given by (10,20,30) group codes in the leader section.
[*]The dogleg endpoint, which you must calculate -- see below.
https://atlight.github.io/formats/images/mleader-vertex-types-annot.pngDepending on the value of common group code 170, a MULTILEADER may be straight (1), spline (2) or "none" (0). Straight rendering simply involves joining relevant vertices of each leader line and providing a dogleg, interrupting the lines at breaks. Spline rendering is done in the same way as LEADER (see above). "None" means that the leaders are not rendered at all - only the content (text or block) is to be shown.Calculating the dogleg/landingAs with LEADER, some calculations must be performed to find the entire geometry. This involves establishing whether a dogleg needs to be drawn, and if so, calculating the endpoint of the dogleg.The dogleg endpoint is simply calculated as landing point + (dogleg length * dogleg direction vector).For a particular leader within the MULTILEADER, a dogleg is drawn if:
[*]the MULTILEADER has doglegs enabled (common group code 291 is nonzero) and
[*]the MULTILEADER is straight (common group code 170 is 1) and
[*]the dogleg length (leader group code 40) is nonzero and
[*]the dogleg direction vector (leader group codes (11,21,31)) is not a zero vector.
If the dogleg is not drawn, the dogleg endpoint still must be calculated, because in this case, the landing point is ignored and the leader lines terminate at the dogleg endpoint instead.https://atlight.github.io/formats/images/mleader-dogleg-on-off-annot.pngBreaksStraight MULTILEADER leader lines can be "broken" to avoid intersections with other linework in the drawing. Each break (also known as DIMBREAK, from the AutoCAD command) is stored as a pair of points. The break (gap in the line) begins at the first point and ends at the second point.https://atlight.github.io/formats/images/mleader-break-crop.pngThe breaks that lie between vertex n and vertex n + 1 are stored after vertex n in the leader line section. Leader line group codes (11,21,31) give the start point and codes (12,22,32) give the end point. The 11,21,31,12,22,32 sequence is repeated for each break in that particular segment of the leader line.Breaks in the dogleg are stored as part of the leader section. The start of a break is given by leader group codes (12,22,32) and the end by (13,23,33), which may be repeated in the same way.Breaks are not used in spline MULTILEADERs.ContentCommon group code 172 determines whether the MULTILEADER has text content (2), block content (1), or no content (0).Text contentIn AutoCAD, the text content of a MULTILEADER is internally represented as an (MTEXT) data member belonging to the class. Although the group codes are different, there is a good chance you will be able to share code between your implementations of MTEXT and MLEADER.AcDbMTextAcDbMLeaderThe text is anchored at the point given by context data group codes (12,22,32), corresponding to MTEXT group codes (10,20,30).Where the same value appears in both the common and context data sections (for example, text color), AutoCAD uses the value given in the context data section.Block contentInstead of text, a MULTILEADER may have a block reference as its content. The common group code 344 stores the handle of a BLOCK_RECORD. Your renderer should insert this block at the position given by context data group codes (15,25,35). The DXF spec lists some other parameters in the context data section (block normal direction, block scale, and block rotation) which are interpreted as for INSERT. There doesn't appear to be a way to set a specific block color for a multileader in AutoCAD, so I don't know what 93 is for.The group code 47 appears 16 times to give some kind of matrix. Since the last four values seem to always be zero, I assume this is a 3D affine transformation, but it is unclear why this matrix is provided when the rotation, scale and translation are also independently present. In my implementation I have chosen to ignore this matrix, because I assume it's only useful when extrusions are in the picture, and I don't wish to support extrusions of MULTILEADERs for the time being.Block attributes are stored very differently in MULTILEADER entities compared to an ordinary INSERT. The handle (not the name) of the relevant ATTDEF is given in common group code 330, followed by an index (177), a "width" of some kind (44), and the value of the attribute (302). This sequence of four codes is repeated as required. If you are writing a DXF converter, chances are you have chosen to strip out ATTDEF entities; you will clearly need to reconsider this so you can render MULTILEADER block attributes.A significant amount of my MULTILEADER code in GDAL is taken up processing block attributes. It might seem like a minor and inconsequential feature, but it is actually very important to implement it properly - it is common to see MULTILEADERs which consist of the leader label (say, a key number) enclosed in a circle. This is invariably structured as a block containing a circle and an ATTDEF for the label into which the text needs to be substituted.ColorsThe overall color of the MULTILEADER is stored in the usual way (62/440 group codes in the common section). But it seems that the developers got lazy for other color values, like common group code 91. The raw value of the union that is part of the AcDbEntityColor class is written straight to the DXF as a signed 32-bit integer. As an example, this means that ByBlock is no longer the familiar 0, but instead -1056964608 (0xC1000000).RGBMExtrusions (OCS)


qq1254582201 发表于 3 天前

Edit Mleader styleBy Virupaksha AithalMleaderstyle objects are stored in the named object dictionary of the drawing database. Database object exposes an objectId “MLeaderStyleDictionaryId” to access this dictionary. Below code shows the procedure to edit a Mleader style.   Below code edits only the mleader style’s text height and color, butMleaderstyle object exposes many more properties to edit like “ArrowSymbolId”, “ArrowSize” “LandingGap” & etc.static public void EditMleaderStyle(){
    Document doc = Application.DocumentManager.MdiActiveDocument;    Database db = doc.Database;    Editor ed = doc.Editor;
    using (Transaction tr =                     db.TransactionManager.StartTransaction())    {      //Name of the mleader Style to edit      const string styleName = "Standard";
      DBDictionary mlstyles = (DBDictionary)tr.GetObject(                                        db.MLeaderStyleDictionaryId,                                        OpenMode.ForRead);
      if (!mlstyles.Contains(styleName))      {            return;      }      ObjectId id = mlstyles.GetAt(styleName);
      //now get the active mleader style      MLeaderStyle currentStyle = tr.GetObject(id,                                 OpenMode.ForWrite) as MLeaderStyle;
      //now edit the style      currentStyle.TextColor =                  Autodesk.AutoCAD.Colors.Color.FromRgb(255, 0, 0);
      //just double the text height      currentStyle.TextHeight = currentStyle.TextHeight * 2;
      tr.Commit();    }}



qq1254582201 发表于 3 天前

AutoCAD .NET: MultiLeader (MLeader) Jig 3 – Jigging Block ContentWe provided various jig implementations before, either using EntityJig or DrawJig, either from scratch or with the assistance of the Entity Jigger or Draw Jigger of AcadNetAddinWizard(Pro).We demonstrated previously how to jig a MultiLeader programmatically through an arrow location and a single landing location using AutoCAD .NET and C#. We also showed how to jig multiple landing locations. In this post, let’s see how to jig a block content instead of the default MText content.Here we go.#region Namespaces

using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.Drawing;
using System.IO;

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

using MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application;
using MgdAcDocument = Autodesk.AutoCAD.ApplicationServices.Document;
using AcWindowsNS = Autodesk.AutoCAD.Windows;

#endregion

namespace AcadNetCSharp
{
    public class MLeaderJigger3 : EntityJig
    {
      #region Fields

      private const string BlockName = "tag";

      public int mCurJigFactorIndex = 1;// Jig Factor Index

      public Autodesk.AutoCAD.Geometry.Point3d mArrowLocation; // Jig Factor #1
      public Autodesk.AutoCAD.Geometry.Point3d mLandingLocation; // Jig Factor #2

      #endregion

      #region Constructors

      public MLeaderJigger3(MLeader ent)
            : base(ent)
      {
            Entity.SetDatabaseDefaults();

            Entity.ContentType = ContentType.BlockContent;

            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                Entity.BlockContentId = bt;

                tr.Commit();
            }

            Entity.EnableDogleg = true;
            Entity.EnableLanding = true;
            Entity.EnableFrameText = false;

            Entity.AddLeaderLine(mLandingLocation);
            Entity.SetFirstVertex(0, mArrowLocation);

            Entity.TransformBy(UCS);
      }

      #endregion

      #region Properties

      private Editor Editor
      {
            get
            {
                return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
            }
      }

      private Matrix3d UCS
      {
            get
            {
                return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem;
            }
      }

      #endregion

      #region Overrides

      public new MLeader Entity// Overload the Entity property for convenience.
      {
            get
            {
                return base.Entity as MLeader;
            }
      }

      protected override bool Update()
      {

            switch (mCurJigFactorIndex)
            {
                case 1:
                  Entity.SetFirstVertex(0, mArrowLocation);
                  Entity.SetLastVertex(0, mArrowLocation);

                  break;
                case 2:
                  Entity.SetLastVertex(0, mLandingLocation);

                  break;

                default:
                  return false;
            }

            return true;
      }

      protected override SamplerStatus Sampler(JigPrompts prompts)
      {
            switch (mCurJigFactorIndex)
            {
                case 1:
                  JigPromptPointOptions prOptions1 = new JigPromptPointOptions("\nArrow Location:");
                  // Set properties such as UseBasePoint and BasePoint of the prompt options object if necessary here.
                  prOptions1.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect | UserInputControls.UseBasePointElevation;
                  PromptPointResult prResult1 = prompts.AcquirePoint(prOptions1);
                  if (prResult1.Status == PromptStatus.Cancel && prResult1.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult1.Value.Equals(mArrowLocation))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mArrowLocation = prResult1.Value;
                        return SamplerStatus.OK;
                  }
                case 2:
                  JigPromptPointOptions prOptions2 = new JigPromptPointOptions("\nLanding Location:");
                  // Set properties such as UseBasePoint and BasePoint of the prompt options object if necessary here.
                  prOptions2.UseBasePoint = true;
                  prOptions2.BasePoint = mArrowLocation;
                  prOptions2.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect | UserInputControls.UseBasePointElevation;
                  PromptPointResult prResult2 = prompts.AcquirePoint(prOptions2);
                  if (prResult2.Status == PromptStatus.Cancel && prResult2.Status == PromptStatus.Error)
                        return SamplerStatus.Cancel;

                  if (prResult2.Value.Equals(mLandingLocation))//Use better comparison method if necessary.
                  {
                        return SamplerStatus.NoChange;
                  }
                  else
                  {
                        mLandingLocation = prResult2.Value;
                        return SamplerStatus.OK;
                  }

                default:
                  break;
            }

            return SamplerStatus.OK;
      }



      #endregion

      #region Methods to Call

      public static MLeader Jig()
      {
            MLeaderJigger3 jigger = null;
            try
            {
                jigger = new MLeaderJigger3(new MLeader());
                PromptResult pr;
                do
                {
                  pr = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.Drag(jigger);
                  if (pr.Status == PromptStatus.Keyword)
                  {
                        // Keyword handling code

                  }
                  else
                  {
                        jigger.mCurJigFactorIndex++;
                  }
                } while (pr.Status != PromptStatus.Cancel && pr.Status != PromptStatus.Error && jigger.mCurJigFactorIndex <= 2);

                if (pr.Status == PromptStatus.Cancel || pr.Status == PromptStatus.Error)
                {
                  if (jigger != null && jigger.Entity != null)
                        jigger.Entity.Dispose();

                  return null;
                }
            
                return jigger.Entity;
            }
            catch(System.Exception ex)
            {
                MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());

                if (jigger != null && jigger.Entity != null)
                  jigger.Entity.Dispose();

                return null;
            }
      }

      #endregion

      #region Test Commands

      
      public static void TestMLeaderJigger3_Method()
      {
            try
            {
                Entity jigEnt = MLeaderJigger3.Jig();
                if (jigEnt != null)
                {
                  Database db = HostApplicationServices.WorkingDatabase;
                  using (Transaction tr = db.TransactionManager.StartTransaction())
                  {
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        btr.AppendEntity(jigEnt);
                        tr.AddNewlyCreatedDBObject(jigEnt, true);
                        tr.Commit();
                  }
                }
            }
            catch (System.Exception ex)
            {
                MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
            }
      }

      #endregion
    }
}

The workflow and output may look like the following:
https://spiderinnet1.typepad.com/.a/6a0153928ee38e970b01b8d1309ce8970c-800wi



页: [1] 2
查看完整版本: 【转载】CAD多重引线相关内容转载合集