明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 817|回复: 5

[几何] C#实现多段线偏移的算法(例子自动创建240mm的墙体)

  [复制链接]
发表于 2023-9-20 00:34 | 显示全部楼层 |阅读模式
前端给媳妇编写一个快速偏移多段线并填充图案的函数,刚开始以为多段线偏移的开发还比较简单,但是弄了以后发现多段线的偏移的处理算法设计到凸角的算法和一些特殊端点的处理。弄好以后,想着有类似需求的朋友们可以参考参考。里面可能还有情况没有考虑到,有新发现的,可以多多交流
还是录一个屏说明一下吧。本人非专业程序人员,只是一名机械设计者。函数有不足的地方多多交流。




   //快速设计墙体,默认墙体厚度240mm
    public class CreateMYWallCommand
    {
        [CommandMethod("CW")]
        public void CreateWallCommand()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptIntegerOptions options = new PromptIntegerOptions("\n请选择向外偏移还是向内偏移 (1 向外偏移, 2 向内偏移): ");
            options.AllowNone = false;
            options.AllowZero = false;
            options.DefaultValue = 1;
            PromptIntegerResult result = ed.GetInteger(options);

            if (result.Status != PromptStatus.OK)
            {
                ed.WriteMessage("Invalid input or command canceled.");
                return; // 退出命令
            }

            int userInput = result.Value;

            PromptEntityResult peResult = ed.GetEntity("请选折一条多段线: ");
            if (peResult.Status != PromptStatus.OK)
                return;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                // Open the selected polyline
                Entity ent = tr.GetObject(peResult.ObjectId, OpenMode.ForRead) as Entity;
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;

                if (ent is Polyline polyline)
                {
                    // Specify the offset distance
                    double offsetDistance = 240; // Modify as needed

                    // 定义并初始化 actualOffsetDistance 变量
                    double actualOffsetDistance = 0.0;

                    // Create a new polyline for offset
                    Polyline newPolyline = new Polyline();

                    for (int i = 0; i < polyline.NumberOfVertices; i++)
                    {
                        Point2d vertex = polyline.GetPoint2dAt(i);
                        Vector2d offsetVector = new Vector2d(0, 0); // Initialize a zero vector

                        int nextIndex = (i + 1) % polyline.NumberOfVertices;
                        int prevIndex = (i + polyline.NumberOfVertices - 1) % polyline.NumberOfVertices;

                        Point2d nextVertex = polyline.GetPoint2dAt(nextIndex);
                        Point2d prevVertex = polyline.GetPoint2dAt(prevIndex);

                        Vector2d nextDir = (nextVertex - vertex).GetNormal();
                        Vector2d prevDir = (prevVertex - vertex).GetNormal();

                        offsetVector = (nextDir + prevDir).GetNormal();

                        // 处理多边形内角大于180度的情况
                        double crossProduct = nextDir.X * prevDir.Y - nextDir.Y * prevDir.X;

                        // 计算夹角的一半的正弦值
                        double angle = Math.Acos(nextDir.DotProduct(prevDir));
                        double halfAngleSin = Math.Sin(angle / 2.0);

                        // 计算 actualOffsetDistance
                        actualOffsetDistance = offsetDistance / halfAngleSin;

                        if (crossProduct <0)
                        {
                            offsetVector = -offsetVector;
                        }

                        // 处理多边形内角180度的情况
                        if (crossProduct == 0) // 夹角为180度的情况
                        {
                            offsetVector = nextDir.GetPerpendicularVector();
                            actualOffsetDistance = offsetDistance;
                        }

                        // 处理起点和终点所在线段方向
                        if (i == 0)
                        {
                            offsetVector = nextDir.GetPerpendicularVector();  // 垂直于起点线段方向的向量
                            actualOffsetDistance = offsetDistance;
                        }
                        else if (i == polyline.NumberOfVertices - 1)
                        {
                            offsetVector = -prevDir.GetPerpendicularVector();  // 垂直于起点线段方向的向量
                            actualOffsetDistance = offsetDistance;
                        }


                        // 获取起始向量
                        Vector2d startVector = polyline.GetPoint2dAt(1) - polyline.GetPoint2dAt(0);
                        // 判断起点向量方向并选择不同命令

                        if (startVector.X >= 0)
                        {
                            if (userInput == 1)
                            {
                                offsetVector = offsetVector * actualOffsetDistance; // 向内偏移
                            }
                            else
                            {
                                offsetVector = -offsetVector * actualOffsetDistance;

                            }
                        }
                        else
                        {

                            if (userInput == 2)
                            {
                                offsetVector = -offsetVector * actualOffsetDistance; // 向内偏移
                            }
                            else
                            {
                                offsetVector = offsetVector * actualOffsetDistance;
                            }
                        }


                        // Offset the vertex position
                        Point2d offsetVertex = vertex + offsetVector;
                        newPolyline.AddVertexAt(i, offsetVertex, 0, 0, 0);
                    }

                    // Add the new polyline to the model space
                    BlockTableRecord currentSpace = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
                    currentSpace.AppendEntity(newPolyline);
                    tr.AddNewlyCreatedDBObject(newPolyline, true);

                    // 连接起点和终点形成封闭区域
                    Point2d startVertex = newPolyline.GetPoint2dAt(0);
                    Point2d endVertex = newPolyline.GetPoint2dAt(newPolyline.NumberOfVertices - 1);

                    Line closeStartLine = new Line(
                        new Point3d(polyline.GetPoint2dAt(0).X, polyline.GetPoint2dAt(0).Y, 0),
                        new Point3d(startVertex.X, startVertex.Y, 0));

                    Line closeEndLine = new Line(
                        new Point3d(polyline.GetPoint2dAt(polyline.NumberOfVertices - 1).X, polyline.GetPoint2dAt(polyline.NumberOfVertices - 1).Y, 0),
                        new Point3d(endVertex.X, endVertex.Y, 0));

                    btr.AppendEntity(closeStartLine);
                    btr.AppendEntity(closeEndLine);
                    tr.AddNewlyCreatedDBObject(closeStartLine, true);
                    tr.AddNewlyCreatedDBObject(closeEndLine, true);

                    Point2d startLineStartPoint = new Point2d(closeStartLine.StartPoint.X, closeStartLine.StartPoint.Y);
                    Point2d startLineEndPoint = new Point2d(closeStartLine.EndPoint.X, closeStartLine.EndPoint.Y);
                    Point2d endLineStartPoint = new Point2d(closeEndLine.StartPoint.X, closeEndLine.StartPoint.Y);
                    Point2d endLineEndPoint = new Point2d(closeEndLine.EndPoint.X, closeEndLine.EndPoint.Y);

                    //创建一个新的封闭多段线,用于填充图案
                    Polyline closedPolyline = new Polyline();
                    closedPolyline.Closed = true;

                    //添加开始线的起点和终点,closedPolyline.NumberOfVertices指的是添加到集合的最后
                    closedPolyline.AddVertexAt(closedPolyline.NumberOfVertices, startLineStartPoint, 0, 0, 0);
                    closedPolyline.AddVertexAt(closedPolyline.NumberOfVertices, startLineEndPoint, 0, 0, 0);

                    //添加偏移多段线的各个点
                    //1获取偏移多段线的各个点坐标
                    List<Point2d> newPolylineVertices = new List<Point2d>();
                    for (int i = 0; i < newPolyline.NumberOfVertices; i++)
                    {
                        Point2d vertex = new Point2d(newPolyline.GetPoint3dAt(i).X, newPolyline.GetPoint3dAt(i).Y);
                        newPolylineVertices.Add(vertex);
                    }
                    //2循环添加偏移多段线的各个点坐标
                    for (int i = 0; i < newPolylineVertices.Count; i++)
                    {
                        closedPolyline.AddVertexAt(closedPolyline.NumberOfVertices, newPolylineVertices[i], 0, 0, 0);
                    }

                    //添加终点线的起点和终点,
                    closedPolyline.AddVertexAt(closedPolyline.NumberOfVertices, endLineEndPoint, 0, 0, 0);
                    closedPolyline.AddVertexAt(closedPolyline.NumberOfVertices, endLineStartPoint, 0, 0, 0);

                    //添加原多段线的各个点
                    //1获取原多段线的各个点坐标
                    List<Point2d> polylineVertices = new List<Point2d>();
                    for (int i = 0; i < polyline.NumberOfVertices; i++)
                    {
                        Point2d vertex = new Point2d(polyline.GetPoint3dAt(i).X, polyline.GetPoint3dAt(i).Y);
                        polylineVertices.Add(vertex);
                    }

                    //2循环添加原多段线的各个点坐标
                    for (int i = polylineVertices.Count - 1; i >= 0; i--)
                    {
                        closedPolyline.AddVertexAt(closedPolyline.NumberOfVertices, polylineVertices[i], 0, 0, 0);
                    }

                    // 将封闭多段线添加到模型空间中
                    ObjectId closedPolylineId = btr.AppendEntity(closedPolyline);
                    tr.AddNewlyCreatedDBObject(closedPolyline, true);

                    // 创建填充对象
                    Hatch hatch = new Hatch();
                    ObjectIdCollection objectIdCollection = new ObjectIdCollection();
                    objectIdCollection.Add(closedPolylineId);
                    hatch.SetHatchPattern(HatchPatternType.PreDefined, "AR-CONC"); // 设置填充图案类型
                    hatch.AppendLoop(HatchLoopTypes.Default, objectIdCollection);

                    // 添加填充到模型空间中
                    btr.AppendEntity(hatch);
                    tr.AddNewlyCreatedDBObject(hatch, true);

                }
                tr.Commit();
            }
        }
    }

本帖子中包含更多资源

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

x

评分

参与人数 1明经币 +1 收起 理由
xj6019 + 1 赞一个!

查看全部评分

发表于 2023-9-20 08:05 | 显示全部楼层
感谢分享,想学点c#无奈可以参考学习的代码实在太少了,只能懵逼中摸索一点点
发表于 2023-9-20 08:11 | 显示全部楼层
大神真厉害,学习了
发表于 2023-9-22 11:30 | 显示全部楼层
这个前端很优秀
发表于 2023-9-22 18:12 | 显示全部楼层
如果不考虑偏移后顶点数量减少的情况下,算出多段线上每一个顶点法向垂直方向的角度,将角度和偏移距离计算出新的点,新点连成一个新的线段,再将原线段的凸度赋值给新的线段,就能得到偏移后的线段了
发表于 2023-10-3 23:18 | 显示全部楼层
是自带的偏移函数不好用吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-6-2 22:55 , Processed in 0.148647 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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