明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 843|回复: 0

Jigging an AutoCAD hatch using .NET

[复制链接]
发表于 2011-4-8 22:17:43 | 显示全部楼层 |阅读模式

作者:kean

原文地址:http://through-the-interface.typepad.com/through_the_interface/2011/04/jigging-an-autocad-hatch-using-net.html

 

This question came in a few weeks ago, which I thought worth addressing:

Hi, Kean! I have a question - how can we create hatch during jig?

The code in this post endeavours to do just that, but – be warned – isn’t fully successful. The problem I chose to interpret this as is “how do you jig the creation of a polyline, using it as the boundary for an associative hatch?”, and it’s not an easy one to solve.

I started by taking Philippe Leefsma’s code from this previous post, which jigs a polyline (including arc segments). I switched it to use a DrawJig – rather than an EntityJig – as we’re creating multiple entities (a polyline and a hatch). I created the objects we want to jig, adding them to the database and the transaction before passing them to the jig’s constructor – an approach that has proven successful for jigging objects in a certain way, whether a Solid3d with a visual style, or a BlockReference with attributes.

Here’s the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Colors;

using System;

 

namespace HatchJig

{

  class JigUtils

  {

    // Custom ArcTangent method, as the Math.Atan

    // doesn't handle specific cases

 

    public static double Atan(double y, double x)

    {

      if (x > 0)

        return Math.Atan(y / x);

      else if (x < 0)

        return Math.Atan(y / x) - Math.PI;

      else  // x == 0

      {

        if (y > 0)

          return Math.PI;

        else if (y < 0)

          return -Math.PI;

        else // if (y == 0) theta is undefined

          return 0.0;

      }

    }

 

    // Computes Angle between current direction

    // (vector from last vertex to current vertex)

    // and the last pline segment

 

    public static double ComputeAngle(

      Point3d startPoint, Point3d endPoint,

      Vector3d xdir, Matrix3d ucs

    )

    {

      Vector3d v =

        new Vector3d(

          (endPoint.X - startPoint.X) / 2,

          (endPoint.Y - startPoint.Y) / 2,

          (endPoint.Z - startPoint.Z) / 2

        );

 

      double cos = v.DotProduct(xdir);

      double sin =

        v.DotProduct(

          Vector3d.ZAxis.TransformBy(ucs).CrossProduct(xdir)

        );

 

      return Atan(sin, cos);

    }

  }

 

  public class HatchJig : DrawJig

  {

    Point3d _tempPoint;

    bool _isArcSeg = false;

    bool _isUndoing = false;

    Matrix3d _ucs;

    Plane _plane;

    Polyline _pline = null;

    Hatch _hat = null;

 

    public HatchJig(

      Matrix3d ucs, Plane plane, Polyline pl, Hatch hat

    )

    {

      _ucs = ucs;

      _plane = plane;

      _pline = pl;

      _hat = hat;

      AddDummyVertex();

    }

 

    protected override bool WorldDraw(

      Autodesk.AutoCAD.GraphicsInterface.WorldDraw wd

    )

    {

      // Update the dummy vertex to be our 3D point

      // projected onto our plane

 

      if (_isArcSeg)

      {

        Point3d lastVertex =

          _pline.GetPoint3dAt(_pline.NumberOfVertices - 2);

 

        Vector3d refDir;

 

        if (_pline.NumberOfVertices < 3)

          refDir = new Vector3d(1.0, 1.0, 0.0);

        else

        {

          // Check bulge to see if last segment was an arc or a line

 

          if (_pline.GetBulgeAt(_pline.NumberOfVertices - 3) != 0)

          {

            CircularArc3d arcSegment =

              _pline.GetArcSegmentAt(_pline.NumberOfVertices - 3);

 

            Line3d tangent = arcSegment.GetTangent(lastVertex);

 

            // Reference direction is the invert of the arc tangent

            // at last vertex

 

            refDir = tangent.Direction.MultiplyBy(-1.0);

          }

          else

          {

            Point3d pt =

              _pline.GetPoint3dAt(_pline.NumberOfVertices - 3);

 

            refDir =

              new Vector3d(

                lastVertex.X - pt.X,

                lastVertex.Y - pt.Y,

                lastVertex.Z - pt.Z

              );

          }

        }

 

        double angle =

          JigUtils.ComputeAngle(

            lastVertex, _tempPoint, refDir, _ucs

          );

 

        // Bulge is defined as tan of one fourth of included angle

        // Need to double the angle since it represents the included

        // angle of the arc

        // So formula is: bulge = Tan(angle * 2 * 0.25)

 

        double bulge = Math.Tan(angle * 0.5);

 

        _pline.SetBulgeAt(_pline.NumberOfVertices - 2, bulge);

      }

      else

      {

        // Line mode. Need to remove last bulge if there was one

 

        if (_pline.NumberOfVertices > 1)

          _pline.SetBulgeAt(_pline.NumberOfVertices - 2, 0);

      }

 

      _pline.SetPointAt(

        _pline.NumberOfVertices - 1, _tempPoint.Convert2d(_plane)

      );

 

      if (_pline.NumberOfVertices == 3)

      {

        _pline.Closed = true;

 

        ObjectIdCollection ids = new ObjectIdCollection();

        ids.Add(_pline.ObjectId);

 

        // Add the hatch loops and complete the hatch

 

        _hat.Associative = true;

        _hat.AppendLoop(HatchLoopTypes.Default, ids);

      }

 

      if (!wd.RegenAbort)

      {

        wd.Geometry.Draw(_pline);

 

        if (_pline.NumberOfVertices > 2)

        {

          _hat.EvaluateHatch(true);

          if (!wd.RegenAbort)

            wd.Geometry.Draw(_hat);

        }

      }

 

      return true;

    }

 

    protected override SamplerStatus Sampler(JigPrompts prompts)

    {

      JigPromptPointOptions jigOpts = new JigPromptPointOptions();

 

      jigOpts.UserInputControls =

        (UserInputControls.Accept3dCoordinates |

         UserInputControls.NullResponseAccepted |

         UserInputControls.NoNegativeResponseAccepted |

         UserInputControls.GovernedByOrthoMode);

 

      _isUndoing = false;

 

      if (_pline.NumberOfVertices == 1)

      {

        // For the first vertex, just ask for the point

 

        jigOpts.Message = "\nSpecify start point: ";

      }

      else if (_pline.NumberOfVertices > 1)

      {

        string msgAndKwds =

          (_isArcSeg ?

            "\nSpecify endpoint of arc or [Line/Undo]: " :

            "\nSpecify next point or [Arc/Undo]: "

          );

 

        string kwds = (_isArcSeg ? "Line Undo" : "Arc Undo");

 

        jigOpts.SetMessageAndKeywords(msgAndKwds, kwds);

      }

      else

        return SamplerStatus.Cancel; // Should never happen

 

      // Get the point itself

 

      PromptPointResult res = prompts.AcquirePoint(jigOpts);

 

      if (res.Status == PromptStatus.Keyword)

      {

        if (res.StringResult.ToUpper() == "ARC")

          _isArcSeg = true;

        else if (res.StringResult.ToUpper() == "LINE")

          _isArcSeg = false;

        else if (res.StringResult.ToUpper() == "UNDO")

          _isUndoing = true;

 

        return SamplerStatus.OK;

      }

      else if (res.Status == PromptStatus.OK)

      {

        // Check if it has changed or not (reduces flicker)

 

        if (_tempPoint == res.Value)

          return SamplerStatus.NoChange;

        else

        {

          _tempPoint = res.Value;

          return SamplerStatus.OK;

        }

      }

 

      return SamplerStatus.Cancel;

    }

 

    public bool IsUndoing

    {

      get

      {

        return _isUndoing;

      }

    }

 

    public void AddDummyVertex()

    {

      // Create a new dummy vertex... can have any initial value

 

      _pline.AddVertexAt(

        _pline.NumberOfVertices, new Point2d(0, 0), 0, 0, 0

      );

    }

 

    public void RemoveLastVertex()

    {

      // Let's first remove our dummy vertex   

 

      if (_pline.NumberOfVertices > 0)

        _pline.RemoveVertexAt(_pline.NumberOfVertices - 1);

 

      // And then check the type of the last segment

 

      if (_pline.NumberOfVertices >= 2)

      {

        double blg = _pline.GetBulgeAt(_pline.NumberOfVertices - 2);

        _isArcSeg = (blg != 0);

      }

    }

 

    [CommandMethod("HATJIG")]

    public static void RunHatchJig()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      // Create a transaction, as we're jigging

      // db-resident objects

 

      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        BlockTableRecord btr =

          (BlockTableRecord)tr.GetObject(

            db.CurrentSpaceId, OpenMode.ForWrite

          );

 

        Vector3d normal =

          Vector3d.ZAxis.TransformBy(

            ed.CurrentUserCoordinateSystem

          );

 

        // We will pass a plane to our jig, to help

        // with UCS transformations

 

        Plane plane = new Plane(Point3d.Origin, normal);

 

        // We also pass a db-resident polyline

 

        Polyline pl = new Polyline();

        pl.Normal = normal;

 

        btr.AppendEntity(pl);

        tr.AddNewlyCreatedDBObject(pl, true);

 

        // And a db-resident hatch

 

        Hatch hat = new Hatch();

 

        // Use a non-solid hatch pattern, to aid jigging

 

        hat.SetHatchPattern(

          HatchPatternType.PreDefined,

          "ANGLE"

        );

 

        // But let's make it transparent, for fun

        // Alpha value is Truncate(255 * (100-n)/100)

 

        hat.ColorIndex = 1;

        hat.Transparency = new Transparency(127);

 

        // Add the hatch to the modelspace & transaction

 

        ObjectId hatId = btr.AppendEntity(hat);

        tr.AddNewlyCreatedDBObject(hat, true);

 

        // And finally pass everything to the jig

 

        HatchJig jig =

          new HatchJig(

            ed.CurrentUserCoordinateSystem, plane, pl, hat

          );

 

        while (true)

        {

          PromptResult res = ed.Drag(jig);

 

          switch (res.Status)

          {

            // New point was added, keep going

 

            case PromptStatus.OK:

              jig.AddDummyVertex();

              break;

 

            // Keyword was entered

 

            case PromptStatus.Keyword:

              if (jig.IsUndoing)

                jig.RemoveLastVertex();

              break;

 

            // The jig completed successfully

 

            case PromptStatus.None:

 

              // You can remove this next line if you want

              // the vertex being jigged to be included

 

              jig.RemoveLastVertex();

              tr.Commit();

              return;

 

            // User cancelled the command

 

            default:

              // No need to erase the polyline & hatch, as

              // the transaction will simply be aborted

              return;

          }

        }

      }

    }

  }

} 

Overall the code works, but the graphics refresh has some issues. The HATJIG command starts well enough:

But as we move the cursor around, there is unfortunate ghosting of the hatch graphics:

Even as we pick new boundary points the hatch gets shown but doesn’t stop being displayed as the boundary changes. It seems as though the transient graphics sub-system – which is being fed the graphics from the DrawJig’s WorldDraw() method – seems to think more needs to be displayed than is actually the case.

At least when the jig is completed the polyline and hatch are displayed properly:

There may be other approaches to solve this – such as using the transient graphics API directly – but I suspect that the nature of the hatch implementation will make it hard to rely on its evaluation and display work effectively when called transiently, whether via a jig or directly.

I decided to post this anyway, in case any readers have bright ideas on how either to fix this implementation or to solve it differently. Someone may even have implemented a solution they don’t mind sharing. Anyone?

本帖子中包含更多资源

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

x
"觉得好,就打赏"
还没有人打赏,支持一下

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-12-24 21:21 , Processed in 0.206248 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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