目录
项目要求:
输入DXF文件、CSV文件,将DXF读取到的数据覆盖到CSV文件。内容包含直线、弧线、圆等图形坐标数据,并以三个数据为一组的形式输出。数据格式如下:设置数据“1”代表直线,“0”代表圆弧和圆。直线数据格式为:起始坐标X,起始坐标Y,图形类型;终点坐标X,终点坐标Y,图形类型。圆弧数据格式为:起始角度,终止角度,图形类型;中心点坐标X,Y,图形类型;半径,图形类型,图形类型。圆的数据格式表示为拆分成两段圆弧来表示。
项目环境:
C#、WinForm
项目实现:
DXF文件
读取DXF文件
打开文件夹,读取文件
private void bnreaddxf_Click(object sender, EventArgs e)
{
OpenFileDialog openFile = new OpenFileDialog();
openFile.Filter = "DXF Files (*.dxf)|*.dxf|All Files (*.*)|*.*";
openFile.Title = "Load DXF File";
if (DialogResult.OK == openFile.ShowDialog())
{
MessageBox.Show("成功打开dxf文件");
//获取文件路径
dxffilepath = openFile.FileName;
//显示文件内容
myDXF.ShowDXF(dxffilepath, pictureBox1);
//解析文件内容
outputdxf();
}
}
解析文件内容
解析格式根据AutoCAD DXF参考格式
1.直线Line
DataLineStruct item = default(DataLineStruct);
do
{
GetLineCouple(sr, out text, out value);
if (text == "10")
{
fX1Pos = (float)Convert.ToDouble(value);
}
if (text == "20")
{
fY1Pos = (float)Convert.ToDouble(value);
}
if (text == "30")
{
num2 = (float)Convert.ToDouble(value);
}
if (text == "11")
{
fX2Pos = (float)Convert.ToDouble(value);
}
if (text == "21")
{
fY2Pos = (float)Convert.ToDouble(value);
}
if (text == "31")
{
num = (float)Convert.ToDouble(value);
}
}
while (text != "31");
item.fX1Pos = fX1Pos;
item.fY1Pos = fY1Pos;
item.fX2Pos = fX2Pos;
item.fY2Pos = fY2Pos;
listLineArray.Add(item);
2.圆弧Arc
do
{
GetLineCouple(sr, out text, out value);
if (text == "10")
{
num11 = (float)Convert.ToDouble(value);
}
if (text == "20")
{
num10 = (float)Convert.ToDouble(value);
}
if (text == "40")
{
num5 = (float)Convert.ToDouble(value);
}
if (text == "50")
{
num4 = (float)Convert.ToDouble(value);
}
if (text == "51")
{
num3 = (float)Convert.ToDouble(value);
}
}
while (text != "51");
num9 = num11 + (float)Math.Cos((double)num4 / 180.0 * Math.PI) * num5;
num8 = num10 + (float)Math.Sin((double)num4 / 180.0 * Math.PI) * num5;
num7 = num11 + (float)Math.Cos((double)num3 / 180.0 * Math.PI) * num5;
num6 = num10 + (float)Math.Sin((double)num3 / 180.0 * Math.PI) * num5;
num2 = num11 - num9;
num = num10 - num8;
DataArcStruct item = default(DataArcStruct);
item.fXPos = num9;
item.fYPos = num8;
item.fX1Pos = num7;
item.fY1Pos = num6;
item.fIPos = num2;
item.fJPos = num;
item.fRPos = num5;
item.fptXPos = num11;
item.fptYPos = num10;
item.fAngle1Pos = num4;
item.fAngle2Pos = num3;
listArcArray.Add(item);
3. 圆Circle
do
{
GetLineCouple(sr, out text, out value);
if (text == "10")
{
fXPos = (float)Convert.ToDouble(value);
}
if (text == "20")
{
fYPos = (float)Convert.ToDouble(value);
}
if (text == "30")
{
num = (float)Convert.ToDouble(value);
}
if (text == "40")
{
fRPos = (float)Convert.ToDouble(value);
}
}
while (text != "40");
DataCircleStruct item = default(DataCircleStruct);
item.fXPos = fXPos;
item.fYPos = fYPos;
item.fRPos = fRPos;
listCircleArray.Add(item);
最终汇总,输出为所需要的格式。
private void outputdxf()
{
int count = 0;//坐标数据
data = new float[150]; //新配方数据(列)
for (int i = 0; i < myDXF.listLineArray.Count; i++)
{
data[count++] = myDXF.listLineArray[i].fX1Pos;//起始坐标
data[count++] = myDXF.listLineArray[i].fY1Pos;
data[count++] = (float)0; //类型
data[count++] = myDXF.listLineArray[i].fX2Pos;//终点坐标
data[count++] = myDXF.listLineArray[i].fY2Pos;
data[count++] = (float)0;
}
for (int j = 0; j < myDXF.listArcArray.Count; j++)
{
PointF center = default(PointF);
float starangle = myDXF.listArcArray[j].fAngle1Pos;
float endangle = myDXF.listArcArray[j].fAngle2Pos;
float radius = myDXF.listArcArray[j].fRPos;
center.X = myDXF.listArcArray[j].fptXPos;
center.Y = myDXF.listArcArray[j].fptYPos;
data[count++] = starangle;//起始角度
data[count++] = endangle;//终止角度
data[count++] = (float)1; //类型
data[count++] = center.X; //中心点X
data[count++] = center.Y; //中心点Y
data[count++] = (float)1; //类型
data[count++] = radius; //半径
data[count++] = (float)1;
data[count++] = (float)1; //类型
}
for (int z = 0; z < myDXF.listCircleArray.Count; z++)
{
PointF center = default(PointF);
float starangle1 = 0;
float endangle1 = 180;
float starangle2 = 180;
float endangle2 = 360;
float radius = myDXF.listCircleArray[z].fRPos;
center.X = myDXF.listCircleArray[z].fXPos;
center.Y = myDXF.listCircleArray[z].fYPos;
data[count++] = starangle1;
data[count++] = endangle1;
data[count++] = (float)1;
data[count++] = center.X; //中心点X
data[count++] = center.Y; //中心点Y
data[count++] = (float)1; //类型
data[count++] = radius; //半径
data[count++] = (float)1;
data[count++] = (float)1; //类型
data[count++] = starangle2;
data[count++] = endangle2;
data[count++] = (float)1;
data[count++] = center.X; //中心点X
data[count++] = center.Y; //中心点Y
data[count++] = (float)1; //类型
data[count++] = radius; //半径
data[count++] = (float)1;
data[count++] = (float)1; //类型
}
}
显示DXF文件
1.将DXF显示在picturebox上
public Bitmap PaintDXF(PictureBox myPicBox)
{
Rectangle displayRectangle = myPicBox.DisplayRectangle;
Bitmap bitmap = new Bitmap(displayRectangle.Width, displayRectangle.Height);
Graphics graphics = Graphics.FromImage(bitmap);
SolidBrush solidBrush = new SolidBrush(Color.Black);
graphics.FillRectangle(solidBrush, displayRectangle);
Pen pen = new Pen(Color.Blue, 2f);
Pen pen2 = new Pen(Color.Blue, 200f);
Pen pen3 = new Pen(Color.FromArgb(50, 50, 50), 1f);
RectangleF rect = default(RectangleF);
PointF pt = default(PointF);
PointF pt2 = default(PointF);
PointF pointF = default(PointF);
PointF pointF2 = default(PointF);
PointF pointF3 = default(PointF);
double num = 0.0;
PointF CenterPoint = default(PointF);
PointF pointF4 = default(PointF);
PointF pointF5 = default(PointF);
double sweepAngle = 0.0;
double startAngle = 0.0;
double num2 = 0.0;
for (int i = 1; i * 40 < displayRectangle.Height; i++)
{
graphics.DrawLine(pen3, 0, 40 * i, displayRectangle.Width, 40 * i);
}
for (int i = 1; i * 40 < displayRectangle.Width; i++)
{
graphics.DrawLine(pen3, 40 * i, 0, 40 * i, displayRectangle.Height);
}
for (int j = 0; j < listLineArray.Count; j++)
{
pt.X = listLineArray[j].fX1Pos;
pt.Y = listLineArray[j].fY1Pos;
pt2.X = listLineArray[j].fX2Pos;
pt2.Y = listLineArray[j].fY2Pos;
pt.X *= m_fratio;
pt.Y *= m_fratio;
pt2.X *= m_fratio;
pt2.Y *= m_fratio;
pt.X = pt.X * m11 + pt.Y * m12 + m13;
pt.Y = pt.X * m21 + pt.Y * m22 + m23;
pt2.X = pt2.X * m11 + pt2.Y * m12 + m13;
pt2.Y = pt2.X * m21 + pt2.Y * m22 + m23;
graphics.DrawLine(pen, pt, pt2);
}
for (int j = 0; j < listCircleArray.Count; j++)
{
float num4 = listCircleArray[j].fRPos * m_fratio;
pt.X = listCircleArray[j].fXPos;
pt.Y = listCircleArray[j].fYPos;
pt.X *= m_fratio;
pt.Y *= m_fratio;
pt.X = pt.X * m11 + pt.Y * m12 + m13;
pt.Y = pt.X * m21 + pt.Y * m22 + m23;
rect.X = pt.X - num4;
rect.Y = pt.Y - num4;
rect.Width = 2f * num4;
rect.Height = 2f * num4;
graphics.DrawEllipse(pen, rect);
}
for (int j = 0; j < listArcArray.Count; j++)
{
RectangleF rectangleF = default(RectangleF);
pt.X = listArcArray[j].fXPos;
pt.Y = listArcArray[j].fYPos;
pt2.X = listArcArray[j].fX1Pos;
pt2.Y = listArcArray[j].fY1Pos;
pointF.X = listArcArray[j].fIPos;
pointF.Y = listArcArray[j].fJPos;
pointF3.X = listArcArray[j].fptXPos;
pointF3.Y = listArcArray[j].fptYPos;
pt.X *= m_fratio;
pt.Y *= m_fratio;
pt2.X *= m_fratio;
pt2.Y *= m_fratio;
pointF.X *= m_fratio;
pointF.Y *= m_fratio;
pt.X = pt.X * m11 + pt.Y * m12 + m13;
pt.Y = pt.X * m21 + pt.Y * m22 + m23;
pt2.X = pt2.X * m11 + pt2.Y * m12 + m13;
pt2.Y = pt2.X * m21 + pt2.Y * m22 + m23;
float num4 = (float)Math.Pow(pointF.X * pointF.X + pointF.Y * pointF.Y, 0.5);
rectangleF = new RectangleF(pt.X + pointF.X - num4, pt.Y + pointF.Y - num4, 2f * num4, 2f * num4);
pointF2.X = (float)(Math.Atan2(Convert.ToDouble(0f - pointF.Y), Convert.ToDouble(0f - pointF.X)) / 3.14 * 180.0);
pointF2.Y = (float)(Math.Atan2(Convert.ToDouble(pt2.Y - pointF.Y - pt.Y), Convert.ToDouble(pt2.X - pointF.X - pt.X)) / 3.14 * 180.0);
if (pointF2.X < 0f)
{
pointF2.X = 360f + pointF2.X;
}
if (pointF2.Y < 0f)
{
pointF2.Y = 360f + pointF2.Y;
}
float num5 = pointF2.Y - pointF2.X;
if (num5 < 0f)
{
num5 += 360f;
}
graphics.DrawArc(pen, rectangleF, pointF2.X, num5);
}
graphics.TranslateTransform(0f, -displayRectangle.Height);
graphics.Dispose();
solidBrush.Dispose();
pen.Dispose();
pen3.Dispose();
return bitmap;
}
2.DXF图形的平移缩放
#region 鼠标控制平移缩放
private void picBox_MouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta < 0)
myDXF.Ratio -= 0.1f;
else
myDXF.Ratio += 0.1f;
if (myDXF.Ratio >= 10)
myDXF.Ratio = 10;
if (myDXF.Ratio <= 0.1)
myDXF.Ratio = 0.1f;
pictureBox1.Image = myDXF.PaintDXF(pictureBox1);
}
private void picBox_ShowDXF_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
isLeftButton = true;
xStart = e.X;
yStart = e.Y;
}
private void picBox_ShowDXF_MouseUp(object sender, MouseEventArgs e)
{
isLeftButton = false;
oldM13 = myDXF.M13;
oldM23 = myDXF.M23;
}
private void picBox_ShowDXF_MouseMove(object sender, MouseEventArgs e)
{
if (isLeftButton == true)
{
xEnd = e.X;
yEnd = e.Y;
myDXF.M13 = oldM13 + xEnd - xStart;
myDXF.M23 = oldM23 + yEnd - yStart;
pictureBox1.Image = myDXF.PaintDXF(pictureBox1);
}
}
#endregion
CSV文件
读取CSV文件
private void readcsv()
{
try
{
DataTable datatable = new DataTable();
int index = 0, index_ok = 0; //替换csv文件列索引、标志位
//打开csv文件
OpenFileDialog openFile = new OpenFileDialog();
openFile.Filter = ".xls|*.csv|All File(*.*)|*.*";
openFile.Title = "Load CSV File";
if (DialogResult.OK == openFile.ShowDialog())
{
csvfilepath = openFile.FileName;
MessageBox.Show("成功打开csv文件");
}
//分析文件
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
将csv文件保存为datatable
在读取CSV文件时就可以保存为datatable格式,以便后期添加数据。
//读取csv文件
StreamReader sr = new StreamReader(csvfilepath);
int csvline = 0;
datatable.Clear();
//将csv文件数据添加到 datatable datatable中
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
string[] values = line.Split(',');
if (csvline == 0) //首行为列名
{
for (int i = 0; i < values.Length; i++)
{
DataColumn column = new DataColumn(values[i]);
datatable.Columns.Add(column);
}
}
else
{
DataRow dr = datatable.NewRow();
for (int i = 0; i < values.Length; i++)
{
String stringdr = values[i];
dr[i] = stringdr;
if (csvline == 1 && index_ok == 0)
{
if (values[i] == "0" || values[i] == null)
{
index = i;
index_ok = 1;
}
else if (i == values.Length - 1)
{
datatable.Columns.Add("组" + (i - 1));
index = i + 1;
index_ok = 1;
}
}
}
datatable.Rows.Add(dr);
}
csvline++;
}
sr.Close();
添加数据
private DataTable addnewdata(int insert, DataTable dt)
{
try
{
if (insert != 0)
{
for (int i = 0; i < data.Length; i++)
{
if (dt.Rows.Count < i + 1)
{
dt.Rows.Add(dt.NewRow());
dt.Rows[i][0] = "成分" + i + 1;
dt.Rows[i][1] = "Modbus_1.变量" + i + 1;
dt.Rows[i][2] = "FLOAT";
}
dt.Rows[i][insert] = data[i];
}
MessageBox.Show("添加成功");
}
}
catch
{
MessageBox.Show("添加失败");
}
return dt;
}
导出CSV文件
将成功添加数据的datatable输出为新的CSV文件,覆盖路径下的原文件。
private void outputcsv(DataTable dt)
{
try
{
// 创建一个StringBuilder来存储CSV内容
StringBuilder csvContent = new StringBuilder();
// 添加表头
for (int i = 0; i < dt.Columns.Count; i++)
{
csvContent.Append(dt.Columns[i].ColumnName.ToString().Trim());
csvContent.Append(i == dt.Columns.Count - 1 ? "\r\n" : ",");
}
// 添加数据行
foreach (DataRow row in dt.Rows)
{
for (int i = 0; i < dt.Columns.Count; i++)
{
csvContent.Append(row[i].ToString().Trim());
csvContent.Append(i == dt.Columns.Count - 1 ? "\r\n" : ",");
}
}
// 将CSV内容写入文件
File.WriteAllText(csvfilepath, csvContent.ToString(), Encoding.Default);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
注意事项:
CSV文件列名不能重复。
如果CSV文件打开出现乱码,解决方法:用记事本打开,重新保存为“带有BOM的UTF-8”。
成果展示
图像缩放平移后