增加分割点在原线的比例关系与Svg处理变换问题
parent
ff848b1443
commit
ab391ed0ec
|
@ -2,9 +2,12 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include "../ThirdPartyLib/qquick/qquicksvgparser_p.h"
|
#include "../ThirdPartyLib/qquick/qquicksvgparser_p.h"
|
||||||
#include <QPolygonF>
|
#include <QPolygonF>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
|
using std::vector;
|
||||||
|
using std::reverse;
|
||||||
|
|
||||||
bool SvgFileLoader::loadSvgFile(const QString& filePath, QPainterPath& painterPath) {
|
bool SvgFileLoader::loadSvgFile(const QString& filePath, QPainterPath& painterPath) {
|
||||||
QFile file(filePath);
|
QFile file(filePath);
|
||||||
|
@ -46,12 +49,12 @@ bool SvgFileLoader::loadSvgFile(const QString& filePath, QPainterPath& painterPa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
qDebug() << painterPath;
|
||||||
file.close();
|
file.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, QString> SvgFileLoader::transformStyle(QString style) {
|
QMap<QString, QString> SvgFileLoader::handleAttrStyle(QString style) {
|
||||||
QMap<QString, QString> resStyleMap;
|
QMap<QString, QString> resStyleMap;
|
||||||
for (auto& attr : style.split(';')) {
|
for (auto& attr : style.split(';')) {
|
||||||
if (attr.isEmpty() || attr.trimmed() == "") continue;
|
if (attr.isEmpty() || attr.trimmed() == "") continue;
|
||||||
|
@ -62,7 +65,7 @@ QMap<QString, QString> SvgFileLoader::transformStyle(QString style) {
|
||||||
return resStyleMap;
|
return resStyleMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPolygonF SvgFileLoader::transformPoints(QString points) {
|
QPolygonF SvgFileLoader::handleAttrPoints(QString points) {
|
||||||
QPolygonF resPointVector;
|
QPolygonF resPointVector;
|
||||||
QPointF point(0, 0);
|
QPointF point(0, 0);
|
||||||
bool isX = true;
|
bool isX = true;
|
||||||
|
@ -80,10 +83,58 @@ QPolygonF SvgFileLoader::transformPoints(QString points) {
|
||||||
return resPointVector;
|
return resPointVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SvgFileLoader::handleAttrTransform(QString transformStyle, QPainterPath& painterPath) {
|
||||||
|
QTransform trans;
|
||||||
|
QStringList ops = transformStyle.split(')');
|
||||||
|
reverse(ops.begin(), ops.end());
|
||||||
|
vector<double> numbers;
|
||||||
|
for (auto op : ops) {
|
||||||
|
op = op.simplified();
|
||||||
|
if (op.isEmpty()) continue;
|
||||||
|
QString type = (*op.split('(').begin()).trimmed();
|
||||||
|
QString numStr = (*op.split('(').rbegin()).trimmed() + ',';
|
||||||
|
QString tmpNum = "";
|
||||||
|
for (auto c : numStr) {
|
||||||
|
if (isdigit(c.toLatin1())) {
|
||||||
|
tmpNum += c;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (c == ',' && tmpNum.size() == 0) {
|
||||||
|
numbers.push_back(0);
|
||||||
|
}
|
||||||
|
else if (tmpNum.size() > 0) {
|
||||||
|
numbers.push_back(tmpNum.toDouble());
|
||||||
|
}
|
||||||
|
tmpNum.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << type << "///:" << numbers;
|
||||||
|
if (type == "translate") {
|
||||||
|
trans.translate(numbers[0], numbers[1]);
|
||||||
|
}
|
||||||
|
if (type == "scale") {
|
||||||
|
trans.scale(numbers[0], numbers[1]);
|
||||||
|
}
|
||||||
|
if (type == "rotate") {
|
||||||
|
trans.translate(numbers[1], numbers[2]);
|
||||||
|
trans.rotate(numbers[0]);
|
||||||
|
trans.translate(-numbers[1], -numbers[2]);
|
||||||
|
}
|
||||||
|
if (type == "skewX") {
|
||||||
|
trans.shear(numbers[0], 0);
|
||||||
|
}
|
||||||
|
if (type == "skewY") {
|
||||||
|
trans.shear(0, numbers[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
painterPath = trans.map(painterPath);
|
||||||
|
qDebug() << painterPath;
|
||||||
|
}
|
||||||
|
|
||||||
void SvgFileLoader::handleLabelG(QPainterPath& painterPath) {
|
void SvgFileLoader::handleLabelG(QPainterPath& painterPath) {
|
||||||
for (auto& attr : xmlReader->attributes()) {
|
for (auto& attr : xmlReader->attributes()) {
|
||||||
if (attr.name().toString() == QLatin1String("style")) {
|
if (attr.name().toString() == QLatin1String("style")) {
|
||||||
styleMap = transformStyle(attr.value().toLatin1());
|
styleMap = handleAttrStyle(attr.value().toLatin1());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
styleMap.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
styleMap.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
||||||
|
@ -94,22 +145,33 @@ void SvgFileLoader::handleLabelG(QPainterPath& painterPath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgFileLoader::handleLabelPath(QPainterPath& painterPath) {
|
void SvgFileLoader::handleLabelPath(QPainterPath& painterPath) {
|
||||||
|
QPainterPath elementPainterPath;
|
||||||
|
QString transformStyle = "";
|
||||||
QMap<QString, QString> labelStyle;
|
QMap<QString, QString> labelStyle;
|
||||||
for (auto& attr : xmlReader->attributes()) {
|
for (auto& attr : xmlReader->attributes()) {
|
||||||
if (attr.name().toString() == QLatin1String("d")) {
|
if (attr.name().toString() == QLatin1String("d")) {
|
||||||
QQuickSvgParser::parsePathDataFast(attr.value().toLatin1(), painterPath);
|
QQuickSvgParser::parsePathDataFast(attr.value().toLatin1(), elementPainterPath);
|
||||||
}
|
}
|
||||||
else if (attr.name().toString() == QLatin1String("style")) {
|
else if (attr.name().toString() == QLatin1String("style")) {
|
||||||
labelStyle = transformStyle(attr.value().toLatin1());
|
labelStyle = handleAttrStyle(attr.value().toLatin1());
|
||||||
|
}
|
||||||
|
else if (attr.name().toString() == QLatin1String("transform")) {
|
||||||
|
transformStyle = attr.value().toLatin1();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!transformStyle.isEmpty()) {
|
||||||
|
handleAttrTransform(transformStyle, elementPainterPath);
|
||||||
|
}
|
||||||
|
painterPath.addPath(elementPainterPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgFileLoader::handleLabelRect(QPainterPath& painterPath) {
|
void SvgFileLoader::handleLabelRect(QPainterPath& painterPath) {
|
||||||
QMap<QString, QString> labelStyle;
|
QMap<QString, QString> labelStyle;
|
||||||
|
QPainterPath elementPainterPath;
|
||||||
|
QString transformStyle = "";
|
||||||
double xBegin = 0, yBegin = 0, width = 0, height = 0;;
|
double xBegin = 0, yBegin = 0, width = 0, height = 0;;
|
||||||
for (auto& attr : xmlReader->attributes()) {
|
for (auto& attr : xmlReader->attributes()) {
|
||||||
if (attr.name().toString() == QLatin1String("x")) {
|
if (attr.name().toString() == QLatin1String("x")) {
|
||||||
|
@ -122,17 +184,26 @@ void SvgFileLoader::handleLabelRect(QPainterPath& painterPath) {
|
||||||
height = attr.value().toDouble();
|
height = attr.value().toDouble();
|
||||||
}
|
}
|
||||||
else if (attr.name().toString() == QLatin1String("style")) {
|
else if (attr.name().toString() == QLatin1String("style")) {
|
||||||
labelStyle = transformStyle(attr.value().toLatin1());
|
labelStyle = handleAttrStyle(attr.value().toLatin1());
|
||||||
|
}
|
||||||
|
else if (attr.name().toString() == QLatin1String("transform")) {
|
||||||
|
transformStyle = attr.value().toLatin1();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << labelStyle;
|
qDebug() << labelStyle;
|
||||||
painterPath.addRect(xBegin, yBegin, xBegin + width, yBegin + height);
|
elementPainterPath.addRect(xBegin, yBegin, xBegin + width, yBegin + height);
|
||||||
|
if (!transformStyle.isEmpty()) {
|
||||||
|
handleAttrTransform(transformStyle, elementPainterPath);
|
||||||
|
}
|
||||||
|
painterPath.addPath(elementPainterPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgFileLoader::handleLabelCircle(QPainterPath& painterPath) {
|
void SvgFileLoader::handleLabelCircle(QPainterPath& painterPath) {
|
||||||
|
QPainterPath elementPainterPath;
|
||||||
|
QString transformStyle = "";
|
||||||
QMap<QString, QString> labelStyle;
|
QMap<QString, QString> labelStyle;
|
||||||
double cx = 0, cy = 0, r = 0;
|
double cx = 0, cy = 0, r = 0;
|
||||||
for (auto& attr : xmlReader->attributes()) {
|
for (auto& attr : xmlReader->attributes()) {
|
||||||
|
@ -144,18 +215,28 @@ void SvgFileLoader::handleLabelCircle(QPainterPath& painterPath) {
|
||||||
r = attr.value().toDouble();
|
r = attr.value().toDouble();
|
||||||
}
|
}
|
||||||
else if (attr.name().toString() == QLatin1String("style")) {
|
else if (attr.name().toString() == QLatin1String("style")) {
|
||||||
labelStyle = transformStyle(attr.value().toLatin1());
|
labelStyle = handleAttrStyle(attr.value().toLatin1());
|
||||||
|
}
|
||||||
|
else if (attr.name().toString() == QLatin1String("transform")) {
|
||||||
|
transformStyle = attr.value().toLatin1();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << labelStyle;
|
qDebug() << labelStyle;
|
||||||
|
elementPainterPath.addEllipse(cx, cy, r, r);
|
||||||
|
if (!transformStyle.isEmpty()) {
|
||||||
|
handleAttrTransform(transformStyle, elementPainterPath);
|
||||||
|
}
|
||||||
|
painterPath.addPath(elementPainterPath);
|
||||||
//addEllipse(cx, cy, r, r, painterPath);
|
//addEllipse(cx, cy, r, r, painterPath);
|
||||||
painterPath.addEllipse(cx, cy, r, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgFileLoader::handleLabelEllipse(QPainterPath& painterPath) {
|
void SvgFileLoader::handleLabelEllipse(QPainterPath& painterPath) {
|
||||||
|
QPainterPath elementPainterPath;
|
||||||
|
QString transformStyle = "";
|
||||||
QMap<QString, QString> labelStyle;
|
QMap<QString, QString> labelStyle;
|
||||||
double cx = 0, cy = 0, rx = 0, ry = 0;
|
double cx = 0, cy = 0, rx = 0, ry = 0;
|
||||||
for (auto& attr : xmlReader->attributes()) {
|
for (auto& attr : xmlReader->attributes()) {
|
||||||
|
@ -168,7 +249,10 @@ void SvgFileLoader::handleLabelEllipse(QPainterPath& painterPath) {
|
||||||
} else if (attr.name().toString() == QLatin1String("ry")) {
|
} else if (attr.name().toString() == QLatin1String("ry")) {
|
||||||
rx = attr.value().toDouble();
|
rx = attr.value().toDouble();
|
||||||
} else if (attr.name().toString() == QLatin1String("style")) {
|
} else if (attr.name().toString() == QLatin1String("style")) {
|
||||||
labelStyle = transformStyle(attr.value().toLatin1());
|
labelStyle = handleAttrStyle(attr.value().toLatin1());
|
||||||
|
}
|
||||||
|
else if (attr.name().toString() == QLatin1String("transform")) {
|
||||||
|
transformStyle = attr.value().toLatin1();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
||||||
|
@ -176,45 +260,68 @@ void SvgFileLoader::handleLabelEllipse(QPainterPath& painterPath) {
|
||||||
}
|
}
|
||||||
qDebug() << labelStyle;
|
qDebug() << labelStyle;
|
||||||
//addEllipse(cx, cy, rx, ry, painterPath);
|
//addEllipse(cx, cy, rx, ry, painterPath);
|
||||||
painterPath.addEllipse(cx, cy, rx, ry);
|
elementPainterPath.addEllipse(cx, cy, rx, ry);
|
||||||
|
if (!transformStyle.isEmpty()) {
|
||||||
|
handleAttrTransform(transformStyle, elementPainterPath);
|
||||||
|
}
|
||||||
|
painterPath.addPath(elementPainterPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgFileLoader::handleLabelPolyline(QPainterPath& painterPath) {
|
void SvgFileLoader::handleLabelPolyline(QPainterPath& painterPath) {
|
||||||
|
QPainterPath elementPainterPath;
|
||||||
|
QString transformStyle = "";
|
||||||
QMap<QString, QString> labelStyle;
|
QMap<QString, QString> labelStyle;
|
||||||
for (auto& attr : xmlReader->attributes()) {
|
for (auto& attr : xmlReader->attributes()) {
|
||||||
if (attr.name().toString() == QLatin1String("points")) {
|
if (attr.name().toString() == QLatin1String("points")) {
|
||||||
QPolygonF points = transformPoints(attr.value().toLatin1());
|
QPolygonF points = handleAttrPoints(attr.value().toLatin1());
|
||||||
painterPath.addPolygon(points);
|
elementPainterPath.addPolygon(points);
|
||||||
}
|
}
|
||||||
else if (attr.name().toString() == QLatin1String("style")) {
|
else if (attr.name().toString() == QLatin1String("style")) {
|
||||||
labelStyle = transformStyle(attr.value().toLatin1());
|
labelStyle = handleAttrStyle(attr.value().toLatin1());
|
||||||
|
}
|
||||||
|
else if (attr.name().toString() == QLatin1String("transform")) {
|
||||||
|
transformStyle = attr.value().toLatin1();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << labelStyle;
|
qDebug() << labelStyle;
|
||||||
|
if (!transformStyle.isEmpty()) {
|
||||||
|
handleAttrTransform(transformStyle, elementPainterPath);
|
||||||
|
}
|
||||||
|
painterPath.addPath(elementPainterPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgFileLoader::handleLabelPolygon(QPainterPath & painterPath) {
|
void SvgFileLoader::handleLabelPolygon(QPainterPath & painterPath) {
|
||||||
|
QPainterPath elementPainterPath;
|
||||||
|
QString transformStyle = "";
|
||||||
QMap<QString, QString> labelStyle;
|
QMap<QString, QString> labelStyle;
|
||||||
for (auto& attr : xmlReader->attributes()) {
|
for (auto& attr : xmlReader->attributes()) {
|
||||||
if (attr.name().toString() == QLatin1String("points")) {
|
if (attr.name().toString() == QLatin1String("points")) {
|
||||||
QPolygonF points = transformPoints(attr.value().toLatin1());
|
QPolygonF points = handleAttrPoints(attr.value().toLatin1());
|
||||||
//points.push_back(*points.begin());
|
//points.push_back(*points.begin());
|
||||||
painterPath.addPolygon(points);
|
elementPainterPath.addPolygon(points);
|
||||||
painterPath.closeSubpath();
|
elementPainterPath.closeSubpath();
|
||||||
}
|
}
|
||||||
else if (attr.name().toString() == QLatin1String("style")) {
|
else if (attr.name().toString() == QLatin1String("style")) {
|
||||||
labelStyle = transformStyle(attr.value().toLatin1());
|
labelStyle = handleAttrStyle(attr.value().toLatin1());
|
||||||
|
}
|
||||||
|
else if (attr.name().toString() == "transform") {
|
||||||
|
transformStyle = attr.value().toLatin1();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
labelStyle.insert(attr.name().toLatin1(), attr.value().toLatin1());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << labelStyle;
|
qDebug() << labelStyle;
|
||||||
|
if (!transformStyle.isEmpty()) {
|
||||||
|
handleAttrTransform(transformStyle, elementPainterPath);
|
||||||
|
}
|
||||||
|
painterPath.addPath(elementPainterPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void SvgFileLoader::addEllipse(double x, double y, double w, double h, QPainterPath& painterPath) {
|
void SvgFileLoader::addEllipse(double x, double y, double w, double h, QPainterPath& painterPath) {
|
||||||
double k = w / 0.75;
|
double k = w / 0.75;
|
||||||
painterPath.moveTo(x, y - h);
|
painterPath.moveTo(x, y - h);
|
||||||
|
@ -222,3 +329,4 @@ void SvgFileLoader::addEllipse(double x, double y, double w, double h, QPainterP
|
||||||
painterPath.cubicTo(QPointF(x - k, y + h), QPointF(x - k, y - h), QPointF(x, y - h));
|
painterPath.cubicTo(QPointF(x - k, y + h), QPointF(x - k, y - h), QPointF(x, y - h));
|
||||||
painterPath.closeSubpath();
|
painterPath.closeSubpath();
|
||||||
}
|
}
|
||||||
|
*/
|
|
@ -13,9 +13,10 @@ private:
|
||||||
bool existFatherLabelG;
|
bool existFatherLabelG;
|
||||||
QMap<QString, QString> styleMap;
|
QMap<QString, QString> styleMap;
|
||||||
std::shared_ptr<QXmlStreamReader> xmlReader;
|
std::shared_ptr<QXmlStreamReader> xmlReader;
|
||||||
QPolygonF transformPoints(QString points);
|
QPolygonF handleAttrPoints(QString points);
|
||||||
QMap<QString, QString> transformStyle(QString style);
|
QMap<QString, QString> handleAttrStyle(QString style);
|
||||||
void addEllipse(double cx, double cy, double h, double w, QPainterPath& painterPath);
|
void handleAttrTransform(QString transformStyle, QPainterPath& painterPath);
|
||||||
|
//void addEllipse(double cx, double cy, double h, double w, QPainterPath& painterPath);
|
||||||
void handleLabelG(QPainterPath& painterPath);
|
void handleLabelG(QPainterPath& painterPath);
|
||||||
void handleLabelPath(QPainterPath& painterPath);
|
void handleLabelPath(QPainterPath& painterPath);
|
||||||
void handleLabelRect(QPainterPath& painterPath);
|
void handleLabelRect(QPainterPath& painterPath);
|
||||||
|
|
|
@ -22,6 +22,12 @@ Point CubicBezier::calculateControlPoint(Point a, Point b) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double CubicBezier::ValueOfFunctionS(double t) {
|
||||||
|
double dxt = -3 * vX[0] * (1 - t) * (1 - t) + 3 * vX[1] * (1 - t) * (1 - 3 * t) + 3 * vX[2] * t * (2 - 3 * t) + 3 * vX[3] * t * t;
|
||||||
|
double dyt = -3 * vY[0] * (1 - t) * (1 - t) + 3 * vY[1] * (1 - t) * (1 - 3 * t) + 3 * vY[2] * t * (2 - 3 * t) + 3 * vY[3] * t * t;
|
||||||
|
return sqrt(dxt * dxt + dyt * dyt);
|
||||||
|
}
|
||||||
|
|
||||||
void CubicBezier::findPointsOfDivison(vector<double> &p, vector<double>& res) {
|
void CubicBezier::findPointsOfDivison(vector<double> &p, vector<double>& res) {
|
||||||
double a = (-p[0] + 3 * p[1] - 3 * p[2] + p[3]);
|
double a = (-p[0] + 3 * p[1] - 3 * p[2] + p[3]);
|
||||||
if (fabs(a) > eps) {
|
if (fabs(a) > eps) {
|
||||||
|
@ -55,20 +61,26 @@ void CubicBezier::transformToCubic() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubicBezier::splitBezierCubic(double t, vector<LinePtr>& res) {
|
void CubicBezier::splitBezierCubic(double t, vector<LinePtr>& res) {
|
||||||
LinePtr Lf(new CubicBezier());
|
|
||||||
float pt = 1 - t;
|
|
||||||
Point pointE = { getLineValueByT(t, false), getLineValueByT(t, true) };
|
Point pointE = { getLineValueByT(t, false), getLineValueByT(t, true) };
|
||||||
Point pointF = getPointByT(getPointByIndex(0), getPointByIndex(1), t);
|
Point pointF = getPointByT(getPointByIndex(0), getPointByIndex(1), t);
|
||||||
Point pointG = getPointByT(getPointByIndex(1), getPointByIndex(2), t);
|
Point pointG = getPointByT(getPointByIndex(1), getPointByIndex(2), t);
|
||||||
Point pointH = getPointByT(getPointByIndex(2), getPointByIndex(3), t);
|
Point pointH = getPointByT(getPointByIndex(2), getPointByIndex(3), t);
|
||||||
Lf->push_back(getPointByIndex(0));
|
vector<Point> vP; vP.clear();
|
||||||
Lf->push_back(pointF);
|
vP.push_back(getPointByIndex(0));
|
||||||
Lf->push_back(getPointByT(pointF, pointG, t));
|
vP.push_back(pointF);
|
||||||
Lf->push_back(pointE);
|
vP.push_back(getPointByT(pointF, pointG, t));
|
||||||
res.push_back(Lf);
|
vP.push_back(pointE);
|
||||||
|
LinePtr lf(new CubicBezier(vP));
|
||||||
|
double totalLen = getIntegralByT(1), len = getIntegralByT(t);
|
||||||
|
if (totalLen <= eps) return;
|
||||||
|
double ratePoint = (1 - len / totalLen) * rate.first + len / totalLen * rate.second;
|
||||||
|
lf->setRate({ rate.first, ratePoint });
|
||||||
|
res.push_back(lf);
|
||||||
setPointByIndex(0, pointE);
|
setPointByIndex(0, pointE);
|
||||||
setPointByIndex(1, getPointByT(pointG, pointH, t));
|
setPointByIndex(1, getPointByT(pointG, pointH, t));
|
||||||
setPointByIndex(2, pointH);
|
setPointByIndex(2, pointH);
|
||||||
|
updateLeftType();
|
||||||
|
setRate({ ratePoint, rate.second });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubicBezier::monotonization(vector <LinePtr>& res) {
|
void CubicBezier::monotonization(vector <LinePtr>& res) {
|
||||||
|
|
|
@ -11,12 +11,14 @@ namespace Renderer
|
||||||
static Point calculateControlPoint(Point a, Point b);
|
static Point calculateControlPoint(Point a, Point b);
|
||||||
static void findPointsOfDivison(std::vector<double>& p, std::vector<double>& res);
|
static void findPointsOfDivison(std::vector<double>& p, std::vector<double>& res);
|
||||||
void splitBezierCubic(double t, std::vector<LinePtr>& res);
|
void splitBezierCubic(double t, std::vector<LinePtr>& res);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual double findTByValue(double value, bool isY);
|
virtual double findTByValue(double value, bool isY);
|
||||||
virtual void monotonization(std::vector <LinePtr>& res);
|
virtual void monotonization(std::vector <LinePtr>& res);
|
||||||
virtual double getLineValueByT(double t, bool isY);
|
virtual double getLineValueByT(double t, bool isY);
|
||||||
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY);
|
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY);
|
||||||
virtual double getMinDistanceFromPoint(Point p);
|
virtual double getMinDistanceFromPoint(Point p);
|
||||||
|
virtual double ValueOfFunctionS(double t);
|
||||||
void transformToCubic();
|
void transformToCubic();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Line.h"
|
#include "Line.h"
|
||||||
|
#include <glm/detail/func_packing.hpp>
|
||||||
using namespace Renderer;
|
using namespace Renderer;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::pair;
|
using std::pair;
|
||||||
|
@ -14,14 +15,29 @@ Line::Line(vector<Point> Vp) {
|
||||||
vX.push_back(now.x);
|
vX.push_back(now.x);
|
||||||
vY.push_back(now.y);
|
vY.push_back(now.y);
|
||||||
}
|
}
|
||||||
|
updateLeftType();
|
||||||
|
rate = { 0, 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Line::updateLeftType() {
|
||||||
if (*vY.rbegin() < vY[0]) leftType = 0;
|
if (*vY.rbegin() < vY[0]) leftType = 0;
|
||||||
else leftType = 1;
|
else leftType = 1;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Line::size() {
|
int Line::size() {
|
||||||
return siz;
|
return siz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Line::setRate(std::pair<double, double> inRate) {
|
||||||
|
rate = inRate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint Line::getRate() {
|
||||||
|
return glm::packUnorm2x16(glm::vec2(rate.first, rate.second));
|
||||||
|
}
|
||||||
|
|
||||||
vector<Point> Line::toPointVector() const {
|
vector<Point> Line::toPointVector() const {
|
||||||
vector<Point> vL;
|
vector<Point> vL;
|
||||||
for (int i = 0; i < siz; i++) {
|
for (int i = 0; i < siz; i++) {
|
||||||
|
@ -152,3 +168,26 @@ bool Line::judgeIntersectionWithWidth(QVector4D bound, double width, int type) {
|
||||||
|| judgeOneSideIntersectionWithWidth(bound.x(), bound.y(), bound.w(), false, width, type)
|
|| judgeOneSideIntersectionWithWidth(bound.x(), bound.y(), bound.w(), false, width, type)
|
||||||
|| judgeOneSideIntersectionWithWidth(bound.z(), bound.y(), bound.w(), false, width, type);
|
|| judgeOneSideIntersectionWithWidth(bound.z(), bound.y(), bound.w(), false, width, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Line::getIntegralByT(double t) {
|
||||||
|
double T[12][12], err = 1, S = 0, tmpPow4 = 1;
|
||||||
|
T[1][1] = t * (ValueOfFunctionS(t) + ValueOfFunctionS(0)) / 2;
|
||||||
|
int n = 1, k = 0;
|
||||||
|
while (err > eps) {
|
||||||
|
++k; S = 0;
|
||||||
|
for (int i = 1; i <= n; i++) {
|
||||||
|
double x = t * (2 * i - 1) / 2;
|
||||||
|
S = S + ValueOfFunctionS(x);
|
||||||
|
}
|
||||||
|
tmpPow4 = 1;
|
||||||
|
T[k + 1][1] = (T[k][1] + t * S) / 2;
|
||||||
|
for (int m = 1; m <= k; m++) {
|
||||||
|
tmpPow4 *= 4;
|
||||||
|
T[k + 1][m + 1] = (tmpPow4 * T[k + 1][m] - T[k][m]) / (tmpPow4 - 1);
|
||||||
|
}
|
||||||
|
err = fabs(T[k + 1][k + 1] - T[k + 1][k]);
|
||||||
|
n <<= 1; t = t / 2;
|
||||||
|
if (k >= 8) break;
|
||||||
|
}
|
||||||
|
return T[k + 1][k + 1];
|
||||||
|
}
|
|
@ -49,21 +49,28 @@ namespace Renderer
|
||||||
protected:
|
protected:
|
||||||
std::vector<double> vX, vY;
|
std::vector<double> vX, vY;
|
||||||
int siz, leftType;
|
int siz, leftType;
|
||||||
|
std::pair<double, double> rate;
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<Line> LinePtr;
|
typedef std::shared_ptr<Line> LinePtr;
|
||||||
Line() :siz(0) {}
|
Line() : siz(0), leftType(0), rate({0, 1}) {}
|
||||||
Line(std::vector<Point> Vp);
|
Line(std::vector<Point> Vp);
|
||||||
int size();
|
int size();
|
||||||
|
bool setRate(std::pair<double, double> inRate);
|
||||||
|
uint getRate();
|
||||||
void clear();
|
void clear();
|
||||||
Point getBegin();
|
Point getBegin();
|
||||||
Point getEnd();
|
Point getEnd();
|
||||||
int direction(bool isY);
|
int direction(bool isY);
|
||||||
|
bool updateLeftType();
|
||||||
virtual double getLineValueByT(double t, bool isY) = 0;
|
virtual double getLineValueByT(double t, bool isY) = 0;
|
||||||
|
// s = sqrt(x^2+y^2);
|
||||||
|
virtual double ValueOfFunctionS(double t) = 0;
|
||||||
virtual void monotonization(std::vector <LinePtr>& res) = 0;
|
virtual void monotonization(std::vector <LinePtr>& res) = 0;
|
||||||
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY) = 0;
|
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY) = 0;
|
||||||
virtual double getMinDistanceFromPoint(Point p) = 0;
|
virtual double getMinDistanceFromPoint(Point p) = 0;
|
||||||
bool judgeOneSideIntersectionWithWidth(double xy, double l, double r, bool isY, double width, int type);
|
bool judgeOneSideIntersectionWithWidth(double xy, double l, double r, bool isY, double width, int type);
|
||||||
virtual double findTByValue(double value, bool isY) = 0;
|
virtual double findTByValue(double value, bool isY) = 0;
|
||||||
|
double getIntegralByT(double t);
|
||||||
bool judgeIntersectionWithWidth(QVector4D bound, double width, int type);
|
bool judgeIntersectionWithWidth(QVector4D bound, double width, int type);
|
||||||
bool judgeIntersection(QVector4D bound);
|
bool judgeIntersection(QVector4D bound);
|
||||||
int getPointSideOfLine(Point p);
|
int getPointSideOfLine(Point p);
|
||||||
|
|
|
@ -108,15 +108,30 @@ void LineTree::monotonization(vector<PointVector>& inLines, vector<std::shared_p
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineTree::simplifyLineVector() {
|
void LineTree::simplifyLineVector() {
|
||||||
|
bool canPut = false;
|
||||||
|
GLuint index = 0;
|
||||||
numLine = allLines.size();
|
numLine = allLines.size();
|
||||||
for (auto& nowLine : allLines) {
|
for (auto& nowLine : allLines) {
|
||||||
PointVector pointVector = nowLine->toPointVector();
|
PointVector pointVector = nowLine->toPointVector();
|
||||||
|
canPut = false;
|
||||||
|
index = 0;
|
||||||
for (Point& p : pointVector) {
|
for (Point& p : pointVector) {
|
||||||
int pointIndex = getPointIndex(p);
|
int pointIndex = getPointIndex(p);
|
||||||
lineIndexs.push_back(pointIndex);
|
if (pointVector.size() == 2) {
|
||||||
if (pointVector.size() == 2)
|
index = (pointIndex << 16) + pointIndex;
|
||||||
lineIndexs.push_back(pointIndex);
|
lineIndexs.push_back(index);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index <<= 16;
|
||||||
|
index += pointIndex;
|
||||||
|
if (canPut) {
|
||||||
|
lineIndexs.push_back(index);
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
canPut = !canPut;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
lineIndexs.push_back(nowLine->getRate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,15 +252,15 @@ vector<BvhTreeData> LineTree::getPointLineAndBvhTree(vector<float>& resPoints, v
|
||||||
for (auto& vectorIter : tmpPoints) {
|
for (auto& vectorIter : tmpPoints) {
|
||||||
resPoints.push_back(vectorIter.second.x);
|
resPoints.push_back(vectorIter.second.x);
|
||||||
resPoints.push_back(vectorIter.second.y);
|
resPoints.push_back(vectorIter.second.y);
|
||||||
vectorIter.second.show();
|
//vectorIter.second.show();
|
||||||
std::cout << '\n';
|
//std::cout << '\n';
|
||||||
}
|
}
|
||||||
// Ïß¼¯
|
// Ïß¼¯
|
||||||
for (auto& nowLineIndex : lineIndexs) {
|
for (auto& nowLineIndex : lineIndexs) {
|
||||||
resLines.push_back(nowLineIndex);
|
resLines.push_back(nowLineIndex);
|
||||||
std::cout << nowLineIndex << ' ';
|
//std::cout << nowLineIndex << ' ';
|
||||||
}
|
}
|
||||||
std::cout << '\n';
|
//std::cout << '\n';
|
||||||
// ·µ»Ø¹¹ÔìBvhTreeÊý¾Ý
|
// ·µ»Ø¹¹ÔìBvhTreeÊý¾Ý
|
||||||
vector<BvhTreeData> resBvhTreeData;
|
vector<BvhTreeData> resBvhTreeData;
|
||||||
for (auto& nowTreeNode : restOfTreeNodes) {
|
for (auto& nowTreeNode : restOfTreeNodes) {
|
||||||
|
@ -253,13 +268,13 @@ vector<BvhTreeData> LineTree::getPointLineAndBvhTree(vector<float>& resPoints, v
|
||||||
oneData.leftSon = resLines.size();
|
oneData.leftSon = resLines.size();
|
||||||
oneData.rightSon = 0;
|
oneData.rightSon = 0;
|
||||||
oneData.bound = nowTreeNode.bound;
|
oneData.bound = nowTreeNode.bound;
|
||||||
std::cout << nowTreeNode.lineSet.size() << ' ';
|
//std::cout << nowTreeNode.lineSet.size() << ' ';
|
||||||
resLines.push_back(nowTreeNode.lineSet.size());
|
resLines.push_back(nowTreeNode.lineSet.size());
|
||||||
for (auto& lineIndex : nowTreeNode.lineSet) {
|
for (auto& lineIndex : nowTreeNode.lineSet) {
|
||||||
resLines.push_back(lineIndex);
|
resLines.push_back(lineIndex);
|
||||||
std::cout << lineIndex << ' ';
|
//std::cout << lineIndex << ' ';
|
||||||
}
|
}
|
||||||
std::cout << '\n';
|
//std::cout << '\n';
|
||||||
resBvhTreeData.push_back(oneData);
|
resBvhTreeData.push_back(oneData);
|
||||||
}
|
}
|
||||||
return resBvhTreeData;
|
return resBvhTreeData;
|
||||||
|
|
|
@ -14,6 +14,10 @@ double StraightLine::getLineValueByT(double t, bool isY) {
|
||||||
return t * (valueEnd - valueBegin) + valueBegin;
|
return t * (valueEnd - valueBegin) + valueBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double StraightLine::ValueOfFunctionS(double t) {
|
||||||
|
return sqrt((vX[1] - vX[0]) * (vX[1] - vX[0]) + (vY[1] - vY[0]) * (vY[1] - vY[0]));
|
||||||
|
}
|
||||||
|
|
||||||
double StraightLine::findTByValue(double value, bool isY) {
|
double StraightLine::findTByValue(double value, bool isY) {
|
||||||
Point pointBegin = getPointByIndex(0), pointEnd = getPointByIndex(1);
|
Point pointBegin = getPointByIndex(0), pointEnd = getPointByIndex(1);
|
||||||
if (!isY) {
|
if (!isY) {
|
||||||
|
|
|
@ -11,5 +11,6 @@ namespace Renderer
|
||||||
virtual double findTByValue(double value, bool isY);
|
virtual double findTByValue(double value, bool isY);
|
||||||
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY);
|
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY);
|
||||||
virtual double getMinDistanceFromPoint(Point p);
|
virtual double getMinDistanceFromPoint(Point p);
|
||||||
|
virtual double ValueOfFunctionS(double t);
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
#include "ElementRendererTest.h"
|
#include "ElementRendererTest.h"
|
||||||
#include "Renderer/Painting/ElementStyle.h"
|
#include "Renderer/Painting/ElementStyle.h"
|
||||||
|
#include <util/SvgFileLoader.h>
|
||||||
|
|
||||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||||
using namespace Renderer;
|
using namespace Renderer;
|
||||||
|
@ -195,4 +196,5 @@ namespace UnitTest
|
||||||
a.exec();
|
a.exec();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,43 @@
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
#include <FramelessHelper/Core/private/framelessconfig_p.h>
|
#include <FramelessHelper/Core/private/framelessconfig_p.h>
|
||||||
|
#include <util/SvgFileLoader.h>
|
||||||
|
#include "Renderer/Painting/CubicBezier.h"
|
||||||
|
#include <Renderer/Painting/StraightLine.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||||
|
|
||||||
namespace UnitTest
|
namespace UnitTest
|
||||||
{
|
{
|
||||||
|
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case QtInfoMsg:
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);
|
||||||
|
break;
|
||||||
|
case QtDebugMsg:
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||||
|
break;
|
||||||
|
case QtWarningMsg:
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
|
||||||
|
break;
|
||||||
|
case QtCriticalMsg:
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);
|
||||||
|
break;
|
||||||
|
case QtFatalMsg:
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
Logger::WriteMessage(std::format("{}({},{}) {}\n",
|
||||||
|
QString(context.file).splitRef("\\").back().toLocal8Bit().data(),
|
||||||
|
context.line,
|
||||||
|
QString(context.function).splitRef("(").first().split(" ").back().split(":").back().toLocal8Bit().data(),
|
||||||
|
msg.toStdString()).c_str());
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||||
|
}
|
||||||
TEST_CLASS(UnitTest)
|
TEST_CLASS(UnitTest)
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -31,4 +62,37 @@ namespace UnitTest
|
||||||
a.exec();
|
a.exec();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TEST_CLASS(SvgLoaderTest)
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TEST_METHOD(LoadSvg)
|
||||||
|
{
|
||||||
|
qInstallMessageHandler(messageHandler);
|
||||||
|
QPainterPath painterPath;
|
||||||
|
SvgFileLoader svgloader;
|
||||||
|
svgloader.loadSvgFile("D:\\BigC\\Project\\ArchitectureColoredPainting\\svg\\test.svg", painterPath);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CLASS(CubicBezierTest)
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TEST_METHOD(CubicIntegral)
|
||||||
|
{
|
||||||
|
qInstallMessageHandler(messageHandler);
|
||||||
|
std::shared_ptr<Renderer::Line> line(new Renderer::CubicBezier());
|
||||||
|
line->push_back({ -1, -1 });
|
||||||
|
line->push_back({ -1, 1 });
|
||||||
|
line->push_back({ 1, 1 });
|
||||||
|
line->push_back({ 1, -1 });
|
||||||
|
vector<std::shared_ptr<Renderer::Line>> outLines;
|
||||||
|
line->monotonization(outLines);
|
||||||
|
for (auto line : outLines) {
|
||||||
|
qDebug() << line->getRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||||
|
<rect width="300" height="100"
|
||||||
|
style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)"
|
||||||
|
transform="translate(50 20)"/>
|
||||||
|
</svg>
|
||||||
|
|
After Width: | Height: | Size: 191 B |
Loading…
Reference in New Issue