PlotterHMI/datafile/dxf/dxfhelper.cpp
2024-02-06 14:19:53 +08:00

521 lines
16 KiB
C++
Raw 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)
{
// 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);
for(auto d: dxfReader.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: dxfReader.dxfLines) {
//qDebug() << "line data:" << d.x1 << d.y1 << d.z1 << "," << d.x2 << d.y2 << d.z2;
if(currentPos!=QPointF(d.x1, d.y1)) {
if(!linepath.isEmpty()) {
QList<QVector3D> linelist;
foreach(auto point, linepath) linelist.append(QVector3D(point));
linepath.clear();
linelist = expandPolygon(linelist, expandOffset);
foreach(QVector3D point, linelist) {
double x = point.x();
double y = point.y();
linepath.append(QPointF(x, y));
currentPos = QPointF(x, y);
}
dxfPaths.append(linepath);
linepath.clear();
}
linepath.append(QPointF(d.x1, d.y1));
linepath.append(QPointF(d.x2, d.y2));
currentPos = QPointF(d.x2, d.y2);
} else {
linepath.append(QPointF(d.x2, d.y2));
currentPos = QPointF(d.x2, d.y2);
}
}
if(!linepath.isEmpty()) {
QList<QVector3D> linelist;
foreach(auto point, linepath) linelist.append(QVector3D(point));
linepath.clear();
linelist = expandPolygon(linelist, expandOffset);
foreach(QVector3D point, linelist) {
double x = point.x();
double y = point.y();
linepath.append(QPointF(x, y));
currentPos = QPointF(x, y);
}
dxfPaths.append(linepath);
linepath.clear();
}
for(auto d: dxfReader.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: dxfReader.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);
// dxfPathList.append(path);
}
for(auto d: dxfReader.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);
// dxfPathList.append(path);
}
for(auto d: dxfReader.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 = dxfReader.dxfVertexs.at(vertexIndex).x;
double y = dxfReader.dxfVertexs.at(vertexIndex).y;
double z = dxfReader.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) {
double x = pointlist.first().x();
double y = pointlist.first().y();
path.append(QPointF(x, y));
currentPos = QPointF(x, y);
}
dxfPaths.append(path);
}
// for(auto d: dxfReader.dxfVertexs) {
// qDebug() << "vertexs data:" << d.x << d.y << d.z << d.bulge;
// }
for(auto d: dxfReader.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: dxfReader.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 = dxfReader.dxfControlPoints.at(controlIndex).x;
int y = dxfReader.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()
{
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;
}
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;
}