From dc89e02515315c078a962aa8507bd8f6b5b2520b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=B0=81=E7=BE=BD?= <2360164671@qq.com> Date: Thu, 12 Jan 2023 15:04:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=95=E5=85=A5=E4=BA=86=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 8 +- ...rchitectureColoredPainting.vcxproj.filters | 18 + .../src/Editor/GraphicElement.cpp | 66 +- .../src/Editor/GraphicElement.h | 23 +- .../src/Editor/PreviewWindow.cpp | 2 +- .../Editor/third-party modules/SvgHelper.cpp | 857 ++++++++++++++++++ .../Editor/third-party modules/SvgHelper.h | 60 ++ .../qquick/qquicksvgparser.cpp | 567 ++++++++++++ .../qquick/qquicksvgparser_p.h | 64 ++ .../qquick/qtquickglobal.h | 56 ++ .../qquick/qtquickglobal_p.h | 66 ++ 11 files changed, 1703 insertions(+), 84 deletions(-) create mode 100644 ArchitectureColoredPainting/src/Editor/third-party modules/SvgHelper.cpp create mode 100644 ArchitectureColoredPainting/src/Editor/third-party modules/SvgHelper.h create mode 100644 ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qquicksvgparser.cpp create mode 100644 ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qquicksvgparser_p.h create mode 100644 ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qtquickglobal.h create mode 100644 ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qtquickglobal_p.h diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index 775940a..6fd14e9 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -32,7 +32,7 @@ 5.15.2_msvc2019_64 - core;gui;widgets;winextras + core;xml;gui;svg;widgets;winextras debug @@ -105,6 +105,7 @@ + @@ -129,6 +130,7 @@ + @@ -158,6 +160,10 @@ + + + + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index 9bc98d8..a54f912 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -147,6 +147,12 @@ Source Files\Renderer\Painting + + Source Files + + + Source Files + @@ -312,6 +318,18 @@ Header Files\Renderer\Painting + + Header Files + + + Header Files + + + Header Files + + + Header Files + diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 8108490..cdd8e42 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -1,75 +1,19 @@ #include "GraphicElement.h" using namespace std; -string ElementTypeStringValue::sStringTag[] = {"undefined", "path", "polygon", "round"}; -string ElementTypeStringValue::stringType(ElementType elementType) -{ - int type = static_cast(elementType); - return sStringTag[type]; -} -ElementType ElementTypeStringValue::enumType(std::string elementType) -{ - for (int i = 1; i <= sElementType; i++) - { - if (elementType == sStringTag[i]) - { - return static_cast(i); - } - } - return ElementType::undefined; -} QPainterPath SimpleElement::getPaintObject() const { return painterPath; } -// TODO -void SimpleElement::pathOperate(QJsonArray paths) + +void SimpleElement::loadSvgFile(const QString& filePath) { - QRect r(100, 100, 100, 100); - painterPath.addRect(r); -} -void SimpleElement::polygonOperate(QJsonArray points) -{ - QPolygonF polygon; - for (auto &&point : points) - { - polygon.append(QPointF(point.toObject().value("x").toDouble(), point.toObject().value("y").toDouble())); - } - painterPath.addPolygon(polygon); -} -void SimpleElement::roundOperate(QJsonObject json) -{ - double xAxis = json.value("x-axis").toDouble(); - double yAxis = json.value("y-axis").toDouble(); - double origin = json.value("origin").toDouble(); - double angle = json.value("angle").toDouble(); - painterPath.arcMoveTo(xAxis * -0.5, yAxis * -0.5, xAxis, yAxis, origin); - painterPath.arcTo(xAxis * -0.5, yAxis * -0.5, xAxis, yAxis, origin, angle); + // TODO } + SimpleElement::SimpleElement(QJsonObject jsonSource) : jsonSource(jsonSource) { painterPath.clear(); - elementType = ElementTypeStringValue::enumType(jsonSource.value("type").toString().toStdString()); - switch (elementType) - { - case ElementType::undefined: - break; - case ElementType::path: { - QJsonArray paths = jsonSource.value("data").toObject().value("operations").toArray(); - pathOperate(paths); - break; - } - case ElementType::polygon: { - QJsonArray points = jsonSource.value("data").toObject().value("points").toArray(); - polygonOperate(points); - break; - } - case ElementType::round: { - roundOperate(jsonSource.value("data").toObject()); - break; - } - default: - break; - } + loadSvgFile(jsonSource.value("data").toObject().value("include").toString()); } GroupElement::GroupElement(FolderLayerWrapper *sourceLayer) diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index 2013c1a..b191304 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -8,26 +8,10 @@ class LayerWrapper; class LeafLayerWrapper; class FolderLayerWrapper; -enum class ElementType -{ - undefined = 0, - path = 1, - polygon = 2, - round = 3 -}; -class ElementTypeStringValue -{ - private: - static std::string sStringTag[]; - static const int sElementType = 3; - - public: - static std::string stringType(ElementType elementType); - static ElementType enumType(std::string elementType); -}; class GraphicElement { public: + QString name=""; virtual QPainterPath getPaintObject() const = 0; }; class SimpleElement : public GraphicElement @@ -35,10 +19,7 @@ class SimpleElement : public GraphicElement private: QJsonObject jsonSource; QPainterPath painterPath; - ElementType elementType; - void pathOperate(QJsonArray paths); - void polygonOperate(QJsonArray points); - void roundOperate(QJsonObject json); + void loadSvgFile(const QString& filePath); public: SimpleElement(QJsonObject jsonSource); diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp index 3b30cff..5c9dbd6 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp @@ -35,7 +35,7 @@ void PreviewWindow::initializeGL() initializeOpenGLFunctions(); glClearColor(1.0, 1.0, 1.0, 1.0); } - +#include "./third-party modules/qquick/qquicksvgparser_p.h" void PreviewWindow::paintGL() { glClear(GL_COLOR_BUFFER_BIT); diff --git a/ArchitectureColoredPainting/src/Editor/third-party modules/SvgHelper.cpp b/ArchitectureColoredPainting/src/Editor/third-party modules/SvgHelper.cpp new file mode 100644 index 0000000..4823a13 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/third-party modules/SvgHelper.cpp @@ -0,0 +1,857 @@ +#include "SvgHelper.h" + +//方便调试时的打印输出 +#define qout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]\t" + +SvgHelper::SvgHelper() +{ + +} + +void SvgHelper::parseSvgImage(QString filepath) +{ + this->filepath = filepath; + + QFile svgFile(filepath); + if (svgFile.open(QFile::ReadOnly)) { + QDomDocument doc; + if (doc.setContent(&svgFile)) + { + svgFile.close(); + // 返回根节点 + QDomElement root = doc.documentElement(); + qout << "root:" << root.nodeName(); + // 获得第一个子节点 + QDomNode node = root.firstChild(); + while (!node.isNull()) //如果节点不空 + { + if (node.isElement()) //如果节点是元素 + { + //转换为元素 + QDomElement e = node.toElement(); + QString tagname = e.tagName(); + qout << "tagname:" << tagname; + if (typeList.contains(tagname)) { + parseSVGTag(e, tagname); + } + else { + foreach(QString type, typeList) { + QDomNodeList list = e.elementsByTagName(type); + if (list.length() > 0) { + for (int i = 0; i < list.count(); i++) { + QDomNode n = list.at(i); + parseSVGTag(n.toElement(), n.nodeName()); + } + } + } + } + } + // 下一个兄弟节点 + node = node.nextSibling(); + } + } + } +} + +QSize matchSize(QString path) +{ + QSvgWidget svgWidget(path); + QSvgRenderer* render = svgWidget.renderer(); + QSize size = render->defaultSize(); + QRect rect = render->viewBox(); + if (rect.size() != size) { + size = rect.size(); + } + return size; +} + +QImage SvgHelper::getSvgImage() { + auto imagesize = matchSize(filepath); + QImage image(imagesize, QImage::Format_ARGB32); + image.fill(QColor(255, 255, 255, 255)); + QPainter p; + p.begin(&image); + p.setPen(Qt::black); + foreach(QPainterPath ppath, svgPathList) { + p.drawPath(ppath); + } + p.end(); + return image; +} + +void SvgHelper::parseSVGTag(QDomElement e, QString tagname) +{ + if (QString::compare(tagname, "path", Qt::CaseInsensitive) == 0) { // 路径 + QString pathvalue = e.attribute("d"); + qout << pathvalue; + parseSvgPath(pathvalue, paintPath); + } + else if (QString::compare(tagname, "rect", Qt::CaseInsensitive) == 0) { + float x = getValueWithoutUnit(e.attribute("x")); + float y = getValueWithoutUnit(e.attribute("y")); + float width = getValueWithoutUnit(e.attribute("width")); + float height = getValueWithoutUnit(e.attribute("height")); + float rx = getValueWithoutUnit(e.attribute("rx")); + float ry = getValueWithoutUnit(e.attribute("rx")); + + qout << x << y << width << height << rx << ry; + + if (rx < 0 || ry < 0) { + paintPath.moveTo(x, y); + paintPath.lineTo(x + width, y); + paintPath.lineTo(x + width, y + height); + paintPath.lineTo(x, y + height); + paintPath.lineTo(x, y); + paintPath.moveTo(x, y); + { + QList list; + list.append(QPointF(x, y)); + list.append(QPointF(x + width, y)); + list.append(QPointF(x + width, y + height)); + list.append(QPointF(x, y)); + svgPointList.append(list); + } + } + else { + float r = qMax(rx, ry); + paintPath.moveTo(x + r, y); + paintPath.lineTo(x + width - r, y); + QRectF rect(x + width - 2 * r, y, 2 * r, 2 * r); + paintPath.arcTo(rect, 90, -90); + paintPath.lineTo(x + width, y + height - r); + rect = QRectF(x + width - 2 * r, y + height - 2 * r, 2 * r, 2 * r); + paintPath.arcTo(rect, 0, -90); + paintPath.lineTo(x + r, y + height); + rect = QRectF(x, y + height - 2 * r, 2 * r, 2 * r); + paintPath.arcTo(rect, -90, -90); + paintPath.lineTo(x, y + r); + rect = QRectF(x, y, 2 * r, 2 * r); + paintPath.arcTo(rect, 180, -90); + paintPath.moveTo(x + r, y); + { + QPainterPath path; + QList list; + list.append(QPointF(x + r, y)); + list.append(QPointF(x + width - r, y)); + + QRectF rect(x + width - 2 * r, y, 2 * r, 2 * r); + path.moveTo(x + width - r, y); + path.arcTo(rect, 90, -90); + for (double i = 0; i < 1; i += 1.0 / path.length()) list.append(path.pointAtPercent(i)); + list.append(path.pointAtPercent(1)); + + list.append(QPointF(x + width, y + height - r)); + + path.clear(); + rect = QRectF(x + width - 2 * r, y + height - 2 * r, 2 * r, 2 * r); + path.arcTo(rect, 0, -90); + for (double i = 0; i < 1; i += 1.0 / path.length()) list.append(path.pointAtPercent(i)); + list.append(path.pointAtPercent(1)); + + list.append(QPointF(x + r, y + height)); + + path.clear(); + rect = QRectF(x, y + height - 2 * r, 2 * r, 2 * r); + path.arcTo(rect, -90, -90); + for (double i = 0; i < 1; i += 1.0 / path.length()) list.append(path.pointAtPercent(i)); + list.append(path.pointAtPercent(1)); + + list.append(QPointF(x, y + r)); + + path.clear(); + rect = QRectF(x, y, 2 * r, 2 * r); + path.arcTo(rect, 180, -90); + for (double i = 0; i < 1; i += 1.0 / path.length()) list.append(path.pointAtPercent(i)); + list.append(path.pointAtPercent(1)); + + list.append(QPointF(x + r, y)); + + svgPointList.append(list); + } + } + } + else if (QString::compare(tagname, "circle", Qt::CaseInsensitive) == 0) { + float cx = getValueWithoutUnit(e.attribute("cx")); + float cy = getValueWithoutUnit(e.attribute("cy")); + float r = getValueWithoutUnit(e.attribute("r")); + + cx = cx < 0 ? 0 : cx; + cy = cy < 0 ? 0 : cy; + + qout << cx << cy << r; + + if (r > 0) { + paintPath.moveTo(cx + r, cy); + paintPath.arcTo(cx - r, cy - r, 2 * r, 2 * r, 0, 360); + paintPath.moveTo(cx + r, cy); + { + QPainterPath path; + QList list; + + path.moveTo(cx + r, cy); + path.arcTo(cx - r, cy - r, 2 * r, 2 * r, 0, 360); + for (double i = 0; i < 1; i += 1.0 / path.length()) list.append(path.pointAtPercent(i)); + list.append(path.pointAtPercent(1)); + svgPointList.append(list); + } + } + } + else if (QString::compare(tagname, "ellipse", Qt::CaseInsensitive) == 0) { + float cx = getValueWithoutUnit(e.attribute("cx")); + float cy = getValueWithoutUnit(e.attribute("cy")); + float rx = getValueWithoutUnit(e.attribute("rx")); + float ry = getValueWithoutUnit(e.attribute("ry")); + + cx = cx < 0 ? 0 : cx; + cy = cy < 0 ? 0 : cy; + + qout << cx << cy << rx << ry; + + if (rx > 0 && ry > 0) { + paintPath.moveTo(cx + rx, cy); + paintPath.arcTo(cx - rx, cy - ry, 2 * rx, 2 * ry, 0, 360); + paintPath.moveTo(cx + rx, cy); + { + QPainterPath path; + QList list; + + path.moveTo(cx + rx, cy); + path.arcTo(cx - rx, cy - ry, 2 * rx, 2 * ry, 0, 360); + for (double i = 0; i < 1; i += 1.0 / path.length()) list.append(path.pointAtPercent(i)); + list.append(path.pointAtPercent(1)); + svgPointList.append(list); + } + } + } + else if (QString::compare(tagname, "line", Qt::CaseInsensitive) == 0) { + float x1 = getValueWithoutUnit(e.attribute("x1")); + float y1 = getValueWithoutUnit(e.attribute("y1")); + float x2 = getValueWithoutUnit(e.attribute("x2")); + float y2 = getValueWithoutUnit(e.attribute("y2")); + + qout << x1 << y1 << x2 << y2; + + paintPath.moveTo(x1, y1); + paintPath.lineTo(x2, y2); + paintPath.moveTo(x2, y2); + { + QList list; + list.append(QPointF(x1, y1)); + list.append(QPointF(x2, y2)); + svgPointList.append(list); + } + } + else if (QString::compare(tagname, "polygon", Qt::CaseInsensitive) == 0) { + QString value = e.attribute("points"); + qout << value; + QVector vPos = segmentationCoordinates(value); + qout << vPos; + + QPointF startPoint; + QList list; + if (vPos.length() > 1) { + startPoint = QPointF(vPos[0], vPos[1]); + paintPath.moveTo(startPoint); + list.append(startPoint); + vPos.removeFirst(); vPos.removeFirst(); + } + + while (vPos.length() / 2 >= 1) { + paintPath.lineTo(vPos[0], vPos[1]); + list.append(QPointF(vPos[0], vPos[1])); + vPos.removeFirst(); vPos.removeFirst(); + } + + if (!startPoint.isNull()) { + paintPath.lineTo(startPoint); + paintPath.moveTo(startPoint); + list.append(startPoint); + } + if (!list.isEmpty()) svgPointList.append(list); + + } + else if (QString::compare(tagname, "polyline", Qt::CaseInsensitive) == 0) { + QString value = e.attribute("points"); + qout << value; + QVector vPos = segmentationCoordinates(value); + qout << vPos; + + QPointF startPoint; + QList list; + if (vPos.length() > 1) { + startPoint = QPointF(vPos[0], vPos[1]); + paintPath.moveTo(startPoint); + list.append(startPoint); + vPos.removeFirst(); vPos.removeFirst(); + } + + while (vPos.length() / 2 >= 1) { + paintPath.lineTo(vPos[0], vPos[1]); + list.append(QPointF(vPos[0], vPos[1])); + vPos.removeFirst(); vPos.removeFirst(); + } + + if (!startPoint.isNull()) { + paintPath.moveTo(startPoint); + // list.append(startPoint); + } + if (!list.isEmpty()) svgPointList.append(list); + + } + + if (!paintPath.isEmpty()) { + svgPathList.append(paintPath); + } + paintPath.clear(); + if (!testpathlist.isEmpty()) { + svgPointList.append(testpathlist); + } + testpathlist.clear(); +} + + +void SvgHelper::parseSvgPath(QString path, QPainterPath& paintPath) +{ + QString cmdLine = ""; + foreach(QChar c, path) { + if (cmdList.contains(c)) { + qout << cmdLine; + if (!cmdLine.isEmpty()) { + dealParsePainter(paintPath, cmdLine); + cmdLine.clear(); + } + } + cmdLine += c; + } + if (!cmdLine.isEmpty()) { + dealParsePainter(paintPath, cmdLine); + cmdLine.clear(); + } +} + + +void SvgHelper::dealParsePainter(QPainterPath& path, QString line) +{ + line = line.trimmed(); + int coordinates; + QString cmd = line.mid(0, 1); + QString value = line.mid(1); + + if (cmd.isUpper()) coordinates = ABSOLUTE_COORDINATES; + else coordinates = RELATIVE_COORDINATES; + + + QVector vNum = segmentationCoordinates(value); + qout << vNum; + + switch (cmdTypeList.indexOf(cmd.toUpper().at(0))) { + case 0: // m + { + bool hasLineflag = vNum.length() > 2; + bool lineto = false; + + if (!path.isEmpty()) svgPathList.append(path); + path.clear(); + if (!testpathlist.isEmpty()) svgPointList.append(testpathlist); + testpathlist.clear(); + + while (vNum.length() / 2 >= 1) { + + QPointF point(vNum.at(0), vNum.at(1)); + if (coordinates == ABSOLUTE_COORDINATES) { + nowPositon = point; + if (lineto) path.lineTo(nowPositon); + else path.moveTo(nowPositon); + testpathlist.append(nowPositon); + } + else { + nowPositon = nowPositon + point; + if (lineto) path.lineTo(nowPositon); + else path.moveTo(nowPositon); + testpathlist.append(nowPositon); + } + qout << "当前坐标" << nowPositon; + if (!lineto) pathStartPosition = nowPositon; + + + + for (int i = 0; i < 2; i++) vNum.removeFirst(); + if (hasLineflag) lineto = true; + } + break; + } + case 1: // l + { + while (vNum.length() / 2 >= 1) { + QPointF point(vNum.at(0), vNum.at(1)); + if (coordinates == ABSOLUTE_COORDINATES) { + path.lineTo(point); + testpathlist.append(point); + nowPositon = point; + } + else { + QPointF targetPoint = nowPositon + point; + path.lineTo(targetPoint); + testpathlist.append(targetPoint); + nowPositon = targetPoint; + } + qout << "当前坐标" << nowPositon; + path.moveTo(nowPositon); + for (int i = 0; i < 2; i++) vNum.removeFirst(); + } + break; + } + case 2: // h + { + while (vNum.length() >= 1) { + if (coordinates == ABSOLUTE_COORDINATES) { + QPointF point(vNum.at(0), nowPositon.y()); + path.lineTo(point); + testpathlist.append(point); + nowPositon = point; + } + else { + QPointF point(nowPositon.x() + vNum.at(0), nowPositon.y()); + path.lineTo(point); + testpathlist.append(point); + nowPositon = point; + } + qout << "当前坐标" << nowPositon; + path.moveTo(nowPositon); + vNum.removeFirst(); + } + break; + } + case 3: // v + { + while (vNum.length() >= 1) { + if (coordinates == ABSOLUTE_COORDINATES) { + QPointF point(nowPositon.x(), vNum.at(0)); + path.lineTo(point); + testpathlist.append(point); + nowPositon = point; + } + else { + QPointF point(nowPositon.x(), nowPositon.y() + vNum.at(0)); + path.lineTo(point); + testpathlist.append(point); + nowPositon = point; + } + qout << "当前坐标" << nowPositon; + path.moveTo(nowPositon); + vNum.removeFirst(); + } + break; + } + case 4: // c + { + while (vNum.length() / 6 >= 1) { + QPointF startPoint = nowPositon; + QPointF c1, c2, endPoint; + if (coordinates == ABSOLUTE_COORDINATES) { + c1 = QPointF(vNum.at(0), vNum.at(1)); + c2 = QPointF(vNum.at(2), vNum.at(3)); + endPoint = QPointF(vNum.at(4), vNum.at(5)); + } + else { + float x = startPoint.x(); + float y = startPoint.y(); + c1 = QPointF(x + vNum.at(0), y + vNum.at(1)); + c2 = QPointF(x + vNum.at(2), y + vNum.at(3)); + endPoint = QPointF(x + vNum.at(4), y + vNum.at(5)); + } + lastControlPosition = c2; + path.moveTo(startPoint); + path.cubicTo(c1, c2, endPoint); // 三次贝塞尔曲线 + path.moveTo(endPoint); + + { + QPainterPath testpath; + + testpath.moveTo(startPoint); + testpath.cubicTo(c1, c2, endPoint); // 三次贝塞尔曲线 + testpath.moveTo(endPoint); + for (double i = 0; i <= 1; i += 1.0 / testpath.length()) testpathlist.append(testpath.pointAtPercent(i)); + } + + nowPositon = endPoint; + qout << "当前坐标" << nowPositon; + + for (int i = 0; i < 6; i++) vNum.removeFirst(); + } + break; + } + case 5: // s + { + while (vNum.length() / 4 >= 1) { + QPointF startPoint = nowPositon; + QPointF c1, c2, endPoint; + if (coordinates == ABSOLUTE_COORDINATES) { + float x = startPoint.x(); + float y = startPoint.y(); + c1 = QPointF(2 * x - lastControlPosition.x(), 2 * y - lastControlPosition.y()); + c2 = QPointF(vNum.at(0), vNum.at(1)); + endPoint = QPointF(vNum.at(2), vNum.at(3)); + } + else { + float x = startPoint.x(); + float y = startPoint.y(); + c1 = QPointF(x + x - lastControlPosition.x(), y + y - lastControlPosition.y()); + c2 = QPointF(x + vNum.at(0), y + vNum.at(1)); + endPoint = QPointF(x + vNum.at(2), y + vNum.at(3)); + } + lastControlPosition = c2; + path.moveTo(startPoint); + path.cubicTo(c1, c2, endPoint); // 三次贝塞尔曲线 + path.moveTo(endPoint); + + { + QPainterPath testpath; + + testpath.moveTo(startPoint); + testpath.cubicTo(c1, c2, endPoint); // 三次贝塞尔曲线 + testpath.moveTo(endPoint); + for (double i = 0; i <= 1; i += 1.0 / testpath.length()) testpathlist.append(testpath.pointAtPercent(i)); + } + + nowPositon = endPoint; + qout << "当前坐标" << nowPositon; + + for (int i = 0; i < 4; i++) vNum.removeFirst(); + } + + break; + } + case 6: // q + { + while (vNum.length() / 4 >= 1) { + QPointF startPoint = nowPositon; + QPointF cPoint; + QPointF endPoint; + if (coordinates == ABSOLUTE_COORDINATES) { + cPoint = QPointF(vNum.at(0), vNum.at(1)); + endPoint = QPointF(vNum.at(2), vNum.at(3)); + } + else { + float x = startPoint.x(); + float y = startPoint.y(); + cPoint = QPointF(x + vNum.at(0), y + vNum.at(1)); + endPoint = QPointF(x + vNum.at(2), y + vNum.at(3)); + } + lastControlPosition = cPoint; + path.moveTo(startPoint); + path.quadTo(cPoint, endPoint); // 二次贝塞尔曲线 + path.moveTo(endPoint); + + { + QPainterPath testpath; + + testpath.moveTo(startPoint); + testpath.quadTo(cPoint, endPoint); // 二次贝塞尔曲线 + testpath.moveTo(endPoint); + for (double i = 0; i <= 1; i += 1.0 / testpath.length()) testpathlist.append(testpath.pointAtPercent(i)); + } + + nowPositon = endPoint; + qout << "当前坐标" << nowPositon; + + for (int i = 0; i < 4; i++) vNum.removeFirst(); + } + break; + } + case 7: // t + { + while (vNum.length() / 2 >= 1) { + QPointF startPoint = nowPositon; + QPointF cPoint; + QPointF endPoint; + if (coordinates == ABSOLUTE_COORDINATES) { + float x = startPoint.x(); + float y = startPoint.y(); + cPoint = QPointF(2 * x - lastControlPosition.x(), 2 * y - lastControlPosition.y()); + endPoint = QPointF(vNum.at(0), vNum.at(1)); + } + else { + float x = startPoint.x(); + float y = startPoint.y(); + cPoint = QPointF(x + x - lastControlPosition.x(), y + y - lastControlPosition.y()); + endPoint = QPointF(x + vNum.at(0), y + vNum.at(1)); + } + lastControlPosition = cPoint; + path.moveTo(startPoint); + path.quadTo(cPoint, endPoint); // 二次贝塞尔曲线 + path.moveTo(endPoint); + + { + QPainterPath testpath; + + testpath.moveTo(startPoint); + testpath.quadTo(cPoint, endPoint); // 二次贝塞尔曲线 + testpath.moveTo(endPoint); + for (double i = 0; i <= 1; i += 1.0 / testpath.length()) testpathlist.append(testpath.pointAtPercent(i)); + } + + nowPositon = endPoint; + qout << "当前坐标" << nowPositon; + + for (int i = 0; i < 2; i++) vNum.removeFirst(); + } + break; + } + case 8: // a + { + while (vNum.length() / 7 >= 1) { + QPointF startPoint = nowPositon; + float rx = vNum.at(0); + float ry = vNum.at(1); + float x_axis_rotation = vNum.at(2); + float large_arc_flag = vNum.at(3); + float sweep_flag = vNum.at(4); + QPointF endPoint; + + double cx; + double cy; + double start_angle; + double delta_angle; + + if (coordinates == ABSOLUTE_COORDINATES) { + endPoint = QPointF(vNum.at(5), vNum.at(6)); + } + else { + float x = startPoint.x(); + float y = startPoint.y(); + endPoint = QPointF(x + vNum.at(5), y + vNum.at(6)); + } + + // svg : [A | a] (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ + // x1 y1 rx ry φ fA fS x2 y2 + svgArcToCenterParam(startPoint.x(), startPoint.y(), rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, endPoint.x(), endPoint.y(), + cx, cy, start_angle, delta_angle); + + start_angle = qRadiansToDegrees(start_angle); + delta_angle = qRadiansToDegrees(delta_angle); + + QRectF rect(cx - rx, cy - ry, 2 * rx, 2 * ry); + + qout << "转换后" << cx << cy << start_angle << delta_angle << rect; + + if (delta_angle != 0) { + path.moveTo(startPoint); + path.arcTo(rect, 360 - start_angle, -delta_angle); // 绘图的坐标系与笛卡尔坐标系不同, 需要转换 + + { + QPainterPath testpath; + + testpath.moveTo(startPoint); + testpath.arcTo(rect, 360 - start_angle, -delta_angle); + testpath.moveTo(endPoint); + for (double i = 0; i <= 1; i += 1.0 / testpath.length()) testpathlist.append(testpath.pointAtPercent(i)); + } + } + path.moveTo(endPoint); + + nowPositon = endPoint; + qout << "当前坐标" << nowPositon; + + for (int i = 0; i < 7; i++) vNum.removeFirst(); + } + + break; + } + case 9: // z + qout << "z:" << pathStartPosition; + path.lineTo(pathStartPosition); + testpathlist.append(pathStartPosition); + break; + } + +} + +QVector SvgHelper::segmentationCoordinates(QString value) +{ + // 将科学记数法暂时替换, 防止分割出错 + if (value.contains("e", Qt::CaseInsensitive)) { + value.replace("e-", "[KXJSFF]"); + value.replace("E-", "[KXJSFF]"); + } + + if (value.contains(" -")) { + value.replace(" -", " [KGFS]"); + } + + if (value.contains(",-")) { + value.replace(",-", ",[DHFS]"); + } + + + qout << "------value:------" << value; + QVector vPos; + QString num = ""; + foreach(QChar c, value) { + if (splitList.contains(c)) { + num = num.trimmed(); + if (!num.isEmpty()) { + if (num.contains(',')) num.remove(','); + vPos.append(getValueWithoutUnit(num)); + num.clear(); + } + } + num += c; + } + num = num.trimmed(); + if (num.contains(',')) num.remove(','); + if (!num.isEmpty()) vPos.append(getValueWithoutUnit(num)); + qout << "------num:------" << num; + return vPos; +} + +float SvgHelper::getValueWithoutUnit(QString input) +{ + // 将科学记数法替换回来 + if (input.contains("[KXJSFF]")) input.replace("[KXJSFF]", "e-"); + if (input.contains("[KGFS]")) input.replace("[KGFS]", "-"); + if (input.contains("[DHFS]")) input.replace("[DHFS]", "-"); + qout << "------input:------" << input; + + if (input.isEmpty()) return -1; + QString str = input; + foreach(QString unit, unitList) { + if (str.contains(unit)) { + str.remove(unit); + } + } + return str.toFloat(); +} + +/** +svg : [A | a] (rx ry x-axis-rotation large-arc-flag sweep-flag x2 y2)+ + +(x1 y1)圆弧路径起点 +(x2 y2)圆弧路径终点 + +rx 椭圆弧的X半轴长度 +ry 椭圆弧的Y半轴长度 +x-axis-rotation 椭圆弧X轴方向的旋转角度 +large-arc-flag 标记是否大弧段 +sweep-flag 标记是否顺时针绘制 + +sample : svgArcToCenterParam(200,200,50,50,0,1,1,300,200, output...) +*/ +double SvgHelper::radian(double ux, double uy, double vx, double vy) { + double dot = ux * vx + uy * vy; + double mod = sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)); + double rad = acos(dot / mod); + if (ux * vy - uy * vx < 0.0) rad = -rad; + return rad; +} + +int SvgHelper::svgArcToCenterParam(double x1, double y1, double rx, double ry, double phi, double fA, double fS, double x2, double y2, + double& cx_out, double& cy_out, double& startAngle_out, double& deltaAngle_out) { + double cx, cy, startAngle, deltaAngle, endAngle; + double PIx2 = M_PI * 2.0; + + if (rx < 0) { + rx = -rx; + } + if (ry < 0) { + ry = -ry; + } + if (rx == 0.0 || ry == 0.0) { // invalid arguments + return -1; + } + + double s_phi = sin(phi); + double c_phi = cos(phi); + double hd_x = (x1 - x2) / 2.0; // half diff of x + double hd_y = (y1 - y2) / 2.0; // half diff of y + double hs_x = (x1 + x2) / 2.0; // half sum of x + double hs_y = (y1 + y2) / 2.0; // half sum of y + + // F6.5.1 + double x1_ = c_phi * hd_x + s_phi * hd_y; + double y1_ = c_phi * hd_y - s_phi * hd_x; + + // F.6.6 Correction of out-of-range radii + // Step 3: Ensure radii are large enough + double lambda = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry); + if (lambda > 1) { + rx = rx * sqrt(lambda); + ry = ry * sqrt(lambda); + } + + double rxry = rx * ry; + double rxy1_ = rx * y1_; + double ryx1_ = ry * x1_; + double sum_of_sq = rxy1_ * rxy1_ + ryx1_ * ryx1_; // sum of square + if (!sum_of_sq) { + return -1; + } + double coe = sqrt(abs((rxry * rxry - sum_of_sq) / sum_of_sq)); + if (fA == fS) { coe = -coe; } + + // F6.5.2 + double cx_ = coe * rxy1_ / ry; + double cy_ = -coe * ryx1_ / rx; + + // F6.5.3 + cx = c_phi * cx_ - s_phi * cy_ + hs_x; + cy = s_phi * cx_ + c_phi * cy_ + hs_y; + + double xcr1 = (x1_ - cx_) / rx; + double xcr2 = (x1_ + cx_) / rx; + double ycr1 = (y1_ - cy_) / ry; + double ycr2 = (y1_ + cy_) / ry; + + // F6.5.5 + startAngle = radian(1.0, 0.0, xcr1, ycr1); + + // F6.5.6 + deltaAngle = radian(xcr1, ycr1, -xcr2, -ycr2); + while (deltaAngle > PIx2) { deltaAngle -= PIx2; } + while (deltaAngle < 0.0) { deltaAngle += PIx2; } + if (fS == false || fS == 0) { deltaAngle -= PIx2; } + endAngle = startAngle + deltaAngle; + while (endAngle > PIx2) { endAngle -= PIx2; } + while (endAngle < 0.0) { endAngle += PIx2; } + + cx_out = cx; + cy_out = cy; + startAngle_out = startAngle; + deltaAngle_out = deltaAngle; + + return 1; +} + +QList > SvgHelper::getSvgPointList() const +{ + return svgPointList; +} + +QList SvgHelper::getSvgPathList() const +{ + return svgPathList; +} + + +/* + get angle ACB, point C is the center point + A(x1,y1) + B(x2,y2) + C(x3,y3) +*/ +double SvgHelper::get_angle_with_points(double x1, double y1, double x2, double y2, double x3, double y3) +{ + double theta = atan2(x1 - x3, y1 - y3) - atan2(x2 - x3, y2 - y3); + if (theta > M_PI) + theta -= 2 * M_PI; + if (theta < -M_PI) + theta += 2 * M_PI; + + theta = abs(theta * 180.0 / M_PI); + + if (y2 <= y3) { + theta = 360.0 - theta; + } + + return theta; +} \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/third-party modules/SvgHelper.h b/ArchitectureColoredPainting/src/Editor/third-party modules/SvgHelper.h new file mode 100644 index 0000000..0f87b48 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/third-party modules/SvgHelper.h @@ -0,0 +1,60 @@ +#pragma once +#ifndef SVGHELPER_H +#define SVGHELPER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const QList cmdList = {'M', 'm', 'L', 'l', 'H', 'h', 'V', 'v', 'C', 'c', + 'S', 's', 'Q', 'q', 'T', 't', 'A', 'a', 'Z', 'z'}; +const QList cmdTypeList = {'M', 'L', 'H', 'V', 'C', 'S', 'Q', 'T', 'A', 'Z'}; +const QList splitList = {' ', '-', ',', '\r', '\n', '\t'}; +const QList unitList = {"em", "px", "%", "cm", "mm", "in", "pt", "pc"}; +const QList typeList = {"path", "rect", "circle", "ellipse", "line", "polygon", "polyline"}; + +#define ABSOLUTE_COORDINATES 1 +#define RELATIVE_COORDINATES 2 + +class SvgHelper +{ + public: + SvgHelper(); + + void parseSvgImage(QString filepath); + QList getSvgPathList() const; + QImage getSvgImage(); + + QList> getSvgPointList() const; + + private: + void parseSVGTag(QDomElement e, QString tagname); + void parseSvgPath(QString path, QPainterPath &paintPath); + void dealParsePainter(QPainterPath &path, QString line); + QVector segmentationCoordinates(QString value); + float getValueWithoutUnit(QString input); + double radian(double ux, double uy, double vx, double vy); + int svgArcToCenterParam(double x1, double y1, double rx, double ry, double phi, double fA, double fS, double x2, + double y2, double &cx_out, double &cy_out, double &startAngle_out, double &deltaAngle_out); + double get_angle_with_points(double x1, double y1, double x2, double y2, double x3, double y3); + + QString filepath; + QPainterPath paintPath; + QList testpathlist; + QPointF nowPositon = QPointF(0, 0); + QPointF pathStartPosition = QPointF(0, 0); + QPointF lastControlPosition = QPointF(0, 0); + QList svgPathList; + QList> svgPointList; +}; + +#endif // SVGHELPER_H diff --git a/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qquicksvgparser.cpp b/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qquicksvgparser.cpp new file mode 100644 index 0000000..d9c38e1 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qquicksvgparser.cpp @@ -0,0 +1,567 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qquicksvgparser_p.h" +#include +#include +#include +QT_BEGIN_NAMESPACE +//copied from Qt SVG (qsvghandler.cpp). +Q_CORE_EXPORT double qstrtod(const char* s00, char const** se, bool* ok); +// '0' is 0x30 and '9' is 0x39 +static inline bool isDigit(ushort ch) +{ + static quint16 magic = 0x3ff; + return ((ch >> 4) == 3) && (magic >> (ch & 15)); +} +static qreal toDouble(const QChar*& str) +{ + const int maxLen = 255;//technically doubles can go til 308+ but whatever + char temp[maxLen + 1]; + int pos = 0; + if (*str == QLatin1Char('-')) { + temp[pos++] = '-'; + ++str; + } + else if (*str == QLatin1Char('+')) { + ++str; + } + while (isDigit(str->unicode()) && pos < maxLen) { + temp[pos++] = str->toLatin1(); + ++str; + } + if (*str == QLatin1Char('.') && pos < maxLen) { + temp[pos++] = '.'; + ++str; + } + while (isDigit(str->unicode()) && pos < maxLen) { + temp[pos++] = str->toLatin1(); + ++str; + } + bool exponent = false; + if ((*str == QLatin1Char('e') || *str == QLatin1Char('E')) && pos < maxLen) { + exponent = true; + temp[pos++] = 'e'; + ++str; + if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) { + temp[pos++] = str->toLatin1(); + ++str; + } + while (isDigit(str->unicode()) && pos < maxLen) { + temp[pos++] = str->toLatin1(); + ++str; + } + } + temp[pos] = '\0'; + qreal val; + if (!exponent && pos < 10) { + int ival = 0; + const char* t = temp; + bool neg = false; + if (*t == '-') { + neg = true; + ++t; + } + while (*t && *t != '.') { + ival *= 10; + ival += (*t) - '0'; + ++t; + } + if (*t == '.') { + ++t; + int div = 1; + while (*t) { + ival *= 10; + ival += (*t) - '0'; + div *= 10; + ++t; + } + val = ((qreal)ival) / ((qreal)div); + } + else { + val = ival; + } + if (neg) + val = -val; + } + else { + bool ok = false; + val = qstrtod(temp, nullptr, &ok); + } + return val; +} +static inline void parseNumbersArray(const QChar*& str, QVarLengthArray& points) +{ + while (str->isSpace()) + ++str; + while (isDigit(str->unicode()) || + *str == QLatin1Char('-') || *str == QLatin1Char('+') || + *str == QLatin1Char('.')) { + points.append(toDouble(str)); + while (str->isSpace()) + ++str; + if (*str == QLatin1Char(',')) + ++str; + //eat the rest of space + while (str->isSpace()) + ++str; + } +} +static void pathArcSegment(QPainterPath& path, + qreal xc, qreal yc, + qreal th0, qreal th1, + qreal rx, qreal ry, qreal xAxisRotation) +{ + qreal sinTh, cosTh; + qreal a00, a01, a10, a11; + qreal x1, y1, x2, y2, x3, y3; + qreal t; + qreal thHalf; + sinTh = qSin(qDegreesToRadians(xAxisRotation)); + cosTh = qCos(qDegreesToRadians(xAxisRotation)); + a00 = cosTh * rx; + a01 = -sinTh * ry; + a10 = sinTh * rx; + a11 = cosTh * ry; + thHalf = 0.5 * (th1 - th0); + t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf); + x1 = xc + qCos(th0) - t * qSin(th0); + y1 = yc + qSin(th0) + t * qCos(th0); + x3 = xc + qCos(th1); + y3 = yc + qSin(th1); + x2 = x3 + t * qSin(th1); + y2 = y3 - t * qCos(th1); + path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, + a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, + a00 * x3 + a01 * y3, a10 * x3 + a11 * y3); +} +void QQuickSvgParser::pathArc(QPainterPath& path, + qreal rx, + qreal ry, + qreal x_axis_rotation, + int large_arc_flag, + int sweep_flag, + qreal x, + qreal y, + qreal curx, qreal cury) +{ + qreal sin_th, cos_th; + qreal a00, a01, a10, a11; + qreal x0, y0, x1, y1, xc, yc; + qreal d, sfactor, sfactor_sq; + qreal th0, th1, th_arc; + int i, n_segs; + qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check; + rx = qAbs(rx); + ry = qAbs(ry); + sin_th = qSin(qDegreesToRadians(x_axis_rotation)); + cos_th = qCos(qDegreesToRadians(x_axis_rotation)); + dx = (curx - x) / 2.0; + dy = (cury - y) / 2.0; + dx1 = cos_th * dx + sin_th * dy; + dy1 = -sin_th * dx + cos_th * dy; + Pr1 = rx * rx; + Pr2 = ry * ry; + Px = dx1 * dx1; + Py = dy1 * dy1; + /* Spec : check if radii are large enough */ + check = Px / Pr1 + Py / Pr2; + if (check > 1) { + rx = rx * qSqrt(check); + ry = ry * qSqrt(check); + } + a00 = cos_th / rx; + a01 = sin_th / rx; + a10 = -sin_th / ry; + a11 = cos_th / ry; + x0 = a00 * curx + a01 * cury; + y0 = a10 * curx + a11 * cury; + x1 = a00 * x + a01 * y; + y1 = a10 * x + a11 * y; + /* (x0, y0) is current point in transformed coordinate space. + (x1, y1) is new point in transformed coordinate space. + The arc fits a unit-radius circle in this space. + */ + d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); + sfactor_sq = 1.0 / d - 0.25; + if (sfactor_sq < 0) sfactor_sq = 0; + sfactor = qSqrt(sfactor_sq); + if (sweep_flag == large_arc_flag) sfactor = -sfactor; + xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); + yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); + /* (xc, yc) is center of the circle. */ + th0 = qAtan2(y0 - yc, x0 - xc); + th1 = qAtan2(y1 - yc, x1 - xc); + th_arc = th1 - th0; + if (th_arc < 0 && sweep_flag) + th_arc += 2 * M_PI; + else if (th_arc > 0 && !sweep_flag) + th_arc -= 2 * M_PI; + n_segs = qCeil(qAbs(th_arc / (M_PI * 0.5 + 0.001))); + for (i = 0; i < n_segs; i++) { + pathArcSegment(path, xc, yc, + th0 + i * th_arc / n_segs, + th0 + (i + 1) * th_arc / n_segs, + rx, ry, x_axis_rotation); + } +} +bool QQuickSvgParser::parsePathDataFast(const QString& dataStr, QPainterPath& path) +{ + qreal x0 = 0, y0 = 0; // starting point + qreal x = 0, y = 0; // current point + char lastMode = 0; + QPointF ctrlPt; + const QChar* str = dataStr.constData(); + const QChar* end = str + dataStr.size(); + while (str != end) { + while (str->isSpace()) + ++str; + QChar pathElem = *str; + ++str; + QVarLengthArray arg; + parseNumbersArray(str, arg); + if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z')) + arg.append(0);//dummy + const qreal* num = arg.constData(); + int count = arg.count(); + while (count > 0) { + qreal offsetX = x; // correction offsets + qreal offsetY = y; // for relative commands + switch (pathElem.unicode()) { + case 'm': { + if (count < 2) { + num++; + count--; + break; + } + x = x0 = num[0] + offsetX; + y = y0 = num[1] + offsetY; + num += 2; + count -= 2; + path.moveTo(x0, y0); + // As per 1.2 spec 8.3.2 The "moveto" commands + // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands, + // the subsequent pairs shall be treated as implicit 'lineto' commands. + pathElem = QLatin1Char('l'); + } + break; + case 'M': { + if (count < 2) { + num++; + count--; + break; + } + x = x0 = num[0]; + y = y0 = num[1]; + num += 2; + count -= 2; + path.moveTo(x0, y0); + // As per 1.2 spec 8.3.2 The "moveto" commands + // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands, + // the subsequent pairs shall be treated as implicit 'lineto' commands. + pathElem = QLatin1Char('L'); + } + break; + case 'z': + case 'Z': { + x = x0; + y = y0; + count--; // skip dummy + num++; + path.closeSubpath(); + } + break; + case 'l': { + if (count < 2) { + num++; + count--; + break; + } + x = num[0] + offsetX; + y = num[1] + offsetY; + num += 2; + count -= 2; + path.lineTo(x, y); + } + break; + case 'L': { + if (count < 2) { + num++; + count--; + break; + } + x = num[0]; + y = num[1]; + num += 2; + count -= 2; + path.lineTo(x, y); + } + break; + case 'h': { + x = num[0] + offsetX; + num++; + count--; + path.lineTo(x, y); + } + break; + case 'H': { + x = num[0]; + num++; + count--; + path.lineTo(x, y); + } + break; + case 'v': { + y = num[0] + offsetY; + num++; + count--; + path.lineTo(x, y); + } + break; + case 'V': { + y = num[0]; + num++; + count--; + path.lineTo(x, y); + } + break; + case 'c': { + if (count < 6) { + num += count; + count = 0; + break; + } + QPointF c1(num[0] + offsetX, num[1] + offsetY); + QPointF c2(num[2] + offsetX, num[3] + offsetY); + QPointF e(num[4] + offsetX, num[5] + offsetY); + num += 6; + count -= 6; + path.cubicTo(c1, c2, e); + ctrlPt = c2; + x = e.x(); + y = e.y(); + break; + } + case 'C': { + if (count < 6) { + num += count; + count = 0; + break; + } + QPointF c1(num[0], num[1]); + QPointF c2(num[2], num[3]); + QPointF e(num[4], num[5]); + num += 6; + count -= 6; + path.cubicTo(c1, c2, e); + ctrlPt = c2; + x = e.x(); + y = e.y(); + break; + } + case 's': { + if (count < 4) { + num += count; + count = 0; + break; + } + QPointF c1; + if (lastMode == 'c' || lastMode == 'C' || + lastMode == 's' || lastMode == 'S') + c1 = QPointF(2 * x - ctrlPt.x(), 2 * y - ctrlPt.y()); + else + c1 = QPointF(x, y); + QPointF c2(num[0] + offsetX, num[1] + offsetY); + QPointF e(num[2] + offsetX, num[3] + offsetY); + num += 4; + count -= 4; + path.cubicTo(c1, c2, e); + ctrlPt = c2; + x = e.x(); + y = e.y(); + break; + } + case 'S': { + if (count < 4) { + num += count; + count = 0; + break; + } + QPointF c1; + if (lastMode == 'c' || lastMode == 'C' || + lastMode == 's' || lastMode == 'S') + c1 = QPointF(2 * x - ctrlPt.x(), 2 * y - ctrlPt.y()); + else + c1 = QPointF(x, y); + QPointF c2(num[0], num[1]); + QPointF e(num[2], num[3]); + num += 4; + count -= 4; + path.cubicTo(c1, c2, e); + ctrlPt = c2; + x = e.x(); + y = e.y(); + break; + } + case 'q': { + if (count < 4) { + num += count; + count = 0; + break; + } + QPointF c(num[0] + offsetX, num[1] + offsetY); + QPointF e(num[2] + offsetX, num[3] + offsetY); + num += 4; + count -= 4; + path.quadTo(c, e); + ctrlPt = c; + x = e.x(); + y = e.y(); + break; + } + case 'Q': { + if (count < 4) { + num += count; + count = 0; + break; + } + QPointF c(num[0], num[1]); + QPointF e(num[2], num[3]); + num += 4; + count -= 4; + path.quadTo(c, e); + ctrlPt = c; + x = e.x(); + y = e.y(); + break; + } + case 't': { + if (count < 2) { + num += count; + count = 0; + break; + } + QPointF e(num[0] + offsetX, num[1] + offsetY); + num += 2; + count -= 2; + QPointF c; + if (lastMode == 'q' || lastMode == 'Q' || + lastMode == 't' || lastMode == 'T') + c = QPointF(2 * x - ctrlPt.x(), 2 * y - ctrlPt.y()); + else + c = QPointF(x, y); + path.quadTo(c, e); + ctrlPt = c; + x = e.x(); + y = e.y(); + break; + } + case 'T': { + if (count < 2) { + num += count; + count = 0; + break; + } + QPointF e(num[0], num[1]); + num += 2; + count -= 2; + QPointF c; + if (lastMode == 'q' || lastMode == 'Q' || + lastMode == 't' || lastMode == 'T') + c = QPointF(2 * x - ctrlPt.x(), 2 * y - ctrlPt.y()); + else + c = QPointF(x, y); + path.quadTo(c, e); + ctrlPt = c; + x = e.x(); + y = e.y(); + break; + } + case 'a': { + if (count < 7) { + num += count; + count = 0; + break; + } + qreal rx = (*num++); + qreal ry = (*num++); + qreal xAxisRotation = (*num++); + qreal largeArcFlag = (*num++); + qreal sweepFlag = (*num++); + qreal ex = (*num++) + offsetX; + qreal ey = (*num++) + offsetY; + count -= 7; + qreal curx = x; + qreal cury = y; + pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag), + int(sweepFlag), ex, ey, curx, cury); + x = ex; + y = ey; + } + break; + case 'A': { + if (count < 7) { + num += count; + count = 0; + break; + } + qreal rx = (*num++); + qreal ry = (*num++); + qreal xAxisRotation = (*num++); + qreal largeArcFlag = (*num++); + qreal sweepFlag = (*num++); + qreal ex = (*num++); + qreal ey = (*num++); + count -= 7; + qreal curx = x; + qreal cury = y; + pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag), + int(sweepFlag), ex, ey, curx, cury); + x = ex; + y = ey; + } + break; + default: + return false; + } + lastMode = pathElem.toLatin1(); + } + } + return true; +} +QT_END_NAMESPACE \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qquicksvgparser_p.h b/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qquicksvgparser_p.h new file mode 100644 index 0000000..852e2b5 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qquicksvgparser_p.h @@ -0,0 +1,64 @@ +#pragma once +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QQUICKSVGPARSER_P_H +#define QQUICKSVGPARSER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +#include "qtquickglobal_p.h" +#include +#include +QT_BEGIN_NAMESPACE +namespace QQuickSvgParser +{ + bool parsePathDataFast(const QString& dataStr, QPainterPath& path); + Q_QUICK_PRIVATE_EXPORT void pathArc(QPainterPath& path, qreal rx, qreal ry, qreal x_axis_rotation, + int large_arc_flag, int sweep_flag, qreal x, qreal y, qreal curx, + qreal cury); +} +QT_END_NAMESPACE +#endif // QQUICKSVGPARSER_P_H \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qtquickglobal.h b/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qtquickglobal.h new file mode 100644 index 0000000..7c01421 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qtquickglobal.h @@ -0,0 +1,56 @@ +#pragma once +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTQUICKGLOBAL_H +#define QTQUICKGLOBAL_H +#include +#include +#include +QT_BEGIN_NAMESPACE +#ifndef QT_STATIC +# if defined(QT_BUILD_QUICK_LIB) +# define Q_QUICK_EXPORT Q_DECL_EXPORT +# else +# define Q_QUICK_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_QUICK_EXPORT +#endif +QT_END_NAMESPACE +#endif // QTQUICKGLOBAL_H \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qtquickglobal_p.h b/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qtquickglobal_p.h new file mode 100644 index 0000000..3aa0685 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/third-party modules/qquick/qtquickglobal_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTQUICKGLOBAL_P_H +#define QTQUICKGLOBAL_P_H +//#include +//#include +//#include +#include +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +#include "qtquickglobal.h" +#define Q_QUICK_PRIVATE_EXPORT Q_QUICK_EXPORT +//void Q_QUICK_PRIVATE_EXPORT qml_register_types_QtQuick(); +//QT_BEGIN_NAMESPACE +//void QQuick_initializeProviders(); +//void QQuick_deinitializeProviders(); +Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH) +Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE) +Q_DECLARE_LOGGING_CATEGORY(DBG_FOCUS) +Q_DECLARE_LOGGING_CATEGORY(DBG_DIRTY) +QT_END_NAMESPACE +#endif // QTQUICKGLOBAL_P_H \ No newline at end of file