雪山飞狐_lzh 发表于 2010-6-9 20:28:00

优化多段线的倒角

在QQ群为风吹桥动改写优化多段线的倒角程序,
原代码使用DB库的曲线并用纯数学计算方式

      /// <summary>
      /// 通过一个顶点将多义线倒圆角,本程序不支持多义线起点和终点处倒圆角
      /// </summary>
      /// <param name="polyline">多义线对象</param>
      /// <param name="vertexIndex">顶点索引号</param>
      /// <param name="radius">圆弧半径</param>
      public static void FilletatVertex(Polyline polyline, int vertexIndex, double radius)
      {
            Database db = HostApplicationServices.WorkingDatabase;//获取数据库
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;//获取editor对象
            using (Transaction trans = db.TransactionManager.StartTransaction())//开始事务   
            {
                try
                {
                  //判断顶点索引号是否属于多义线;
                  if (vertexIndex <= 0 || vertexIndex >= polyline.NumberOfVertices)
                  {
                        ed.WriteMessage("\n顶点无效。");
                        return;
                  }
                  else if ((polyline.GetBulgeAt(vertexIndex - 1) != 0) && (polyline.GetBulgeAt(vertexIndex) != 0))
                  {
                        ed.WriteMessage("\n顶点两侧不是直线。");
                        return;
                  }
                  else
                  {
                        Point2d pnt = polyline.GetPoint2dAt(vertexIndex);
                        Vector2d vec1 = polyline.GetPoint2dAt(vertexIndex - 1) - pnt;//由顶点与前一个顶点组成的向量
                        Vector2d vec2 = polyline.GetPoint2dAt(vertexIndex + 1) - pnt;//由顶点与后一个顶点组成的向量
                        double angle = vec1.GetAngleTo(vec2);//获得角点两侧线段间的角度变化
                        ed.WriteMessage(angle.ToString());
                        ed.WriteMessage("\n" + vec1.Length.ToString());
                        ed.WriteMessage("\n" + (radius / Math.Tan(angle / 2)).ToString());
                        ed.WriteMessage("\n" + vec2.Length.ToString());
                        ed.WriteMessage("\n" + (radius / Math.Tan(angle / 2)).ToString());
                        if ((vec1.Length < radius / Math.Tan(angle / 2)) || (vec2.Length < radius / Math.Tan(angle / 2)))
                        {
                            ed.WriteMessage("\n半径太大。");
                            return;
                        }
                        else
                        {
                            double lentemp = radius / Math.Tan(angle / 2);
                            Point2d addedVertex1 = pnt + vec1.GetNormal() * lentemp;
                            Point2d addedVertex2 = pnt + vec2.GetNormal() * lentemp;
                            polyline.RemoveVertexAt(vertexIndex);
                            polyline.AddVertexAt(vertexIndex, addedVertex1, 0, 0, 0);
                            polyline.AddVertexAt(vertexIndex + 1, addedVertex2, 0, 0, 0);
                            //polyline.AddVertexAt(vertexIndex, addedVertex1.Convert2d(new Plane()), 0, 0, 0);
                            //polyline.AddVertexAt(vertexIndex + 1, addedVertex2.Convert2d(new Plane()), 0, 0, 0);

                            //根据前后三顶点判断该顶点处多义线的前进方向是顺时针还是逆时针
                            CircularArc2d cir = new CircularArc2d(polyline.GetPoint2dAt(vertexIndex - 1), pnt, polyline.GetPoint2dAt(vertexIndex + 1));
                            double ang = Math.PI - angle;
                            double bulge = Math.Abs(Math.Tan(ang / 4));
                            if (cir.IsClockWise)
                            {
                              polyline.SetBulgeAt(vertexIndex, -1 * bulge);//若为顺时针,则凸度为负;否则为正
                            }
                            else
                            {
                              polyline.SetBulgeAt(vertexIndex, bulge);
                            }
                        }
                  }
                }
                catch (Autodesk.AutoCAD.Runtime.Exception e)
                {
                  ed.WriteMessage(e.ToString());
                  trans.Abort();
                }
                finally
                {
                  trans.Commit();
                }
            }
      }


joyhai 发表于 2020-7-13 11:12:41

你好,ToCurve() 是自定义的函数吗? 我这也提示缺这个函数,请指教,谢谢。

雪山飞狐_lzh 发表于 2010-6-9 20:32:00

本帖最后由 作者 于 2010-7-16 21:13:43 编辑

感觉直接用Ge库的曲线应该也可以做,改写代码如下


      /// <summary>
      /// 为优化多段线倒角
      /// </summary>
      /// <param name="polyline">优化多段线</param>
      /// <param name="index">顶点索引号</param>
      /// <param name="radius">倒角半径</param>
      /// <param name="isFillet">倒角类型</param>
      public static void ChamferAt(this Polyline polyline, int index, double radius, bool isFillet)
      {
            if (index < 1 || index > polyline.NumberOfVertices - 2)
                throw new System.Exception("错误的索引号");
            if (polyline.GetSegmentType(index - 1) != SegmentType.Line || polyline.GetSegmentType(index) != SegmentType.Line)
                throw new System.Exception("非直线段不能倒角");
            //获取当前索引号的前后两段直线,并组合为Ge复合曲线
            Curve3d[] c3ds =
                new Curve3d[]
                  {
                        polyline.GetLineSegmentAt(index - 1),
                        polyline.GetLineSegmentAt(index)
                  };
            var cc3d = new CompositeCurve3d(c3ds);
            //试倒直角
            //子曲线的个数有三种情况:
            //1、=3时倒角方向正确
            //2、=2时倒角方向相反
            //3、=0或为直线时失败
            c3ds =
                cc3d.GetTrimmedOffset
                (
                  radius,
                  Vector3d.ZAxis,
                  OffsetCurveExtensionType.Chamfer
                );
            if (c3ds.Length > 0 && c3ds is CompositeCurve3d)
            {
                  var newcc3d = c3ds as CompositeCurve3d;
                  c3ds = newcc3d.GetCurves();
                  if (c3ds.Length == 3)
                  {
                        c3ds =
                            cc3d.GetTrimmedOffset
                            (
                              -radius,
                              Vector3d.ZAxis,
                              OffsetCurveExtensionType.Chamfer
                            );
                        if (c3ds.Length == 0 || c3ds is LineSegment3d)
                        {
                            throw new System.Exception("倒角半径过大");
                        }
                  }
                  else if (c3ds.Length == 2)
                  {
                        radius = -radius;
                  }
            }
            else
            {
                throw new System.Exception("倒角半径过大");
            }
            //GetTrimmedOffset会生成倒角+偏移,故先反方向倒角,再倒回
            c3ds =
                cc3d.GetTrimmedOffset
                (
                  -radius,
                  Vector3d.ZAxis,
                  OffsetCurveExtensionType.Extend
                );
            OffsetCurveExtensionType type =
                isFillet ?
                OffsetCurveExtensionType.Fillet : OffsetCurveExtensionType.Chamfer;
            c3ds =
                c3ds.GetTrimmedOffset
                (
                  radius,
                  Vector3d.ZAxis,
                  type
                );
            //将结果Ge曲线转为Db曲线,并将相关的数值反映到原曲线
            Polyline plTemp = c3ds.ToCurve() as Polyline;
            polyline.RemoveVertexAt(index);
            polyline.AddVertexAt(index, plTemp.GetPoint2dAt(1), plTemp.GetBulgeAt(1), 0, 0);
            polyline.AddVertexAt(index + 1, plTemp.GetPoint2dAt(2), 0, 0, 0);
      }



      
      public void test()
      {
            var db = HostApplicationServices.WorkingDatabase;
            var doc = Application.DocumentManager.GetDocument(db);
            var ed = doc.Editor;
            var resEnt = ed.GetEntity("\n请选择优化多段线:");
            var resInt = ed.GetInteger("\n请输入索引号:");
            bool isFillet = false;
            PromptDoubleOptions opt = new PromptDoubleOptions("\n请输入倒角半径:");
            opt.Keywords.Add("F");
            var resDbl = ed.GetDouble(opt);
            if (resDbl.Status == PromptStatus.Keyword)
            {
                isFillet = true;
                resDbl = ed.GetDouble(opt);
            }
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                Polyline pl = resEnt.ObjectId.GetObject(OpenMode.ForWrite) as Polyline;
                ChamferAt(pl, resInt.Value, resDbl.Value, isFillet);
                tr.Commit();
            }
      }

命令行的输入:
命令: ctest
请选择优化多段线:
请输入索引号: 3
请输入倒角半径 : f
请输入倒角半径 : 5
命令: ctest
请选择优化多段线:
请输入索引号: 2
请输入倒角半径 : 5

倒角效果:

single-yu 发表于 2010-6-9 20:34:00

<p>顶飞狐版主呀,学习了!</p>

hmxmylove 发表于 2010-6-9 20:36:00

lincoln_ma 发表于 2010-6-9 22:01:00

楼主强大,顶

雪山飞狐_lzh 发表于 2010-6-10 13:56:00

<p>修正试倒角时的Bug,2楼代码已更改</p>

wenxi0504 发表于 2012-12-5 11:45:27

太好的东西,正是需要的资料。

卓kk 发表于 2013-1-31 22:51:48

sicky111 发表于 2013-5-13 02:00:46

要是有LISP代码就好了。

sdaulj 发表于 2014-5-6 23:17:36

路过并表示强烈支持!
页: [1] 2
查看完整版本: 优化多段线的倒角