本人现在正在做着gerber文件转dxf文件,虽然最后很艰辛地将之转换了过来,但是上司要求将dxf中所画的图形轮廓化(意思是本来通过dxflib转化出来的图形都是实心的,后来自己又重新将实心自己写代码重绘,将实心图形都变换成了边框.)但是要求是将任意一个实体转化为边框,其中就包括多边形,本人思考了大半个月,尝试了数种方法都解决不了(举个例子:我想过两个方法:1. 每画一个图形都去判断数组上是否存在该点是已经被使用了,这样可以分析去重叠区域,进而得知多边形的折点,但这样做的话会有个很大的弊端就是需要将所有的图形化成一个个的点,用点再去一次次判断,因为比如说两个长方形部分重叠,重叠一部分的话通过四个顶点的范围判断是不准确的,所以要换成一个个点去判断,这样会导致运行量巨大,并不现实.
2.就是先将gerber化成图片(bmp\jpg),再通过opencv的canny轮廓算法去找出每个实体的轮廓并画出来,再通过图片转成dxf,但由于这样转回来的dxf的图形会出现很尴尬的问题:canny检测的图形再画的,但导致图形轮廓不规则(换句话就是说会出现锯齿\凹凸等情况,同时坐标的大小耶发生了变化.)我曾使用各种滤波耶无法解决这个问题.)因此,想请教一下:希望有此经验或者能有解决方向的大师指点一下方向或解决方法.
这个涉及到dxf的格式,简单说下:
☆标题段(HEADER)标题段记录AutoCAD系统的所有标题变量的当前值或当前状态。标题变量记录了AutoCAD系统的当前工作环境,如SNAP捕捉当前状态、栅格间距式样、当前图层层名及线型、颜色等。
☆表段(TABLES)表段共包含4个表,每个表又包含可变数目的表项。这些表在文件中出现的顺序是线型表(LTYPE)、图层表(LAYER)、字样表(STYLE)、视图表(VIEW)。
☆块段(BLOCK)块段记录了所用块的块名,当前图层层名、块的种类、块的插入基点及组成该块的所有成员。块的种类分为图形块、带有属性的块和无名块三种。无名块包括用HATCH命令生成的剖面线和用DIM命令所完成的尺寸标准。
☆实体段(ENTITIES)实体段记录了每个实体的名称、所在图层及其名字、线型、颜色等。
☆文件结束段(EOF OF FILE)DXF文件的结束标志。
一个DXF文件由若干个组构成,每个组占两行,第一行为组的代码,第二行为组值。组代码相当于数据类型的代码,它由CAD图形系统所规定,而组值为具体的数值,二者结合起来表示一个数据的含义和值。例如,代码10代表一个点的X坐标,占一行,而其第二行4.5425则是点X坐标的具体数值,二者结合表示一点,其X坐标值为4.5425。
(1)组代码和组值的类型组代码为一个非负的不超过三位的整数,而组值由组代码的类型决定。例如:
代码0~9组值类型为字符型。
代码10~59组值类型为实型。
代码60~79组值类型为整型。
代码999表示解释行。
(2)组代码的含义每个组代码均有规定的含义,有些代码含义是固定的,而有些组代码则因应用场合不同而有多个含义,应具体分析。另外,一些代码是备用的,目前版本尚未用到,现将他们的含义举例介绍如下。
0:表示一个事物的开始,如一个块、表、图层、实体等。
1:字符型数据的值,如TEXT的字符串、文件名、属性值等。
2:一个事物的名字,如段、表、块、线型、视图等的名字。
3~5:字符型数据的值,如文件名、线型说明等。
6:线型名(固定类型)。
8:图层名(固定类型)。
关于实体的坐标与相应的组代码10~18、20~28、30~38的用法应根据实体所用到点的数量,按组代码个位的0、1、2、……的顺序使用。例如LINE的起点组代码为10、20、30,而11、21、31为其终点。其他类似。
DXF文件的结构相当复杂,完整读取DXF文件也是一项异常繁琐的工程。在实际应用中,为了提取图形的实体信息,可以省略DXF文件中的许多项,只要获取其中的层表、块段和实体段,就可以完成相应几何图形的描述。在层表中说明每一层的颜色、线型,在块段中说明块所在的层、属性及其在图形中的位置,在实体段中说明直线的起点、终点及圆的圆心、半径等几何信息和各实体所在的层。根据实体所在的层,在层表中搜索每一层的颜色、线型并将其添加到实体对象中。在利用CAD进行绘图时,需将变量参数DIMASO设为ON,以保证块段中定义的尺寸块为一个整体,并可被正确无误地获取。根据尺寸类型名、尺寸定义的起点、终点坐标与实体类型名、实体空间坐标是否匹配,对实体对象进行尺寸附加。在绘图时,如对自定义的粗糙度、形位公差等块不进行"EXPLODE"炸开操作,也可通过增加相应读取函数提取其属性。
下面举例说明实体段在DXF文件中的格式。
圆弧(ARC)
0(开始)ARC(圆弧)
8(层的组码)
W1(层名为"W1")
10(圆弧圆心的X坐标组码)
7.0(圆弧圆心的X坐标组值)
20(圆弧圆心的Y坐标组码)
9.0(圆弧圆心的Y坐标组值)
30(圆弧圆心的Z坐标组码)
0.0(圆弧圆心的Z坐标组值)
40(圆弧的半径组码)
25.0(圆弧的半径值)
50(圆弧的起始角度组码)
90.0(圆弧的起始角度值)
51(圆弧的终止角度组码)
180.0(圆弧的终止角度组值)
若实体的线型用BYLAYER,颜色为256(即BYLAYER),基面高度和厚度为零,其格式可简化。
用C语言可以定一个结构体,然后读取解析,具体的代码你要采纳了可以帮你写。正好以前写过呢。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace 浏览dwg
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ViewDWG viewDwg = new ViewDWG();
pictureBox1.Image = viewDwg.GetDwgImage("c:\\1.dwg");
}
class ViewDWG
{
struct BITMAPFILEHEADER
{
public short bfType;
public int bfSize;
public short bfReserved1;
public short bfReserved2;
public int bfOffBits;
}
public Image GetDwgImage(string FileName)
{
if (!(File.Exists(FileName)))
{
throw new FileNotFoundException("文件没有被找到");
}
FileStream DwgF; //文件流
int PosSentinel; //文件描述块的位置
BinaryReader br; //读取二进制文件
int TypePreview; //缩略图格式
int PosBMP; //缩略图位置
int LenBMP; //缩略图大小
short biBitCount; //缩略图比特深度
BITMAPFILEHEADER biH; //BMP文件头,DWG文件中不包含位图文件头,要自行加上去
byte[] BMPInfo; //包含在DWG文件中的BMP文件体
MemoryStream BMPF = new MemoryStream(); //保存位图的内存文件流
BinaryWriter bmpr = new BinaryWriter(BMPF); //写二进制文件类
Image myImg = null;
try
{
DwgF = new FileStream(FileName, FileMode.Open, FileAccess.Read); //文件流
br = new BinaryReader(DwgF);
DwgF.Seek(13, SeekOrigin.Begin); //从第十三字节开始读取
PosSentinel = br.ReadInt32(); //第13到17字节指示缩略图描述块的位置
DwgF.Seek(PosSentinel + 30, SeekOrigin.Begin); //将指针移到缩略图描述块的第31字节
TypePreview = br.ReadByte(); //第31字节为缩略图格式信息,2 为BMP格式,3为WMF格式
if (TypePreview == 1)
{
}
else if (TypePreview == 2 || TypePreview == 3)
{
PosBMP = br.ReadInt32(); //DWG文件保存的位图所在位置
LenBMP = br.ReadInt32(); //位图的大小
DwgF.Seek(PosBMP + 14, SeekOrigin.Begin); //移动指针到位图块
biBitCount = br.ReadInt16(); //读取比特深度
DwgF.Seek(PosBMP, SeekOrigin.Begin); //从位图块开始处读取全部位图内容备用
BMPInfo = br.ReadBytes(LenBMP); //不包含文件头的位图信息
br.Close();
DwgF.Close();
biH.bfType = 19778; //建立位图文件头
if (biBitCount < 9)
{
biH.bfSize = 54 + 4 * (int)(Math.Pow(2, biBitCount)) + LenBMP;
}
else
{
biH.bfSize = 54 + LenBMP;
}
biH.bfReserved1 = 0; //保留字节
biH.bfReserved2 = 0; //保留字节
biH.bfOffBits = 14 + 40 + 1024; //图像数据偏移
//以下开始写入位图文件头
bmpr.Write(biH.bfType); //文件类型
bmpr.Write(biH.bfSize); //文件大小
bmpr.Write(biH.bfReserved1); //0
bmpr.Write(biH.bfReserved2); //0
bmpr.Write(biH.bfOffBits); //图像数据偏移
bmpr.Write(BMPInfo); //写入位图
BMPF.Seek(0, SeekOrigin.Begin); //指针移到文件开始处
myImg = Image.FromStream(BMPF); //创建位图文件对象
bmpr.Close();
BMPF.Close();
}
return myImg;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
}
}
C#读取DWG文件(方法3)
struct BITMAPFILEHEADER
{
public short bfType;
public int bfSize;
public short bfReserved1;
public short bfReserved2;
public int bfOffBits;
}
public static System.Drawing.Image GetDwgImage(string FileName)
{
if (!(File.Exists(FileName)))
{
throw new FileNotFoundException("文件没有被找到");
}
FileStream DwgF=null; //文件流
int PosSentinel; //文件描述块的位置
BinaryReader br=null; //读取二进制文件
int TypePreview; //缩略图格式
int PosBMP; //缩略图位置
int LenBMP; //缩略图大小
short biBitCount; //缩略图比特深度
BITMAPFILEHEADER biH; //BMP文件头,DWG文件中不包含位图文件头,要自行加上去
byte[] BMPInfo; //包含在DWG文件中的BMP文件体
MemoryStream BMPF = new MemoryStream(); //保存位图的内存文件流
BinaryWriter bmpr = new BinaryWriter(BMPF); //写二进制文件类
System.Drawing.Image myImg = null;
try
{
DwgF = new FileStream(FileName, FileMode.Open, FileAccess.Read); //文件流
br = new BinaryReader(DwgF);
DwgF.Seek(13, SeekOrigin.Begin); //从第十三字节开始读取
PosSentinel = br.ReadInt32(); //第13到17字节指示缩略图描述块的位置
DwgF.Seek(PosSentinel + 30, SeekOrigin.Begin); //将指针移到缩略图描述块的第31字节
TypePreview = br.ReadByte(); //第31字节为缩略图格式信息,2 为BMP格式,3为WMF格式
if (TypePreview == 1)
{
}
else if (TypePreview == 2 || TypePreview == 3)
{
PosBMP = br.ReadInt32(); //DWG文件保存的位图所在位置
DwgF.Seek(PosSentinel + 16, SeekOrigin.Begin);//原来这一句是没有的,通过和VC版的单步调试相比较得来,
//如果没有这一句,比较小的dwg能够打开,但是大的(比如1.5M以上)打开就会出错,原因不详
LenBMP = br.ReadInt32(); //位图的大小
DwgF.Seek(PosBMP + 14, SeekOrigin.Begin); //移动指针到位图块
biBitCount = br.ReadInt16(); //读取比特深度
DwgF.Seek(PosBMP, SeekOrigin.Begin); //从位图块开始处读取全部位图内容备用
BMPInfo = br.ReadBytes(LenBMP); //不包含文件头的位图信息
br.Close();
DwgF.Close();
biH.bfType = 19778; //建立位图文件头
if (biBitCount < 9)
{
biH.bfSize = 54 + 4 * (int)(Math.Pow(2, biBitCount)) + LenBMP;
}
else
{
biH.bfSize = 54 + LenBMP;
}
biH.bfReserved1 = 0; //保留字节
biH.bfReserved2 = 0; //保留字节
biH.bfOffBits = 14 + 40 + 1024; //图像数据偏移
//以下开始写入位图文件头
bmpr.Write(biH.bfType); //文件类型
bmpr.Write(biH.bfSize); //文件大小
bmpr.Write(biH.bfReserved1); //0
bmpr.Write(biH.bfReserved2); //0
bmpr.Write(biH.bfOffBits); //图像数据偏移
bmpr.Write(BMPInfo); //写入位图
BMPF.Seek(0, SeekOrigin.Begin); //指针移到文件开始处
myImg = System.Drawing.Image.FromStream(BMPF); //创建位图文件对象
bmpr.Close();
BMPF.Close();
}
return myImg;
}
catch (EndOfStreamException)
{
throw new EndOfStreamException("文件不是标准的DWG格式文件,无法预览!");
}
catch (IOException ex)
{
if (ex.Message == "试图将文件指针移到文件开头之前。\r\n")
{
throw new IOException("文件不是标准的DWG格式文件,无法预览!");
}
else if (ex.Message == "文件“" + FileName + "”正由另一进程使用,因此该进程无法访问该文件。")
{
//复制文件,继续预览
File.Copy(FileName, Application.StartupPath + @"\linshi.dwg", true);
Image image = GetDwgImage(Application.StartupPath + @"\linshi.dwg");
File.Delete(Application.StartupPath + @"\linshi.dwg");
return image;
}
else
{
throw new Exception(ex.Message);
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
if (DwgF != null)
{
DwgF.Close();
}
if (br != null)
{
br.Close();
}
bmpr.Close();
BMPF.Close();
}
}
读取出来的背景色为白色,效果比较差,很多颜色显示不出来,当时认为显示DWG文件出错误了,问了些高手,(呵呵,别人告诉自己本身取出的就是白色背景,需要自己改变背景色,在此鄙视一下自己)所以继续用C#操作返回的IMAGE对象,改变背景色
///
///显示DWG文件
///
/// 要显示的宽度
/// 要显示的高度
///
public static System.Drawing.Image ShowDWG(int Pwidth,int PHeight,string FilePath)
{
System.Drawing.Image image = GetDwgImage(FilePath);
Bitmap bitmap = new Bitmap(image);
int Height = bitmap.Height;
int Width = bitmap.Width;
Bitmap newbitmap = new Bitmap(Width, Height);
Bitmap oldbitmap = (Bitmap)bitmap;
Color pixel;
for (int x = 1; x < Width; x++)
{
for (int y = 1; y < Height; y++)
{
pixel = oldbitmap.GetPixel(x, y);
int r = pixel.R, g = pixel.G, b = pixel.B;
if (pixel.Name == "ffffffff" || pixel.Name == "ff000000")
{
r = 255 - pixel.R;
g = 255 - pixel.G;
b = 255 - pixel.B;
}
newbitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
Bitmap bt = new Bitmap(newbitmap, Pwidth, PHeight);
return newbitmap;
}