PlotterHMI/datafile/dxf/dxfhelper.cpp
huahaiyan 42e10f6b15 20240326
1、增加马克间距;
2、完善dxf解析;
2024-03-26 08:54:57 +08:00

661 lines
20 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "dxfhelper.h"
#include "dxfreader.h"
#include <QImage>
#include <QPainter>
DxfHelper::DxfHelper()
{
}
double norm(double x, double y)
{
return sqrt(x * x + y * y);
}
QList<QVector3D> DxfHelper::expandPolygon(QList<QVector3D> polygon, float expand)
{
QList<QVector3D> new_polygon;
int len = polygon.length();
if(len<3||qFuzzyIsNull(expand)) return polygon;
bool repeatFlag = false;
if(polygon.first()==polygon.back()) {
repeatFlag = true;
polygon.removeLast();
len = polygon.length();
}
int convertNum = 0;
for (int i = 0; i < len; i++)
{
QVector3D p = polygon[i];
QVector3D p1 = polygon[i == 0 ? len - 1 : i - 1];
QVector3D p2 = polygon[i == len - 1 ? 0 : i + 1];
float v1x = p1.x() - p.x();
float v1y = p1.y() - p.y();
float n1 = norm(v1x, v1y);
float vv1x = v1x / n1;
float vv1y = v1y / n1;
float v2x = p2.x() - p.x();
float v2y = p2.y() - p.y();
float n2 = norm(v2x, v2y);
float vv2x = v2x / n2;
float vv2y = v2y / n2;
float vectorLen = -expand / sqrt((1 - (vv1x * vv2x + vv1y * vv2y)) / 2.0f);
float judge = v1x * v2y - v2x * v1y;
if (judge < 0) vectorLen *= -1;
if (judge < 0) convertNum++;
float vx = vv1x + vv2x;
float vy = vv1y + vv2y;
vectorLen = vectorLen / norm(vx, vy);
vx *= vectorLen;
vy *= vectorLen;
new_polygon.append(QVector3D(vx + p.x(), vy + p.y(), 0));
}
if(convertNum==len) {
new_polygon.clear();
for (int i = 0; i < len; i++)
{
QVector3D p = polygon[i];
QVector3D p1 = polygon[i == 0 ? len - 1 : i - 1];
QVector3D p2 = polygon[i == len - 1 ? 0 : i + 1];
float v1x = p1.x() - p.x();
float v1y = p1.y() - p.y();
float n1 = norm(v1x, v1y);
float vv1x = v1x / n1;
float vv1y = v1y / n1;
float v2x = p2.x() - p.x();
float v2y = p2.y() - p.y();
float n2 = norm(v2x, v2y);
float vv2x = v2x / n2;
float vv2y = v2y / n2;
float vectorLen = -expand / sqrt((1 - (vv1x * vv2x + vv1y * vv2y)) / 2.0f);
float vx = vv1x + vv2x;
float vy = vv1y + vv2y;
vectorLen = vectorLen / norm(vx, vy);
vx *= vectorLen;
vy *= vectorLen;
new_polygon.append(QVector3D(vx + p.x(), vy + p.y(), 0));
}
}
if(repeatFlag) new_polygon.append(new_polygon.first());
return new_polygon;
}
bool DxfHelper::generateDxf(const QString &fileName)
{
//获取引用块集合
QList<std::string> blockNameList;
//getDxfReferenceBlocks(fileName,blockNameList);
// currentPos = QPointF(QRandomGenerator::global()->bounded(9999.99), QRandomGenerator::global()->bounded(9999.99));
currentPos = QPointF(9999.99, 9999.99);
vertexIndex = 0;
controlIndex = 0;
dxfPaths.clear();
DxfReader dxfReader(fileName);
QList<BlockDatas> blockDataList = dxfReader.getBlockDatas();
BlockDatas blockData;
//扫描判断哪个块的数据最多,其他块的数据全部不显示,只显示数据最多的块
for (int i = 0; i < blockDataList.size(); i++)
{
if(blockNameList.size() == 0)
{
blockData.dxfLines.append(blockDataList[i].dxfLines);
//blockData.dxfText.append(blockDataList[i].dxfText);
blockData.dxfArcs.append(blockDataList[i].dxfArcs);
blockData.dxfCircles.append(blockDataList[i].dxfCircles);
blockData.dxfEllipses.append(blockDataList[i].dxfEllipses);
blockData.dxfPolylines.append(blockDataList[i].dxfPolylines);
blockData.dxfPoints.append(blockDataList[i].dxfPoints);
blockData.dxfSplines.append(blockDataList[i].dxfSplines);
blockData.dxfVertexs.append(blockDataList[i].dxfVertexs);
}
else
{
if(blockNameList.contains(blockDataList[i].blockName) == true)
{
blockData.dxfLines.append(blockDataList[i].dxfLines);
//blockData.dxfText.append(blockDataList[i].dxfText);
blockData.dxfArcs.append(blockDataList[i].dxfArcs);
blockData.dxfCircles.append(blockDataList[i].dxfCircles);
blockData.dxfEllipses.append(blockDataList[i].dxfEllipses);
blockData.dxfPolylines.append(blockDataList[i].dxfPolylines);
blockData.dxfPoints.append(blockDataList[i].dxfPoints);
blockData.dxfSplines.append(blockDataList[i].dxfSplines);
blockData.dxfVertexs.append(blockDataList[i].dxfVertexs);
}
}
}
for(auto d: blockData.dxfText)
{
qDebug() << "text data:" << d.text.c_str() << d.angle << d.style.c_str() << d.height;
}
for(auto d: dxfReader.dxfLinetypes)
{
qDebug() << "linetypes data:" << d.name.c_str() << d.flags << d.pattern << d.description.c_str() << d.patternLength << d.numberOfDashes;
}
QVector<QPointF> linepath;
for(auto d: blockData.dxfLines)
{
//qDebug() << "line data:" << d.x1 << d.y1 << d.z1 << "," << d.x2 << d.y2 << d.z2;
linepath.append(QPointF(d.x1, d.y1));
linepath.append(QPointF(d.x2, d.y2));
dxfPaths.append(linepath);
linepath.clear();
}
for(auto d: blockData.dxfArcs)
{
//qDebug() << "arcs data:" << d.cx << d.cy << d.cz << d.angle1 << d.angle2 << d.radius;
double cx = d.cx;
double cy = d.cy;
// double cz = d.cz;
double angle1 = d.angle1;
double angle2 = d.angle2;
double radius = d.radius;
radius = radius + expandOffset;
QPainterPath path;
double startXPos = cx + cos(abs(angle1)*M_PI/180)*radius;
double startYPos = cy + sin(abs(angle1)*M_PI/180)*radius;
path.moveTo(startXPos, startYPos);
double angleStart ,anglePassed;
angleStart = angle1;
if(angleStart>=180) angleStart = angleStart-360;
anglePassed = angleStart-angle2;
if(angleStart<180) angleStart = -angleStart;
if(anglePassed<-360) anglePassed = anglePassed+360;
QRectF rect(cx-radius, cy-radius, 2*radius, 2*radius);
path.arcTo(rect, angleStart, anglePassed);
QVector<QPointF> arcpath;
for(double i = 0; i <= 1; i += 0.003) { // TODO: 步长随图片大小调整
QPointF point = path.pointAtPercent(i);
double x = point.x();
double y = point.y();
arcpath.append(point);
currentPos=QPointF(x, y);
}
dxfPaths.append(arcpath);
// dxfPathList.append(path);
}
for(auto d: blockData.dxfCircles)
{
//qDebug() << "circle data:" << d.cx << d.cy << d.cz << d.radius;
double cx = d.cx;
double cy = d.cy;
// double cz = d.cz;
double radius = d.radius;
radius = radius + expandOffset;
QPainterPath path;
path.moveTo(cx+radius, cy);
path.arcTo(cx-radius, cy-radius, 2*radius, 2*radius, 0, 360);
QVector<QPointF> circlepath;
for(double i = 0; i <= 1; i += 0.003) { // TODO: 步长随图片大小调整
QPointF point = path.pointAtPercent(i);
double x = point.x();
double y = point.y();
circlepath.append(point);
currentPos=QPointF(x, y);
}
dxfPaths.append(circlepath);
}
for(auto d: blockData.dxfEllipses)
{
// 起点角度要×ratio
//qDebug() << "ellipses data:" << d.cx << d.cy << d.cz << d.mx << d.my << d.mz << d.ratio << d.angle1 << d.angle2;
double cx = d.cx;
double cy = d.cy;
// double cz = d.cz;
double mx = d.mx;
double my = d.my;
// double mz = d.mz;
double ratio = d.ratio;
double angle1 = d.angle1;
double angle2 = d.angle2;
double rab = sqrt((cx- mx)*(cx - mx) +(cy - my)*(cy - my));
double resy = (expandOffset*(my-cy))/rab + my;
double resx = (expandOffset*(mx-cx))/rab + mx;
mx = resx;
my = resy;
QPainterPath path;
double angle_1 = angle1;
double angle_2 = angle2;
while(angle_1>=3.14&&angle_2>=6.28) {
angle_1 -= M_PI;
angle_2 -= M_PI;
}
angle_1 = angle_1*180/M_PI;
angle_2 = angle_2*180/M_PI;
double angleStart ,anglePassed;
angleStart = angle_1;
if(angleStart>=180) angleStart = angleStart-360;
anglePassed = angleStart-angle_2;
if(angleStart<180) angleStart = -angleStart;
if(anglePassed<-360) anglePassed = anglePassed+360;
if(abs(anglePassed)<1) anglePassed = 360;
double c_x = cx;
double c_y = cy;
double dl = sqrt(mx*mx+my*my);
double ds = dl*ratio;
double rx;
double ry;
if(qFuzzyIsNull(mx)) {
rx = ds; ry = dl;
angleStart += 90;
} else {
rx = dl; ry = ds;
}
double angle=angleStart;
if(angle<0) angle=-angle;
else if(angle>=0) angle = 360-angle;
//if(!qFuzzyCompare(abs(anglePassed),360)) angle *= ratio;
if(!qFuzzyCompare(float(anglePassed),(float)360)) angle *= ratio;
double a=qDegreesToRadians(angle);
double R=rx*ry/sqrt(pow(rx*sin(a),2)+pow(ry*cos(a),2)); //计算对应角度的半径
double startXPos=c_x+R*cos(a);
double startYPos=c_y+R*sin(a);
path.moveTo(startXPos, startYPos);
//qDebug() << c_x << c_y << rx << ry << angleStart << anglePassed << angle;
path.arcTo(c_x-rx, c_y-ry, 2*rx, 2*ry, angleStart, anglePassed);
QVector<QPointF> ellipsepath;
for(double i = 0; i <= 1; i += 0.003)
{ // TODO: 步长随图片大小调整
QPointF point = path.pointAtPercent(i);
double x = point.x();
double y = point.y();
ellipsepath.append(point);
currentPos=QPointF(x, y);
}
dxfPaths.append(ellipsepath);
}
for(auto d: blockData.dxfPolylines)
{
//qDebug() << "polylines data:" << d.m << d.n << d.flags << d.number << d.elevation;
QList<QVector3D> pointlist;
QVector<QPointF> path;
for(unsigned int i = 0; i < d.number; i++) {
double x = blockData.dxfVertexs.at(vertexIndex).x;
double y = blockData.dxfVertexs.at(vertexIndex).y;
double z = blockData.dxfVertexs.at(vertexIndex).z;
pointlist.append(QVector3D(x, y, z));
vertexIndex++;
}
pointlist = expandPolygon(pointlist, expandOffset);
foreach(QVector3D point, pointlist) {
double x = point.x();
double y = point.y();
path.append(QPointF(x, y));
currentPos = QPointF(x, y);
}
if(d.flags && pointlist.size() > 0) {
double x = pointlist.first().x();
double y = pointlist.first().y();
path.append(QPointF(x, y));
currentPos = QPointF(x, y);
}
dxfPaths.append(path);
}
QVector<QPointF> path;
for(int i = 0; i < blockData.dxfVertexs.size(); i++)
{
QPointF point;
//qDebug() << "vertexs data:" << d.x << d.y << d.z << d.bulge;
point.setX(blockData.dxfVertexs.at(i).x);
point.setY(blockData.dxfVertexs.at(i).y);
path.append(point);
if(path.size() == 2)
{
// if(i+1 < blockData.dxfVertexs.size())
// {
// QPointF point1;
// //qDebug() << "vertexs data:" << d.x << d.y << d.z << d.bulge;
// point1.setX(blockData.dxfVertexs.at(i+1).x);
// point1.setY(blockData.dxfVertexs.at(i+1).y);
// if(point1 != point)
// {
// path.append(point1);
// }
// }
dxfPaths.append(path);
path.clear();
}
}
// for(auto d: blockData.dxfVertexs)
// {
// QPointF point;
// //qDebug() << "vertexs data:" << d.x << d.y << d.z << d.bulge;
// point.setX(d.x);
// point.setY(d.y);
// path.append(point);
// if(path.size() == 2)
// {
// dxfPaths.append(path);
// path.clear();
// }
// }
for(auto d: blockData.dxfPoints)
{
//qDebug() << "points data:" << d.x << d.y << d.z;
QVector<QPointF> path;
path.append(QPointF(d.x, d.y));
dxfPaths.append(path);
currentPos = QPointF(d.x, d.y);
}
// for(auto d: blockData.dxfSplines)
// {
//qDebug() << "splines data:" << d.nFit << d.flags << d.degree << d.nKnots << d.nControl << d.tangentEndX << d.tangentEndY << d.tangentEndZ << d.tangentStartX << d.tangentStartY << d.tangentStartZ;
// std::vector<QVector2D> pointList;
// for(unsigned int i = 0; i < d.nControl; i++)
// {
// int x = blockData.dxfControlPoints.at(controlIndex).x;
// int y = blockData.dxfControlPoints.at(controlIndex).y;
// pointList.push_back(QVector2D(x, y));
// currentPos = QPointF(x, y);
// controlIndex++;
// }
// QList<QVector3D> templist;
// foreach(auto point, pointList) templist.append(point);
// templist = expandPolygon(templist, expandOffset);
// QVector<QVector2D> inputList;
// foreach(auto point, templist) inputList.append(point.toVector2D());
// inputList.push_front(inputList.first());
// inputList.push_back(inputList.back());
// std::vector<QVector2D> finalList(inputList.begin(), inputList.end());
// SplineHelper splineHelper(finalList, TypeCubicBSpline);
// auto splinePath = splineHelper.getSplinePath();
// dxfPaths.append(splinePath);
// }
// for(auto d: dxfReader.dxfControlPoints) {
// qDebug() << "control points data:" << d.w << d.x << d.y << d.z;
// }
// for(auto d: dxfReader.dxfXLines) {
// qDebug() << "XLines data:" << d.bx << d.by << d.bz << d.dx << d.dy << d.dz;
// }
// for(auto d: dxfReader.dxfRays) {
// qDebug() << "rays data:" << d.bx << d.by << d.bz << d.dx << d.dy << d.dz;
// }
// for(auto d: dxfReader.dxfFitPoints) {
// qDebug() << "fit points data:" << d.x << d.y << d.z;
// }
// for(auto d: dxfReader.dxfHatchs) {
// qDebug() << "hatchs data:" << d.angle << d.scale << d.solid << d.originX << d.originY << d.pattern.c_str() << d.numLoops;
// }
// for(auto d: dxfReader.dxfHatchLoops) {
// qDebug() << "hatchLoops data:" << d.numEdges;
// }
// for(auto d: dxfReader.dxfHatchEdges) {
// qDebug() << "hatchEdges data:" << d.cx << d.cy << d.mx << d.my << d.x1 << d.y1 << d.x2 << d.y2 << d.ccw << d.nFit << d.ratio << d.angle1 << d.angle2 << d.degree << d.nKnots << d.radius << d.defined << d.weights << d.nControl << d.periodic << d.rational << d.vertices << d.fitPoints << d.endTangentX << d.endTangentY << d.endTangentY << d.controlPoints << d.startTangentX << d.startTangentY;
// }
return true;
}
void DxfHelper::matchDXFSize()
{
double minx = __DBL_MAX__;
double maxx = __DBL_MIN__;
double miny = __DBL_MAX__;
double maxy = __DBL_MIN__;
foreach (QVector<QPointF> path, dxfPaths) {
for(int i = 0; i < path.length(); i++) {
QPointF point = path.at(i);
double x = point.x();
double y = point.y();
if(x<minx) minx = x;
if(x>maxx) maxx = x;
if(y<miny) miny = y;
if(y>maxy) maxy = y;
}
}
int width = maxx - minx;
int height = maxy - miny;
imageSize = QSize(width, height);
dxfBorderList.clear();
dxfBorderList.append(minx);
dxfBorderList.append(miny);
dxfBorderList.append(maxx);
dxfBorderList.append(maxy);
}
QImage DxfHelper::generateDXFImage()
{
// //放大数据
// QVector<QVector<QPointF>> dxfPathscp;
// foreach (QVector<QPointF> path, dxfPaths)
// {
// QVector<QPointF> pathcp;
// for(int i = 0; i < path.length(); i++)
// {
// QPointF point = path.at(i);
// double x = point.x()*10;
// double y = point.y()*10;
// pathcp.append(QPointF(x,y));
// }
// dxfPathscp.append(pathcp);
// }
// dxfPaths.clear();
// dxfPaths = dxfPathscp;
matchDXFSize();
double minx = dxfBorderList.at(0);
double miny = dxfBorderList.at(1);
int penwidth = imageSize.width()/400;
int border = penwidth;
QImage image((imageSize.width()+2*border), (imageSize.height()+2*border), QImage::Format_ARGB32);
image.fill(Qt::white);
QPainter p(&image);
p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // 抗锯齿和使用平滑转换算法
QPen pen;
if(penwidth<1) penwidth = 1;
pen.setWidth(penwidth);
pen.setColor(Qt::black);
p.setPen(pen);
QPainterPath painterpath;
foreach (QVector<QPointF> path, dxfPaths) {
for(int i = 0; i < path.length(); i++) {
double x = path.at(i).x()-minx;
double y = path.at(i).y()-miny;
y = imageSize.height()-y;
x += border;
y += border;
QPointF point(x, y);
if(i == 0) painterpath.moveTo(point);
else painterpath.lineTo(point);
}
// dxfPathList.append(painterpath);
}
//qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]\t"<< "dxf path length:" <<dxfPaths.length();
p.drawPath(painterpath);
p.end();
return image;
}
QList<double> DxfHelper::getDxfBorderList() const
{
return dxfBorderList;
}
bool DxfHelper::getDxfReferenceBlocks(const QString &fileName, QList<std::string> &blockNameList)
{
blockNameList.clear();
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Failed to open file:" << fileName;
return false;
}
int addFlag = 0;
int blockFlag = 0;
int getFlag = 0;
int endFlag = 0;
QTextStream in(&file);
while (!in.atEnd())
{
std::string line = in.readLine().remove(QRegExp("\\s")).toStdString();
// 处理每一行数据
if(line == "AcDbBlockReference")//块被引用的标志
{
addFlag = 1;
continue;
}
if(addFlag == 1)
{
if(line == "AcDbBlockBegin")//块开始标志
{
blockFlag = 1;
endFlag = 0;
continue;
}
if(blockFlag == 1)
{
if(line == "2")//下一行为块名称
{
getFlag = 1;
continue;
}
if(getFlag == 1)//块名称
{
if(blockNameList.contains(line) == false)
//if(!line.empty() && line[0] != '*')
{
blockNameList.append(line);
}
getFlag = 0;
continue;
}
}
if(line == "AcDbBlockEnd")//块结束标志
{
blockFlag = 0;
endFlag = 1;
continue;
}
}
}
if(endFlag == 0 && addFlag == 1)
{
if(blockNameList.size() > 0)
{
blockNameList.removeLast();
}
}
file.close();
return true;
}
QSize DxfHelper::getImageSize() const
{
return imageSize;
}
QList<QPainterPath> DxfHelper::getDxfPathList() const
{
return dxfPathList;
}
QVector<QVector<QPointF> > DxfHelper::getDxfPaths() const
{
return dxfPaths;
}
QList<DXFLine> DxfHelper::getDxfLineList() const
{
return dxfLineList;
}
QList<DXFRect> DxfHelper::getDxfRectList() const
{
return dxfRectList;
}
QList<DXFArc> DxfHelper::getDxfArcList() const
{
return dxfArcList;
}
QList<DXFCircle> DxfHelper::getDxfCircleList() const
{
return dxfCircleList;
}
QList<DXFEllipse> DxfHelper::getDxfEllipseList() const
{
return dxfEllipseList;
}
QList<DXFPolyline> DxfHelper::getDxfPolylineList() const
{
return dxfPolylineList;
}
QList<DXFSpline> DxfHelper::getDxfSplineList() const
{
return dxfSplineList;
}
void DxfHelper::setExpandOffset(double value)
{
expandOffset = value;
}