找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 2174|回复: 0

[分享] Update to the AutoCAD .NET entity jig framework

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-7-30 22:12:36 来自手机 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 csharp 于 2014-7-31 08:16 编辑

Update to the AutoCAD .NET entity jig framework

http://through-the-interface.typepad.com/through_the_interface/2012/12/update-to-the-autocad-net-entity-jig-framework.html

Update to the AutoCAD .NET entity jig framework
In the last post I introduced a simple framework to make the definition of multi-input entity jigs more straightforward. A big thanks to Chuck Wilbur, who provided some feedback that has resulted in a nicer base implementation, which we’ll take for a spin in today’s post.
Here’s the updated C# framework code that makes use of a simple class hierarchy for our phase definitions:
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System.Collections.Generic;
using System;

namespace JigFrameworks
{
  // Two abstract base classes: one for all phases...

  public abstract class Phase
  {
    // Our member data (could add real properties, as needed)

    public string Message;
    public object Value;

    public Phase(string msg)
    {
      Message = msg;
    }
  }

  // And another for geometric classes...

  public abstract class GeometryPhase : Phase
  {
    // Geometric classes can also have an offset for the basepoint

    public Func<List<Phase>, Point3d, Vector3d> Offset;

    public GeometryPhase(
      string msg,
      Func<List<Phase>, Point3d, Vector3d> offset = null
    ) : base(msg)
    {
      Offset = offset;
    }
  }

  // A phase for distance input

  public class DistancePhase : GeometryPhase
  {
    public DistancePhase(
      string msg,
      object defval = null,
      Func<List<Phase>, Point3d, Vector3d> offset = null
    ) : base(msg, offset)
    {
      Value = (defval == null ? 0 : defval);
    }
  }

  // A phase for distance input related to Autodesk Shape Manager
  // (whose internal tolerance if 1e-06, so we need a larger
  // default value to allow Solid3d creation to succeed)

  public class SolidDistancePhase : DistancePhase
  {
    public SolidDistancePhase(
      string msg,
      object defval = null,
      Func<List<Phase>, Point3d, Vector3d> offset = null
    ) : base(msg, defval, offset)
    {
      Value = (defval == null ? 1e-05 : defval);
    }
  }

  // A phase for point input

  public class PointPhase : GeometryPhase
  {
    public PointPhase(
      string msg,
      object defval = null,
      Func<List<Phase>, Point3d, Vector3d> offset = null
    ) : base(msg, offset)
    {
      Value =
        (defval == null ? Point3d.Origin : defval);
    }
  }

  // A phase for angle input

  public class AnglePhase : GeometryPhase
  {
    public AnglePhase(
      string msg,
      object defval = null,
      Func<List<Phase>, Point3d, Vector3d> offset = null
    ) : base(msg, offset)
    {
      Value = (defval == null ? 0 : defval);
    }
  }

  // And a non-geometric phase for string input

  public class StringPhase : Phase
  {
    public StringPhase(
      string msg,
      string defval = null
    ) : base(msg)
    {
      Value = (defval == null ? "" : defval);
    }
  }

  // Our jig framework class

  public class EntityJigFramework : EntityJig
  {
    // Member data

    Matrix3d _ucs;
    Point3d _pt;
    Entity _ent;
    List<Phase> _phases;
    int _phase;
    Func<Entity, List<Phase>, Point3d, Matrix3d, bool> _update;

    // Constructor

    public EntityJigFramework(
      Matrix3d ucs, Entity ent, Point3d pt, List<Phase> phases,
      Func<Entity, List<Phase>, Point3d, Matrix3d, bool> update
    ) : base(ent)
    {
      _ucs = ucs;
      _ent = ent;
      _pt = pt;
      _phases = phases;
      _phase = 0;
      _update = update;
    }

    // Move on to the next phase

    internal void NextPhase()
    {
      _phase++;
    }

    // Check whether we're at the last phase

    internal bool IsLastPhase()
    {
      return (_phase == _phases.Count - 1);
    }

    // EntityJig protocol

    protected override SamplerStatus Sampler(JigPrompts prompts)
    {
      // Get the current phase

      var p = _phases[_phase];

      // If we're dealing with a geometry-typed phase (distance,
      // point ot angle input) we can use some common code

      var gp = p as GeometryPhase;
      if (gp != null)
      {
        JigPromptGeometryOptions opts;
        if (gp is DistancePhase)
          opts = new JigPromptDistanceOptions();
        else if (gp is AnglePhase)
          opts = new JigPromptAngleOptions();
        else if (gp is PointPhase)
          opts = new JigPromptPointOptions();
        else // Should never happen
          opts = null;

        // Set up the user controls

        opts.UserInputControls =
          (UserInputControls.Accept3dCoordinates
          | UserInputControls.NoZeroResponseAccepted
          | UserInputControls.NoNegativeResponseAccepted);

        // All our distance inputs will be with a base point
        // (which means the initial base point or an offset from
        // that)

        opts.UseBasePoint = true;
        opts.Cursor = CursorType.RubberBand;

        opts.Message = p.Message;
        opts.BasePoint =
          (gp.Offset == null ?
            _pt.TransformBy(_ucs) :
            (_pt + gp.Offset.Invoke(_phases, _pt)).TransformBy(_ucs)
          );

        // The acquisition method varies on the phase type

        if (gp is DistancePhase)
        {
          var phase = (DistancePhase)gp;
          var pdr =
            prompts.AcquireDistance(
              (JigPromptDistanceOptions)opts
            );

          if (pdr.Status == PromptStatus.OK)
          {
            // If the difference between the new value and its
            // previous value is negligible, return "no change"

            if (
              Math.Abs((double)phase.Value - pdr.Value) <
              Tolerance.Global.EqualPoint
            )
              return SamplerStatus.NoChange;

            // Otherwise we update the appropriate variable
            // based on the phase

            phase.Value = pdr.Value;
            _phases[_phase] = phase;
            return SamplerStatus.OK;
          }
        }
        else if (gp is PointPhase)
        {
          var phase = (PointPhase)gp;
          var ppr =
            prompts.AcquirePoint((JigPromptPointOptions)opts);

          if (ppr.Status == PromptStatus.OK)
          {
            // If the difference between the new value and its
            // previous value is negligible, return "no change"

            var tmp = ppr.Value.TransformBy(_ucs.Inverse());

            if (
              tmp.DistanceTo((Point3d)phase.Value) <
              Tolerance.Global.EqualPoint
            )
              return SamplerStatus.NoChange;

            // Otherwise we update the appropriate variable
            // based on the phase

            phase.Value = tmp;
            _phases[_phase] = phase;
            return SamplerStatus.OK;
          }
        }
        else if (gp is AnglePhase)
        {
          var phase = (AnglePhase)gp;
          var par =
            prompts.AcquireAngle((JigPromptAngleOptions)opts);

          if (par.Status == PromptStatus.OK)
          {
            // If the difference between the new value and its
            // previous value is negligible, return "no change"

            if (
              (double)phase.Value - par.Value <
              Tolerance.Global.EqualPoint
            )
              return SamplerStatus.NoChange;

            // Otherwise we update the appropriate variable
            // based on the phase

            phase.Value = par.Value;
            _phases[_phase] = phase;
            return SamplerStatus.OK;
          }
        }
      }
      else
      {
        // p is StringPhase

        var phase = (StringPhase)p;

        var psr = prompts.AcquireString(p.Message);

        if (psr.Status == PromptStatus.OK)
        {
          phase.Value = psr.StringResult;
          _phases[_phase] = phase;
          return SamplerStatus.OK;
        }
      }
      return SamplerStatus.Cancel;
    }

    protected override bool Update()
    {
      // Right now we have an indiscriminate catch around our
      // entity update callback: this could be modified to be
      // more selective and/or to provide information on exceptions

      try
      {
        return _update.Invoke(_ent, _phases, _pt, _ucs);
      }
      catch
      {
        return false;
      }
    }

    public Entity GetEntity()
    {
      return Entity;
    }

    // Our method to perform the jig and step through the
    // phases until done

    internal void RunTillComplete(Editor ed, Transaction tr)
    {
      // Perform the jig operation in a loop

      while (true)
      {
        var res = ed.Drag(this);

        if (res.Status == PromptStatus.OK)
        {
          if (!IsLastPhase())
          {
            // Progress the phase

            NextPhase();
          }
          else
          {
            // Only commit when all phases have been accepted

            tr.Commit();
            return;
          }
        }
        else
        {
          // The user has cancelled: returning aborts the
          // transaction

          return;
        }
      }
    }
  }
}

Now let’s take it for a spin. Here’s some C# code that uses the framework to define jigs (and their respective commands) for frustums (FJ), cylinders (CYJ), cones (COJ) and tori (TJ):
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using System.Collections.Generic;
using System;
using JigFrameworks;

namespace EntityJigs
{
  public class Commands
  {
    [CommandMethod("FJ")]
    public void FrustumJig()
    {
      var doc =
        Application.DocumentManager.MdiActiveDocument;
      var db = doc.Database;
      var ed = doc.Editor;

      // First let's get the start position of the frustum

      var ppr = ed.GetPoint("\nSpecify frustum location: ");

      if (ppr.Status == PromptStatus.OK)
      {
        // In order for the visual style to be respected,
        // we'll add the to-be-jigged solid to the database

        var tr = doc.TransactionManager.StartTransaction();
        using (tr)
        {
          var btr =
            (BlockTableRecord)tr.GetObject(
              db.CurrentSpaceId, OpenMode.ForWrite
            );

          var sol = new Solid3d();
          btr.AppendEntity(sol);
          tr.AddNewlyCreatedDBObject(sol, true);

          // Create our jig object passing in the selected point

          var jf =
            new EntityJigFramework(
              ed.CurrentUserCoordinateSystem, sol, ppr.Value,
              new List<Phase>()
              {
                // Three phases, one of which has a custom
                // offset for the base point

                new SolidDistancePhase("\nSpecify bottom radius: "),
                new SolidDistancePhase("\nSpecify height: "),
                new SolidDistancePhase(
                  "\nSpecify top radius: ",
                  1e-05,
                  (vals, pt) =>
                  {
                    return
                      new Vector3d(0, 0, (double)vals[1].Value);
                  }
                )
              },
              (e, vals, cen, ucs) =>
              {
                // Our entity update function

                var s = (Solid3d)e;
                s.CreateFrustum(
                  (double)vals[1].Value,
                  (double)vals[0].Value,
                  (double)vals[0].Value,
                  (double)vals[2].Value
                );
                s.TransformBy(
                  Matrix3d.Displacement(
                    cen.GetAsVector() +
                    new Vector3d(0, 0, (double)vals[1].Value / 2)
                  ).PreMultiplyBy(ucs)
                );
                return true;
              }
            );
          jf.RunTillComplete(ed, tr);
        }
      }
    }

    [CommandMethod("CYJ")]
    public void CylinderJig()
    {
      var doc =
        Application.DocumentManager.MdiActiveDocument;
      var db = doc.Database;
      var ed = doc.Editor;

      // First let's get the start position of the cylinder

      var ppr = ed.GetPoint("\nSpecify cylinder location: ");

      if (ppr.Status == PromptStatus.OK)
      {
        // In order for the visual style to be respected,
        // we'll add the to-be-jigged solid to the database

        var tr = doc.TransactionManager.StartTransaction();
        using (tr)
        {
          var btr =
            (BlockTableRecord)tr.GetObject(
              db.CurrentSpaceId, OpenMode.ForWrite
            );

          var sol = new Solid3d();
          btr.AppendEntity(sol);
          tr.AddNewlyCreatedDBObject(sol, true);

          // Create our jig object passing in the selected point

          var jf =
            new EntityJigFramework(
              ed.CurrentUserCoordinateSystem, sol, ppr.Value,
              new List<Phase>()
              {
                // Three phases, one of which has a custom
                // offset for the base point

                new SolidDistancePhase("\nSpecify radius: "),
                new SolidDistancePhase("\nSpecify height: "),
              },
              (e, vals, cen, ucs) =>
              {
                // Our entity update function

                var s = (Solid3d)e;
                s.CreateFrustum(
                  (double)vals[1].Value,
                  (double)vals[0].Value,
                  (double)vals[0].Value,
                  (double)vals[0].Value
                );
                s.TransformBy(
                  Matrix3d.Displacement(
                    cen.GetAsVector() +
                    new Vector3d(0, 0, (double)vals[1].Value / 2)
                  ).PreMultiplyBy(ucs)
                );
                return true;
              }
            );
          jf.RunTillComplete(ed, tr);
        }
      }
    }

    [CommandMethod("COJ")]
    public void ConeJig()
    {
      var doc =
        Application.DocumentManager.MdiActiveDocument;
      var db = doc.Database;
      var ed = doc.Editor;

      // First let's get the start position of the cylinder

      var ppr = ed.GetPoint("\nSpecify cone location: ");

      if (ppr.Status == PromptStatus.OK)
      {
        // In order for the visual style to be respected,
        // we'll add the to-be-jigged solid to the database

        var tr = doc.TransactionManager.StartTransaction();
        using (tr)
        {
          var btr =
            (BlockTableRecord)tr.GetObject(
              db.CurrentSpaceId, OpenMode.ForWrite
            );

          var sol = new Solid3d();
          btr.AppendEntity(sol);
          tr.AddNewlyCreatedDBObject(sol, true);

          // Create our jig object passing in the selected point

          var jf =
            new EntityJigFramework(
              ed.CurrentUserCoordinateSystem, sol, ppr.Value,
              new List<Phase>()
              {
                // Three phases, one of which has a custom
                // offset for the base point

                new SolidDistancePhase("\nSpecify radius: "),
                new SolidDistancePhase("\nSpecify height: "),
              },
              (e, vals, cen, ucs) =>
              {
                // Our entity update function

                var s = (Solid3d)e;
                s.CreateFrustum(
                  (double)vals[1].Value,
                  (double)vals[0].Value,
                  (double)vals[0].Value,
                  0
                );
                s.TransformBy(
                  Matrix3d.Displacement(
                    cen.GetAsVector() +
                    new Vector3d(0, 0, (double)vals[1].Value / 2)
                  ).PreMultiplyBy(ucs)
                );
                return true;
              }
            );
          jf.RunTillComplete(ed, tr);
        }
      }
    }

    [CommandMethod("TJ")]
    public void TorusJig()
    {
      var doc =
        Application.DocumentManager.MdiActiveDocument;
      var db = doc.Database;
      var ed = doc.Editor;

      // First let's get the start position of the frustum

      var ppr = ed.GetPoint("\nSpecify torus location: ");

      if (ppr.Status == PromptStatus.OK)
      {
        // In order for the visual style to be respected,
        // we'll add the to-be-jigged solid to the database

        var tr = doc.TransactionManager.StartTransaction();
        using (tr)
        {
          var btr =
            (BlockTableRecord)tr.GetObject(
              db.CurrentSpaceId, OpenMode.ForWrite
            );

          var sol = new Solid3d();
          btr.AppendEntity(sol);
          tr.AddNewlyCreatedDBObject(sol, true);

          // Create our jig object passing in the selected point

          var jf =
            new EntityJigFramework(
              ed.CurrentUserCoordinateSystem, sol, ppr.Value,
              new List<Phase>()
              {
                // Three phases, one of which has a custom
                // offset for the base point

                new SolidDistancePhase("\nSpecify outer radius: "),
                new SolidDistancePhase(
                  "\nSpecify inner radius: ",
                  1e-05,
                  (vals, pt) =>
                  {
                    return
                      new Vector3d(0, 0, (double)vals[0].Value);
                  }
                )
              },
              (e, vals, cen, ucs) =>
              {
                // Our entity update function

                var s = (Solid3d)e;
                s.CreateTorus(
                  (double)vals[0].Value,
                  (double)vals[1].Value
                );
                s.TransformBy(
                  Matrix3d.Displacement(
                    cen.GetAsVector() +
                    new Vector3d(0, 0, (double)vals[1].Value)
                  ).PreMultiplyBy(ucs)
                );
                return true;
              }
            );
          jf.RunTillComplete(ed, tr);
        }
      }
    }
  }
}

Let’s see these commands in action:
0.jpg
In the next post we’ll see a slightly more complicated example, where we jig a square (at least in X and Y) box between diagonal corners.


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

本版积分规则

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

GMT+8, 2024-5-21 22:53 , Processed in 0.348141 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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