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]()