本人最近刚刚开始接触CAD的dxf文件解析,所以一开始对dxf的解析并不是很熟悉,也是在网上查阅了大量的资料,发现解析椭圆和样条曲线的案例很少,几乎没有完整的相关源码介绍。导致我的解析过程是非常痛苦漫长的,好在历经3天,在经历一次次失败后,终于正确的解析出来了。画不多说,直接上源码吧。
椭圆解析:
头文件部分内容如下:
std::vector<tContour> m_contours; //所有的轮廓
//轮廓结构
typedef struct _tContour{
QVector<QPointF> path; //轮廓路径
bool bClosure; //轮廓是否封闭
int iType; //轮廓类型
Qt::GlobalColor color; //轮廓颜色
double dArea; //轮廓面积:平方英尺(sqf)
Qt::PenStyle lt; //线条类型
int lineWidth; //轮廓粗细调节
QPointF centroid; //轮廓重心
}tContour;
vector < pair<DL_EllipseData,DL_Attributes>> m_VecDxfEllipse; //存储解析出来的椭圆信息
1.利用dxflib库从dxf文件中读取椭圆数据放到vector容器中
//读取椭圆数据
void Dxf::addEllipse(const DL_EllipseData &data)
{
if (!(m_bEntities)) {
return ;
}
m_VecDxfEllipse.push_back(pair<DL_EllipseData,DL_Attributes>(data,attributes));
// qDebug()<<data.cx<<data.cy<<data.cz<<data.mx<<data.my<<data.mz<<data.ratio<<data.angle1<<data.angle2;
qDebug()<<"cx:"<<data.cx<<"cy:"<<data.cy<<"cz:"<<data.cz
<<"mx:"<<data.mx<<"my"<<data.my<<"mz"<<data.mz
<<"ratio:"<<data.ratio<<"angle1:"<<data.angle1<<"angle2:"<<data.angle2;
// qDebug()<<"addEllipse";
}
2.根据读出来的数据求出椭圆的坐标,放到m_contour容器中
double Dxf::getDotProduct( QPointF v1, QPointF v2) {
return v1.x() * v2.x() + v1.y ()* v2.y();
}
double Dxf::getMagnitude2D(QPointF point) const {
return sqrt(point.x() * point.x() + point.y() * point.y());
}
double Dxf::getAngle(QPointF point) {
double ret = 0.0;
double m = getMagnitude2D(point);
if (m > 1.0e-6) {
double dp = getDotProduct(QPointF(point.x(),point.y()),QPointF(1.0,0.0));
if (dp / m >= 1.0) {
ret = 0.0;
} else if (dp / m < -1.0) {
ret = M_PI;
} else {
ret = acos(dp / m);
}
if (point.y() < 0.0) {
ret = 2*M_PI - ret;
}
}
return ret;
}
QPointF Dxf::rotate(double angle,QPointF point)
{
double r = getMagnitude2D(point);
double a = getAngle(point) + angle;
double x = cos(a) * r;
double y = sin(a) * r;
return QPointF(x,y);
}
QPointF Dxf::rotate(DL_EllipseData data,double angle,QPointF& vc,QPointF &vp)
{
vp = vc + rotate(angle,(vp - vc));
return vp;
}
//解析dxf椭圆数据
void Dxf::readEllipse()
{
for(int i = 0; i < m_VecDxfEllipse.size();i++)
{
tContour contour;
DL_EllipseData data(m_VecDxfEllipse.at(i).first);
QPointF cp = QPointF(data.cx,data.cy);
double radius1 = sqrt(pow(data.mx,2) + pow(data.my,2));
double radius2 = radius1 * data.ratio;
double angle = getAngle(QPointF(data.mx,data.my));
double a1 = data.angle1;
double a2 = data.angle2;
bool reversed = false;
double aStep; // Angle Step (rad)
double a; // Current Angle (rad)
aStep=M_PI/128;
QPointF vp;
QPointF vc(cp.x(), cp.y());
vp.setX(cp.x()+cos(a1) * radius1);
vp.setY(cp.y() + sin(a1) * radius2);
rotate(data,angle, vc,vp);
contour.path.push_back(vp);
if (!reversed)
{
// Arc Counterclockwise:
if (a1>a2-(1.0e-9))
{
a2+=2*M_PI;
}
for (a=a1+aStep; a<=a2; a+=aStep)
{
vp.setX(cp.x()+cos(a)*radius1);
vp.setY(cp.y()+sin(a)*radius2);
rotate(data,angle, vc,vp);
contour.path.push_back(vp);
}
}
else
{
// Arc Clockwise:
if (a1<a2+(1.0e-9))
{
a2-=2*M_PI;
}
for (a=a1-aStep; a>=a2; a-=aStep)
{
vp.setX(cp.x()+cos(a)*radius1);
vp.setY(cp.y()+sin(a)*radius2);
rotate(data,angle, vc,vp);
contour.path.push_back(vp);
}
}
vp.setX(cp.x()+cos(a)*radius1);
vp.setY(cp.y()+sin(a)*radius2);
rotate(data,angle, vc,vp);
contour.path.push_back(vp);
m_contours.push_back(contour);
}
}
3.绘制椭圆
//绘制椭圆
void Dxf::drawEllipse(QPainter& painter)
{
//解析dxf椭圆数据
readEllipse();
QPen pen;
for(int i = 0;i < m_contours.size();i++)
{
QPainterPath paths;
QPolygonF pg(m_contours.at(i).path);
paths.addPolygon(pg);
painter.setPen(QPen(Qt::black, 1));
painter.drawPath(paths);
// painter.fillPath(paths,Qt::red);
}
}
效果如图所示:左边是画图软件LibreCAD解析的效果,右边是自己解析出来的效果,画图软件对图形进行了旋转,而我自己没添加旋转功能,大家也可以自行添加。
大致就是这样的一个步骤,整个解析和计算的过程还是比较复杂的,对于新手来说确实有一定的难度,如果大家觉得我这篇文章对你有帮助,记得点赞加收藏,后续我会更新解析dxf样条曲线spline的详细源码,让小伙伴们少走弯路。