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