diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e6ba8f7f..2532f607 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -169,6 +169,12 @@ MainWindow::MainWindow() "selection")); connect(pasteAct, &QAction::triggered, this, &MainWindow::paste); + QAction *markAsBranchAct = new QAction(tr("Mark as &Branch"), this); + connect(markAsBranchAct, &QAction::triggered, skeletonWidget->graphicsView(), &SkeletonEditGraphicsView::markAsBranch); + + QAction *markAsTrunkAct = new QAction(tr("Mark as &Trunk"), this); + connect(markAsTrunkAct, &QAction::triggered, skeletonWidget->graphicsView(), &SkeletonEditGraphicsView::markAsTrunk); + QAction *changeTurnaroundAct = new QAction(tr("&Change Turnaround..."), this); connect(changeTurnaroundAct, &QAction::triggered, skeletonWidget, &SkeletonWidget::changeTurnaround); @@ -187,6 +193,9 @@ MainWindow::MainWindow() editMenu->addAction(copyAct); editMenu->addAction(pasteAct); editMenu->addSeparator(); + editMenu->addAction(markAsBranchAct); + editMenu->addAction(markAsTrunkAct); + editMenu->addSeparator(); editMenu->addAction(changeTurnaroundAct); bool connectResult = false; diff --git a/src/skeletoneditgraphicsview.cpp b/src/skeletoneditgraphicsview.cpp index accba1cf..1649ff9d 100644 --- a/src/skeletoneditgraphicsview.cpp +++ b/src/skeletoneditgraphicsview.cpp @@ -508,6 +508,7 @@ void SkeletonEditGraphicsView::loadFromSnapshot(SkeletonSnapshot *snapshot) (*snapshotNode)["y"].toFloat() * yMul, (*snapshotNode)["radius"].toFloat() * radiusMul); nodeItem->setSideColorName((*snapshotNode)["sideColorName"]); + nodeItem->markAsBranch("true" == (*snapshotNode)["isBranch"]); nodeItemMap[nodeIterator->first] = nodeItem; } for (nodeIterator = snapshot->nodes.begin(); nodeIterator != snapshot->nodes.end(); nodeIterator++) { @@ -543,6 +544,7 @@ void SkeletonEditGraphicsView::saveToSnapshot(SkeletonSnapshot *snapshot) (*snapshotNode)["id"] = nodeId; (*snapshotNode)["sideColorName"] = nodeItem->sideColorName(); (*snapshotNode)["radius"] = QString("%1").arg(nodeItem->radius()); + (*snapshotNode)["isBranch"] = QString("%1").arg(nodeItem->isBranch() ? "true" : "false"); QPointF origin = nodeItem->origin(); (*snapshotNode)["x"] = QString("%1").arg(origin.x()); (*snapshotNode)["y"] = QString("%1").arg(origin.y()); @@ -574,4 +576,20 @@ void SkeletonEditGraphicsView::saveToSnapshot(SkeletonSnapshot *snapshot) } } +void SkeletonEditGraphicsView::markAsBranch() +{ + if (m_nextStartNodeItem) { + m_nextStartNodeItem->markAsBranch(true); + m_nextStartNodeItem->nextSidePair()->markAsBranch(true); + emit nodesChanged(); + } +} +void SkeletonEditGraphicsView::markAsTrunk() +{ + if (m_nextStartNodeItem) { + m_nextStartNodeItem->markAsBranch(false); + m_nextStartNodeItem->nextSidePair()->markAsBranch(false); + emit nodesChanged(); + } +} diff --git a/src/skeletoneditgraphicsview.h b/src/skeletoneditgraphicsview.h index d6f5730d..cd5e8206 100644 --- a/src/skeletoneditgraphicsview.h +++ b/src/skeletoneditgraphicsview.h @@ -20,6 +20,8 @@ signals: public slots: void turnOffAddNodeMode(); void turnOnAddNodeMode(); + void markAsBranch(); + void markAsTrunk(); public: SkeletonEditGraphicsView(QWidget *parent = 0); void updateBackgroundImage(const QImage &image); diff --git a/src/skeletoneditnodeitem.cpp b/src/skeletoneditnodeitem.cpp index 67340280..3b6225a8 100644 --- a/src/skeletoneditnodeitem.cpp +++ b/src/skeletoneditnodeitem.cpp @@ -8,12 +8,24 @@ SkeletonEditNodeItem::SkeletonEditNodeItem(const QRectF &rect, QGraphicsItem *pa m_checked(false), m_nextSidePair(NULL), m_sideColor(Theme::red), - m_sideColorName("red") + m_sideColorName("red"), + m_isBranch(false) { setData(0, "node"); updateAppearance(); } +void SkeletonEditNodeItem::markAsBranch(bool isBranch) +{ + m_isBranch = isBranch; + updateAppearance(); +} + +bool SkeletonEditNodeItem::isBranch() +{ + return m_isBranch; +} + const QString &SkeletonEditNodeItem::sideColorName() { return m_sideColorName; @@ -98,7 +110,7 @@ void SkeletonEditNodeItem::setOrigin(QPointF point) void SkeletonEditNodeItem::updateAppearance() { QColor penColor = m_sideColor; - penColor.setAlphaF(m_checked ? Theme::checkedAlpha : Theme::normalAlpha); + penColor.setAlphaF(m_checked ? Theme::checkedAlpha : (m_isBranch ? Theme::branchAlpha : Theme::normalAlpha)); QPen pen(penColor); pen.setWidth(Theme::skeletonNodeBorderSize); setPen(pen); diff --git a/src/skeletoneditnodeitem.h b/src/skeletoneditnodeitem.h index 701c5df9..8bb25bb9 100644 --- a/src/skeletoneditnodeitem.h +++ b/src/skeletoneditnodeitem.h @@ -19,6 +19,8 @@ public: void setHovered(bool hovered); bool checked(); void setChecked(bool checked); + void markAsBranch(bool isBranch); + bool isBranch(); SkeletonEditNodeItem *nextSidePair(); void setNextSidePair(SkeletonEditNodeItem *nodeItem); const QColor &sideColor(); @@ -32,6 +34,7 @@ private: SkeletonEditNodeItem *m_nextSidePair; QColor m_sideColor; QString m_sideColorName; + bool m_isBranch; private: void updateAppearance(); }; diff --git a/src/skeletonsnapshot.cpp b/src/skeletonsnapshot.cpp index bacfea69..ce3a1386 100644 --- a/src/skeletonsnapshot.cpp +++ b/src/skeletonsnapshot.cpp @@ -33,6 +33,71 @@ void SkeletonSnapshot::splitByConnectivity(std::vector *groups { std::map> nodeLinkMap; std::map>::iterator edgeIterator; + std::map neighborCountMap; + for (edgeIterator = edges.begin(); edgeIterator != edges.end(); edgeIterator++) { + neighborCountMap[edgeIterator->second["from"]]++; + neighborCountMap[edgeIterator->second["to"]]++; + } + int nextNewXnodeId = 1; + std::vector> newPendingEdges; + for (edgeIterator = edges.begin(); edgeIterator != edges.end(); ) { + std::map *oneNode = &nodes[edgeIterator->second["from"]]; + std::map *linkNode = &nodes[edgeIterator->second["to"]]; + if ("true" != (*oneNode)["isBranch"]) { + oneNode = &nodes[edgeIterator->second["to"]]; + linkNode = &nodes[edgeIterator->second["from"]]; + if ("true" != (*oneNode)["isBranch"]) { + edgeIterator++; + continue; + } else { + if (neighborCountMap[(*linkNode)["id"]] < 3) { + edgeIterator++; + continue; + } + } + } else { + if (neighborCountMap[(*linkNode)["id"]] < 3) { + edgeIterator++; + continue; + } + } + + if ("red" == (*oneNode)["sideColorName"]) { + QString nodeId = QString("nodex%1").arg(nextNewXnodeId++); + std::map *newNode = &nodes[nodeId]; + *newNode = *linkNode; + (*newNode)["id"] = nodeId; + (*newNode)["radius"] = (*newNode)["radius"].toFloat() / 2; + + std::map *pairNode = &nodes[(*oneNode)["nextSidePair"]]; + QString pairNodeId = QString("nodex%1").arg(nextNewXnodeId++); + std::map *newPairNode = &nodes[pairNodeId]; + *newPairNode = *pairNode; + (*newPairNode)["id"] = pairNodeId; + (*newPairNode)["radius"] = (*newPairNode)["radius"].toFloat() / 2; + + (*newNode)["nextSidePair"] = pairNodeId; + (*newPairNode)["nextSidePair"] = nodeId; + + newPendingEdges.push_back(std::make_pair((*oneNode)["id"], nodeId)); + } + + edgeIterator = edges.erase(edgeIterator); + } + int nextNewXedgeId = 1; + for (size_t i = 0; i < newPendingEdges.size(); i++) { + QString edgeId = QString("edgex%1").arg(nextNewXedgeId++); + std::map *newEdge = &edges[edgeId]; + (*newEdge)["id"] = edgeId; + (*newEdge)["from"] = newPendingEdges[i].first; + (*newEdge)["to"] = newPendingEdges[i].second; + + edgeId = QString("edgex%1").arg(nextNewXedgeId++); + newEdge = &edges[edgeId]; + (*newEdge)["id"] = edgeId; + (*newEdge)["from"] = nodes[newPendingEdges[i].first]["nextSidePair"]; + (*newEdge)["to"] = nodes[newPendingEdges[i].second]["nextSidePair"]; + } for (edgeIterator = edges.begin(); edgeIterator != edges.end(); edgeIterator++) { nodeLinkMap[edgeIterator->second["from"]].push_back(edgeIterator->second["to"]); nodeLinkMap[edgeIterator->second["to"]].push_back(edgeIterator->second["from"]); diff --git a/src/skeletontomesh.cpp b/src/skeletontomesh.cpp index 1501f9d1..7f05af89 100644 --- a/src/skeletontomesh.cpp +++ b/src/skeletontomesh.cpp @@ -236,6 +236,8 @@ Mesh *SkeletonToMesh::takeResultMesh() void SkeletonToMesh::process() { std::vector groups; + QRectF globalFront = m_snapshot.boundingBoxFront(); + QRectF globalSide = m_snapshot.boundingBoxSide(); m_snapshot.splitByConnectivity(&groups); std::vector meshIds; @@ -257,9 +259,9 @@ void SkeletonToMesh::process() std::map>::iterator nextSidePair = skeleton->nodes.find(nodeIterator->second["nextSidePair"]); if (nextSidePair == skeleton->nodes.end()) continue; - float x = (nodeIterator->second["x"].toFloat() - front.left()) / canvasHeight; - float y = (nodeIterator->second["y"].toFloat()) / canvasHeight; - float z = (nextSidePair->second["x"].toFloat() - side.left()) / canvasHeight; + float x = (nodeIterator->second["x"].toFloat() - globalFront.left()) / canvasHeight; + float y = (nodeIterator->second["y"].toFloat() - globalFront.top()) / canvasHeight; + float z = (nextSidePair->second["x"].toFloat() - globalSide.left()) / canvasHeight; float r = nodeIterator->second["radius"].toFloat() / canvasHeight; float t = nextSidePair->second["radius"].toFloat() / canvasHeight; int bmeshNodeId = meshlite_bmesh_add_node(meshliteContext, bmeshId, x, y, z, r, t); diff --git a/src/theme.cpp b/src/theme.cpp index b11a5c26..e8c60dce 100644 --- a/src/theme.cpp +++ b/src/theme.cpp @@ -18,6 +18,7 @@ QColor Theme::red = QColor(0xfc, 0x66, 0x21); QColor Theme::green = QColor(0xaa, 0xeb, 0xc4); QColor Theme::blue = QColor(0x2a, 0x5a, 0xac); float Theme::normalAlpha = 128.0 / 255; +float Theme::branchAlpha = 64.0 / 255; float Theme::checkedAlpha = 1.0; float Theme::fillAlpha = 50.0 / 255; int Theme::skeletonNodeBorderSize = 1; diff --git a/src/theme.h b/src/theme.h index dec3b7b2..d2be9c9d 100644 --- a/src/theme.h +++ b/src/theme.h @@ -12,6 +12,7 @@ public: static QColor blue; static float normalAlpha; static float checkedAlpha; + static float branchAlpha; static float fillAlpha; static int skeletonNodeBorderSize; static int skeletonEdgeWidth;