NETDXF 读写dxf,天圆地方变径展开图和立体图

 

namespace Circle2RectDev
{
    partial class Form1
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗体设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要修改
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
            this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            this.tableLayoutPanel1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(5, 790);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(333, 44);
            this.button1.TabIndex = 0;
            this.button1.Text = "生成图纸";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // propertyGrid1
            // 
            this.propertyGrid1.Location = new System.Drawing.Point(5, 5);
            this.propertyGrid1.Name = "propertyGrid1";
            this.propertyGrid1.Size = new System.Drawing.Size(333, 777);
            this.propertyGrid1.TabIndex = 1;
            // 
            // tableLayoutPanel1
            // 
            this.tableLayoutPanel1.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Inset;
            this.tableLayoutPanel1.ColumnCount = 2;
            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 30.04219F));
            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 69.95781F));
            this.tableLayoutPanel1.Controls.Add(this.propertyGrid1, 0, 0);
            this.tableLayoutPanel1.Controls.Add(this.button1, 0, 1);
            this.tableLayoutPanel1.Controls.Add(this.pictureBox1, 1, 0);
            this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
            this.tableLayoutPanel1.Name = "tableLayoutPanel1";
            this.tableLayoutPanel1.RowCount = 2;
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 89.62656F));
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10.37344F));
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
            this.tableLayoutPanel1.Size = new System.Drawing.Size(1137, 880);
            this.tableLayoutPanel1.TabIndex = 2;
            // 
            // pictureBox1
            // 
            this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.pictureBox1.ErrorImage = global::Circle2RectDev.Properties.Resources.天圆地方;
            this.pictureBox1.Image = global::Circle2RectDev.Properties.Resources.天圆地方;
            this.pictureBox1.Location = new System.Drawing.Point(346, 5);
            this.pictureBox1.Name = "pictureBox1";
            this.pictureBox1.Size = new System.Drawing.Size(786, 777);
            this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
            this.pictureBox1.TabIndex = 2;
            this.pictureBox1.TabStop = false;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 18F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(1137, 880);
            this.Controls.Add(this.tableLayoutPanel1);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
            this.Name = "Form1";
            this.Text = "正天圆地方展开";
            this.tableLayoutPanel1.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.PropertyGrid propertyGrid1;
        private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
        private System.Windows.Forms.PictureBox pictureBox1;
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Circle2RectDev
{
    public partial class Form1 : Form
    {
        public TransitionPiece WorkingObject { get; set; }
        public Form1()
        {
            InitializeComponent();
            this.propertyGrid1.SelectedObject = this.WorkingObject = new TransitionPiece(2000, 1800, 500, 2500,250);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // 2. 创建绘图器
            var generator = new DxfGenerator(this.WorkingObject);
            // 3. 生成并保存
            generator.Generate();
            var fn = $"Circle2RectDev_{WorkingObject.Width}x{WorkingObject.Depth}xR{WorkingObject.RectangleRoundRadius}-r{WorkingObject.CircleRadius}-H{WorkingObject.Height}_{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.dxf";
            generator.Save(fn);
            Process.Start(fn);
        }
    }
}
using netDxf;
using netDxf.Entities;
using netDxf.Tables;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Security.Cryptography;
using System.Windows.Forms;
using static netDxf.Entities.HatchBoundaryPath;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TextBox;
using Line = netDxf.Entities.Line;
namespace Circle2RectDev
{
    #region 1. 几何模型类 (负责计算)

    /// <summary>
    /// 天圆地方几何模型
    /// 负责计算三视图坐标和展开图的顶点坐标
    /// </summary>
    public class TransitionPiece
    {
        // 输入参数
        /// <summary>
        /// 矩形长
        /// </summary>
        /// 
        [Category("方形参数")]
        [Description("矩形长")]
        public double Width { get; set; }      // 

        /// <summary>
        /// 矩形宽
        /// </summary>
        [Category("方形参数")]
        [Description("矩形宽度")]
        public double Depth { get; set; }      // 

        /// <summary>
        ///  顶部圆半径
        /// </summary>
        [Description("顶部圆半径")]
        public double CircleRadius { get; set; }     //

        /// <summary>
        /// 垂直高度
        /// </summary>

        [Description("垂直高度")]
        public double Height { get; set; }     // 垂直高度

        /// <summary>
        /// 底部矩形圆角半径
        /// </summary>
        /// 
        [Category("方形参数")]
        [Description("底部矩形圆角半径")]
        public double RectangleRoundRadius { get; set; }//

        /// <summary>
        /// 圆周分段数
        /// </summary>

        [Description("圆周分段数")]
        public int NumSegments { get; set; } = 128;// ,必须是 4 的倍数

        /// <summary>
        /// 
        /// </summary>
        /// <param name="w">矩形长</param>
        /// <param name="d">矩形宽</param>
        /// <param name="r">顶部圆半径</param>
        /// <param name="h">垂直高度</param>
        /// <param name="r1">底部矩形圆角半径</param>
        public TransitionPiece(double w, double d, double r, double h, double r1 = 0.0)
        {
            Width = w;
            Depth = d;
            CircleRadius = r;
            Height = h;
            RectangleRoundRadius = r1;
        }

        // --- 展开图计算 (核心算法:三角形法) ---



    }


    #endregion

    #region 2. DXF 绘图类 (负责表现)

    public class DxfGenerator
    {
        private DxfDocument doc;
        private TransitionPiece piece;
        private double spacing = 250.0;


        public DxfGenerator(TransitionPiece p)
        {
            piece = p;
            doc = new DxfDocument();
            var ts = doc.TextStyles.Add(new TextStyle("Arial", "arial.ttf"));
            doc.DrawingVariables.TextStyle = ts.Name;
            doc.DrawingVariables.CeLtScale = 150;
            doc.DrawingVariables.PdMode = netDxf.Header.PointShape.CircleCross;
            doc.DrawingVariables.PdSize = 10;
        }

        public void Generate()
        {
            DrawTopView(new Vector2(0, 0));
            //DrawFrontView(new Vector2(0, 2 * piece.Depth));
            //DrawLeftView(new Vector2(piece.Width * 1.5, 2 * piece.Depth));
            DrawDevelopment(new Vector2(0, -1.5 * piece.Height));
            doc.Viewport.ViewCenter = new Vector2(0, 0);
            doc.Viewport.ViewHeight = piece.Height * 3.0;
            doc.Viewport.ViewAspectRatio = 1.0;
        }

        public void Save(string filename)
        {
            doc.Save(filename);
        }

        // --- 绘图实现 ---

        private void DrawTopView(Vector2 offset)
        {
            var oneQuaterBulge = Math.Tan(0.125 * Math.PI);
            var entities = new List<EntityObject>();
            double hw = piece.Width / 2;
            double hd = piece.Depth / 2;
            // 矩形
            var lbpt = new Vector2(-hw, -hd) + offset;
            var rbpt = new Vector2(hw, -hd) + offset;
            var rtpt = new Vector2(hw, hd) + offset;
            var ltpt = new Vector2(-hw, hd) + offset;
            var rect = new LwPolyline(new List<LwPolylineVertex>
            {
               new LwPolylineVertex(lbpt+new Vector2(piece.RectangleRoundRadius,0), 0),
               new LwPolylineVertex(rbpt+new Vector2(-piece.RectangleRoundRadius,0), oneQuaterBulge),
                new LwPolylineVertex(rbpt+new Vector2(0,piece.RectangleRoundRadius), 0),
                 new LwPolylineVertex(rtpt+new Vector2(0,-piece.RectangleRoundRadius), oneQuaterBulge),
                new LwPolylineVertex(rtpt+new Vector2(-piece.RectangleRoundRadius,0), 0),
                  new LwPolylineVertex(ltpt+new Vector2(piece.RectangleRoundRadius,0), oneQuaterBulge),
                new LwPolylineVertex(ltpt+new Vector2(0,-piece.RectangleRoundRadius), 0),
                  new LwPolylineVertex(lbpt+new Vector2(0,piece.RectangleRoundRadius), oneQuaterBulge),
                  new LwPolylineVertex(lbpt+new Vector2(piece.RectangleRoundRadius,0), 0),
            });
            rect.Layer = new Layer("Bottom_Rect") { Color = AciColor.Blue };
            entities.Add(rect);
            // 圆
            var circle = new Circle(offset.To3d(piece.Height), piece.CircleRadius);
            circle.Layer = new Layer("Top_Circle") { Color = AciColor.Red };
            entities.Add(circle);
            var assistLay = new Layer("Assist") { Color = AciColor.Yellow, Linetype = Linetype.Dashed };


            DimensionStyle style = DimensionStyle.Iso25;
            style.TextInsideAlign = false; // 设置文字对齐方式
            style.DimScaleOverall = hd * 0.03;
            // 3. 创建图层 (可选)
            Layer layer = new Layer("Dimensions") { Color = AciColor.Cyan };
            doc.Layers.Add(layer);
            LinearDimension linearDim = new LinearDimension(ltpt, rtpt, 0.03 * piece.Depth, 0, style) { Layer = layer };
            LinearDimension linearDim1 = new LinearDimension(lbpt, ltpt, 0.03 * piece.Depth, 90, style) { Layer = layer };
            DiametricDimension dimdia = new DiametricDimension(circle, 45, style) { Layer = layer };
            LinearDimension linearDim2 = new LinearDimension(new Vector2(0, 0), new Vector2(0, piece.Height), 0.03 * piece.Depth, 90, style) { Layer = layer, Normal = -Vector3.UnitY };
            if (piece.RectangleRoundRadius > 0)
            {
                var cpt = rbpt + new Vector2(-piece.RectangleRoundRadius, piece.RectangleRoundRadius);
                var cpt1 = cpt + new Vector2(piece.RectangleRoundRadius * Math.Cos(Math.PI * 1.75), piece.RectangleRoundRadius * Math.Sin(Math.PI * 1.75));
                RadialDimension rdim = new RadialDimension(cpt, cpt1, style) { Layer = layer };
                entities.AddRange([linearDim, linearDim1, dimdia, linearDim2, rdim]);
            }
            else
            {
                entities.AddRange([linearDim, linearDim1, dimdia, linearDim2]);
            }

            //mark线,64等分
            //var num = 64;
            var num = piece.NumSegments / 4;
            try
            {
                for (int i = 0; i <= piece.NumSegments; i++)
                {
                    var curAngle = i * 2 * Math.PI / piece.NumSegments;
                    var x = (piece.CircleRadius * Math.Cos(curAngle)) + offset.X;
                    var y = (piece.CircleRadius * Math.Sin(curAngle)) + offset.Y;
                    var curPt = new Vector3(x, y, piece.Height);
                    var x1 = piece.RectangleRoundRadius * Math.Cos(curAngle);
                    var y1 = piece.RectangleRoundRadius * Math.Sin(curAngle);
                    var curPtRound = new Vector3(x1, y1, 0);
                    var curptOnRectRound = Vector3.Zero;
                    //var v = new Vector2(x - offset.X, y - offset.Y).ToP2D();
                    // var v1 = v.Quadrant;
                    var curDeg = curAngle * 180.0 / Math.PI;
                    System.Diagnostics.Debug.WriteLine($"i:{i},{curDeg}");
                    if (curDeg % 90 != 0)
                    {
                        switch (curDeg)
                        {
                            case > 0 and < 90.00:
                                curptOnRectRound = new Vector3(x1 + (hw - piece.RectangleRoundRadius), y1 + (hd - piece.RectangleRoundRadius), 0);
                                break;
                            case > 90 and < 180.00:
                                curptOnRectRound = new Vector3(x1 - (hw - piece.RectangleRoundRadius), y1 + (hd - piece.RectangleRoundRadius), 0);

                                break;
                            case > 180 and < 270.00:
                                curptOnRectRound = new Vector3(x1 - (hw - piece.RectangleRoundRadius), y1 - (hd - piece.RectangleRoundRadius), 0);
                                break;
                            default:
                                curptOnRectRound = new Vector3(x1 + (hw - piece.RectangleRoundRadius), y1 - (hd - piece.RectangleRoundRadius), 0);
                                break;
                        }
                        entities.Add(new Line(curPt, curptOnRectRound) { Layer = assistLay, LinetypeScale = 12, Color = AciColor.FromCadIndex((short)i) });
                        if (piece.RectangleRoundRadius > 0)
                        {
                            entities.Add(new Text(i.ToString() + "'", curptOnRectRound, 0.02 * piece.RectangleRoundRadius) { Alignment = TextAlignment.MiddleLeft, Style = doc.TextStyles["Arial"], Rotation = curAngle * 180.0 / Math.PI, Color = AciColor.FromCadIndex((short)i) });
                        }

                    }
                    else
                    {
                        var newpt = Vector3.Zero;
                        if ((int)(curDeg / 90) < 4)
                        {
                            switch ((int)(curDeg / 90))
                            {
                                case 0:
                                    curptOnRectRound = new Vector3(rtpt.X, rtpt.Y - piece.RectangleRoundRadius, 0);
                                    newpt = new Vector3(rbpt.X, rbpt.Y + piece.RectangleRoundRadius, 0);
                                    break;
                                case 1:
                                    curptOnRectRound = new Vector3(ltpt.X + piece.RectangleRoundRadius, ltpt.Y, 0);
                                    newpt = new Vector3(rtpt.X - piece.RectangleRoundRadius, rtpt.Y, 0);
                                    break;
                                case 2:
                                    curptOnRectRound = new Vector3(lbpt.X, lbpt.Y + piece.RectangleRoundRadius, 0);
                                    newpt = new Vector3(ltpt.X, ltpt.Y - piece.RectangleRoundRadius, 0);
                                    break;
                                case 3:
                                    curptOnRectRound = new Vector3(rbpt.X - piece.RectangleRoundRadius, rbpt.Y, 0);
                                    newpt = new Vector3(lbpt.X + piece.RectangleRoundRadius, rbpt.Y, 0);
                                    break;
                            }
                            entities.Add(new Line(curPt, curptOnRectRound) { Layer = assistLay, LinetypeScale = 12, Color = AciColor.FromCadIndex((short)i) });
                            if (piece.RectangleRoundRadius > 0)
                            {
                                entities.Add(new Text(i.ToString() + "'", curptOnRectRound, 0.02 * piece.RectangleRoundRadius) { Alignment = TextAlignment.MiddleLeft, Style = doc.TextStyles["Arial"], Rotation = curAngle * 180.0 / Math.PI, Color = AciColor.FromCadIndex((short)i) });
                                entities.Add(new Text((i == 0 ? piece.NumSegments : i) + "''", newpt, 0.02 * piece.RectangleRoundRadius) { Alignment = TextAlignment.MiddleLeft, Style = doc.TextStyles["Arial"], Rotation = curAngle * 180.0 / Math.PI, Color = AciColor.FromCadIndex((short)i) });
                            }
                            entities.Add(new Line(curPt, newpt) { Layer = assistLay, LinetypeScale = 12, Color = AciColor.FromCadIndex((short)i) });
                        }
                    }
                    entities.Add(new Text(i.ToString(), curPt, 0.01 * piece.Depth) { Alignment = TextAlignment.MiddleLeft, Style = doc.TextStyles["Arial"], Rotation = curAngle * 180.0 / Math.PI, Color = AciColor.FromCadIndex((short)i) });

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.StackTrace, "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // entities.Add(new Line(new Vector3(piece.CircleRadius + offset.X, 0 + offset.Y, piece.Height), rbpt.To3d()) { Layer = assistLay, LinetypeScale = 12 });
            // 标签
            entities.Add(new Text("俯视图", offset + new Vector2(0, -0.85 * piece.Depth), 0.1 * piece.Depth) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"] });
            entities.Add(new Text("A", lbpt, 2.5 * piece.Depth * 0.01) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"], ObliqueAngle = 15.0 });
            entities.Add(new Text("B", rbpt, 2.5 * piece.Depth * 0.01) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"], ObliqueAngle = 15.0 });
            entities.Add(new Text("C", rtpt, 2.5 * piece.Depth * 0.01) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"], ObliqueAngle = 15.0 });
            entities.Add(new Text("D", ltpt, 2.5 * piece.Depth * 0.01) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"], ObliqueAngle = 15.0 });
            doc.AddEntity(entities);
        }
        #region
        private void DrawFrontView(Vector2 offset)
        {
            var entities = new List<EntityObject>();
            double hw = piece.Width / 2;

            // 底部
            entities.Add(new Line(new Vector2(-hw, 0) + offset, new Vector2(hw, 0) + offset)
            {
                Layer = new Layer("Bottom_Rect") { Color = AciColor.Blue }
            });

            // 顶部
            entities.Add(new Line(new Vector2(-piece.CircleRadius, piece.Height) + offset, new Vector2(piece.CircleRadius, piece.Height) + offset)
            {
                Layer = new Layer("Top_Circle") { Color = AciColor.Red }
            });

            // 侧边
            entities.Add(new Line(new Vector2(-hw, 0) + offset, new Vector2(-piece.CircleRadius, piece.Height) + offset));
            entities.Add(new Line(new Vector2(hw, 0) + offset, new Vector2(piece.CircleRadius, piece.Height) + offset));

            entities.Add(new Text("主视图", offset + new Vector2(0, -30), 5) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"] });
            doc.AddEntity(entities);
        }

        private void DrawLeftView(Vector2 offset)
        {
            var entities = new List<EntityObject>();
            double hd = piece.Depth / 2;

            // 底部
            entities.Add(new Line(new Vector2(-hd, 0) + offset, new Vector2(hd, 0) + offset)
            {
                Layer = new Layer("Bottom_Rect") { Color = AciColor.Blue }
            });
            // 顶部
            entities.Add(new Line(new Vector2(-piece.CircleRadius, piece.Height) + offset, new Vector2(piece.CircleRadius, piece.Height) + offset)
            {
                Layer = new Layer("Top_Circle") { Color = AciColor.Red }
            });
            // 侧边
            entities.Add(new Line(new Vector2(-hd, 0) + offset, new Vector2(-piece.CircleRadius, piece.Height) + offset));
            entities.Add(new Line(new Vector2(hd, 0) + offset, new Vector2(piece.CircleRadius, piece.Height) + offset));

            entities.Add(new Text("左视图", offset + new Vector2(0, -30), 5) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"] });
            doc.AddEntity(entities);
        }
        #endregion
        private void DrawDevelopment(Vector2 offset)
        {
            var entities = new List<EntityObject>();
            entities.Add(new Text("展开图", offset + new Vector2(0, -piece.Depth * 0.85), 0.1 * piece.Depth) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"] });
            //绘制展开图矩形width部分
            var lbpt = new Vector2(-piece.Width * 0.5 + piece.RectangleRoundRadius, piece.Depth * -0.5);
            var rbpt = new Vector2(piece.Width * 0.5 - piece.RectangleRoundRadius, piece.Depth * -0.5);
            var p0 = (new Vector2(0, -piece.CircleRadius)).To3d(piece.Height);
            var v10 = (p0 - lbpt.To3d()).Modulus();
            var v20 = (p0 - rbpt.To3d()).Modulus();
            var cirV10 = new Circle(lbpt, v10);
            var cirV20 = new Circle(rbpt, v20);
            var pt = cirV10.GetCircleIntersectionPoints(cirV20).FirstOrDefault(c => lbpt.GetRotationDirection(c, rbpt) == -1);
            var sideTriangle = new LwPolyline(new List<Vector2> { lbpt + offset, pt + offset, rbpt + offset })
            {
                Layer = new Layer("Development") { Color = AciColor.Green },
                LinetypeScale = 15,
                IsClosed = true
            };
            entities.Add(new Text(piece.RectangleRoundRadius > 0 ? $"{0.75 * piece.NumSegments}''" : "A", lbpt + offset, 2.5 * piece.Depth * 0.01) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"], ObliqueAngle = 15.0 });
            entities.Add(new Text(piece.RectangleRoundRadius > 0 ? $"{0.75 * piece.NumSegments}'" : "B", rbpt + offset, 2.5 * piece.Depth * 0.01) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"], ObliqueAngle = 15.0 });
            entities.Add(new Text((0.75 * piece.NumSegments).ToString(), pt + offset, 2.5 * piece.Depth * 0.01) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"], ObliqueAngle = 15.0 });
            entities.Add(sideTriangle);

            DimensionStyle style = DimensionStyle.Iso25;
            style.TextInsideAlign = false; // 设置文字对齐方式
            style.DimScaleOverall = piece.Depth * 0.5 * 0.03;
            // 3. 创建图层 (可选)
            Layer layer = new Layer("Dimensions") { Color = AciColor.Cyan };
            doc.Layers.Add(layer);
            LinearDimension linearDim = new LinearDimension(lbpt + offset, rbpt + offset, 0, 0, style) { Layer = layer };
            entities.Add(linearDim);
            //var rbpt = new Vector2(piece.Width * 0.5, -piece.Depth * 0.5) + offset;
            var lwptsTop = new List<Vector2>() { pt + offset };
            var lwptsBtm = new List<Vector2>() { rbpt + offset };
            var arcLength_Top = piece.CircleRadius * 2 * Math.PI / piece.NumSegments;
            var arcLength_Btm = piece.RectangleRoundRadius * 2 * Math.PI / piece.NumSegments;
            for (int i = (int)(0.75 * piece.NumSegments) + 1; i <= piece.NumSegments; i++)
            {
                var curAngle = (i - 1) * 2 * Math.PI / piece.NumSegments;
                var nextAngle = i * 2 * Math.PI / piece.NumSegments;
                var curPt_Top = new Vector3((double)(piece.CircleRadius * Math.Cos(curAngle)), (double)(piece.CircleRadius * Math.Sin(curAngle)), piece.Height);//理论上的上口点坐标
                var nexPt_Top = new Vector3(piece.CircleRadius * Math.Cos(nextAngle), piece.CircleRadius * Math.Sin(nextAngle), piece.Height);
                var curPt_Btm = new Vector3((double)(piece.RectangleRoundRadius > 0 ? piece.RectangleRoundRadius * Math.Cos(curAngle) : 0.0) + (piece.Width * 0.5 - piece.RectangleRoundRadius), (double)(piece.RectangleRoundRadius > 0 ? piece.RectangleRoundRadius * Math.Sin(curAngle) : 0.0) - (piece.Depth * 0.5 - piece.RectangleRoundRadius), 0);//理论上的下口点坐标
                var nexPt_Btm = new Vector3((double)(piece.RectangleRoundRadius > 0 ? piece.RectangleRoundRadius * Math.Cos(nextAngle) : 0.0) + (piece.Width * 0.5 - piece.RectangleRoundRadius), (double)(piece.RectangleRoundRadius > 0 ? piece.RectangleRoundRadius * Math.Sin(nextAngle) : 0.0) - (piece.Depth * 0.5 - piece.RectangleRoundRadius), 0);//理论上的下口点坐标
                //计算上口;
                Circle cir = new Circle(lwptsTop.LastOrDefault(), arcLength_Top);
                //entities.Add(cir.ToDxfShape());     
                Circle cir1 = new Circle(lwptsBtm.LastOrDefault(), (nexPt_Top - curPt_Btm).Modulus());
                //entities.Add(cir1.ToDxfShape());
                //上口交点
                var interPt_Top = cir.GetCircleIntersectionPoints(cir1).FirstOrDefault(c => lwptsTop.LastOrDefault().GetRotationDirection(lwptsBtm.LastOrDefault(), c) == 1);
                //entities.Add(new Point(interPt_Top.To3d()));//
                //ptBtmTemp = curPt_Btm.To2d();
                lwptsTop.Add(interPt_Top);

                Vector2 interPt_btm = lwptsBtm.LastOrDefault();
                if (piece.RectangleRoundRadius > 0)
                {
                    //计算下口.
                    Circle cir2 = new Circle(lwptsTop.LastOrDefault(), (nexPt_Top - nexPt_Btm).Modulus());
                    //entities.Add(cir2.ToDxfShape());
                    Circle cir3 = new Circle(lwptsBtm.LastOrDefault(), arcLength_Btm);
                    // entities.Add(cir3.ToDxfShape());
                    interPt_btm = cir2.GetCircleIntersectionPoints(cir3).FirstOrDefault(c => lwptsBtm.LastOrDefault().GetRotationDirection(interPt_Top, c) == -1);
                    lwptsBtm.Add(interPt_btm);
                    var textDeg = interPt_Top.GetVector2To(interPt_btm).Angle() * MathHelper.RadToDeg;
                    entities.Add(new Text(i.ToString() + "'", interPt_btm, piece.Depth * 0.003) { Alignment = TextAlignment.MiddleLeft, Rotation = textDeg, Style = doc.TextStyles["Arial"], Color = AciColor.FromCadIndex((short)i) });
                }
                var l1 = new netDxf.Entities.Line(interPt_Top, interPt_btm);
                entities.Add(new Text(i.ToString(), interPt_Top, piece.Depth * 0.01) { Alignment = TextAlignment.MiddleLeft, Style = doc.TextStyles["Arial"], Rotation = l1.Direction.To2d().Angle() * 180.0 / Math.PI, Color = AciColor.FromCadIndex((short)i) });
                l1.Linetype = Linetype.Dashed;
                l1.Color = AciColor.FromCadIndex((short)i);
                entities.Add(l1);
            }
            //绘制展开图矩形depth部分
            var cir0 = new Circle(lwptsBtm.LastOrDefault(), piece.Depth - 2 * piece.RectangleRoundRadius);
            var cirx = new Circle(lwptsTop.LastOrDefault(), lwptsTop.LastOrDefault().DistanceTo(lwptsBtm.LastOrDefault()));
            var inpts = cir0.GetCircleIntersectionPoints(cirx);
            inpts.ForEach(interPt =>
            {
                if (lwptsTop.LastOrDefault().GetRotationDirection(interPt, lwptsBtm.LastOrDefault()) == -1)
                {
                    var sideView1 = new LwPolyline(new Vector2[]
                    {
                      lwptsTop.LastOrDefault(),
                        interPt,
                        lwptsBtm.LastOrDefault()
                    });
                    sideView1.Layer = new Layer("Development") { Color = AciColor.Green };
                    sideView1.LinetypeScale = 15;
                    sideView1.Color = AciColor.Blue;
                    sideView1.IsClosed = true;
                    entities.Add(sideView1);
                    entities.Add(new Text(piece.RectangleRoundRadius > 0 ? $"{piece.NumSegments}''" : "C", interPt, 2.5 * piece.Depth * 0.01) { Alignment = TextAlignment.MiddleCenter, Style = doc.TextStyles["Arial"], ObliqueAngle = 15.0 });
                    LinearDimension linearDim = new LinearDimension(lwptsBtm.LastOrDefault(), interPt, 0,
                        lwptsBtm.LastOrDefault().GetVector2To(interPt).Angle() * MathHelper.RadToDeg, style)
                    { Layer = layer };
                    entities.Add(linearDim);
                    //pt = interPt.ToNetDxfPoint;
                }
            });
            var top3dCurve = new LwPolyline(lwptsTop)
            {
                Layer = new Layer("Development") { Color = AciColor.Green },
                LinetypeScale = 15,
                IsClosed = false
            };
            entities.Add(top3dCurve);

            var btm3dCurve = new LwPolyline(lwptsBtm)
            {
                Layer = new Layer("Development") { Color = AciColor.Green },
                LinetypeScale = 15,
                IsClosed = false
            };
            entities.Add(btm3dCurve);
            doc.AddEntity(entities);
        }


    #endregion
    }

    public static class NetDxfEx
    {

        public static Vector3 To3d(this Vector2 v2d, double z = 0d)
        {
            return new Vector3(v2d.X, v2d.Y, z);
        }
        public static Vector2 To2d(this Vector3 v3d)
        {
            return new Vector2(v3d.X, v3d.Y);
        }

        /// <summary>
        /// 判断三个点的旋转方向(基于叉积)
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        /// <returns> 逆时针(CCW),-1: 顺时针(CW),0: 三点共线</returns>
        public static int GetRotationDirection(this Vector2 p1, Vector2 p2, Vector2 p3)
        {
            var v12 = p2 - p1;
            var v13 = p3 - p1;
            // 计算叉积:v12 × v13 = v12.X * v13.Y - v12.Y * v13.X
            var cross = v12.X * v13.Y - v12.Y * v13.X;
            // 返回方向结果
            if (cross > 0) return 1;      // 逆时针
            if (cross < 0) return -1;     // 顺时针
            return 0;                      // 共线
        }

        /// <summary>
        /// 计算两个圆的交点
        /// </summary>
        /// <param name="center1">圆1的圆心</param>
        /// <param name="radius1">圆1的半径</param>
        /// <param name="center2">圆2的圆心</param>
        /// <param name="radius2">圆2的半径</param>
        /// <returns>交点列表(可能为0个、1个或2个点)</returns>
        public static List<Vector2> GetCircleIntersectionPoints(Vector2 center1, double radius1, Vector2 center2, double radius2)
        {
            var result = new List<Vector2>();

            // 计算两圆心之间的距离
            double d = center1.DistanceTo(center2);

            // 检查相离或包含的情况
            if (d > radius1 + radius2 || d < Math.Abs(radius1 - radius2) || d < 1e-10)
            {
                return result; // 无交点或两圆心重合
            }

            // 计算辅助量 a(圆1圆心到根轴的距离)
            double a = (d * d + radius1 * radius1 - radius2 * radius2) / (2 * d);

            // 计算交点到根轴的距离 h
            double h_squared = radius1 * radius1 - a * a;

            if (h_squared < 0)
            {
                return result; // 数值误差,无交点
            }

            double h = Math.Sqrt(h_squared);

            // 根轴上的点
            var p = center1 + (center2 - center1) * (a / d);

            // 两个交点的垂直方向向量
            var perpendicular = new Vector2(-(center2.Y - center1.Y), center2.X - center1.X) / d;

            // 第一个交点
            result.Add(p + perpendicular * h);

            // 第二个交点(如果h不为0)
            if (h > 1e-10)
            {
                result.Add(p - perpendicular * h);
            }

            return result;
        }

        /// <summary>
        /// 计算两个圆的交点(重载版本)
        /// </summary>
        /// <param name="circle1">圆1(圆心, 半径)</param>
        /// <param name="circle2">圆2(圆心, 半径)</param>
        /// <returns>交点列表</returns>
        public static List<Vector2> GetCircleIntersectionPoints((Vector2 center, double radius) circle1, (Vector2 center, double radius) circle2)
        {
            return GetCircleIntersectionPoints(circle1.center, circle1.radius, circle2.center, circle2.radius);
        }

        /// <summary>
        /// 计算两个圆的交点(重载版本)
        /// </summary>
        /// <param name="circle1">圆1(圆心, 半径)</param>
        /// <param name="circle2">圆2(圆心, 半径)</param>
        /// <returns>交点列表</returns>
        public static List<Vector2> GetCircleIntersectionPoints(this Circle circle1, Circle circle2)
        {
            return GetCircleIntersectionPoints(circle1.Center.To2d(), circle1.Radius, circle2.Center.To2d(), circle2.Radius);
        }

        /// <summary>
        /// 计算两点之间的距离
        /// </summary>
        public static double DistanceTo(this Vector2 p1, Vector2 p2)
        {
            return (p2 - p1).Modulus();
        }

        /// <summary>
        /// Calculates the angle, in degrees, between the specified two-dimensional vector and the positive x-axis.
        /// </summary>
        /// <param name="v">The two-dimensional vector for which to calculate the angle.</param>
        /// <returns>The angle, in degrees, between the vector and the positive x-axis. The value is always positive and ranges
        /// from 0 to 360.</returns>
        public static double Angle(this Vector2 v)
        {
            return Vector2.Angle(v);
        }

        /// <summary>
        /// Calculates the directional vector from the starting point to the ending point.
        /// </summary>
        /// <param name="sp">The starting point as a Vector2 structure.</param>
        /// <param name="ep">The ending point as a Vector2 structure.</param>
        /// <returns>A Vector2 representing the direction and distance from the starting point to the ending point.</returns>
        public static Vector2 GetVector2To(this Vector2 sp, Vector2 ep) => ep - sp;
    }
}

 

image

posted @ 2026-04-20 20:44  南胜NanSheng  阅读(48)  评论(0)    收藏  举报