diff --git a/ArchitectureColoredPainting/res/Shaders/element.comp b/ArchitectureColoredPainting/res/Shaders/element.comp index fd09af8..511c470 100644 --- a/ArchitectureColoredPainting/res/Shaders/element.comp +++ b/ArchitectureColoredPainting/res/Shaders/element.comp @@ -1093,6 +1093,7 @@ void main() bool onVeryBegin = false; bool onVeryEnd = false; vec2 tangentEndLast; + vec2 tangentFirstBegin; uint lastHitIndex = 0; bool lastHitElement = false; hitElement = false; @@ -1108,7 +1109,19 @@ void main() pBegin = path[++pathIndex]; p3Last = pBegin; p2Last = pBegin; - onVeryBegin = true; + if(endType == 4) + { + //onVeryBegin = false; + vec2 lastP1 = path[pathSize-3]; + vec2 lastP2 = path[pathSize-2]; + vec2 lastP3 = path[pathSize-1]; + if (lastP3 != lastP2) + tangentEndLast = normalize(lastP3 - lastP2); + else + tangentEndLast = normalize(lastP3 - lastP1); + } + else + onVeryBegin = true; continue; } mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]); @@ -1119,7 +1132,13 @@ void main() vec2 pTemp = path[pathIndex + 1]; if (isinf(pTemp.x)) { - onVeryEnd = true; + if(endType == 4) + { + //onVeryEnd = false; + tangentBeginNext = tangentFirstBegin; + } + else + onVeryEnd = true; } else { @@ -1180,6 +1199,8 @@ void main() } } tangentEndLast = tangentEnd; + if(pathIndex == 0) + tangentFirstBegin = tangentBegin; } p3Last = p[3]; p2Last = p[2]; diff --git a/ArchitectureColoredPainting/src/Editor/LayerManager.cpp b/ArchitectureColoredPainting/src/Editor/LayerManager.cpp index 06f0170..b1d2e60 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerManager.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerManager.cpp @@ -13,8 +13,21 @@ LayerWrapper *LayerManager::getRoot() const } void LayerManager::paint(QPainter *painter, QSize size,LayerWrapper* selecetedLayer) const { + painter->save(); root->getCache(); root->paint(painter); + painter->restore(); + painter->save(); + // painter->setBrush(QBrush(Qt::white)); + //painter->setCompositionMode(QPainter::CompositionMode_Difference); + if (selecetedLayer != nullptr) + { + painter->setPen(QPen(Qt::gray, 2, Qt::DashLine)); + selecetedLayer->paintVisualBounding(painter); + //painter->setPen(QPen(Qt::gray, 2, Qt::DashDotLine)); + //selecetedLayer->paintVisualBounding(painter); + } + painter->restore(); } bool LayerManager::singleSelectedCheck() const { diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 1240eb2..d2f1453 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -284,7 +284,14 @@ int FolderLayerWrapper::getReferencedBy()const void LayerWrapper::paint(QPainter* painter, QTransform transform, bool force) { - + // if (this->selected) + // { + // painter->save(); + //painter->setPen(QPen(Qt::red, 2)); + //painter->setTransform(transform); + //painter->drawRect(this->cache.getBoundingRect()); + //painter->restore(); + // } } void FolderLayerWrapper::paint(QPainter* painter, QTransform transform, bool force) @@ -428,4 +435,21 @@ bool LeafLayerWrapper::referencingGroupElement() const bool LayerWrapper::canApplyStyles() const { return typeid(*this) == typeid(LeafLayerWrapper) && !referencingGroupElement(); +} + +void LayerWrapper::paintVisualBounding(QPainter* painter) const +{ + if (hidden) + return; + QTransform transform; + auto layer = this->parent; + while (layer != nullptr) + { + transform = transform * layer->property.transform; + layer = layer->parent; + } + painter->save(); + painter->setTransform(transform); + painter->drawRect(cache.getBoundingRect()); + painter->restore(); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 6312f12..c45ec21 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -75,6 +75,7 @@ class LayerWrapper virtual size_t referencedCount(bool excludeSelf = false) const; virtual bool deleteable(bool excludeSubTree = false) const; virtual bool referencingGroupElement() const; + virtual void paintVisualBounding(QPainter* painter) const; bool canApplyStyles() const; }; diff --git a/ArchitectureColoredPainting/src/Editor/PixelPath.cpp b/ArchitectureColoredPainting/src/Editor/PixelPath.cpp index 3087f39..e673504 100644 --- a/ArchitectureColoredPainting/src/Editor/PixelPath.cpp +++ b/ArchitectureColoredPainting/src/Editor/PixelPath.cpp @@ -78,7 +78,8 @@ PixelPath PixelPath::trans(QTransform& mat)const painter.setTransform(mat); painter.drawPixmap(0, 0, pixmap); result.painterPath.addPath(this->painterPath); - result.boundingRect = mat.mapRect(boundingRect); + result.painterPath = mat.map(result.painterPath); + result.boundingRect = result.painterPath.boundingRect(); return result; } diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp index dbe317c..410b8af 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp @@ -1,4 +1,5 @@ #include "PreviewWindow.h" +#include PreviewWindow::PreviewWindow(QWidget *parent) : QOpenGLWidget(parent) { @@ -84,7 +85,17 @@ void PreviewWindow::mouseMoveEvent(QMouseEvent* event) int dx = event->x() - m_lastPos.x(); int dy = event->y() - m_lastPos.y(); if (currentLayer != nullptr) { - if (event->buttons() & Qt::LeftButton) { + if (QApplication::keyboardModifiers() == Qt::ControlModifier && (event->buttons() & Qt::LeftButton)) + { + currentLayer->property.scale.setX(std::max(0.0, currentLayer->property.scale.x() + dx / 50.0)); + currentLayer->property.scale.setY(std::max(0.0, currentLayer->property.scale.y() + dy / 50.0)); + } + else if (QApplication::keyboardModifiers() == (Qt::ControlModifier | Qt::ShiftModifier) && (event->buttons() & Qt::LeftButton)) + { + currentLayer->property.scale.setX(std::max(0.0, currentLayer->property.scale.x() * (1.0 + dx / 50.0))); + currentLayer->property.scale.setY(std::max(0.0, currentLayer->property.scale.y() * (1.0 + dx / 50.0))); + } + else if (event->buttons() & Qt::LeftButton) { // 如果按下的是左键,那么平移图形 currentLayer->property.offset.setX(currentLayer->property.offset.x() + dx); currentLayer->property.offset.setY(currentLayer->property.offset.y() + dy); diff --git a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp index ce93afb..aa23ce6 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp +++ b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp @@ -83,9 +83,7 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr QPainterPath painterPath = pixelPath.getPainterPath(); QRectF bound = painterPath.boundingRect(); //qDebug() << leafLayer<<"------" << painterPath; - //qDebug() << transform; - // transform to initial painterPath - // transfrom to -1, 1 + // transform to -1, 1 QTransform trans; double maxLen = std::max(bound.width(), bound.height()); qDebug() << maxLen << bound; @@ -102,22 +100,19 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr auto baseStyles = leafLayer->styles.toBaseStyles(); Renderer::BaseElement element; element.contour = contour; - for (auto baseStyle : baseStyles) { + for (auto& baseStyle : baseStyles) { double lineWidth = 0; if (baseStyle.material->type() == Renderer::MaterialStyleType::kStroke) { - auto material = dynamic_cast(baseStyle.material.get()); - material->halfWidth = material->halfWidth / maxLen; + auto material = std::static_pointer_cast(baseStyle.material); + material->halfWidth /= maxLen; lineWidth = material->halfWidth; qDebug() << material->halfWidth; } - QRectF rect = painterPath.boundingRect(); - rect.setX(-lineWidth + rect.x()); - rect.setY(-lineWidth + rect.y()); - rect.setWidth(lineWidth * 2 + rect.width()); - rect.setHeight(lineWidth * 2 + rect.height()); - QPainterPath path; - path.addRect(rect); - rect = transform.map(path).boundingRect(); + QPainterPathStroker stroker; + stroker.setWidth(lineWidth); + stroker.setCapStyle(Qt::RoundCap); + QPainterPath strokePath = stroker.createStroke(painterPath); + auto rect = transform.map(strokePath).boundingRect(); elementTransform.bound = glm::vec4(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height()); qDebug() << elementTransform.bound.x << elementTransform.bound.y << elementTransform.bound.z << elementTransform.bound.z; transform = transform.inverted(); @@ -125,7 +120,7 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr transform.m11(), transform.m12(), transform.m21(), transform.m22(), transform.m31(), transform.m32() ); - qDebug() << transform; + //qDebug() << transform; elementTransform.zIndex = 0; element.style = baseStyle.material; diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp index 0d72542..9919f73 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp @@ -1,5 +1,6 @@ #include "MaterialStyleStroke.h" #include +#include using namespace Renderer; @@ -105,8 +106,8 @@ std::unique_ptr Renderer::MaterialStyleStroke::clone() const bool Renderer::MaterialStyleStroke::operator==(const MaterialStyle& m) const { - return type() == m.type() - && halfWidth == static_cast(m).halfWidth + return type() == m.type() + && halfWidth == static_cast(m).halfWidth && strokeType == static_cast(m).strokeType && endType == static_cast(m).endType && *materialStroke == *static_cast(m).materialStroke; @@ -117,4 +118,10 @@ float Renderer::MaterialStyleStroke::getHalfWidth() const return halfWidth; } - +#define endTypeBoxLabel(start, end) QStringLiteral(start##" -> "##end) +const std::array, 4> Renderer::MaterialStyleStroke::strokeEndTypeNames = { + std::pair{endTypeBoxLabel("圆头", "圆头"), StrokeEndType::kRound}, + std::pair{endTypeBoxLabel("平头", "圆头"), StrokeEndType::kFlatRound}, + std::pair{endTypeBoxLabel("圆头", "平头"), StrokeEndType::kRoundFlat}, + std::pair{endTypeBoxLabel("平头", "平头"), StrokeEndType::kFlat} +}; \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h index 29fd55b..e6bf8af 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h @@ -43,7 +43,7 @@ namespace Renderer }; enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 }; - enum class StrokeEndType { kRound = 0b00, kFlat = 0b11, kRoundFlat = 0b10, kFlatRound = 0b01 }; + enum class StrokeEndType { kRound = 0b00, kFlat = 0b11, kRoundFlat = 0b10, kFlatRound = 0b01, kClosed = 0b100/*用于封闭图形*/ }; class MaterialStyleStroke : public MaterialStyle { @@ -59,5 +59,6 @@ namespace Renderer StrokeType strokeType; StrokeEndType endType; std::shared_ptr materialStroke; + static const std::array, 4> strokeEndTypeNames; }; } diff --git a/UnitTest/ElementRendererTest.cpp b/UnitTest/ElementRendererTest.cpp index aba0474..5760980 100644 --- a/UnitTest/ElementRendererTest.cpp +++ b/UnitTest/ElementRendererTest.cpp @@ -42,17 +42,38 @@ namespace UnitTest { virtual std::vector toBaseStyles() const override { - return { BaseStyle(std::make_shared(), - std::make_shared( - std::make_shared(Material(QColor(255,255,0))))) }; + std::make_shared(std::make_shared(Material(QColor(255,255,0))))) }; + } + } style; + TestGLWidget w(style, path); + w.show(); + a.exec(); + } + TEST_METHOD(TestFillPlainAndStrokeRadialGradient) + { + QApplication a(argc, argv); + class Style : public Renderer::ElementStyle + { + virtual std::vector toBaseStyles() const override + { + std::map materialMap = { + {0.20, Material{QColor(255,255,255)}}, + {0.60, Material{QColor(165,176,207)}}, + {1.00, Material{QColor(58,64,151)}} + }; + return { BaseStyle(std::make_shared(), + std::make_shared( + std::make_shared(Material(QColor(255,255,0))))), + BaseStyle(std::make_shared(), + std::make_shared(10, StrokeType::kBothSides, StrokeEndType::kRound, + std::make_shared(materialMap, false))) }; } } style; TestGLWidget w(style, path); w.show(); a.exec(); } - }; TEST_CLASS(ElementRendererStokeTypeTest) diff --git a/UnitTest/UnitTest.cpp b/UnitTest/UnitTest.cpp index 25bcf67..0005c41 100644 --- a/UnitTest/UnitTest.cpp +++ b/UnitTest/UnitTest.cpp @@ -122,20 +122,6 @@ namespace UnitTest }; TEST_CLASS(PaintingUtilTest) { - TEST_METHOD(TransfromTest) - { - qInstallMessageHandler(messageHandler); - QPainterPath path; - path.addRect(0, 0, 20, 20); - QTransform trans; - qDebug() << path.boundingRect(); - //qDebug() << trans; - //qDebug() << acos(-0.707107); - glm::vec2 scale; - float rotate; - PaintingUtil::decomposeTransform(trans, rotate, scale); - qDebug() << rotate; - qDebug() << scale.x << scale.y; - } + }; } diff --git a/test.json b/test.json index 15441e2..ce11428 100644 --- a/test.json +++ b/test.json @@ -59,7 +59,7 @@ "name": "Leaf2", "styles": [ { - "enableEachSideIndependent": false, + "enableEachSideIndependent": true, "left": "AAAAQAEAIZwAf////1UA/w==", "right": "AADgQAAACJw=", "type": "stroke"