From 1bd1d580694c200a326c01bd524c8265aa582322 Mon Sep 17 00:00:00 2001 From: huxingyi Date: Sat, 19 Dec 2020 15:07:44 +0930 Subject: [PATCH] Clean up --- dust3d.pro | 3 - src/document.cpp | 1364 +--------------------------------- src/document.h | 338 ++------- src/parttreewidget.cpp | 30 +- src/regionfiller.cpp | 1496 -------------------------------------- src/regionfiller.h | 74 -- src/skeletondocument.cpp | 1217 ++++++++++++++++++++++++++++++- src/skeletondocument.h | 210 +++++- 8 files changed, 1494 insertions(+), 3238 deletions(-) delete mode 100644 src/regionfiller.cpp delete mode 100644 src/regionfiller.h diff --git a/dust3d.pro b/dust3d.pro index 74ed34e8..ba3598e4 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -394,9 +394,6 @@ HEADERS += src/proceduralanimation.h SOURCES += src/boundingboxmesh.cpp HEADERS += src/boundingboxmesh.h -SOURCES += src/regionfiller.cpp -HEADERS += src/regionfiller.h - SOURCES += src/meshwrapper.cpp HEADERS += src/meshwrapper.h diff --git a/src/document.cpp b/src/document.cpp index f20849e6..6f528ea1 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -23,59 +23,7 @@ unsigned long Document::m_maxSnapshot = 1000; Document::Document() : - SkeletonDocument(), - // public - textureImage(nullptr), - textureImageByteArray(nullptr), - textureNormalImage(nullptr), - textureNormalImageByteArray(nullptr), - textureMetalnessImage(nullptr), - textureMetalnessImageByteArray(nullptr), - textureRoughnessImage(nullptr), - textureRoughnessImageByteArray(nullptr), - textureAmbientOcclusionImage(nullptr), - textureAmbientOcclusionImageByteArray(nullptr), - rigType(RigType::None), - weldEnabled(true), - brushColor(Qt::white), - objectLocked(false), - // private - m_isResultMeshObsolete(false), - m_meshGenerator(nullptr), - m_resultMesh(nullptr), - m_paintedMesh(nullptr), - m_resultMeshNodesCutFaces(nullptr), - m_isMeshGenerationSucceed(true), - m_batchChangeRefCount(0), - m_currentObject(nullptr), - m_isTextureObsolete(false), - m_textureGenerator(nullptr), - m_isPostProcessResultObsolete(false), - m_postProcessor(nullptr), - m_postProcessedObject(new Object), - m_resultTextureMesh(nullptr), - m_textureImageUpdateVersion(0), - m_allPositionRelatedLocksEnabled(true), - m_smoothNormal(!Preferences::instance().flatShading()), - m_rigGenerator(nullptr), - m_resultRigWeightMesh(nullptr), - m_resultRigBones(nullptr), - m_resultRigWeights(nullptr), - m_isRigObsolete(false), - m_riggedObject(new Object), - m_currentRigSucceed(false), - m_materialPreviewsGenerator(nullptr), - m_motionsGenerator(nullptr), - m_meshGenerationId(0), - m_nextMeshGenerationId(1), - m_scriptRunner(nullptr), - m_isScriptResultObsolete(false), - m_texturePainter(nullptr), - m_isMouseTargetResultObsolete(false), - m_paintMode(PaintMode::None), - m_mousePickRadius(0.02), - m_generatedCacheContext(nullptr), - m_texturePainterContext(nullptr) + SkeletonDocument() { connect(&Preferences::instance(), &Preferences::partColorChanged, this, &Document::applyPreferencePartColorChange); connect(&Preferences::instance(), &Preferences::flatShadingChanged, this, &Document::applyPreferenceFlatShadingChange); @@ -130,315 +78,6 @@ void Document::uiReady() emit editModeChanged(); } -void Document::Document::enableAllPositionRelatedLocks() -{ - m_allPositionRelatedLocksEnabled = true; -} - -void Document::Document::disableAllPositionRelatedLocks() -{ - m_allPositionRelatedLocksEnabled = false; -} - -void Document::reduceNode(QUuid nodeId) -{ - const SkeletonNode *node = findNode(nodeId); - if (nullptr == node) { - qDebug() << "Find node failed:" << nodeId; - return; - } - if (node->edgeIds.size() != 2) { - return; - } - QUuid firstEdgeId = node->edgeIds[0]; - QUuid secondEdgeId = node->edgeIds[1]; - const SkeletonEdge *firstEdge = findEdge(firstEdgeId); - if (nullptr == firstEdge) { - qDebug() << "Find edge failed:" << firstEdgeId; - return; - } - const SkeletonEdge *secondEdge = findEdge(secondEdgeId); - if (nullptr == secondEdge) { - qDebug() << "Find edge failed:" << secondEdgeId; - return; - } - QUuid firstNeighborNodeId = firstEdge->neighborOf(nodeId); - QUuid secondNeighborNodeId = secondEdge->neighborOf(nodeId); - removeNode(nodeId); - addEdge(firstNeighborNodeId, secondNeighborNodeId); -} - -void Document::breakEdge(QUuid edgeId) -{ - const SkeletonEdge *edge = findEdge(edgeId); - if (nullptr == edge) { - qDebug() << "Find edge failed:" << edgeId; - return; - } - if (edge->nodeIds.size() != 2) { - return; - } - QUuid firstNodeId = edge->nodeIds[0]; - QUuid secondNodeId = edge->nodeIds[1]; - const SkeletonNode *firstNode = findNode(firstNodeId); - if (nullptr == firstNode) { - qDebug() << "Find node failed:" << firstNodeId; - return; - } - const SkeletonNode *secondNode = findNode(secondNodeId); - if (nullptr == secondNode) { - qDebug() << "Find node failed:" << secondNodeId; - return; - } - QVector3D firstOrigin(firstNode->getX(), firstNode->getY(), firstNode->getZ()); - QVector3D secondOrigin(secondNode->getX(), secondNode->getY(), secondNode->getZ()); - QVector3D middleOrigin = (firstOrigin + secondOrigin) / 2; - float middleRadius = (firstNode->radius + secondNode->radius) / 2; - removeEdge(edgeId); - QUuid middleNodeId = createNode(QUuid::createUuid(), middleOrigin.x(), middleOrigin.y(), middleOrigin.z(), middleRadius, firstNodeId); - if (middleNodeId.isNull()) { - qDebug() << "Add middle node failed"; - return; - } - addEdge(middleNodeId, secondNodeId); -} - -void Document::reverseEdge(QUuid edgeId) -{ - SkeletonEdge *edge = (SkeletonEdge *)findEdge(edgeId); - if (nullptr == edge) { - qDebug() << "Find edge failed:" << edgeId; - return; - } - if (edge->nodeIds.size() != 2) { - return; - } - std::swap(edge->nodeIds[0], edge->nodeIds[1]); - auto part = partMap.find(edge->partId); - if (part != partMap.end()) - part->second.dirty = true; - emit edgeReversed(edgeId); - emit skeletonChanged(); -} - -void Document::removeEdge(QUuid edgeId) -{ - const SkeletonEdge *edge = findEdge(edgeId); - if (nullptr == edge) { - qDebug() << "Find edge failed:" << edgeId; - return; - } - if (isPartReadonly(edge->partId)) - return; - const SkeletonPart *oldPart = findPart(edge->partId); - if (nullptr == oldPart) { - qDebug() << "Find part failed:" << edge->partId; - return; - } - QString nextPartName = oldPart->name; - QUuid oldPartId = oldPart->id; - std::vector> groups; - splitPartByEdge(&groups, edgeId); - std::vector> newPartNodeNumMap; - std::vector newPartIds; - for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) { - const auto newUuid = QUuid::createUuid(); - SkeletonPart &part = partMap[newUuid]; - part.id = newUuid; - part.copyAttributes(*oldPart); - part.name = nextPartName; - for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) { - auto nodeIt = nodeMap.find(*nodeIdIt); - if (nodeIt == nodeMap.end()) { - qDebug() << "Find node failed:" << *nodeIdIt; - continue; - } - nodeIt->second.partId = part.id; - part.nodeIds.push_back(nodeIt->first); - for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - qDebug() << "Find edge failed:" << *edgeIdIt; - continue; - } - edgeIt->second.partId = part.id; - } - } - addPartToComponent(part.id, findComponentParentId(part.componentId)); - newPartNodeNumMap.push_back({part.id, part.nodeIds.size()}); - newPartIds.push_back(part.id); - emit partAdded(part.id); - } - for (auto nodeIdIt = edge->nodeIds.begin(); nodeIdIt != edge->nodeIds.end(); nodeIdIt++) { - auto nodeIt = nodeMap.find(*nodeIdIt); - if (nodeIt == nodeMap.end()) { - qDebug() << "Find node failed:" << *nodeIdIt; - continue; - } - nodeIt->second.edgeIds.erase(std::remove(nodeIt->second.edgeIds.begin(), nodeIt->second.edgeIds.end(), edgeId), nodeIt->second.edgeIds.end()); - emit nodeOriginChanged(nodeIt->first); - } - edgeMap.erase(edgeId); - emit edgeRemoved(edgeId); - removePart(oldPartId); - - if (!newPartNodeNumMap.empty()) { - std::sort(newPartNodeNumMap.begin(), newPartNodeNumMap.end(), [&]( - const std::pair &first, const std::pair &second) { - return first.second > second.second; - }); - updateLinkedPart(oldPartId, newPartNodeNumMap[0].first); - } - - emit skeletonChanged(); -} - -void Document::removeNode(QUuid nodeId) -{ - const SkeletonNode *node = findNode(nodeId); - if (nullptr == node) { - qDebug() << "Find node failed:" << nodeId; - return; - } - if (isPartReadonly(node->partId)) - return; - const SkeletonPart *oldPart = findPart(node->partId); - if (nullptr == oldPart) { - qDebug() << "Find part failed:" << node->partId; - return; - } - QString nextPartName = oldPart->name; - QUuid oldPartId = oldPart->id; - std::vector> groups; - splitPartByNode(&groups, nodeId); - std::vector> newPartNodeNumMap; - std::vector newPartIds; - for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) { - const auto newUuid = QUuid::createUuid(); - SkeletonPart &part = partMap[newUuid]; - part.id = newUuid; - part.copyAttributes(*oldPart); - part.name = nextPartName; - for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) { - auto nodeIt = nodeMap.find(*nodeIdIt); - if (nodeIt == nodeMap.end()) { - qDebug() << "Find node failed:" << *nodeIdIt; - continue; - } - nodeIt->second.partId = part.id; - part.nodeIds.push_back(nodeIt->first); - for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - qDebug() << "Find edge failed:" << *edgeIdIt; - continue; - } - edgeIt->second.partId = part.id; - } - } - addPartToComponent(part.id, findComponentParentId(part.componentId)); - newPartNodeNumMap.push_back({part.id, part.nodeIds.size()}); - newPartIds.push_back(part.id); - emit partAdded(part.id); - } - for (auto edgeIdIt = node->edgeIds.begin(); edgeIdIt != node->edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - qDebug() << "Find edge failed:" << *edgeIdIt; - continue; - } - QUuid neighborId = edgeIt->second.neighborOf(nodeId); - auto nodeIt = nodeMap.find(neighborId); - if (nodeIt == nodeMap.end()) { - qDebug() << "Find node failed:" << neighborId; - continue; - } - nodeIt->second.edgeIds.erase(std::remove(nodeIt->second.edgeIds.begin(), nodeIt->second.edgeIds.end(), *edgeIdIt), nodeIt->second.edgeIds.end()); - edgeMap.erase(*edgeIdIt); - emit edgeRemoved(*edgeIdIt); - } - nodeMap.erase(nodeId); - emit nodeRemoved(nodeId); - removePart(oldPartId); - - if (!newPartNodeNumMap.empty()) { - std::sort(newPartNodeNumMap.begin(), newPartNodeNumMap.end(), [&]( - const std::pair &first, const std::pair &second) { - return first.second > second.second; - }); - updateLinkedPart(oldPartId, newPartNodeNumMap[0].first); - } - - emit skeletonChanged(); -} - -void Document::addNode(float x, float y, float z, float radius, QUuid fromNodeId) -{ - createNode(QUuid::createUuid(), x, y, z, radius, fromNodeId); -} - -void Document::addNodeWithId(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId) -{ - createNode(nodeId, x, y, z, radius, fromNodeId); -} - -QUuid Document::createNode(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId) -{ - QUuid partId; - const SkeletonNode *fromNode = nullptr; - bool newPartAdded = false; - if (fromNodeId.isNull()) { - const auto newUuid = QUuid::createUuid(); - SkeletonPart &part = partMap[newUuid]; - part.id = newUuid; - partId = part.id; - emit partAdded(partId); - newPartAdded = true; - } else { - fromNode = findNode(fromNodeId); - if (nullptr == fromNode) { - qDebug() << "Find node failed:" << fromNodeId; - return QUuid(); - } - partId = fromNode->partId; - if (isPartReadonly(partId)) - return QUuid(); - auto part = partMap.find(partId); - if (part != partMap.end()) - part->second.dirty = true; - } - SkeletonNode node(nodeId); - node.partId = partId; - node.setRadius(radius); - node.setX(x); - node.setY(y); - node.setZ(z); - nodeMap[node.id] = node; - partMap[partId].nodeIds.push_back(node.id); - - emit nodeAdded(node.id); - - if (nullptr != fromNode) { - SkeletonEdge edge; - edge.partId = partId; - edge.nodeIds.push_back(fromNode->id); - edge.nodeIds.push_back(node.id); - edgeMap[edge.id] = edge; - - nodeMap[node.id].edgeIds.push_back(edge.id); - nodeMap[fromNode->id].edgeIds.push_back(edge.id); - - emit edgeAdded(edge.id); - } - - if (newPartAdded) - addPartToComponent(partId, m_currentCanvasComponentId); - - emit skeletonChanged(); - - return node.id; -} - void Document::addMotion(QUuid motionId, QString name, std::map parameters) { QUuid newMotionId = motionId; @@ -504,121 +143,6 @@ bool Document::originSettled() const return !qFuzzyIsNull(getOriginX()) && !qFuzzyIsNull(getOriginY()) && !qFuzzyIsNull(getOriginZ()); } -void Document::addEdge(QUuid fromNodeId, QUuid toNodeId) -{ - if (findEdgeByNodes(fromNodeId, toNodeId)) { - qDebug() << "Add edge but edge already existed:" << fromNodeId << toNodeId; - return; - } - - const SkeletonNode *fromNode = nullptr; - const SkeletonNode *toNode = nullptr; - bool toPartRemoved = false; - - fromNode = findNode(fromNodeId); - if (nullptr == fromNode) { - qDebug() << "Find node failed:" << fromNodeId; - return; - } - - if (isPartReadonly(fromNode->partId)) - return; - - toNode = findNode(toNodeId); - if (nullptr == toNode) { - qDebug() << "Find node failed:" << toNodeId; - return; - } - - if (isPartReadonly(toNode->partId)) - return; - - QUuid toPartId = toNode->partId; - - auto fromPart = partMap.find(fromNode->partId); - if (fromPart == partMap.end()) { - qDebug() << "Find part failed:" << fromNode->partId; - return; - } - - fromPart->second.dirty = true; - - if (fromNode->partId != toNode->partId) { - toPartRemoved = true; - std::vector toGroup; - std::set visitMap; - joinNodeAndNeiborsToGroup(&toGroup, toNodeId, &visitMap); - for (auto nodeIdIt = toGroup.begin(); nodeIdIt != toGroup.end(); nodeIdIt++) { - auto nodeIt = nodeMap.find(*nodeIdIt); - if (nodeIt == nodeMap.end()) { - qDebug() << "Find node failed:" << *nodeIdIt; - continue; - } - nodeIt->second.partId = fromNode->partId; - fromPart->second.nodeIds.push_back(nodeIt->first); - for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - qDebug() << "Find edge failed:" << *edgeIdIt; - continue; - } - edgeIt->second.partId = fromNode->partId; - } - } - } - - SkeletonEdge edge; - edge.partId = fromNode->partId; - edge.nodeIds.push_back(fromNode->id); - edge.nodeIds.push_back(toNodeId); - edgeMap[edge.id] = edge; - - nodeMap[toNodeId].edgeIds.push_back(edge.id); - nodeMap[fromNode->id].edgeIds.push_back(edge.id); - - emit edgeAdded(edge.id); - - if (toPartRemoved) { - updateLinkedPart(toPartId, fromNode->partId); - removePart(toPartId); - } - - emit skeletonChanged(); -} - -void Document::updateLinkedPart(QUuid oldPartId, QUuid newPartId) -{ - for (auto &partIt: partMap) { - if (partIt.second.cutFaceLinkedId == oldPartId) { - partIt.second.dirty = true; - partIt.second.setCutFaceLinkedId(newPartId); - } - } - std::set dirtyPartIds; - for (auto &nodeIt: nodeMap) { - if (nodeIt.second.cutFaceLinkedId == oldPartId) { - dirtyPartIds.insert(nodeIt.second.partId); - nodeIt.second.setCutFaceLinkedId(newPartId); - } - } - for (const auto &partId: dirtyPartIds) { - SkeletonPart *part = (SkeletonPart *)findPart(partId); - if (nullptr == part) - continue; - part->dirty = true; - } -} - -const Component *Document::findComponent(QUuid componentId) const -{ - if (componentId.isNull()) - return &rootComponent; - auto it = componentMap.find(componentId); - if (it == componentMap.end()) - return nullptr; - return &it->second; -} - const Material *Document::findMaterial(QUuid materialId) const { auto it = materialMap.find(materialId); @@ -635,141 +159,6 @@ const Motion *Document::findMotion(QUuid motionId) const return &it->second; } -void Document::scaleNodeByAddRadius(QUuid nodeId, float amount) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - qDebug() << "Find node failed:" << nodeId; - return; - } - if (isPartReadonly(it->second.partId)) - return; - if (radiusLocked) - return; - it->second.setRadius(it->second.radius + amount); - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeRadiusChanged(nodeId); - emit skeletonChanged(); -} - -bool Document::isPartReadonly(QUuid partId) const -{ - const SkeletonPart *part = findPart(partId); - if (nullptr == part) { - qDebug() << "Find part failed:" << partId; - return true; - } - return part->locked || !part->visible; -} - -void Document::moveNodeBy(QUuid nodeId, float x, float y, float z) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - qDebug() << "Find node failed:" << nodeId; - return; - } - if (m_allPositionRelatedLocksEnabled && isPartReadonly(it->second.partId)) - return; - bool changed = false; - if (!(m_allPositionRelatedLocksEnabled && xlocked)) { - it->second.addX(x); - changed = true; - } - if (!(m_allPositionRelatedLocksEnabled && ylocked)) { - it->second.addY(y); - changed = true; - } - if (!(m_allPositionRelatedLocksEnabled && zlocked)) { - it->second.addZ(z); - changed = true; - } - if (!changed) - return; - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeOriginChanged(nodeId); - emit skeletonChanged(); -} - -void Document::moveOriginBy(float x, float y, float z) -{ - if (!(m_allPositionRelatedLocksEnabled && xlocked)) - addOriginX(x); - if (!(m_allPositionRelatedLocksEnabled && ylocked)) - addOriginY(y); - if (!(m_allPositionRelatedLocksEnabled && zlocked)) - addOriginZ(z); - markAllDirty(); - emit originChanged(); - emit skeletonChanged(); -} - -void Document::setNodeOrigin(QUuid nodeId, float x, float y, float z) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - qDebug() << "Find node failed:" << nodeId; - return; - } - if ((m_allPositionRelatedLocksEnabled && isPartReadonly(it->second.partId))) - return; - if (!(m_allPositionRelatedLocksEnabled && xlocked)) - it->second.setX(x); - if (!(m_allPositionRelatedLocksEnabled && ylocked)) - it->second.setY(y); - if (!(m_allPositionRelatedLocksEnabled && zlocked)) - it->second.setZ(z); - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeOriginChanged(nodeId); - emit skeletonChanged(); -} - -void Document::setNodeRadius(QUuid nodeId, float radius) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - qDebug() << "Find node failed:" << nodeId; - return; - } - if (isPartReadonly(it->second.partId)) - return; - if (!radiusLocked) - it->second.setRadius(radius); - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeRadiusChanged(nodeId); - emit skeletonChanged(); -} - -void Document::switchNodeXZ(QUuid nodeId) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - qDebug() << "Find node failed:" << nodeId; - return; - } - if (isPartReadonly(it->second.partId)) - return; - { - float oldX = it->second.getX(); - float oldZ = it->second.getZ(); - it->second.setX(oldZ); - it->second.setZ(oldX); - } - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeOriginChanged(nodeId); - emit skeletonChanged(); -} - void Document::setNodeBoneMark(QUuid nodeId, BoneMark mark) { auto it = nodeMap.find(nodeId); @@ -966,82 +355,6 @@ void Document::setPaintMode(PaintMode mode) paint(); } -void Document::joinNodeAndNeiborsToGroup(std::vector *group, QUuid nodeId, std::set *visitMap, QUuid noUseEdgeId) -{ - if (nodeId.isNull() || visitMap->find(nodeId) != visitMap->end()) - return; - const SkeletonNode *node = findNode(nodeId); - if (nullptr == node) { - qDebug() << "Find node failed:" << nodeId; - return; - } - visitMap->insert(nodeId); - group->push_back(nodeId); - for (auto edgeIt = node->edgeIds.begin(); edgeIt != node->edgeIds.end(); edgeIt++) { - if (noUseEdgeId == *edgeIt) - continue; - const SkeletonEdge *edge = findEdge(*edgeIt); - if (nullptr == edge) { - qDebug() << "Find edge failed:" << *edgeIt; - continue; - } - for (auto nodeIt = edge->nodeIds.begin(); nodeIt != edge->nodeIds.end(); nodeIt++) { - joinNodeAndNeiborsToGroup(group, *nodeIt, visitMap, noUseEdgeId); - } - } -} - -void Document::splitPartByNode(std::vector> *groups, QUuid nodeId) -{ - const SkeletonNode *node = findNode(nodeId); - std::set visitMap; - visitMap.insert(nodeId); - for (auto edgeIt = node->edgeIds.begin(); edgeIt != node->edgeIds.end(); edgeIt++) { - std::vector group; - const SkeletonEdge *edge = findEdge(*edgeIt); - if (nullptr == edge) { - qDebug() << "Find edge failed:" << *edgeIt; - continue; - } - joinNodeAndNeiborsToGroup(&group, edge->neighborOf(nodeId), &visitMap, *edgeIt); - if (!group.empty()) - groups->push_back(group); - } -} - -void Document::splitPartByEdge(std::vector> *groups, QUuid edgeId) -{ - const SkeletonEdge *edge = findEdge(edgeId); - if (nullptr == edge) { - qDebug() << "Find edge failed:" << edgeId; - return; - } - std::set visitMap; - for (auto nodeIt = edge->nodeIds.begin(); nodeIt != edge->nodeIds.end(); nodeIt++) { - std::vector group; - joinNodeAndNeiborsToGroup(&group, *nodeIt, &visitMap, edgeId); - if (!group.empty()) - groups->push_back(group); - } -} - -void Document::resetDirtyFlags() -{ - for (auto &part: partMap) { - part.second.dirty = false; - } - for (auto &component: componentMap) { - component.second.dirty = false; - } -} - -void Document::markAllDirty() -{ - for (auto &part: partMap) { - part.second.dirty = true; - } -} - void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeIds, DocumentToSnapshotFor forWhat, const std::set &limitMotionIds, @@ -1059,7 +372,7 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId if (!part) continue; limitPartIds.insert(node->partId); - const Component *component = findComponent(part->componentId); + const SkeletonComponent *component = findComponent(part->componentId); while (component) { limitComponentIds.insert(component->id); if (component->id.isNull()) @@ -1127,8 +440,6 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId part["countershaded"] = "true"; if (partIt.second.smooth) part["smooth"] = "true"; - //if (partIt.second.gridded) - // part["gridded"] = "true"; snapshot->parts[part["id"]] = part; } for (const auto &nodeIt: nodeMap) { @@ -1267,90 +578,6 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId } } -void Document::createSinglePartFromEdges(const std::vector &nodes, - const std::vector> &edges) -{ - std::vector newAddedNodeIds; - std::vector newAddedEdgeIds; - std::vector newAddedPartIds; - std::map nodeIndexToIdMap; - - QUuid partId = QUuid::createUuid(); - - Component component(QUuid(), partId.toString(), "partId"); - component.combineMode = CombineMode::Normal; - componentMap[component.id] = component; - rootComponent.addChild(component.id); - - auto &newPart = partMap[partId]; - newPart.id = partId; - newPart.componentId = component.id; - newAddedPartIds.push_back(newPart.id); - - auto nodeToId = [&](size_t nodeIndex) { - auto findId = nodeIndexToIdMap.find(nodeIndex); - if (findId != nodeIndexToIdMap.end()) - return findId->second; - const auto &position = nodes[nodeIndex]; - SkeletonNode newNode; - newNode.partId = newPart.id; - newNode.setX(getOriginX() + position.x()); - newNode.setY(getOriginY() - position.y()); - newNode.setZ(getOriginZ() - position.z()); - newNode.setRadius(0); - nodeMap[newNode.id] = newNode; - newPart.nodeIds.push_back(newNode.id); - newAddedNodeIds.push_back(newNode.id); - nodeIndexToIdMap.insert({nodeIndex, newNode.id}); - return newNode.id; - }; - - for (const auto &edge: edges) { - QUuid firstNodeId = nodeToId(edge.first); - QUuid secondNodeId = nodeToId(edge.second); - - SkeletonEdge newEdge; - newEdge.nodeIds.push_back(firstNodeId); - newEdge.nodeIds.push_back(secondNodeId); - newEdge.partId = newPart.id; - - nodeMap[firstNodeId].edgeIds.push_back(newEdge.id); - nodeMap[secondNodeId].edgeIds.push_back(newEdge.id); - - newAddedEdgeIds.push_back(newEdge.id); - - edgeMap[newEdge.id] = newEdge; - } - - for (const auto &nodeIt: newAddedNodeIds) { - qDebug() << "new node:" << nodeIt; - emit nodeAdded(nodeIt); - } - for (const auto &edgeIt: newAddedEdgeIds) { - qDebug() << "new edge:" << edgeIt; - emit edgeAdded(edgeIt); - } - for (const auto &partIt: newAddedPartIds) { - qDebug() << "new part:" << partIt; - emit partAdded(partIt); - } - - for (const auto &partIt : newAddedPartIds) { - emit partVisibleStateChanged(partIt); - } - - emit uncheckAll(); - for (const auto &nodeIt: newAddedNodeIds) { - emit checkNode(nodeIt); - } - for (const auto &edgeIt: newAddedEdgeIds) { - emit checkEdge(edgeIt); - } - - emit componentChildrenChanged(QUuid()); - emit skeletonChanged(); -} - void Document::updateObject(Object *object) { delete m_postProcessedObject; @@ -1518,7 +745,6 @@ void Document::addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource sou part.materialId = oldNewIdMap[QUuid(materialIdIt->second)]; part.countershaded = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "countershaded")); part.smooth = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "smooth")); - //part.gridded = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "gridded"));; newAddedPartIds.insert(part.id); } for (const auto &it: cutFaceLinkedIdModifyMap) { @@ -1605,7 +831,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource sou for (const auto &componentKv: snapshot.components) { QString linkData = valueOfKeyInMapOrEmpty(componentKv.second, "linkData"); QString linkDataType = valueOfKeyInMapOrEmpty(componentKv.second, "linkDataType"); - Component component(QUuid(), linkData, linkDataType); + SkeletonComponent component(QUuid(), linkData, linkDataType); oldNewIdMap[QUuid(componentKv.first)] = component.id; component.name = valueOfKeyInMapOrEmpty(componentKv.second, "name"); component.expanded = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "expanded")); @@ -1715,7 +941,7 @@ void Document::silentReset() materialMap.clear(); materialIdList.clear(); motionMap.clear(); - rootComponent = Component(); + rootComponent = SkeletonComponent(); removeRigResults(); } @@ -2155,39 +1381,11 @@ const Object &Document::currentPostProcessedObject() const return *m_postProcessedObject; } -void Document::setPartLockState(QUuid partId, bool locked) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - qDebug() << "Part not found:" << partId; - return; - } - if (part->second.locked == locked) - return; - part->second.locked = locked; - emit partLockStateChanged(partId); - emit optionsChanged(); -} - -void Document::setPartVisibleState(QUuid partId, bool visible) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - qDebug() << "Part not found:" << partId; - return; - } - if (part->second.visible == visible) - return; - part->second.visible = visible; - emit partVisibleStateChanged(partId); - emit optionsChanged(); -} - void Document::setComponentCombineMode(QUuid componentId, CombineMode combineMode) { auto component = componentMap.find(componentId); if (component == componentMap.end()) { - qDebug() << "Component not found:" << componentId; + qDebug() << "SkeletonComponent not found:" << componentId; return; } if (component->second.combineMode == combineMode) @@ -2213,400 +1411,6 @@ void Document::setPartSubdivState(QUuid partId, bool subdived) emit skeletonChanged(); } -void Document::setPartDisableState(QUuid partId, bool disabled) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - qDebug() << "Part not found:" << partId; - return; - } - if (part->second.disabled == disabled) - return; - part->second.disabled = disabled; - part->second.dirty = true; - emit partDisableStateChanged(partId); - emit skeletonChanged(); -} - -const Component *Document::findComponentParent(QUuid componentId) const -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - qDebug() << "Component not found:" << componentId; - return nullptr; - } - - if (component->second.parentId.isNull()) - return &rootComponent; - - return (Component *)findComponent(component->second.parentId); -} - -QUuid Document::findComponentParentId(QUuid componentId) const -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - qDebug() << "Component not found:" << componentId; - return QUuid(); - } - - return component->second.parentId; -} - -void Document::moveComponentUp(QUuid componentId) -{ - Component *parent = (Component *)findComponentParent(componentId); - if (nullptr == parent) - return; - - QUuid parentId = findComponentParentId(componentId); - - parent->moveChildUp(componentId); - parent->dirty = true; - emit componentChildrenChanged(parentId); - emit skeletonChanged(); -} - -void Document::moveComponentDown(QUuid componentId) -{ - Component *parent = (Component *)findComponentParent(componentId); - if (nullptr == parent) - return; - - QUuid parentId = findComponentParentId(componentId); - - parent->moveChildDown(componentId); - parent->dirty = true; - emit componentChildrenChanged(parentId); - emit skeletonChanged(); -} - -void Document::moveComponentToTop(QUuid componentId) -{ - Component *parent = (Component *)findComponentParent(componentId); - if (nullptr == parent) - return; - - QUuid parentId = findComponentParentId(componentId); - - parent->moveChildToTop(componentId); - parent->dirty = true; - emit componentChildrenChanged(parentId); - emit skeletonChanged(); -} - -void Document::moveComponentToBottom(QUuid componentId) -{ - Component *parent = (Component *)findComponentParent(componentId); - if (nullptr == parent) - return; - - QUuid parentId = findComponentParentId(componentId); - - parent->moveChildToBottom(componentId); - parent->dirty = true; - emit componentChildrenChanged(parentId); - emit skeletonChanged(); -} - -void Document::renameComponent(QUuid componentId, QString name) -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - qDebug() << "Component not found:" << componentId; - return; - } - - if (component->second.name == name) - return; - - if (!name.trimmed().isEmpty()) - component->second.name = name; - emit componentNameChanged(componentId); - emit optionsChanged(); -} - -void Document::setComponentExpandState(QUuid componentId, bool expanded) -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - qDebug() << "Component not found:" << componentId; - return; - } - - if (component->second.expanded == expanded) - return; - - component->second.expanded = expanded; - emit componentExpandStateChanged(componentId); - emit optionsChanged(); -} - -void Document::createNewComponentAndMoveThisIn(QUuid componentId) -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - qDebug() << "Component not found:" << componentId; - return; - } - - Component *oldParent = (Component *)findComponentParent(componentId); - - Component newParent(QUuid::createUuid()); - newParent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1); - - oldParent->replaceChild(componentId, newParent.id); - newParent.parentId = oldParent->id; - newParent.addChild(componentId); - componentMap[newParent.id] = newParent; - - component->second.parentId = newParent.id; - - emit componentChildrenChanged(oldParent->id); - emit componentAdded(newParent.id); - emit optionsChanged(); -} - -void Document::createNewChildComponent(QUuid parentComponentId) -{ - Component *parentComponent = (Component *)findComponent(parentComponentId); - if (!parentComponent->linkToPartId.isNull()) { - parentComponentId = parentComponent->parentId; - parentComponent = (Component *)findComponent(parentComponentId); - } - - Component newComponent(QUuid::createUuid()); - newComponent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1); - - parentComponent->addChild(newComponent.id); - newComponent.parentId = parentComponentId; - - componentMap[newComponent.id] = newComponent; - - emit componentChildrenChanged(parentComponentId); - emit componentAdded(newComponent.id); - emit optionsChanged(); -} - -void Document::removePart(QUuid partId) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - qDebug() << "Part not found:" << partId; - return; - } - - if (!part->second.componentId.isNull()) { - removeComponent(part->second.componentId); - return; - } - - removePartDontCareComponent(partId); -} - -void Document::removePartDontCareComponent(QUuid partId) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - qDebug() << "Part not found:" << partId; - return; - } - - std::vector removedNodeIds; - std::vector removedEdgeIds; - - for (auto nodeIt = nodeMap.begin(); nodeIt != nodeMap.end();) { - if (nodeIt->second.partId != partId) { - nodeIt++; - continue; - } - removedNodeIds.push_back(nodeIt->second.id); - nodeIt = nodeMap.erase(nodeIt); - } - - for (auto edgeIt = edgeMap.begin(); edgeIt != edgeMap.end();) { - if (edgeIt->second.partId != partId) { - edgeIt++; - continue; - } - removedEdgeIds.push_back(edgeIt->second.id); - edgeIt = edgeMap.erase(edgeIt); - } - - partMap.erase(part); - - for (const auto &nodeId: removedNodeIds) { - emit nodeRemoved(nodeId); - } - for (const auto &edgeId: removedEdgeIds) { - emit edgeRemoved(edgeId); - } - emit partRemoved(partId); -} - -void Document::addPartToComponent(QUuid partId, QUuid componentId) -{ - Component child(QUuid::createUuid()); - - if (!componentId.isNull()) { - auto parentComponent = componentMap.find(componentId); - if (parentComponent == componentMap.end()) { - componentId = QUuid(); - rootComponent.addChild(child.id); - } else { - parentComponent->second.addChild(child.id); - } - } else { - rootComponent.addChild(child.id); - } - - partMap[partId].componentId = child.id; - child.linkToPartId = partId; - child.parentId = componentId; - componentMap[child.id] = child; - - emit componentChildrenChanged(componentId); - emit componentAdded(child.id); -} - -void Document::removeComponent(QUuid componentId) -{ - removeComponentRecursively(componentId); - emit skeletonChanged(); -} - -void Document::removeComponentRecursively(QUuid componentId) -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - qDebug() << "Component not found:" << componentId; - return; - } - - if (!component->second.linkToPartId.isNull()) { - removePartDontCareComponent(component->second.linkToPartId); - } - - auto childrenIds = component->second.childrenIds; - for (const auto &childId: childrenIds) { - removeComponentRecursively(childId); - } - - QUuid parentId = component->second.parentId; - if (!parentId.isNull()) { - auto parentComponent = componentMap.find(parentId); - if (parentComponent == componentMap.end()) { - qDebug() << "Component not found:" << parentId; - } - parentComponent->second.dirty = true; - parentComponent->second.removeChild(componentId); - } else { - rootComponent.removeChild(componentId); - } - - componentMap.erase(component); - emit componentRemoved(componentId); - emit componentChildrenChanged(parentId); -} - -void Document::setCurrentCanvasComponentId(QUuid componentId) -{ - m_currentCanvasComponentId = componentId; - const Component *component = findComponent(m_currentCanvasComponentId); - if (nullptr == component) { - //qDebug() << "Current component switch to nullptr componentId:" << componentId; - m_currentCanvasComponentId = QUuid(); - } else { - //qDebug() << "Current component switch to " << component->name << "componentId:" << componentId; - if (!component->linkToPartId.isNull()) { - m_currentCanvasComponentId = component->parentId; - component = findComponent(m_currentCanvasComponentId); - //if (nullptr != component) { - // qDebug() << "Then switch to " << component->name << "componentId:" << m_currentCanvasComponentId; - //} - } - } -} - -void Document::addComponent(QUuid parentId) -{ - Component component(QUuid::createUuid()); - - if (!parentId.isNull()) { - auto parentComponent = componentMap.find(parentId); - if (parentComponent == componentMap.end()) { - qDebug() << "Component not found:" << parentId; - return; - } - parentComponent->second.addChild(component.id); - } else { - rootComponent.addChild(component.id); - } - - component.parentId = parentId; - componentMap[component.id] = component; - - emit componentChildrenChanged(parentId); - emit componentAdded(component.id); -} - -bool Document::isDescendantComponent(QUuid componentId, QUuid suspiciousId) -{ - const Component *loopComponent = findComponentParent(suspiciousId); - while (nullptr != loopComponent) { - if (loopComponent->id == componentId) - return true; - loopComponent = findComponentParent(loopComponent->parentId); - } - return false; -} - -void Document::moveComponent(QUuid componentId, QUuid toParentId) -{ - if (componentId == toParentId) - return; - - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - qDebug() << "Component not found:" << componentId; - return; - } - - if (component->second.parentId == toParentId) - return; - - if (isDescendantComponent(componentId, toParentId)) - return; - - if (component->second.parentId.isNull()) { - rootComponent.removeChild(componentId); - emit componentChildrenChanged(rootComponent.id); - } else { - auto oldParent = componentMap.find(component->second.parentId); - if (oldParent != componentMap.end()) { - oldParent->second.dirty = true; - oldParent->second.removeChild(componentId); - emit componentChildrenChanged(oldParent->second.id); - } - } - - component->second.parentId = toParentId; - - if (toParentId.isNull()) { - rootComponent.addChild(componentId); - emit componentChildrenChanged(rootComponent.id); - } else { - auto newParent = componentMap.find(toParentId); - if (newParent != componentMap.end()) { - newParent->second.dirty = true; - newParent->second.addChild(componentId); - emit componentChildrenChanged(newParent->second.id); - } - } - - emit skeletonChanged(); -} - void Document::settleOrigin() { if (originSettled()) @@ -3127,164 +1931,6 @@ void Document::checkExportReadyState() emit exportReady(); } -void Document::collectComponentDescendantParts(QUuid componentId, std::vector &partIds) const -{ - const Component *component = findComponent(componentId); - if (nullptr == component) - return; - - if (!component->linkToPartId.isNull()) { - partIds.push_back(component->linkToPartId); - return; - } - - for (const auto &childId: component->childrenIds) { - collectComponentDescendantParts(childId, partIds); - } -} - -void Document::collectComponentDescendantComponents(QUuid componentId, std::vector &componentIds) const -{ - const Component *component = findComponent(componentId); - if (nullptr == component) - return; - - if (!component->linkToPartId.isNull()) { - return; - } - - for (const auto &childId: component->childrenIds) { - componentIds.push_back(childId); - collectComponentDescendantComponents(childId, componentIds); - } -} - -void Document::hideOtherComponents(QUuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - std::set partIdSet; - for (const auto &partId: partIds) { - partIdSet.insert(partId); - } - for (const auto &part: partMap) { - if (partIdSet.find(part.first) != partIdSet.end()) - continue; - setPartVisibleState(part.first, false); - } -} - -void Document::lockOtherComponents(QUuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - std::set partIdSet; - for (const auto &partId: partIds) { - partIdSet.insert(partId); - } - for (const auto &part: partMap) { - if (partIdSet.find(part.first) != partIdSet.end()) - continue; - setPartLockState(part.first, true); - } -} - -void Document::hideAllComponents() -{ - for (const auto &part: partMap) { - setPartVisibleState(part.first, false); - } -} - -void Document::showAllComponents() -{ - for (const auto &part: partMap) { - setPartVisibleState(part.first, true); - } -} - -void Document::showOrHideAllComponents() -{ - bool foundVisiblePart = false; - for (const auto &part: partMap) { - if (part.second.visible) { - foundVisiblePart = true; - } - } - if (foundVisiblePart) - hideAllComponents(); - else - showAllComponents(); -} - -void Document::collapseAllComponents() -{ - for (const auto &component: componentMap) { - if (!component.second.linkToPartId.isNull()) - continue; - setComponentExpandState(component.first, false); - } -} - -void Document::expandAllComponents() -{ - for (const auto &component: componentMap) { - if (!component.second.linkToPartId.isNull()) - continue; - setComponentExpandState(component.first, true); - } -} - -void Document::lockAllComponents() -{ - for (const auto &part: partMap) { - setPartLockState(part.first, true); - } -} - -void Document::unlockAllComponents() -{ - for (const auto &part: partMap) { - setPartLockState(part.first, false); - } -} - -void Document::hideDescendantComponents(QUuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - for (const auto &partId: partIds) { - setPartVisibleState(partId, false); - } -} - -void Document::showDescendantComponents(QUuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - for (const auto &partId: partIds) { - setPartVisibleState(partId, true); - } -} - -void Document::lockDescendantComponents(QUuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - for (const auto &partId: partIds) { - setPartLockState(partId, true); - } -} - -void Document::unlockDescendantComponents(QUuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - for (const auto &partId: partIds) { - setPartLockState(partId, false); - } -} - void Document::generateRig() { if (nullptr != m_rigGenerator) { diff --git a/src/document.h b/src/document.h index 0a0f2e90..57a96669 100644 --- a/src/document.h +++ b/src/document.h @@ -40,153 +40,6 @@ public: Snapshot snapshot; }; -class Component -{ -public: - Component() - { - } - Component(const QUuid &withId, const QString &linkData=QString(), const QString &linkDataType=QString()) - { - id = withId.isNull() ? QUuid::createUuid() : withId; - if (!linkData.isEmpty()) { - if ("partId" == linkDataType) { - linkToPartId = QUuid(linkData); - } - } - } - QUuid id; - QString name; - QUuid linkToPartId; - QUuid parentId; - bool expanded = true; - CombineMode combineMode = Preferences::instance().componentCombineMode(); - bool dirty = true; - float smoothAll = 0.0; - float smoothSeam = 0.0; - std::vector childrenIds; - QString linkData() const - { - return linkToPartId.isNull() ? QString() : linkToPartId.toString(); - } - QString linkDataType() const - { - return linkToPartId.isNull() ? QString() : QString("partId"); - } - void addChild(QUuid childId) - { - if (m_childrenIdSet.find(childId) != m_childrenIdSet.end()) - return; - m_childrenIdSet.insert(childId); - childrenIds.push_back(childId); - } - void removeChild(QUuid childId) - { - if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) - return; - m_childrenIdSet.erase(childId); - auto findResult = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (findResult != childrenIds.end()) - childrenIds.erase(findResult); - } - void replaceChild(QUuid childId, QUuid newId) - { - if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) - return; - if (m_childrenIdSet.find(newId) != m_childrenIdSet.end()) - return; - m_childrenIdSet.erase(childId); - m_childrenIdSet.insert(newId); - auto findResult = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (findResult != childrenIds.end()) - *findResult = newId; - } - void moveChildUp(QUuid childId) - { - auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (it == childrenIds.end()) { - qDebug() << "Child not found in list:" << childId; - return; - } - - auto index = std::distance(childrenIds.begin(), it); - if (index == 0) - return; - std::swap(childrenIds[index - 1], childrenIds[index]); - } - void moveChildDown(QUuid childId) - { - auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (it == childrenIds.end()) { - qDebug() << "Child not found in list:" << childId; - return; - } - - auto index = std::distance(childrenIds.begin(), it); - if (index == (int)childrenIds.size() - 1) - return; - std::swap(childrenIds[index], childrenIds[index + 1]); - } - void moveChildToTop(QUuid childId) - { - auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (it == childrenIds.end()) { - qDebug() << "Child not found in list:" << childId; - return; - } - - auto index = std::distance(childrenIds.begin(), it); - if (index == 0) - return; - for (int i = index; i >= 1; i--) - std::swap(childrenIds[i - 1], childrenIds[i]); - } - void moveChildToBottom(QUuid childId) - { - auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (it == childrenIds.end()) { - qDebug() << "Child not found in list:" << childId; - return; - } - - auto index = std::distance(childrenIds.begin(), it); - if (index == (int)childrenIds.size() - 1) - return; - for (int i = index; i <= (int)childrenIds.size() - 2; i++) - std::swap(childrenIds[i], childrenIds[i + 1]); - } - void setSmoothAll(float toSmoothAll) - { - if (toSmoothAll < 0) - toSmoothAll = 0; - else if (toSmoothAll > 1) - toSmoothAll = 1; - smoothAll = toSmoothAll; - } - void setSmoothSeam(float toSmoothSeam) - { - if (toSmoothSeam < 0) - toSmoothSeam = 0; - else if (toSmoothSeam > 1) - toSmoothSeam = 1; - smoothSeam = toSmoothSeam; - } - bool smoothAllAdjusted() const - { - return fabs(smoothAll - 0.0) >= 0.01; - } - bool smoothSeamAdjusted() const - { - return fabs(smoothSeam - 0.0) >= 0.01; - } - bool smoothAdjusted() const - { - return smoothAllAdjusted() || smoothSeamAdjusted(); - } -private: - std::set m_childrenIdSet; -}; - class Motion { public: @@ -261,25 +114,9 @@ class Document : public SkeletonDocument { Q_OBJECT signals: - void partAdded(QUuid partId); - void nodeAdded(QUuid nodeId); - void edgeAdded(QUuid edgeId); - void partRemoved(QUuid partId); - void componentNameChanged(QUuid componentId); - void componentChildrenChanged(QUuid componentId); - void componentRemoved(QUuid componentId); - void componentAdded(QUuid componentId); - void componentExpandStateChanged(QUuid componentId); - void componentLayerChanged(QUuid componentId); - void nodeRemoved(QUuid nodeId); - void edgeRemoved(QUuid edgeId); - void nodeRadiusChanged(QUuid nodeId); void nodeBoneMarkChanged(QUuid nodeId); - void nodeColorStateChanged(QUuid nodeId); void nodeCutRotationChanged(QUuid nodeId); void nodeCutFaceChanged(QUuid nodeId); - void nodeOriginChanged(QUuid nodeId); - void edgeReversed(QUuid edgeId); void partPreviewChanged(QUuid partId); void resultMeshChanged(); void resultPartPreviewsChanged(); @@ -287,7 +124,6 @@ signals: void turnaroundChanged(); void editModeChanged(); void paintModeChanged(); - void skeletonChanged(); //void resultSkeletonChanged(); void resultTextureChanged(); void resultColorTextureChanged(); @@ -295,10 +131,7 @@ signals: void postProcessedResultChanged(); void resultRigChanged(); void rigChanged(); - void partLockStateChanged(QUuid partId); - void partVisibleStateChanged(QUuid partId); void partSubdivStateChanged(QUuid partId); - void partDisableStateChanged(QUuid partId); void partXmirrorStateChanged(QUuid partId); //void partZmirrorStateChanged(QUuid partId); void partBaseChanged(QUuid partId); @@ -320,11 +153,9 @@ signals: void partHollowThicknessChanged(QUuid partId); void partCountershadeStateChanged(QUuid partId); void partSmoothStateChanged(QUuid partId); - void partGridStateChanged(QUuid partId); void componentCombineModeChanged(QUuid componentId); void cleanup(); void cleanupScript(); - void originChanged(); void xlockStateChanged(); void ylockStateChanged(); void zlockStateChanged(); @@ -338,7 +169,6 @@ signals: void uncheckAll(); void checkNode(QUuid nodeId); void checkEdge(QUuid edgeId); - void optionsChanged(); void rigTypeChanged(); void motionsChanged(); void motionAdded(QUuid motionId); @@ -368,30 +198,28 @@ signals: void mousePickRadiusChanged(); void objectLockStateChanged(); public: // need initialize - QImage *textureImage; - QByteArray *textureImageByteArray; - QImage *textureNormalImage; - QByteArray *textureNormalImageByteArray; - QImage *textureMetalnessImage; - QByteArray *textureMetalnessImageByteArray; - QImage *textureRoughnessImage; - QByteArray *textureRoughnessImageByteArray; - QImage *textureAmbientOcclusionImage; - QByteArray *textureAmbientOcclusionImageByteArray; - RigType rigType; - bool weldEnabled; - QColor brushColor; - bool objectLocked; + QImage *textureImage = nullptr; + QByteArray *textureImageByteArray = nullptr; + QImage *textureNormalImage = nullptr; + QByteArray *textureNormalImageByteArray = nullptr; + QImage *textureMetalnessImage = nullptr; + QByteArray *textureMetalnessImageByteArray = nullptr; + QImage *textureRoughnessImage = nullptr; + QByteArray *textureRoughnessImageByteArray = nullptr; + QImage *textureAmbientOcclusionImage = nullptr; + QByteArray *textureAmbientOcclusionImageByteArray = nullptr; + RigType rigType = RigType::None; + bool weldEnabled = true; + QColor brushColor = Qt::white; + bool objectLocked = false; float brushMetalness = Model::m_defaultMetalness; float brushRoughness = Model::m_defaultRoughness; public: Document(); ~Document(); - std::map componentMap; std::map materialMap; std::vector materialIdList; std::map motionMap; - Component rootComponent; QImage preview; bool undoable() const override; bool redoable() const override; @@ -412,9 +240,6 @@ public: Import }; void addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource source=SnapshotSource::Paste); - const Component *findComponent(QUuid componentId) const; - const Component *findComponentParent(QUuid componentId) const; - QUuid findComponentParentId(QUuid componentId) const; const Material *findMaterial(QUuid materialId) const; const Motion *findMotion(QUuid motionId) const; Model *takeResultMesh(); @@ -436,8 +261,6 @@ public: const Object ¤tPostProcessedObject() const; bool isExportReady() const; bool isPostProcessResultObsolete() const; - void collectComponentDescendantParts(QUuid componentId, std::vector &partIds) const; - void collectComponentDescendantComponents(QUuid componentId, std::vector &componentIds) const; const std::vector> &resultRigMessages() const; const Object ¤tRiggedObject() const; bool currentRigSucceed() const; @@ -455,29 +278,15 @@ public slots: void undo() override; void redo() override; void paste() override; - void removeNode(QUuid nodeId); - void removeEdge(QUuid edgeId); - void removePart(QUuid partId); - void addNodeWithId(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId); - void addNode(float x, float y, float z, float radius, QUuid fromNodeId); - void scaleNodeByAddRadius(QUuid nodeId, float amount); - void moveNodeBy(QUuid nodeId, float x, float y, float z); - void setNodeOrigin(QUuid nodeId, float x, float y, float z); - void setNodeRadius(QUuid nodeId, float radius); void setNodeBoneMark(QUuid nodeId, BoneMark mark); void setNodeCutRotation(QUuid nodeId, float cutRotation); void setNodeCutFace(QUuid nodeId, CutFace cutFace); void setNodeCutFaceLinkedId(QUuid nodeId, QUuid linkedId); void clearNodeCutFaceSettings(QUuid nodeId); - void switchNodeXZ(QUuid nodeId); - void moveOriginBy(float x, float y, float z); - void addEdge(QUuid fromNodeId, QUuid toNodeId); void setEditMode(SkeletonDocumentEditMode mode); void setMeshLockState(bool locked); void setPaintMode(PaintMode mode); void setMousePickRadius(float radius); - void createSinglePartFromEdges(const std::vector &nodes, - const std::vector> &edges); void uiReady(); void generateMesh(); void regenerateMesh(); @@ -495,10 +304,7 @@ public slots: void pickMouseTarget(const QVector3D &nearPosition, const QVector3D &farPosition); void paint(); void paintReady(); - void setPartLockState(QUuid partId, bool locked); - void setPartVisibleState(QUuid partId, bool visible); void setPartSubdivState(QUuid partId, bool subdived); - void setPartDisableState(QUuid partId, bool disabled); void setPartXmirrorState(QUuid partId, bool mirrored); //void setPartZmirrorState(QUuid partId, bool mirrored); void setPartBase(QUuid partId, PartBase base); @@ -522,31 +328,6 @@ public slots: void setPartCountershaded(QUuid partId, bool countershaded); void setPartSmoothState(QUuid partId, bool smooth); void setComponentCombineMode(QUuid componentId, CombineMode combineMode); - void moveComponentUp(QUuid componentId); - void moveComponentDown(QUuid componentId); - void moveComponentToTop(QUuid componentId); - void moveComponentToBottom(QUuid componentId); - void renameComponent(QUuid componentId, QString name); - void removeComponent(QUuid componentId); - void addComponent(QUuid parentId); - void moveComponent(QUuid componentId, QUuid toParentId); - void setCurrentCanvasComponentId(QUuid componentId); - void createNewComponentAndMoveThisIn(QUuid componentId); - void createNewChildComponent(QUuid parentComponentId); - void setComponentExpandState(QUuid componentId, bool expanded); - void hideOtherComponents(QUuid componentId); - void lockOtherComponents(QUuid componentId); - void hideAllComponents(); - void showAllComponents(); - void showOrHideAllComponents(); - void collapseAllComponents(); - void expandAllComponents(); - void lockAllComponents(); - void unlockAllComponents(); - void hideDescendantComponents(QUuid componentId); - void showDescendantComponents(QUuid componentId); - void lockDescendantComponents(QUuid componentId); - void unlockDescendantComponents(QUuid componentId); void saveSnapshot(); void batchChangeBegin(); void batchChangeEnd(); @@ -555,15 +336,10 @@ public slots: void clearHistories(); void silentReset(); void silentResetScript(); - void breakEdge(QUuid edgeId); - void reduceNode(QUuid nodeId); - void reverseEdge(QUuid edgeId); void setXlockState(bool locked); void setYlockState(bool locked); void setZlockState(bool locked); void setRadiusLockState(bool locked); - void enableAllPositionRelatedLocks(); - void disableAllPositionRelatedLocks(); void toggleSmoothNormal(); void enableWeld(bool enabled); void setRigType(RigType toRigType); @@ -590,62 +366,48 @@ public slots: void setMousePickMaskNodeIds(const std::set &nodeIds); void updateObject(Object *object); private: - void splitPartByNode(std::vector> *groups, QUuid nodeId); - void joinNodeAndNeiborsToGroup(std::vector *group, QUuid nodeId, std::set *visitMap, QUuid noUseEdgeId=QUuid()); - void splitPartByEdge(std::vector> *groups, QUuid edgeId); - bool isPartReadonly(QUuid partId) const; - QUuid createNode(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId); void settleOrigin(); void checkExportReadyState(); - void removePartDontCareComponent(QUuid partId); - void addPartToComponent(QUuid partId, QUuid componentId); - bool isDescendantComponent(QUuid componentId, QUuid suspiciousId); - void removeComponentRecursively(QUuid componentId); - void resetDirtyFlags(); - void markAllDirty(); void removeRigResults(); - void updateLinkedPart(QUuid oldPartId, QUuid newPartId); bool updateDefaultVariables(const std::map> &defaultVariables); -private: // need initialize - bool m_isResultMeshObsolete; - MeshGenerator *m_meshGenerator; - Model *m_resultMesh; - Model *m_paintedMesh; - std::map> *m_resultMeshNodesCutFaces; - bool m_isMeshGenerationSucceed; - int m_batchChangeRefCount; - Object *m_currentObject; - bool m_isTextureObsolete; - TextureGenerator *m_textureGenerator; - bool m_isPostProcessResultObsolete; - MeshResultPostProcessor *m_postProcessor; - Object *m_postProcessedObject; - Model *m_resultTextureMesh; - unsigned long long m_textureImageUpdateVersion; - QUuid m_currentCanvasComponentId; - bool m_allPositionRelatedLocksEnabled; - bool m_smoothNormal; - RigGenerator *m_rigGenerator; - Model *m_resultRigWeightMesh; - std::vector *m_resultRigBones; - std::map *m_resultRigWeights; - bool m_isRigObsolete; - Object *m_riggedObject; - bool m_currentRigSucceed; - MaterialPreviewsGenerator *m_materialPreviewsGenerator; - MotionsGenerator *m_motionsGenerator; - quint64 m_meshGenerationId; - quint64 m_nextMeshGenerationId; +private: + bool m_isResultMeshObsolete = false; + MeshGenerator *m_meshGenerator = nullptr; + Model *m_resultMesh = nullptr; + Model *m_paintedMesh = nullptr; + std::map> *m_resultMeshNodesCutFaces = nullptr; + bool m_isMeshGenerationSucceed = true; + int m_batchChangeRefCount = 0; + Object *m_currentObject = nullptr; + bool m_isTextureObsolete = false; + TextureGenerator *m_textureGenerator = nullptr; + bool m_isPostProcessResultObsolete = false; + MeshResultPostProcessor *m_postProcessor = nullptr; + Object *m_postProcessedObject = new Object; + Model *m_resultTextureMesh = nullptr; + unsigned long long m_textureImageUpdateVersion = 0; + bool m_smoothNormal = !Preferences::instance().flatShading(); + RigGenerator *m_rigGenerator = nullptr; + Model *m_resultRigWeightMesh = nullptr; + std::vector *m_resultRigBones = nullptr; + std::map *m_resultRigWeights = nullptr; + bool m_isRigObsolete = false; + Object *m_riggedObject = new Object; + bool m_currentRigSucceed = false; + MaterialPreviewsGenerator *m_materialPreviewsGenerator = nullptr; + MotionsGenerator *m_motionsGenerator = nullptr; + quint64 m_meshGenerationId = 0; + quint64 m_nextMeshGenerationId = 0; std::map> m_cachedVariables; std::map> m_mergedVariables; - ScriptRunner *m_scriptRunner; - bool m_isScriptResultObsolete; - TexturePainter *m_texturePainter; - bool m_isMouseTargetResultObsolete; - PaintMode m_paintMode; - float m_mousePickRadius; - GeneratedCacheContext *m_generatedCacheContext; - TexturePainterContext *m_texturePainterContext; + ScriptRunner *m_scriptRunner = nullptr; + bool m_isScriptResultObsolete = false; + TexturePainter *m_texturePainter = nullptr; + bool m_isMouseTargetResultObsolete = false; + PaintMode m_paintMode = PaintMode::None; + float m_mousePickRadius = 0.02f; + GeneratedCacheContext *m_generatedCacheContext = nullptr; + TexturePainterContext *m_texturePainterContext = nullptr; private: static unsigned long m_maxSnapshot; std::deque m_undoItems; diff --git a/src/parttreewidget.cpp b/src/parttreewidget.cpp index 78ea2fe6..c68f2e19 100644 --- a/src/parttreewidget.cpp +++ b/src/parttreewidget.cpp @@ -133,9 +133,9 @@ void PartTreeWidget::updateComponentAppearance(QUuid componentId) void PartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected) { - const Component *component = m_document->findComponent(componentId); + const SkeletonComponent *component = m_document->findComponent(componentId); if (nullptr == component) { - qDebug() << "Component not found:" << componentId; + qDebug() << "SkeletonComponent not found:" << componentId; return; } if (!component->linkToPartId.isNull()) { @@ -196,7 +196,7 @@ void PartTreeWidget::handleSingleClick(const QPoint &pos) auto componentId = QUuid(item->data(0, Qt::UserRole).toString()); if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) { if (!m_shiftStartComponentId.isNull()) { - const Component *parent = m_document->findComponentParent(m_shiftStartComponentId); + const SkeletonComponent *parent = m_document->findComponentParent(m_shiftStartComponentId); if (parent) { if (!parent->childrenIds.empty()) { bool startAdd = false; @@ -288,7 +288,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted) //delete m_delayedMousePressTimer; //m_delayedMousePressTimer = nullptr; - const Component *component = nullptr; + const SkeletonComponent *component = nullptr; const SkeletonPart *part = nullptr; PartWidget *partWidget = nullptr; @@ -305,7 +305,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted) QUuid componentId = *componentIds.begin(); component = m_document->findComponent(componentId); if (nullptr == component) { - qDebug() << "Component not found:" << componentId; + qDebug() << "SkeletonComponent not found:" << componentId; return; } if (component && !component->linkToPartId.isNull()) { @@ -394,7 +394,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted) if (nullptr == partBaseSelectBox) { std::set partBases; for (const auto &componentId: componentIds) { - const Component *oneComponent = m_document->findComponent(componentId); + const SkeletonComponent *oneComponent = m_document->findComponent(componentId); if (nullptr == oneComponent || oneComponent->linkToPartId.isNull()) continue; const SkeletonPart *onePart = m_document->findPart(oneComponent->linkToPartId); @@ -419,7 +419,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted) if (index < startIndex) return; for (const auto &componentId: componentIds) { - const Component *oneComponent = m_document->findComponent(componentId); + const SkeletonComponent *oneComponent = m_document->findComponent(componentId); if (nullptr == oneComponent || oneComponent->linkToPartId.isNull()) continue; emit setPartBase(oneComponent->linkToPartId, (PartBase)(index - startIndex)); @@ -432,7 +432,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted) if (nullptr == combineModeSelectBox) { std::set combineModes; for (const auto &componentId: componentIds) { - const Component *oneComponent = m_document->findComponent(componentId); + const SkeletonComponent *oneComponent = m_document->findComponent(componentId); if (nullptr == oneComponent) continue; combineModes.insert(oneComponent->combineMode); @@ -732,7 +732,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted) }); addChildGroupsFunc = [this, &groupsActions, &addChildGroupsFunc, &moveToMenu, &componentIds](QUuid currentId, int tabs) -> void { - const Component *current = m_document->findComponent(currentId); + const SkeletonComponent *current = m_document->findComponent(currentId); if (nullptr == current) return; if (!current->id.isNull() && current->linkDataType().isEmpty()) { @@ -799,7 +799,7 @@ void PartTreeWidget::componentNameChanged(QUuid componentId) return; } - const Component *component = m_document->findComponent(componentId); + const SkeletonComponent *component = m_document->findComponent(componentId); if (nullptr == component) { qDebug() << "Find component failed:" << componentId; return; @@ -816,7 +816,7 @@ void PartTreeWidget::componentExpandStateChanged(QUuid componentId) return; } - const Component *component = m_document->findComponent(componentId); + const SkeletonComponent *component = m_document->findComponent(componentId); if (nullptr == component) { qDebug() << "Find component failed:" << componentId; return; @@ -837,12 +837,12 @@ void PartTreeWidget::componentTargetChanged(QUuid componentId) void PartTreeWidget::addComponentChildrenToItem(QUuid componentId, QTreeWidgetItem *parentItem) { - const Component *parentComponent = m_document->findComponent(componentId); + const SkeletonComponent *parentComponent = m_document->findComponent(componentId); if (nullptr == parentComponent) return; for (const auto &childId: parentComponent->childrenIds) { - const Component *component = m_document->findComponent(childId); + const SkeletonComponent *component = m_document->findComponent(childId); if (nullptr == component) continue; if (!component->linkToPartId.isNull()) { @@ -885,7 +885,7 @@ void PartTreeWidget::deleteItemChildren(QTreeWidgetItem *item) while (!children.isEmpty()) { auto first = children.takeFirst(); auto componentId = QUuid(first->data(0, Qt::UserRole).toString()); - const Component *component = m_document->findComponent(componentId); + const SkeletonComponent *component = m_document->findComponent(componentId); if (nullptr != component) { m_componentItemMap.erase(componentId); if (!component->linkToPartId.isNull()) { @@ -983,7 +983,7 @@ void PartTreeWidget::groupChanged(QTreeWidgetItem *item, int column) auto componentId = QUuid(item->data(0, Qt::UserRole).toString()); - const Component *component = m_document->findComponent(componentId); + const SkeletonComponent *component = m_document->findComponent(componentId); if (nullptr == component) { qDebug() << "Find component failed:" << componentId; return; diff --git a/src/regionfiller.cpp b/src/regionfiller.cpp deleted file mode 100644 index e93b33a9..00000000 --- a/src/regionfiller.cpp +++ /dev/null @@ -1,1496 +0,0 @@ -#include -#include -#include -#include -#include "regionfiller.h" - -// -// This is an implementation of the following paper -// -// -// A. Nasri1∗, M. Sabin2 and Z. Yasseen1 -// - -#define isEven(n) (0 == (n) % 2) -#define isOdd(n) (!isEven(n)) - -RegionFiller::RegionFiller(const std::vector *vertices, - const std::vector> *polylines) : - m_sourceVertices(vertices), - m_sourcePolylines(new std::vector>(*polylines)) -{ -} - -RegionFiller::~RegionFiller() -{ - delete m_sourcePolylines; -} - -bool RegionFiller::resolveEvenSidedEvenSumOfSegmentsAndBothL2L2AreEven() -{ - return resolveOddSidedEvenSumOfSegments(m_sideNum / 2); -} - -std::vector RegionFiller::createPointsToMapBetween(size_t fromIndex, - size_t toIndex, - size_t segments, - std::map, std::vector> *map) -{ - size_t a = fromIndex; - size_t b = toIndex; - bool needReverse = false; - if (a > b) { - std::swap(a, b); - needReverse = true; - } - auto key = std::make_pair(a, b); - auto findPoints = map->find(key); - if (findPoints != map->end()) { - return needReverse ? reversed(findPoints->second) : findPoints->second; - } - std::vector newPointIndices; - createPointsBetween(a, b, segments, &newPointIndices); - map->insert({key, newPointIndices}); - return needReverse ? reversed(newPointIndices) : newPointIndices; -} - -void RegionFiller::createPointsBetween(size_t fromIndex, - size_t toIndex, - size_t segments, - std::vector *newPointIndices) -{ - if (fromIndex == toIndex || 0 == segments) - return; - auto fromVertex = m_oldAndNewVertices[fromIndex]; - auto toVertex = m_oldAndNewVertices[toIndex]; - float stepFactor = 1.0 / segments; - newPointIndices->push_back(fromIndex); - for (size_t i = 1; i <= segments - 1; ++i) { - float factor = stepFactor * i; - RegionFiller::Node node; - node.position = fromVertex.position * (1.0 - factor) + toVertex.position * factor; - node.radius = fromVertex.radius * (1.0 - factor) + toVertex.radius * factor; - if (m_centerSources.find(toVertex.source) != m_centerSources.end()) { - node.source = fromVertex.source; - } else if (m_centerSources.find(fromVertex.source) != m_centerSources.end()) { - node.source = toVertex.source; - } else { - if (factor > 0.5) { - node.source = toVertex.source; - } else { - node.source = fromVertex.source; - } - } - size_t newIndex = m_oldAndNewVertices.size(); - m_oldAndNewVertices.push_back(node); - newPointIndices->push_back(newIndex); - } - newPointIndices->push_back(toIndex); -} - -std::vector RegionFiller::createPointsBetween(size_t fromIndex, - size_t toIndex, - size_t segments) -{ - std::vector newPointIndices; - createPointsBetween(fromIndex, toIndex, segments, &newPointIndices); - return newPointIndices; -} - -void RegionFiller::collectEdgePoints(size_t polyline, int startPos, int stopPos, - std::vector *pointIndices) -{ - const auto &edgeIndices = (*m_sourcePolylines)[polyline]; - int step = startPos < stopPos ? 1 : -1; - int totalSteps = std::abs(startPos - stopPos) + 1; - int current = startPos; - for (int i = 0; i < totalSteps; ++i) { - pointIndices->push_back(edgeIndices[current]); - current += step; - } -} - -std::vector RegionFiller::collectEdgePoints(size_t polyline, int startPos, int stopPos) -{ - std::vector pointIndices; - collectEdgePoints(polyline, startPos, stopPos, &pointIndices); - return pointIndices; -} - -std::vector RegionFiller::reversed(const std::vector &pointIndices) -{ - std::vector newPointIndices = pointIndices; - std::reverse(newPointIndices.begin(), newPointIndices.end()); - return newPointIndices; -} - -float RegionFiller::averageRadius(size_t *maxNodeIndex) -{ - float sumOfRadius = 0; - size_t num = 0; - float maxRadius = 0; - for (const auto &polyline: *m_sourcePolylines) { - for (const auto &it: polyline) { - const auto &vertex = (*m_sourceVertices)[it]; - if (vertex.radius >= maxRadius) { - maxRadius = vertex.radius; - if (nullptr != maxNodeIndex) - *maxNodeIndex = it; - } - sumOfRadius += vertex.radius; - ++num; - } - } - if (0 == num) - return 0; - auto radius = sumOfRadius / num; - return radius; -} - -bool RegionFiller::resolveOddSidedEvenSumOfSegments(int siUpperBound) -{ - auto si = [&](int i) { - int sum = 0; - for (int j = 1; j <= siUpperBound; ++j) { - sum += std::pow(-1, j + 1) * - m_sideSegmentNums[(i + 2 * j - 1) % m_sideSegmentNums.size()]; - } - return sum; - }; - auto di = [&](int i) { - return std::ceil(si(i) * 0.5); - }; - - std::vector gRaySegmentNums(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - gRaySegmentNums[i] = di(i); - if (gRaySegmentNums[i] <= 0) { - qDebug() << "resolveOddSidedEvenSumOfSegments failed, di:" << gRaySegmentNums[i]; - return false; - } - } - - std::vector eIndices(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - auto length = gRaySegmentNums[(i + 1) % gRaySegmentNums.size()]; - eIndices[i] = m_sideSegmentNums[i] - length; - } - - std::set cornerVertices; - std::vector> edgeSegments; // tuple - for (int i = 0; i < m_sideNum; ++i) { - if (gRaySegmentNums[i] <= 0) { - edgeSegments.push_back(std::make_tuple(0, (*m_sourcePolylines)[i].size() - 1, i)); - continue; - } - const auto &pointEdgeIndex = eIndices[i]; - cornerVertices.insert((*m_sourcePolylines)[i][pointEdgeIndex]); - if (pointEdgeIndex > 0) - edgeSegments.push_back(std::make_tuple(0, pointEdgeIndex, i)); - if (pointEdgeIndex < (int)(*m_sourcePolylines)[i].size() - 1) - edgeSegments.push_back(std::make_tuple(pointEdgeIndex, (*m_sourcePolylines)[i].size() - 1, i)); - } - - std::vector> gPositionAndAreas; - for (size_t i = 0; i < edgeSegments.size(); ++i) { - size_t j = (i + 1) % edgeSegments.size(); - size_t m = (j + 2) % edgeSegments.size(); - const auto &segmentI = edgeSegments[i]; - const auto &segmentJ = edgeSegments[j]; - const auto &segmentM = edgeSegments[m]; - std::vector firstSegmentPoints; - std::vector secondSegmentPoints; - std::vector forthSegmentPoints; - collectEdgePoints(std::get<2>(segmentI), std::get<0>(segmentI), std::get<1>(segmentI), - &firstSegmentPoints); - collectEdgePoints(std::get<2>(segmentJ), std::get<0>(segmentJ), std::get<1>(segmentJ), - &secondSegmentPoints); - collectEdgePoints(std::get<2>(segmentM), std::get<0>(segmentM), std::get<1>(segmentM), - &forthSegmentPoints); - if (cornerVertices.find((*m_sourcePolylines)[std::get<2>(segmentI)][std::get<0>(segmentI)]) != cornerVertices.end() && - cornerVertices.find((*m_sourcePolylines)[std::get<2>(segmentI)][std::get<1>(segmentI)]) != cornerVertices.end()) { - const auto &p1 = (*m_sourceVertices)[(*m_sourcePolylines)[std::get<2>(segmentI)][std::get<0>(segmentI)]]; - const auto &p2 = (*m_sourceVertices)[(*m_sourcePolylines)[std::get<2>(segmentI)][std::get<1>(segmentI)]]; - gPositionAndAreas.push_back(std::make_pair((p1.position + p2.position) * 0.5, - (firstSegmentPoints.size() - 1) * (secondSegmentPoints.size() - 1) * 0.5)); - continue; - } - if (cornerVertices.find((*m_sourcePolylines)[std::get<2>(segmentI)][std::get<0>(segmentI)]) != cornerVertices.end() && - cornerVertices.find((*m_sourcePolylines)[std::get<2>(segmentJ)][std::get<1>(segmentJ)]) != cornerVertices.end()) { - ++i; - const auto &p1 = (*m_sourceVertices)[(*m_sourcePolylines)[std::get<2>(segmentI)][std::get<0>(segmentI)]]; - const auto &p2 = (*m_sourceVertices)[(*m_sourcePolylines)[std::get<2>(segmentI)][std::get<1>(segmentI)]]; - const auto &p3 = (*m_sourceVertices)[(*m_sourcePolylines)[std::get<2>(segmentJ)][std::get<1>(segmentJ)]]; - gPositionAndAreas.push_back(std::make_pair(p1.position + p2.position - p3.position, - (firstSegmentPoints.size() - 1) * (secondSegmentPoints.size() - 1))); - } - } - - QVector3D gTop; - float gBottom = 0; - for (const auto &it: gPositionAndAreas) { - gTop += it.first / it.second; - gBottom += 1.0 / it.second; - } - auto gPosition = gTop / gBottom; - size_t gIndex = m_oldAndNewVertices.size(); - Node node; - node.position = gPosition; - node.radius = averageRadius(&node.source); - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - - std::map, std::vector> map; - for (size_t i = 0; i < edgeSegments.size(); ++i) { - size_t j = (i + 1) % edgeSegments.size(); - size_t m = (j + 2) % edgeSegments.size(); - const auto &segmentI = edgeSegments[i]; - const auto &segmentJ = edgeSegments[j]; - const auto &segmentM = edgeSegments[m]; - std::vector firstSegmentPoints; - std::vector secondSegmentPoints; - std::vector forthSegmentPoints; - collectEdgePoints(std::get<2>(segmentI), std::get<0>(segmentI), std::get<1>(segmentI), - &firstSegmentPoints); - collectEdgePoints(std::get<2>(segmentJ), std::get<0>(segmentJ), std::get<1>(segmentJ), - &secondSegmentPoints); - collectEdgePoints(std::get<2>(segmentM), std::get<0>(segmentM), std::get<1>(segmentM), - &forthSegmentPoints); - if (cornerVertices.find((*m_sourcePolylines)[std::get<2>(segmentI)][std::get<0>(segmentI)]) != cornerVertices.end() && - cornerVertices.find((*m_sourcePolylines)[std::get<2>(segmentI)][std::get<1>(segmentI)]) != cornerVertices.end()) { - std::vector> region = { - firstSegmentPoints, - createPointsToMapBetween((*m_sourcePolylines)[std::get<2>(segmentI)][std::get<1>(segmentI)], - gIndex, forthSegmentPoints.size() - 1, &map), - createPointsToMapBetween(gIndex, - (*m_sourcePolylines)[std::get<2>(segmentI)][std::get<0>(segmentI)], secondSegmentPoints.size() - 1, &map) - }; - m_newRegions.push_back(region); - continue; - } - if (cornerVertices.find((*m_sourcePolylines)[std::get<2>(segmentI)][std::get<0>(segmentI)]) != cornerVertices.end() && - cornerVertices.find((*m_sourcePolylines)[std::get<2>(segmentJ)][std::get<1>(segmentJ)]) != cornerVertices.end()) { - ++i; - std::vector> region = { - firstSegmentPoints, - secondSegmentPoints, - createPointsToMapBetween((*m_sourcePolylines)[std::get<2>(segmentJ)][std::get<1>(segmentJ)], - gIndex, firstSegmentPoints.size() - 1, &map), - createPointsToMapBetween(gIndex, - (*m_sourcePolylines)[std::get<2>(segmentI)][std::get<0>(segmentI)], secondSegmentPoints.size() - 1, &map) - }; - m_newRegions.push_back(region); - } - } - - return true; -} - -bool RegionFiller::resolveEvenSidedEvenSumOfSegmentsAndBothL2L2AreOdd() -{ - return resolveOddSidedOddSumOfSegments(m_sideNum / 2); -} - -bool RegionFiller::resolveOddSidedOddSumOfSegments(int siUpperBound) -{ - auto si = [&](int i) { - int sum = 0; - for (int j = 1; j <= siUpperBound; ++j) { - sum += std::pow(-1, j + 1) * - (m_sideSegmentNums[(i + 2 * j - 1) % m_sideSegmentNums.size()] - 1); - } - return sum; - }; - auto di = [&](int i) { - return std::round(si(i) * 0.5); - }; - std::vector gRaySegmentNums(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - gRaySegmentNums[i] = di(i); - if (gRaySegmentNums[i] <= 0) { - qDebug() << "resolveOddSidedOddSumOfSegments failed, di:" << gRaySegmentNums[i]; - return false; - } - } - - std::vector areas(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - areas[i] = gRaySegmentNums[i] * gRaySegmentNums[(i + 1) % m_sideNum]; - } - - std::vector> eIndices(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - auto length = gRaySegmentNums[(i + 1) % gRaySegmentNums.size()]; - eIndices[i] = std::vector{(int)m_sideSegmentNums[i] - length - 1, - (int)m_sideSegmentNums[i] - length - }; - if (eIndices[i][0] < 0 || eIndices[i][1] < 0) - return false; - } - std::vector eEdgeLengths(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - eEdgeLengths[i] = ((*m_sourceVertices)[(*m_sourcePolylines)[i][eIndices[i][0]]].position - - (*m_sourceVertices)[(*m_sourcePolylines)[i][eIndices[i][1]]].position).length(); - } - float averageDislocationEdgeLength = std::accumulate(eEdgeLengths.begin(), eEdgeLengths.end(), 0.0) / eEdgeLengths.size(); - - auto gi = [&](int i) { - int j = (i + m_sideNum - 1) % m_sideNum; - return (*m_sourceVertices)[(*m_sourcePolylines)[i][eIndices[i][0]]].position + - (*m_sourceVertices)[(*m_sourcePolylines)[j][eIndices[j][1]]].position - - (*m_sourceVertices)[(*m_sourcePolylines)[i][0]].position; - }; - auto gOffsetTargets = [&](int i) { - int h = (i + m_sideNum - 1) % m_sideNum; - return ((*m_sourceVertices)[(*m_sourcePolylines)[i][eIndices[i][0]]].position + - (*m_sourceVertices)[(*m_sourcePolylines)[h][eIndices[h][1]]].position) * 0.5; - }; - - QVector3D gTop; - float gBottom = 0; - for (int i = 0; i < m_sideNum; ++i) { - gTop += gi(i) / areas[i]; - gBottom += 1.0 / areas[i]; - } - - auto gPosition = gTop / gBottom; - size_t gSource = 0; - auto gRadius = averageRadius(&gSource); - m_centerSources.insert(gSource); - - std::vector>> segmentsWithG(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - segmentsWithG[i].resize(2); - } - std::vector gFace(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - int j = (i + 1) % m_sideNum; - auto offsetTarget = gOffsetTargets(j); - auto gPositionPerEdge = gPosition + (offsetTarget - gPosition).normalized() * averageDislocationEdgeLength * 0.7; - size_t gIndex = m_oldAndNewVertices.size(); - gFace[j] = gIndex; - Node node; - node.position = gPositionPerEdge; - node.radius = gRadius; - node.source = gSource; - m_oldAndNewVertices.push_back(node); - createPointsBetween(gIndex, (*m_sourcePolylines)[i][eIndices[i][1]], gRaySegmentNums[i], &segmentsWithG[i][1]); - createPointsBetween(gIndex, (*m_sourcePolylines)[j][eIndices[j][0]], gRaySegmentNums[j], &segmentsWithG[j][0]); - } - m_newFaces.push_back(gFace); - - std::vector>> reversedSegmentsWithG(m_sideNum); - reversedSegmentsWithG = segmentsWithG; - for (int i = 0; i < m_sideNum; ++i) { - for (int x = 0; x < 2; ++x) - std::reverse(reversedSegmentsWithG[i][x].begin(), reversedSegmentsWithG[i][x].end()); - } - - for (int i = 0; i < m_sideNum; ++i) { - int j = (i + 1) % m_sideNum; - std::vector e0c1; - collectEdgePoints(i, eIndices[i][1], (*m_sourcePolylines)[i].size() - 1, &e0c1); - std::vector c1e1; - collectEdgePoints(j, 0, eIndices[j][0], &c1e1); - std::vector> region = { - e0c1, - c1e1, - reversedSegmentsWithG[j][0], - segmentsWithG[i][1] - }; - m_newRegions.push_back(region); - } - - // rectangle slices - for (int i = 0; i < m_sideNum; ++i) { - int j = (i + 1) % m_sideNum; - std::vector e1e2 = { - (*m_sourcePolylines)[i][eIndices[i][0]], - (*m_sourcePolylines)[i][eIndices[i][1]] - }; - std::vector gCoreEdge = { - gFace[j], - gFace[i] - }; - std::vector> region = { - e1e2, - reversedSegmentsWithG[i][1], - gCoreEdge, - segmentsWithG[i][0], - }; - m_newRegions.push_back(region); - } - - return true; -} - -bool RegionFiller::resolveEvenSideEvenSumOfSegmentsAndL1IsOddL2IsEven() -{ - std::rotate(m_sourcePolylines->begin(), m_sourcePolylines->begin() + 1, m_sourcePolylines->end()); - prepare(); - return resolveEvenSideEvenSumOfSegmentsAndL1IsEvenL2IsOdd(); -} - -bool RegionFiller::resolveEvenSideEvenSumOfSegmentsAndL1IsEvenL2IsOdd() -{ - auto modifiedSideSegmentNums = m_sideSegmentNums; - for (int i = 0; i < m_sideNum; i += 2) { - modifiedSideSegmentNums[i] -= 1; - } - - auto si = [&](int i) { - int sum = 0; - int halfSideNum = m_sideNum / 2; - for (int j = 1; j <= halfSideNum; ++j) { - sum += std::pow(-1, j + 1) * - (modifiedSideSegmentNums[(i + 2 * j - 1) % m_sideSegmentNums.size()]); - } - return sum; - }; - auto di = [&](int i) { - return std::round(si(i) * 0.5); - }; - std::vector gRaySegmentNums(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - gRaySegmentNums[i] = di(i); - if (gRaySegmentNums[i] <= 0) { - qDebug() << "resolveEvenSideEvenSumOfSegmentsAndL1IsEvenL2IsOdd failed, di:" << gRaySegmentNums[i]; - return false; - } - } - - std::vector areas(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - areas[i] = gRaySegmentNums[i] * gRaySegmentNums[(i + 1) % m_sideNum]; - } - - std::vector> eIndices(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - auto length = gRaySegmentNums[(i + gRaySegmentNums.size() - 1) % gRaySegmentNums.size()]; - if (0 == i % 2) { - eIndices[i] = std::vector{(int)length, - (int)length + 1 - }; - } else { - eIndices[i] = std::vector{(int)length, - (int)length - }; - } - if (eIndices[i][0] < 0 || eIndices[i][1] < 0) { - qDebug() << "resolveEvenSideEvenSumOfSegmentsAndL1IsEvenL2IsOdd failed"; - return false; - } - } - std::vector eEdgeLengths(m_sideNum, (float)0.0); - int validEdgeNum = 0; - for (int i = 0; i < m_sideNum; ++i) { - const auto &firstIndex = eIndices[i][0]; - const auto &secondIndex = eIndices[i][1]; - if (firstIndex == secondIndex) - continue; - validEdgeNum++; - eEdgeLengths[i] = ((*m_sourceVertices)[(*m_sourcePolylines)[i][firstIndex]].position - - (*m_sourceVertices)[(*m_sourcePolylines)[i][secondIndex]].position).length(); - } - float averageDislocationEdgeLength = std::accumulate(eEdgeLengths.begin(), eEdgeLengths.end(), 0.0) / validEdgeNum; - - auto gi = [&](int i) { - int h = (i + m_sideNum - 1) % m_sideNum; - return (*m_sourceVertices)[(*m_sourcePolylines)[i][eIndices[i][0]]].position + - (*m_sourceVertices)[(*m_sourcePolylines)[h][eIndices[h][1]]].position - - (*m_sourceVertices)[(*m_sourcePolylines)[i][0]].position; - }; - auto gOffsetTargets = [&](int i) { - int h = (i + m_sideNum - 1) % m_sideNum; - return ((*m_sourceVertices)[(*m_sourcePolylines)[i][eIndices[i][0]]].position + - (*m_sourceVertices)[(*m_sourcePolylines)[h][eIndices[h][1]]].position) * 0.5; - }; - - QVector3D gTop; - float gBottom = 0; - for (int i = 0; i < m_sideNum; ++i) { - gTop += gi(i) / areas[i]; - gBottom += 1.0 / areas[i]; - } - - auto gPosition = gTop / gBottom; - size_t gSource = 0; - auto gRadius = averageRadius(&gSource); - - std::vector gFace(m_sideNum / 2); - for (size_t k = 0; k < gFace.size(); ++k) { - int i = k * 2; - int h = (i + m_sideNum - 1) % m_sideNum; - auto offsetTarget = gOffsetTargets(i) * 0.5 + gOffsetTargets(h) * 0.5; - size_t gIndex = m_oldAndNewVertices.size(); - auto gPositionPerEdge = gPosition + (offsetTarget - gPosition).normalized() * averageDislocationEdgeLength * 0.7; - Node node; - node.position = gPositionPerEdge; - node.radius = gRadius; - node.source = gSource; - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - gFace[k] = gIndex; - } - m_newFaces.push_back(gFace); - - std::vector>> segmentsWithG(m_sideNum); - for (int i = 0; i < m_sideNum; ++i) { - segmentsWithG[i].resize(2); - } - for (int i = 0; i < m_sideNum; ++i) { - int k = i / 2; - const auto &g0Index = gFace[k % gFace.size()]; - const auto &g1Index = gFace[(k + 1) % gFace.size()]; - if (eIndices[i][0] == eIndices[i][1]) { - createPointsBetween(g1Index, (*m_sourcePolylines)[i][eIndices[i][0]], gRaySegmentNums[i], - &segmentsWithG[i][0]); - segmentsWithG[i][1] = segmentsWithG[i][0]; - } else { - createPointsBetween(g0Index, (*m_sourcePolylines)[i][eIndices[i][0]], gRaySegmentNums[i], - &segmentsWithG[i][0]); - createPointsBetween(g1Index, (*m_sourcePolylines)[i][eIndices[i][1]], gRaySegmentNums[i], - &segmentsWithG[i][1]); - } - } - - std::vector>> reversedSegmentsWithG(m_sideNum); - reversedSegmentsWithG = segmentsWithG; - for (int i = 0; i < m_sideNum; ++i) { - for (int x = 0; x < 2; ++x) - std::reverse(reversedSegmentsWithG[i][x].begin(), reversedSegmentsWithG[i][x].end()); - } - - for (int i = 0; i < m_sideNum; ++i) { - int j = (i + 1) % m_sideNum; - std::vector e0c1; - collectEdgePoints(i, eIndices[i][1], (*m_sourcePolylines)[i].size() - 1, &e0c1); - std::vector c1e1; - collectEdgePoints(j, 0, eIndices[j][0], &c1e1); - std::vector> region = { - e0c1, c1e1, reversedSegmentsWithG[j][0], segmentsWithG[i][1] - }; - m_newRegions.push_back(region); - } - - // Rectangle slices - for (size_t k = 0; k < gFace.size(); ++k) { - int i = k * 2; - std::vector e1e2 = { - (*m_sourcePolylines)[i][eIndices[i][0]], - (*m_sourcePolylines)[i][eIndices[i][1]] - }; - std::vector g1g0 = { - gFace[(k + 1) % gFace.size()], - gFace[k % gFace.size()] - }; - std::vector> region = { - g1g0, segmentsWithG[i][0], e1e2, reversedSegmentsWithG[i][1] - }; - m_newRegions.push_back(region); - } - - return true; -} - -bool RegionFiller::resolveQuadrilateralRegionMismatchSimilarCase(int m, int n, int p, int q, bool pqSwapped) -{ - return resolveQuadrilateralRegionWithIntegerSolution(m, n, p, q, pqSwapped); -} - -bool RegionFiller::resolveQuadrilateralRegionWithNonIntegerSolution(int m, int n, int p, int q, bool pqSwapped) -{ - float aPlusB = m_sideSegmentNums[m] - m_sideSegmentNums[n]; - float aFloat = ((m_sideSegmentNums[m] - m_sideSegmentNums[n]) + (m_sideSegmentNums[p] - m_sideSegmentNums[q])) / 2.0; - float bFloat = (m_sideSegmentNums[m] - m_sideSegmentNums[n]) - aFloat; - float a = std::ceil(aFloat); - float b = std::ceil(bFloat); - - int c0EdgeIndex = pqSwapped ? (*m_sourcePolylines)[m].size() - 1 : 0; - int c1EdgeIndex = pqSwapped ? (*m_sourcePolylines)[p].size() - 1 : 0; - int c2EdgeIndex = pqSwapped ? (*m_sourcePolylines)[n].size() - 1 : 0; - int c3EdgeIndex = pqSwapped ? (*m_sourcePolylines)[q].size() - 1 : 0; - - int c0AlternativeEdgeIndex = pqSwapped ? 0 : (*m_sourcePolylines)[q].size() - 1; - int c1AlternativeEdgeIndex = pqSwapped ? 0 : (*m_sourcePolylines)[m].size() - 1; - int c2AlternativeEdgeIndex = pqSwapped ? 0 : (*m_sourcePolylines)[p].size() - 1; - int c3AlternativeEdgeIndex = pqSwapped ? 0 : (*m_sourcePolylines)[n].size() - 1; - - const auto &c0Index = (*m_sourcePolylines)[m][c0EdgeIndex]; - const auto &c1Index = (*m_sourcePolylines)[p][c1EdgeIndex]; - - const auto &c0 = (*m_sourceVertices)[c0Index].position; - const auto &c1 = (*m_sourceVertices)[c1Index].position; - - int f0 = m_sideSegmentNums[n] / 2; - int f1 = m_sideSegmentNums[n] - f0; - int f2 = std::ceil((m_sideSegmentNums[p] - a) / 2.0); - int f3 = m_sideSegmentNums[p] - a - f2; - - if (f3 < 0) { - qDebug() << "resolveQuadrilateralRegionWithNonIntegerSolution failed, f3:" << f3; - return false; - } - - int e0EdgeIndex = f0; - if (pqSwapped) - e0EdgeIndex = (*m_sourcePolylines)[m].size() - 1 - e0EdgeIndex; - const auto &e0Index = (*m_sourcePolylines)[m][e0EdgeIndex]; - - int e2EdgeIndex = f0 + aPlusB; - if (pqSwapped) - e2EdgeIndex = (*m_sourcePolylines)[m].size() - 1 - e2EdgeIndex; - const auto &e2Index = (*m_sourcePolylines)[m][e2EdgeIndex]; - - int e3EdgeIndex = f2; - if (pqSwapped) - e3EdgeIndex = (*m_sourcePolylines)[p].size() - 1 - e3EdgeIndex; - const auto &e3Index = (*m_sourcePolylines)[p][e3EdgeIndex]; - - int e4EdgeIndex = (*m_sourcePolylines)[p].size() - 1 - f3; - if (pqSwapped) - e4EdgeIndex = (*m_sourcePolylines)[p].size() - 1 - e4EdgeIndex; - const auto &e4Index = (*m_sourcePolylines)[p][e4EdgeIndex]; - - int e5EdgeIndex = f3; - if (pqSwapped) - e5EdgeIndex = (*m_sourcePolylines)[q].size() - 1 - e5EdgeIndex; - const auto &e5Index = (*m_sourcePolylines)[q][e5EdgeIndex]; - - int e6EdgeIndex = (*m_sourcePolylines)[q].size() - 1 - f2; - if (pqSwapped) - e6EdgeIndex = (*m_sourcePolylines)[q].size() - 1 - e6EdgeIndex; - const auto &e6Index = (*m_sourcePolylines)[q][e6EdgeIndex]; - - int e7EdgeIndex = f1; - if (pqSwapped) - e7EdgeIndex = (*m_sourcePolylines)[n].size() - 1 - e7EdgeIndex; - const auto &e7Index = (*m_sourcePolylines)[n][e7EdgeIndex]; - - const auto &e0 = (*m_sourceVertices)[e0Index].position; - const auto &e2 = (*m_sourceVertices)[e2Index].position; - const auto &e3 = (*m_sourceVertices)[e3Index].position; - const auto &e4 = (*m_sourceVertices)[e4Index].position; - const auto &e5 = (*m_sourceVertices)[e5Index].position; - const auto &e6 = (*m_sourceVertices)[e6Index].position; - const auto &e7 = (*m_sourceVertices)[e7Index].position; - - auto g1InitialPosition = e0 + e6 - c0; - auto g2InitialPosition = e2 + e3 - c1; - auto gpInitialPosition1 = (e5 + e4) * 0.5; - auto gpInitialPosition2 = gpInitialPosition1; - auto g1a = f0 * f2; - auto g2a = f1 * f2; - auto gp1a = f0 * f3 + f0 * b; - auto gp2a = f1 * f3 + f1 * a; - - float weightG1 = 1.0 / g1a; - float weightG2 = 1.0 / g2a; - float weightGp1 = 1.0 / gp1a; - float weightGp2 = 1.0 / gp2a; - - size_t gSource = 0; - auto gRadius = averageRadius(&gSource); - - auto gPosition = (g1InitialPosition * weightG1 + - g2InitialPosition * weightG2 + - gpInitialPosition1 * weightGp1 + - gpInitialPosition2 * weightGp2) / - (weightG1 + weightG2 + weightGp1 + weightGp2); - - auto averageOffsetDistance = e0.distanceToPoint(e2); - - auto g1Position = gPosition + (((e0 + e6) * 0.5) - gPosition).normalized() * averageOffsetDistance * 0.7; - auto g2Position = gPosition + (((e2 + e3) * 0.5) - gPosition).normalized() * averageOffsetDistance * 0.7; - auto gpPosition = gPosition + (e7 - gPosition).normalized() * averageOffsetDistance * 0.7; - - auto g1Index = m_oldAndNewVertices.size(); - { - Node node; - node.position = g1Position; - node.radius = gRadius; - node.source = gSource; - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - } - - auto g2Index = m_oldAndNewVertices.size(); - { - Node node; - node.position = g2Position; - node.radius = gRadius; - node.source = gSource; - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - } - - auto gpIndex = m_oldAndNewVertices.size(); - if (0 != f3) { - Node node; - node.position = gpPosition; - node.radius = gRadius; - node.source = gSource; - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - } else { - gpIndex = e7Index; - } - - std::map, std::vector> map; - - { - std::vector> region = { - collectEdgePoints(m, c0EdgeIndex, e0EdgeIndex), - createPointsToMapBetween(e0Index, g1Index, f2, &map), - createPointsToMapBetween(g1Index, e6Index, f0, &map), - collectEdgePoints(q, e6EdgeIndex, c0AlternativeEdgeIndex) - }; - m_newRegions.push_back(region); - } - - { - std::vector> region = { - collectEdgePoints(m, e0EdgeIndex, e2EdgeIndex), - createPointsToMapBetween(e2Index, g2Index, f2, &map), - createPointsToMapBetween(g2Index, g1Index, aPlusB, &map), - createPointsToMapBetween(g1Index, e0Index, f2, &map) - }; - m_newRegions.push_back(region); - } - - { - std::vector> region = { - collectEdgePoints(m, e2EdgeIndex, c1AlternativeEdgeIndex), - collectEdgePoints(p, c1EdgeIndex, e3EdgeIndex), - createPointsToMapBetween(e3Index, g2Index, f1, &map), - createPointsToMapBetween(g2Index, e2Index, f2, &map) - }; - m_newRegions.push_back(region); - } - - if (gpIndex != e7Index) { - std::vector> region = { - createPointsToMapBetween(g2Index, e3Index, f1, &map), - collectEdgePoints(p, e3EdgeIndex, e4EdgeIndex), - createPointsToMapBetween(e4Index, gpIndex, f1, &map), - createPointsToMapBetween(gpIndex, g2Index, a, &map) - }; - m_newRegions.push_back(region); - } else { - std::vector> region = { - createPointsToMapBetween(g2Index, e3Index, f1, &map), - collectEdgePoints(p, e3EdgeIndex, c2AlternativeEdgeIndex), - collectEdgePoints(n, c2EdgeIndex, e7EdgeIndex), - createPointsToMapBetween(gpIndex, g2Index, a, &map) - }; - m_newRegions.push_back(region); - } - - if (gpIndex != e7Index) { - std::vector> region = { - collectEdgePoints(p, e4EdgeIndex, c2AlternativeEdgeIndex), - collectEdgePoints(n, c2EdgeIndex, e7EdgeIndex), - createPointsToMapBetween(e7Index, gpIndex, f3, &map), - createPointsToMapBetween(gpIndex, e4Index, f1, &map) - }; - m_newRegions.push_back(region); - } - - if (gpIndex != e7Index) { - std::vector> region = { - createPointsToMapBetween(gpIndex, e7Index, f3, &map), - collectEdgePoints(n, e7EdgeIndex, c3AlternativeEdgeIndex), - collectEdgePoints(q, c3EdgeIndex, e5EdgeIndex), - createPointsToMapBetween(e5Index, gpIndex, f0, &map) - }; - m_newRegions.push_back(region); - } - - if (gpIndex != e7Index) { - std::vector> region = { - createPointsToMapBetween(g1Index, gpIndex, b, &map), - createPointsToMapBetween(gpIndex, e5Index, f0, &map), - collectEdgePoints(q, e5EdgeIndex, e6EdgeIndex), - createPointsToMapBetween(e6Index, g1Index, f0, &map) - }; - m_newRegions.push_back(region); - } else { - std::vector> region = { - createPointsToMapBetween(g1Index, gpIndex, b, &map), - collectEdgePoints(n, e7EdgeIndex, c3AlternativeEdgeIndex), - collectEdgePoints(q, c3EdgeIndex, e6EdgeIndex), - createPointsToMapBetween(e6Index, g1Index, f0, &map) - }; - m_newRegions.push_back(region); - } - { - std::vector> region = { - createPointsToMapBetween(g1Index, g2Index, aPlusB, &map), - createPointsToMapBetween(g2Index, gpIndex, a, &map), - createPointsToMapBetween(gpIndex, g1Index, b, &map) - }; - m_newRegions.push_back(region); - } - return true; -} - -bool RegionFiller::resolveQuadrilateralRegionWithIntegerSolution(int m, int n, int p, int q, bool pqSwapped) -{ - // a + b = m − n - // a − b = p − q - // (a + b) + (a - b) = (m - n) + (p - q) - // a = ((m - n) + (p - q)) / 2 - - int a = ((m_sideSegmentNums[m] - m_sideSegmentNums[n]) + (m_sideSegmentNums[p] - m_sideSegmentNums[q])) / 2; - int b = (m_sideSegmentNums[m] - m_sideSegmentNums[n]) - a; - - bool isMismatchSimilar = 0 == b; - - int f0 = m_sideSegmentNums[n] / 2; - int f1 = m_sideSegmentNums[n] - f0; - int f2 = (m_sideSegmentNums[q] - b) / 2; - int f3 = m_sideSegmentNums[q] - b - f2; - - if (f3 < 0) { - qDebug() << "resolveQuadrilateralRegionWithIntegerSolution failed, f3:" << f3; - return false; - } - - float a1 = f0 * f2; - float a2 = f0 * b; - float a3 = f0 * f3; - float a4 = f1 * f2; - float a5 = f1 * a; - float a6 = f1 * f3; - float a7 = a * f2; - float a8 = b * f2; - float a9 = a * b; - - int c0EdgeIndex = pqSwapped ? (*m_sourcePolylines)[m].size() - 1 : 0; - int c1EdgeIndex = pqSwapped ? (*m_sourcePolylines)[p].size() - 1 : 0; - int c2EdgeIndex = pqSwapped ? (*m_sourcePolylines)[n].size() - 1 : 0; - int c3EdgeIndex = pqSwapped ? (*m_sourcePolylines)[q].size() - 1 : 0; - - int c0AlternativeEdgeIndex = pqSwapped ? 0 : (*m_sourcePolylines)[q].size() - 1; - int c1AlternativeEdgeIndex = pqSwapped ? 0 : (*m_sourcePolylines)[m].size() - 1; - int c2AlternativeEdgeIndex = pqSwapped ? 0 : (*m_sourcePolylines)[p].size() - 1; - int c3AlternativeEdgeIndex = pqSwapped ? 0 : (*m_sourcePolylines)[n].size() - 1; - - const auto &c0Index = (*m_sourcePolylines)[m][c0EdgeIndex]; - const auto &c1Index = (*m_sourcePolylines)[p][c1EdgeIndex]; - const auto &c2Index = (*m_sourcePolylines)[n][c2EdgeIndex]; - const auto &c3Index = (*m_sourcePolylines)[q][c3EdgeIndex]; - - const auto &c0 = (*m_sourceVertices)[c0Index].position; - const auto &c1 = (*m_sourceVertices)[c1Index].position; - const auto &c2 = (*m_sourceVertices)[c2Index].position; - const auto &c3 = (*m_sourceVertices)[c3Index].position; - - int e0EdgeIndex = f0; - if (pqSwapped) - e0EdgeIndex = (*m_sourcePolylines)[m].size() - 1 - e0EdgeIndex; - const auto &e0Index = (*m_sourcePolylines)[m][e0EdgeIndex]; - - int e1EdgeIndex = f0 + a; - if (pqSwapped) - e1EdgeIndex = (*m_sourcePolylines)[m].size() - 1 - e1EdgeIndex; - const auto &e1Index = (*m_sourcePolylines)[m][e1EdgeIndex]; - - int e2EdgeIndex = f0 + a + b; - if (pqSwapped) - e2EdgeIndex = (*m_sourcePolylines)[m].size() - 1 - e2EdgeIndex; - const auto &e2Index = (*m_sourcePolylines)[m][e2EdgeIndex]; - - int e3EdgeIndex = f2; - if (pqSwapped) - e3EdgeIndex = (*m_sourcePolylines)[p].size() - 1 - e3EdgeIndex; - const auto &e3Index = (*m_sourcePolylines)[p][e3EdgeIndex]; - - int e4EdgeIndex = f2 + a; - if (pqSwapped) - e4EdgeIndex = (*m_sourcePolylines)[p].size() - 1 - e4EdgeIndex; - const auto &e4Index = (*m_sourcePolylines)[p][e4EdgeIndex]; - - int e5EdgeIndex = f3; - if (pqSwapped) - e5EdgeIndex = (*m_sourcePolylines)[q].size() - 1 - e5EdgeIndex; - const auto &e5Index = (*m_sourcePolylines)[q][e5EdgeIndex]; - - int e6EdgeIndex = f3 + b; - if (pqSwapped) - e6EdgeIndex = (*m_sourcePolylines)[q].size() - 1 - e6EdgeIndex; - const auto &e6Index = (*m_sourcePolylines)[q][e6EdgeIndex]; - - int e7EdgeIndex = f1; - if (pqSwapped) - e7EdgeIndex = (*m_sourcePolylines)[n].size() - 1 - e7EdgeIndex; - const auto &e7Index = (*m_sourcePolylines)[n][e7EdgeIndex]; - - const auto &e0 = (*m_sourceVertices)[e0Index].position; - const auto &e1 = (*m_sourceVertices)[e1Index].position; - const auto &e2 = (*m_sourceVertices)[e2Index].position; - const auto &e3 = (*m_sourceVertices)[e3Index].position; - const auto &e4 = (*m_sourceVertices)[e4Index].position; - const auto &e5 = (*m_sourceVertices)[e5Index].position; - const auto &e6 = (*m_sourceVertices)[e6Index].position; - const auto &e7 = (*m_sourceVertices)[e7Index].position; - - auto g1 = e1 + e5 - c0; - auto gn = e1 + e4 - c1; - auto g2 = e4 + e7 - c2; - auto gp = e5 + e7 - c3; - - auto weight1 = 1.0 / (a1 + a2 + a7 + a9); - auto weightn = 1.0 / (a4 + a5 + a8 + a9); - auto weight2 = 1.0 / (a6); - auto weightp = 1.0 / (a3); - - auto gPosition = (g1 * weight1 + gn * weightn + g2 * weight2 + gp * weightp) / - (weight1 + weightn + weight2 + weightp); - - size_t gSource = 0; - auto gRadius = averageRadius(&gSource); - - auto averageOffsetDistance = e0.distanceToPoint(e2); - if (!isMismatchSimilar) - averageOffsetDistance *= 0.5; - auto g1Position = gPosition + (e6 - gPosition).normalized() * averageOffsetDistance * 0.7; - auto gnPosition = gPosition + (e1 - gPosition).normalized() * averageOffsetDistance * 0.7; - auto g2Position = gPosition + (e3 - gPosition).normalized() * averageOffsetDistance * 0.7; - auto gpPosition = gPosition + (e7 - gPosition).normalized() * averageOffsetDistance * 0.7; - - if (isMismatchSimilar) { - gpPosition = ((*m_sourceVertices)[e0Index].position + - (*m_sourceVertices)[e5Index].position + - (*m_sourceVertices)[e7Index].position + - (*m_sourceVertices)[e4Index].position) / 4.0; - gnPosition = ((*m_sourceVertices)[e0Index].position + - gpPosition + - (*m_sourceVertices)[e3Index].position + - (*m_sourceVertices)[c1Index].position) / 4.0; - } - - size_t g1Index = m_oldAndNewVertices.size(); - if (!isMismatchSimilar) { - Node node; - node.position = g1Position; - node.radius = gRadius; - node.source = gSource; - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - } - - size_t gnIndex = m_oldAndNewVertices.size(); - { - Node node; - node.position = gnPosition; - node.radius = gRadius; - node.source = gSource; - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - } - - size_t g2Index = m_oldAndNewVertices.size(); - if (!isMismatchSimilar) { - Node node; - node.position = g2Position; - node.radius = gRadius; - node.source = gSource; - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - } - - size_t gpIndex = m_oldAndNewVertices.size(); - { - Node node; - node.position = gpPosition; - node.radius = gRadius; - node.source = gSource; - m_centerSources.insert(node.source); - m_oldAndNewVertices.push_back(node); - } - - if (isMismatchSimilar) { - g1Index = gpIndex; - g2Index = gnIndex; - } - - std::map, std::vector> map; - - std::vector> region1 = { - collectEdgePoints(m, c0EdgeIndex, e0EdgeIndex), - createPointsToMapBetween(e0Index, g1Index, f2, &map), - createPointsToMapBetween(g1Index, e6Index, f0, &map), - collectEdgePoints(q, e6EdgeIndex, c0AlternativeEdgeIndex) - }; - m_newRegions.push_back(region1); - - if (e5Index != e6Index) { - std::vector> region2 = { - createPointsToMapBetween(e6Index, g1Index, f0, &map), - createPointsToMapBetween(g1Index, gpIndex, b, &map), - createPointsToMapBetween(gpIndex, e5Index, f0, &map), - collectEdgePoints(q, e5EdgeIndex, e6EdgeIndex) - }; - m_newRegions.push_back(region2); - } - - std::vector> region3 = { - createPointsToMapBetween(e5Index, gpIndex, f0, &map), - createPointsToMapBetween(gpIndex, e7Index, f3, &map), - collectEdgePoints(n, e7EdgeIndex, c3AlternativeEdgeIndex), - collectEdgePoints(q, c3EdgeIndex, e5EdgeIndex) - }; - m_newRegions.push_back(region3); - - std::vector> region4 = { - collectEdgePoints(m, e2EdgeIndex, c1AlternativeEdgeIndex), - collectEdgePoints(p, c1EdgeIndex, e3EdgeIndex), - createPointsToMapBetween(e3Index, g2Index, f1, &map), - createPointsToMapBetween(g2Index, e2Index, f2, &map) - }; - m_newRegions.push_back(region4); - - if (e3Index != e4Index) { - std::vector> region5 = { - createPointsToMapBetween(g2Index, e3Index, f1, &map), - collectEdgePoints(p, e3EdgeIndex, e4EdgeIndex), - createPointsToMapBetween(e4Index, gpIndex, f1, &map), - createPointsToMapBetween(gpIndex, g2Index, a, &map) - }; - m_newRegions.push_back(region5); - } - - std::vector> region6 = { - createPointsToMapBetween(gpIndex, e4Index, f1, &map), - collectEdgePoints(p, e4EdgeIndex, c2AlternativeEdgeIndex), - collectEdgePoints(n, c2EdgeIndex, e7EdgeIndex), - createPointsToMapBetween(e7Index, gpIndex, f3, &map) - }; - m_newRegions.push_back(region6); - - if (g1Index != gnIndex && e0Index != e1Index) { - std::vector> region7 = { - collectEdgePoints(m, e0EdgeIndex, e1EdgeIndex), - createPointsToMapBetween(e1Index, gnIndex, f2, &map), - createPointsToMapBetween(gnIndex, g1Index, a, &map), - createPointsToMapBetween(g1Index, e0Index, f2, &map) - }; - m_newRegions.push_back(region7); - } - - if (g2Index != gnIndex && e1Index != e2Index) { - std::vector> region8 = { - collectEdgePoints(m, e1EdgeIndex, e2EdgeIndex), - createPointsToMapBetween(e2Index, g2Index, f2, &map), - createPointsToMapBetween(g2Index, gnIndex, b, &map), - createPointsToMapBetween(gnIndex, e1Index, f2, &map) - }; - m_newRegions.push_back(region8); - } - - if (!isMismatchSimilar) { - std::vector> region9 = { - createPointsToMapBetween(g1Index, gnIndex, a, &map), - createPointsToMapBetween(gnIndex, g2Index, b, &map), - createPointsToMapBetween(g2Index, gpIndex, a, &map), - createPointsToMapBetween(gpIndex, g1Index, b, &map) - }; - m_newRegions.push_back(region9); - } - - return true; -} - -bool RegionFiller::resolveQuadrilateralRegion() -{ - int diff02 = std::abs(m_sideSegmentNums[0] - m_sideSegmentNums[2]); - int diff13 = std::abs(m_sideSegmentNums[1] - m_sideSegmentNums[3]); - int m, n, p, q; - if (diff02 >= diff13) { - if (m_sideSegmentNums[0] > m_sideSegmentNums[2]) { - m = 0; - n = 2; - p = 1; - q = 3; - } else { - m = 2; - n = 0; - p = 3; - q = 1; - } - } else { - if (m_sideSegmentNums[1] > m_sideSegmentNums[3]) { - m = 1; - n = 3; - p = 2; - q = 0; - } else { - m = 3; - n = 1; - p = 0; - q = 2; - } - } - bool pqSwapped = false; - if (m_sideSegmentNums[p] < m_sideSegmentNums[q]) { - std::swap(p, q); - pqSwapped = true; - } - if (diff02 != diff13) { - if (isEven(m_sumOfSegments)) { - return resolveQuadrilateralRegionWithIntegerSolution(m, n, p, q, pqSwapped); - } else { - return resolveQuadrilateralRegionWithNonIntegerSolution(m, n, p, q, pqSwapped); - } - } else { - return resolveQuadrilateralRegionMismatchSimilarCase(m, n, p, q, pqSwapped); - } -} - -const std::vector &RegionFiller::getOldAndNewVertices() -{ - return m_oldAndNewVertices; -} - -const std::vector> &RegionFiller::getNewFaces() -{ - return m_newFaces; -} - -void RegionFiller::prepare() -{ - m_sideNum = m_sourcePolylines->size(); - m_sideSegmentNums.clear(); - for (const auto &it: *m_sourcePolylines) { - auto l = (int)it.size() - 1; - m_sideSegmentNums.push_back(l); - } - m_sumOfSegments = std::accumulate(m_sideSegmentNums.begin(), m_sideSegmentNums.end(), 0); -} - -bool RegionFiller::resolveQuadrilateralRegionDirectCase() -{ - std::vector> region = { - collectEdgePoints(0, 0, (*m_sourcePolylines)[0].size() - 1), - collectEdgePoints(1, 0, (*m_sourcePolylines)[1].size() - 1), - collectEdgePoints(2, 0, (*m_sourcePolylines)[2].size() - 1), - collectEdgePoints(3, 0, (*m_sourcePolylines)[3].size() - 1) - }; - m_newRegions.push_back(region); - return true; -} - -void RegionFiller::fillWithoutPartition() -{ - m_oldAndNewVertices = *m_sourceVertices; - m_newFaces.clear(); - convertPolylinesToFaces(); -} - -bool RegionFiller::fill() -{ - m_oldAndNewVertices = *m_sourceVertices; - - prepare(); - - if (4 == m_sideNum) { - if (m_sideSegmentNums[0] == m_sideSegmentNums[2] && - m_sideSegmentNums[1] == m_sideSegmentNums[3]) { - if (!resolveQuadrilateralRegionDirectCase()) { - qDebug() << "resolveQuadrilateralRegionDirectCase failed"; - return false; - } - } else { - if (!resolveQuadrilateralRegion()) { - qDebug() << "resolveQuadrilateralRegion failed"; - return false; - } - } - } else { - if (isOdd(m_sideNum)) { - if (isEven(m_sumOfSegments)) { - if (!resolveOddSidedEvenSumOfSegments(m_sideNum)) { - qDebug() << "resolveOddSidedEvenSumOfSegments failed, m_sideNum:" << m_sideNum; - return false; - } - } else { - if (!resolveOddSidedOddSumOfSegments(m_sideNum)) { - qDebug() << "resolveOddSidedOddSumOfSegments failed, m_sideNum:" << m_sideNum; - return false; - } - } - } else { - int l1 = 0; - int l2 = 0; - - int halfSideNum = m_sideNum / 2; - - for (int i = 1; i <= halfSideNum; ++i) { - l1 += m_sideSegmentNums[(i * 2 - 1) % m_sideNum]; - l2 += m_sideSegmentNums[(i * 2 - 1 - 1) % m_sideNum]; - } - - if (isEven(l1) && isEven(l2)) { - if (!resolveEvenSidedEvenSumOfSegmentsAndBothL2L2AreEven()) { - qDebug() << "resolveEvenSidedEvenSumOfSegmentsAndBothL2L2AreEven failed"; - return false; - } - } else if (isOdd(l1) && isOdd(l2)) { - if (!resolveEvenSidedEvenSumOfSegmentsAndBothL2L2AreOdd()) { - qDebug() << "resolveEvenSidedEvenSumOfSegmentsAndBothL2L2AreOdd failed"; - return false; - } - } else if (isEven(l1) && isOdd(l2)) { - if (!resolveEvenSideEvenSumOfSegmentsAndL1IsEvenL2IsOdd()) { - qDebug() << "resolveEvenSideEvenSumOfSegmentsAndL1IsEvenL2IsOdd failed"; - return false; - } - } else { - if (!resolveEvenSideEvenSumOfSegmentsAndL1IsOddL2IsEven()) { - qDebug() << "resolveEvenSideEvenSumOfSegmentsAndL1IsOddL2IsEven failed"; - return false; - } - } - } - } - - if (!convertRegionsToPatches()) { - qDebug() << "convertRegionsToPatches failed"; - return false; - } - - return true; -} - -void RegionFiller::convertRegionsToFaces() -{ - if (m_newRegions.empty()) { - qDebug() << "No region, should not happen"; - return; - } - - for (const auto ®ion: m_newRegions) { - std::vector face; - for (const auto &line: region) { - for (size_t i = 1; i < line.size(); ++i) { - face.push_back(line[i]); - } - } - if (face.size() < 3) { - qDebug() << "Face length invalid:" << face.size(); - continue; - } - m_newFaces.push_back(face); - } -} - -void RegionFiller::convertPolylinesToFaces() -{ - if (m_sourcePolylines->empty()) - return; - - std::vector face; - for (const auto &line: *m_sourcePolylines) { - for (size_t i = 1; i < line.size(); ++i) { - face.push_back(line[i]); - } - } - if (face.size() < 3) { - return; - } - m_newFaces.push_back(face); -} - -bool RegionFiller::createCoonsPatchFrom(const std::vector &c0, - const std::vector &c1, - const std::vector &d0, - const std::vector &d1, - bool fillLastTriangle) -{ - auto Lc_Position = [&](int s, int t) { - float factor = (float)t / d0.size(); - return (1.0 - factor) * m_oldAndNewVertices[c0[s]].position + factor * m_oldAndNewVertices[c1[s]].position; - }; - auto Ld_Position = [&](int s, int t) { - float factor = (float)s / c0.size(); - return (1.0 - factor) * m_oldAndNewVertices[d0[t]].position + factor * m_oldAndNewVertices[d1[t]].position; - }; - auto B_Position = [&](int s, int t) { - float tFactor = (float)t / d0.size(); - float sFactor = (float)s / c0.size(); - return m_oldAndNewVertices[c0[0]].position * (1.0 - sFactor) * (1.0 - tFactor) + - m_oldAndNewVertices[c0[c0.size() - 1]].position * sFactor * (1.0 - tFactor) + - m_oldAndNewVertices[c1[0]].position * (1.0 - sFactor) * tFactor + - m_oldAndNewVertices[c1[c1.size() - 1]].position * sFactor * tFactor; - }; - auto C_Position = [&](int s, int t) { - return Lc_Position(s, t) + Ld_Position(s, t) - B_Position(s, t); - }; - - auto Lc_Radius = [&](int s, int t) { - float factor = (float)t / d0.size(); - return (1.0 - factor) * m_oldAndNewVertices[c0[s]].radius + factor * m_oldAndNewVertices[c1[s]].radius; - }; - auto Ld_Radius = [&](int s, int t) { - float factor = (float)s / c0.size(); - return (1.0 - factor) * m_oldAndNewVertices[d0[t]].radius + factor * m_oldAndNewVertices[d1[t]].radius; - }; - auto B_Radius = [&](int s, int t) { - float tFactor = (float)t / d0.size(); - float sFactor = (float)s / c0.size(); - return m_oldAndNewVertices[c0[0]].radius * (1.0 - sFactor) * (1.0 - tFactor) + - m_oldAndNewVertices[c0[c0.size() - 1]].radius * sFactor * (1.0 - tFactor) + - m_oldAndNewVertices[c1[0]].radius * (1.0 - sFactor) * tFactor + - m_oldAndNewVertices[c1[c1.size() - 1]].radius * sFactor * tFactor; - }; - auto C_Radius = [&](int s, int t) { - return Lc_Radius(s, t) + Ld_Radius(s, t) - B_Radius(s, t); - }; - - auto getSource = [&](size_t i, size_t j, float factor) { - if (m_centerSources.find(m_oldAndNewVertices[j].source) != m_centerSources.end()) { - return m_oldAndNewVertices[i].source; - } else if (m_centerSources.find(m_oldAndNewVertices[i].source) != m_centerSources.end()) { - return m_oldAndNewVertices[j].source; - } else { - if (factor > 0.5) { - return m_oldAndNewVertices[j].source; - } - return m_oldAndNewVertices[i].source; - } - }; - - auto Lc_Source = [&](int s, int t) { - float factor = (float)t / d0.size(); - return getSource(c0[s], c1[s], factor); - }; - auto C_Source = [&](int s, int t) { - return Lc_Source(s, t); - }; - - std::vector> grid(c0.size()); - for (int s = 1; s < (int)c0.size() - 1; ++s) { - grid[s].resize(d0.size()); - for (int t = 1; t < (int)d0.size() - 1; ++t) { - Node node; - node.position = C_Position(s, t); - node.radius = C_Radius(s, t); - node.source = C_Source(s, t); - grid[s][t] = m_oldAndNewVertices.size(); - m_oldAndNewVertices.push_back(node); - } - } - grid[0].resize(d0.size()); - grid[c0.size() - 1].resize(d0.size()); - for (size_t i = 0; i < c0.size(); ++i) { - grid[i][0] = c0[i]; - grid[i][d0.size() - 1] = c1[i]; - } - for (size_t i = 0; i < d0.size(); ++i) { - grid[0][i] = d0[i]; - grid[c0.size() - 1][i] = d1[i]; - } - for (int s = 1; s < (int)c0.size(); ++s) { - for (int t = 1; t < (int)d0.size(); ++t) { - std::vector face = { - grid[s - 1][t - 1], - grid[s - 1][t], - grid[s][t], - grid[s][t - 1] - }; - m_newFaces.push_back(face); - } - } - if (fillLastTriangle) { - std::vector face = { - grid[c0.size() - 1][d0.size() - 2], - grid[c0.size() - 2][d0.size() - 2], - grid[c0.size() - 2][d0.size() - 1] - }; - m_newFaces.push_back(face); - } - return true; -} - -bool RegionFiller::createCoonsPatch(const std::vector> ®ion) -{ - // https://en.wikipedia.org/wiki/Coons_patch - if (region.size() != 4) { - if (region.size() == 3) { - createCoonsPatchThreeSidedRegion(region); - return true; - } - qDebug() << "Invalid region edges:" << region.size(); - return false; - } - const auto &c0 = region[0]; - auto c1 = region[2]; - std::reverse(c1.begin(), c1.end()); - const auto &d1 = region[1]; - auto d0 = region[3]; - std::reverse(d0.begin(), d0.end()); - if (c0.empty() || - c0.size() != c1.size() || - d0.empty() || - d0.size() != d1.size()) { - qDebug() << "Invalid region size:" << c0.size() << c1.size() << d0.size() << d1.size(); - return false; - } - return createCoonsPatchFrom(c0, c1, d0, d1, false); -} - -bool RegionFiller::createCoonsPatchThreeSidedRegion(const std::vector> ®ion) -{ - if (region.size() != 3) { - qDebug() << "Not three sided region"; - return false; - } - - int longest = 0; - size_t longestLength = region[longest].size(); - for (int i = 1; i < 3; ++i) { - if (region[i].size() > longestLength) { - longest = i; - longestLength = region[i].size(); - } - } - - int c = longest; - int a = (c + 1) % 3; - int b = (a + 1) % 3; - - auto c0 = region[a]; - std::reverse(c0.begin(), c0.end()); - auto c1 = std::vector(region[c].begin(), region[c].begin() + c0.size()); - - auto d0 = region[b]; - auto d1 = std::vector(region[c].begin() + region[c].size() - d0.size(), region[c].begin() + region[c].size()); - std::reverse(d1.begin(), d1.end()); - - bool fillTriangle = region[c].size() != region[a].size() && - region[a].size() != region[b].size(); - if (c0.size() < d0.size()) { - if (!createCoonsPatchFrom(d0, d1, c0, c1, fillTriangle)) - return false; - } else { - if (!createCoonsPatchFrom(c0, c1, d0, d1, fillTriangle)) - return false; - } - - return true; -} - -bool RegionFiller::convertRegionsToPatches() -{ - if (m_newRegions.empty()) { - qDebug() << "No region, should not happen"; - return false; - } - for (const auto ®ion: m_newRegions) { - if (!createCoonsPatch(region)) - return false; - } - - return true; -} diff --git a/src/regionfiller.h b/src/regionfiller.h deleted file mode 100644 index 0ab01473..00000000 --- a/src/regionfiller.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef DUST3D_REGION_FILLER_H -#define DUST3D_REGION_FILLER_H -#include -#include -#include - -class RegionFiller -{ -public: - struct Node - { - QVector3D position; - float radius = 0.0; - size_t source = 0; - }; - RegionFiller(const std::vector *vertices, - const std::vector> *polylines); - ~RegionFiller(); - bool fill(); - void fillWithoutPartition(); - const std::vector &getOldAndNewVertices(); - const std::vector> &getNewFaces(); -private: - const std::vector *m_sourceVertices = nullptr; - std::vector> *m_sourcePolylines = nullptr; - int m_sideNum = 0; - int m_sumOfSegments = 0; - std::vector m_sideSegmentNums; - std::vector m_oldAndNewVertices; - std::vector> m_newFaces; - std::vector>> m_newRegions; - std::set m_centerSources; - float averageRadius(size_t *maxNodeIndex=nullptr); - void createPointsBetween(size_t fromIndex, - size_t toIndex, - size_t segments, - std::vector *newPointIndices); - std::vector createPointsBetween(size_t fromIndex, - size_t toIndex, - size_t segments); - void collectEdgePoints(size_t polyline, int startPos, int stopPos, - std::vector *pointIndices); - std::vector collectEdgePoints(size_t polyline, int startPos, int stopPos); - std::vector reversed(const std::vector &pointIndices); - std::vector createPointsToMapBetween(size_t fromIndex, - size_t toIndex, - size_t segments, - std::map, std::vector> *map); - bool resolveOddSidedEvenSumOfSegments(int siUpperBound); - bool resolveOddSidedOddSumOfSegments(int siUpperBound); - bool resolveEvenSidedEvenSumOfSegmentsAndBothL2L2AreEven(); - bool resolveEvenSidedEvenSumOfSegmentsAndBothL2L2AreOdd(); - bool resolveEvenSideEvenSumOfSegmentsAndL1IsEvenL2IsOdd(); - bool resolveEvenSideEvenSumOfSegmentsAndL1IsOddL2IsEven(); - bool resolveQuadrilateralRegion(); - bool resolveQuadrilateralRegionWithIntegerSolution(int m, int n, int p, int q, bool pqSwapped); - bool resolveQuadrilateralRegionMismatchSimilarCase(int m, int n, int p, int q, bool pqSwapped); - bool resolveQuadrilateralRegionWithNonIntegerSolution(int m, int n, int p, int q, bool pqSwapped); - bool resolveQuadrilateralRegionDirectCase(); - void convertRegionsToFaces(); - void prepare(); - bool createCoonsPatch(const std::vector> ®ion); - bool convertRegionsToPatches(); - bool createCoonsPatchFrom(const std::vector &c0, - const std::vector &c1, - const std::vector &d0, - const std::vector &d1, - bool fillLastTriangle=false); - bool createCoonsPatchThreeSidedRegion(const std::vector> ®ion); - void convertPolylinesToFaces(); -}; - -#endif - diff --git a/src/skeletondocument.cpp b/src/skeletondocument.cpp index a772a7b5..f1d988ca 100644 --- a/src/skeletondocument.cpp +++ b/src/skeletondocument.cpp @@ -81,5 +81,1220 @@ bool SkeletonDocument::isNodeConnectable(QUuid nodeId) const const SkeletonPart *part = findPart(node->partId); if (nullptr == part) return false; - return part->gridded; + return true; +} + +void SkeletonDocument::reduceNode(QUuid nodeId) +{ + const SkeletonNode *node = findNode(nodeId); + if (nullptr == node) { + qDebug() << "Find node failed:" << nodeId; + return; + } + if (node->edgeIds.size() != 2) { + return; + } + QUuid firstEdgeId = node->edgeIds[0]; + QUuid secondEdgeId = node->edgeIds[1]; + const SkeletonEdge *firstEdge = findEdge(firstEdgeId); + if (nullptr == firstEdge) { + qDebug() << "Find edge failed:" << firstEdgeId; + return; + } + const SkeletonEdge *secondEdge = findEdge(secondEdgeId); + if (nullptr == secondEdge) { + qDebug() << "Find edge failed:" << secondEdgeId; + return; + } + QUuid firstNeighborNodeId = firstEdge->neighborOf(nodeId); + QUuid secondNeighborNodeId = secondEdge->neighborOf(nodeId); + removeNode(nodeId); + addEdge(firstNeighborNodeId, secondNeighborNodeId); +} + +void SkeletonDocument::breakEdge(QUuid edgeId) +{ + const SkeletonEdge *edge = findEdge(edgeId); + if (nullptr == edge) { + qDebug() << "Find edge failed:" << edgeId; + return; + } + if (edge->nodeIds.size() != 2) { + return; + } + QUuid firstNodeId = edge->nodeIds[0]; + QUuid secondNodeId = edge->nodeIds[1]; + const SkeletonNode *firstNode = findNode(firstNodeId); + if (nullptr == firstNode) { + qDebug() << "Find node failed:" << firstNodeId; + return; + } + const SkeletonNode *secondNode = findNode(secondNodeId); + if (nullptr == secondNode) { + qDebug() << "Find node failed:" << secondNodeId; + return; + } + QVector3D firstOrigin(firstNode->getX(), firstNode->getY(), firstNode->getZ()); + QVector3D secondOrigin(secondNode->getX(), secondNode->getY(), secondNode->getZ()); + QVector3D middleOrigin = (firstOrigin + secondOrigin) / 2; + float middleRadius = (firstNode->radius + secondNode->radius) / 2; + removeEdge(edgeId); + QUuid middleNodeId = createNode(QUuid::createUuid(), middleOrigin.x(), middleOrigin.y(), middleOrigin.z(), middleRadius, firstNodeId); + if (middleNodeId.isNull()) { + qDebug() << "Add middle node failed"; + return; + } + addEdge(middleNodeId, secondNodeId); +} + +void SkeletonDocument::reverseEdge(QUuid edgeId) +{ + SkeletonEdge *edge = (SkeletonEdge *)findEdge(edgeId); + if (nullptr == edge) { + qDebug() << "Find edge failed:" << edgeId; + return; + } + if (edge->nodeIds.size() != 2) { + return; + } + std::swap(edge->nodeIds[0], edge->nodeIds[1]); + auto part = partMap.find(edge->partId); + if (part != partMap.end()) + part->second.dirty = true; + emit edgeReversed(edgeId); + emit skeletonChanged(); +} + +void SkeletonDocument::removeEdge(QUuid edgeId) +{ + const SkeletonEdge *edge = findEdge(edgeId); + if (nullptr == edge) { + qDebug() << "Find edge failed:" << edgeId; + return; + } + if (isPartReadonly(edge->partId)) + return; + const SkeletonPart *oldPart = findPart(edge->partId); + if (nullptr == oldPart) { + qDebug() << "Find part failed:" << edge->partId; + return; + } + QString nextPartName = oldPart->name; + QUuid oldPartId = oldPart->id; + std::vector> groups; + splitPartByEdge(&groups, edgeId); + std::vector> newPartNodeNumMap; + std::vector newPartIds; + for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) { + const auto newUuid = QUuid::createUuid(); + SkeletonPart &part = partMap[newUuid]; + part.id = newUuid; + part.copyAttributes(*oldPart); + part.name = nextPartName; + for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) { + auto nodeIt = nodeMap.find(*nodeIdIt); + if (nodeIt == nodeMap.end()) { + qDebug() << "Find node failed:" << *nodeIdIt; + continue; + } + nodeIt->second.partId = part.id; + part.nodeIds.push_back(nodeIt->first); + for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + qDebug() << "Find edge failed:" << *edgeIdIt; + continue; + } + edgeIt->second.partId = part.id; + } + } + addPartToComponent(part.id, findComponentParentId(part.componentId)); + newPartNodeNumMap.push_back({part.id, part.nodeIds.size()}); + newPartIds.push_back(part.id); + emit partAdded(part.id); + } + for (auto nodeIdIt = edge->nodeIds.begin(); nodeIdIt != edge->nodeIds.end(); nodeIdIt++) { + auto nodeIt = nodeMap.find(*nodeIdIt); + if (nodeIt == nodeMap.end()) { + qDebug() << "Find node failed:" << *nodeIdIt; + continue; + } + nodeIt->second.edgeIds.erase(std::remove(nodeIt->second.edgeIds.begin(), nodeIt->second.edgeIds.end(), edgeId), nodeIt->second.edgeIds.end()); + emit nodeOriginChanged(nodeIt->first); + } + edgeMap.erase(edgeId); + emit edgeRemoved(edgeId); + removePart(oldPartId); + + if (!newPartNodeNumMap.empty()) { + std::sort(newPartNodeNumMap.begin(), newPartNodeNumMap.end(), [&]( + const std::pair &first, const std::pair &second) { + return first.second > second.second; + }); + updateLinkedPart(oldPartId, newPartNodeNumMap[0].first); + } + + emit skeletonChanged(); +} + +void SkeletonDocument::removeNode(QUuid nodeId) +{ + const SkeletonNode *node = findNode(nodeId); + if (nullptr == node) { + qDebug() << "Find node failed:" << nodeId; + return; + } + if (isPartReadonly(node->partId)) + return; + const SkeletonPart *oldPart = findPart(node->partId); + if (nullptr == oldPart) { + qDebug() << "Find part failed:" << node->partId; + return; + } + QString nextPartName = oldPart->name; + QUuid oldPartId = oldPart->id; + std::vector> groups; + splitPartByNode(&groups, nodeId); + std::vector> newPartNodeNumMap; + std::vector newPartIds; + for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) { + const auto newUuid = QUuid::createUuid(); + SkeletonPart &part = partMap[newUuid]; + part.id = newUuid; + part.copyAttributes(*oldPart); + part.name = nextPartName; + for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) { + auto nodeIt = nodeMap.find(*nodeIdIt); + if (nodeIt == nodeMap.end()) { + qDebug() << "Find node failed:" << *nodeIdIt; + continue; + } + nodeIt->second.partId = part.id; + part.nodeIds.push_back(nodeIt->first); + for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + qDebug() << "Find edge failed:" << *edgeIdIt; + continue; + } + edgeIt->second.partId = part.id; + } + } + addPartToComponent(part.id, findComponentParentId(part.componentId)); + newPartNodeNumMap.push_back({part.id, part.nodeIds.size()}); + newPartIds.push_back(part.id); + emit partAdded(part.id); + } + for (auto edgeIdIt = node->edgeIds.begin(); edgeIdIt != node->edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + qDebug() << "Find edge failed:" << *edgeIdIt; + continue; + } + QUuid neighborId = edgeIt->second.neighborOf(nodeId); + auto nodeIt = nodeMap.find(neighborId); + if (nodeIt == nodeMap.end()) { + qDebug() << "Find node failed:" << neighborId; + continue; + } + nodeIt->second.edgeIds.erase(std::remove(nodeIt->second.edgeIds.begin(), nodeIt->second.edgeIds.end(), *edgeIdIt), nodeIt->second.edgeIds.end()); + edgeMap.erase(*edgeIdIt); + emit edgeRemoved(*edgeIdIt); + } + nodeMap.erase(nodeId); + emit nodeRemoved(nodeId); + removePart(oldPartId); + + if (!newPartNodeNumMap.empty()) { + std::sort(newPartNodeNumMap.begin(), newPartNodeNumMap.end(), [&]( + const std::pair &first, const std::pair &second) { + return first.second > second.second; + }); + updateLinkedPart(oldPartId, newPartNodeNumMap[0].first); + } + + emit skeletonChanged(); +} + +void SkeletonDocument::addNode(float x, float y, float z, float radius, QUuid fromNodeId) +{ + createNode(QUuid::createUuid(), x, y, z, radius, fromNodeId); +} + +void SkeletonDocument::addNodeWithId(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId) +{ + createNode(nodeId, x, y, z, radius, fromNodeId); +} + +QUuid SkeletonDocument::createNode(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId) +{ + QUuid partId; + const SkeletonNode *fromNode = nullptr; + bool newPartAdded = false; + if (fromNodeId.isNull()) { + const auto newUuid = QUuid::createUuid(); + SkeletonPart &part = partMap[newUuid]; + part.id = newUuid; + partId = part.id; + emit partAdded(partId); + newPartAdded = true; + } else { + fromNode = findNode(fromNodeId); + if (nullptr == fromNode) { + qDebug() << "Find node failed:" << fromNodeId; + return QUuid(); + } + partId = fromNode->partId; + if (isPartReadonly(partId)) + return QUuid(); + auto part = partMap.find(partId); + if (part != partMap.end()) + part->second.dirty = true; + } + SkeletonNode node(nodeId); + node.partId = partId; + node.setRadius(radius); + node.setX(x); + node.setY(y); + node.setZ(z); + nodeMap[node.id] = node; + partMap[partId].nodeIds.push_back(node.id); + + emit nodeAdded(node.id); + + if (nullptr != fromNode) { + SkeletonEdge edge; + edge.partId = partId; + edge.nodeIds.push_back(fromNode->id); + edge.nodeIds.push_back(node.id); + edgeMap[edge.id] = edge; + + nodeMap[node.id].edgeIds.push_back(edge.id); + nodeMap[fromNode->id].edgeIds.push_back(edge.id); + + emit edgeAdded(edge.id); + } + + if (newPartAdded) + addPartToComponent(partId, m_currentCanvasComponentId); + + emit skeletonChanged(); + + return node.id; +} + +void SkeletonDocument::joinNodeAndNeiborsToGroup(std::vector *group, QUuid nodeId, std::set *visitMap, QUuid noUseEdgeId) +{ + if (nodeId.isNull() || visitMap->find(nodeId) != visitMap->end()) + return; + const SkeletonNode *node = findNode(nodeId); + if (nullptr == node) { + qDebug() << "Find node failed:" << nodeId; + return; + } + visitMap->insert(nodeId); + group->push_back(nodeId); + for (auto edgeIt = node->edgeIds.begin(); edgeIt != node->edgeIds.end(); edgeIt++) { + if (noUseEdgeId == *edgeIt) + continue; + const SkeletonEdge *edge = findEdge(*edgeIt); + if (nullptr == edge) { + qDebug() << "Find edge failed:" << *edgeIt; + continue; + } + for (auto nodeIt = edge->nodeIds.begin(); nodeIt != edge->nodeIds.end(); nodeIt++) { + joinNodeAndNeiborsToGroup(group, *nodeIt, visitMap, noUseEdgeId); + } + } +} + +void SkeletonDocument::splitPartByNode(std::vector> *groups, QUuid nodeId) +{ + const SkeletonNode *node = findNode(nodeId); + std::set visitMap; + visitMap.insert(nodeId); + for (auto edgeIt = node->edgeIds.begin(); edgeIt != node->edgeIds.end(); edgeIt++) { + std::vector group; + const SkeletonEdge *edge = findEdge(*edgeIt); + if (nullptr == edge) { + qDebug() << "Find edge failed:" << *edgeIt; + continue; + } + joinNodeAndNeiborsToGroup(&group, edge->neighborOf(nodeId), &visitMap, *edgeIt); + if (!group.empty()) + groups->push_back(group); + } +} + +void SkeletonDocument::splitPartByEdge(std::vector> *groups, QUuid edgeId) +{ + const SkeletonEdge *edge = findEdge(edgeId); + if (nullptr == edge) { + qDebug() << "Find edge failed:" << edgeId; + return; + } + std::set visitMap; + for (auto nodeIt = edge->nodeIds.begin(); nodeIt != edge->nodeIds.end(); nodeIt++) { + std::vector group; + joinNodeAndNeiborsToGroup(&group, *nodeIt, &visitMap, edgeId); + if (!group.empty()) + groups->push_back(group); + } +} + +const SkeletonComponent *SkeletonDocument::findComponentParent(QUuid componentId) const +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << componentId; + return nullptr; + } + + if (component->second.parentId.isNull()) + return &rootComponent; + + return (SkeletonComponent *)findComponent(component->second.parentId); +} + +QUuid SkeletonDocument::findComponentParentId(QUuid componentId) const +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << componentId; + return QUuid(); + } + + return component->second.parentId; +} + +void SkeletonDocument::moveComponentUp(QUuid componentId) +{ + SkeletonComponent *parent = (SkeletonComponent *)findComponentParent(componentId); + if (nullptr == parent) + return; + + QUuid parentId = findComponentParentId(componentId); + + parent->moveChildUp(componentId); + parent->dirty = true; + emit componentChildrenChanged(parentId); + emit skeletonChanged(); +} + +void SkeletonDocument::moveComponentDown(QUuid componentId) +{ + SkeletonComponent *parent = (SkeletonComponent *)findComponentParent(componentId); + if (nullptr == parent) + return; + + QUuid parentId = findComponentParentId(componentId); + + parent->moveChildDown(componentId); + parent->dirty = true; + emit componentChildrenChanged(parentId); + emit skeletonChanged(); +} + +void SkeletonDocument::moveComponentToTop(QUuid componentId) +{ + SkeletonComponent *parent = (SkeletonComponent *)findComponentParent(componentId); + if (nullptr == parent) + return; + + QUuid parentId = findComponentParentId(componentId); + + parent->moveChildToTop(componentId); + parent->dirty = true; + emit componentChildrenChanged(parentId); + emit skeletonChanged(); +} + +void SkeletonDocument::moveComponentToBottom(QUuid componentId) +{ + SkeletonComponent *parent = (SkeletonComponent *)findComponentParent(componentId); + if (nullptr == parent) + return; + + QUuid parentId = findComponentParentId(componentId); + + parent->moveChildToBottom(componentId); + parent->dirty = true; + emit componentChildrenChanged(parentId); + emit skeletonChanged(); +} + +void SkeletonDocument::renameComponent(QUuid componentId, QString name) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << componentId; + return; + } + + if (component->second.name == name) + return; + + if (!name.trimmed().isEmpty()) + component->second.name = name; + emit componentNameChanged(componentId); + emit optionsChanged(); +} + +void SkeletonDocument::setComponentExpandState(QUuid componentId, bool expanded) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << componentId; + return; + } + + if (component->second.expanded == expanded) + return; + + component->second.expanded = expanded; + emit componentExpandStateChanged(componentId); + emit optionsChanged(); +} + +void SkeletonDocument::createNewComponentAndMoveThisIn(QUuid componentId) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << componentId; + return; + } + + SkeletonComponent *oldParent = (SkeletonComponent *)findComponentParent(componentId); + + SkeletonComponent newParent(QUuid::createUuid()); + newParent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1); + + oldParent->replaceChild(componentId, newParent.id); + newParent.parentId = oldParent->id; + newParent.addChild(componentId); + componentMap[newParent.id] = newParent; + + component->second.parentId = newParent.id; + + emit componentChildrenChanged(oldParent->id); + emit componentAdded(newParent.id); + emit optionsChanged(); +} + +void SkeletonDocument::createNewChildComponent(QUuid parentComponentId) +{ + SkeletonComponent *parentComponent = (SkeletonComponent *)findComponent(parentComponentId); + if (!parentComponent->linkToPartId.isNull()) { + parentComponentId = parentComponent->parentId; + parentComponent = (SkeletonComponent *)findComponent(parentComponentId); + } + + SkeletonComponent newComponent(QUuid::createUuid()); + newComponent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1); + + parentComponent->addChild(newComponent.id); + newComponent.parentId = parentComponentId; + + componentMap[newComponent.id] = newComponent; + + emit componentChildrenChanged(parentComponentId); + emit componentAdded(newComponent.id); + emit optionsChanged(); +} + +void SkeletonDocument::removePart(QUuid partId) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + qDebug() << "Part not found:" << partId; + return; + } + + if (!part->second.componentId.isNull()) { + removeComponent(part->second.componentId); + return; + } + + removePartDontCareComponent(partId); +} + +void SkeletonDocument::removePartDontCareComponent(QUuid partId) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + qDebug() << "Part not found:" << partId; + return; + } + + std::vector removedNodeIds; + std::vector removedEdgeIds; + + for (auto nodeIt = nodeMap.begin(); nodeIt != nodeMap.end();) { + if (nodeIt->second.partId != partId) { + nodeIt++; + continue; + } + removedNodeIds.push_back(nodeIt->second.id); + nodeIt = nodeMap.erase(nodeIt); + } + + for (auto edgeIt = edgeMap.begin(); edgeIt != edgeMap.end();) { + if (edgeIt->second.partId != partId) { + edgeIt++; + continue; + } + removedEdgeIds.push_back(edgeIt->second.id); + edgeIt = edgeMap.erase(edgeIt); + } + + partMap.erase(part); + + for (const auto &nodeId: removedNodeIds) { + emit nodeRemoved(nodeId); + } + for (const auto &edgeId: removedEdgeIds) { + emit edgeRemoved(edgeId); + } + emit partRemoved(partId); +} + +void SkeletonDocument::addPartToComponent(QUuid partId, QUuid componentId) +{ + SkeletonComponent child(QUuid::createUuid()); + + if (!componentId.isNull()) { + auto parentComponent = componentMap.find(componentId); + if (parentComponent == componentMap.end()) { + componentId = QUuid(); + rootComponent.addChild(child.id); + } else { + parentComponent->second.addChild(child.id); + } + } else { + rootComponent.addChild(child.id); + } + + partMap[partId].componentId = child.id; + child.linkToPartId = partId; + child.parentId = componentId; + componentMap[child.id] = child; + + emit componentChildrenChanged(componentId); + emit componentAdded(child.id); +} + +void SkeletonDocument::removeComponent(QUuid componentId) +{ + removeComponentRecursively(componentId); + emit skeletonChanged(); +} + +void SkeletonDocument::removeComponentRecursively(QUuid componentId) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << componentId; + return; + } + + if (!component->second.linkToPartId.isNull()) { + removePartDontCareComponent(component->second.linkToPartId); + } + + auto childrenIds = component->second.childrenIds; + for (const auto &childId: childrenIds) { + removeComponentRecursively(childId); + } + + QUuid parentId = component->second.parentId; + if (!parentId.isNull()) { + auto parentComponent = componentMap.find(parentId); + if (parentComponent == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << parentId; + } + parentComponent->second.dirty = true; + parentComponent->second.removeChild(componentId); + } else { + rootComponent.removeChild(componentId); + } + + componentMap.erase(component); + emit componentRemoved(componentId); + emit componentChildrenChanged(parentId); +} + +void SkeletonDocument::setCurrentCanvasComponentId(QUuid componentId) +{ + m_currentCanvasComponentId = componentId; + const SkeletonComponent *component = findComponent(m_currentCanvasComponentId); + if (nullptr == component) { + //qDebug() << "Current component switch to nullptr componentId:" << componentId; + m_currentCanvasComponentId = QUuid(); + } else { + //qDebug() << "Current component switch to " << component->name << "componentId:" << componentId; + if (!component->linkToPartId.isNull()) { + m_currentCanvasComponentId = component->parentId; + component = findComponent(m_currentCanvasComponentId); + //if (nullptr != component) { + // qDebug() << "Then switch to " << component->name << "componentId:" << m_currentCanvasComponentId; + //} + } + } +} + +void SkeletonDocument::addComponent(QUuid parentId) +{ + SkeletonComponent component(QUuid::createUuid()); + + if (!parentId.isNull()) { + auto parentComponent = componentMap.find(parentId); + if (parentComponent == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << parentId; + return; + } + parentComponent->second.addChild(component.id); + } else { + rootComponent.addChild(component.id); + } + + component.parentId = parentId; + componentMap[component.id] = component; + + emit componentChildrenChanged(parentId); + emit componentAdded(component.id); +} + +bool SkeletonDocument::isDescendantComponent(QUuid componentId, QUuid suspiciousId) +{ + const SkeletonComponent *loopComponent = findComponentParent(suspiciousId); + while (nullptr != loopComponent) { + if (loopComponent->id == componentId) + return true; + loopComponent = findComponentParent(loopComponent->parentId); + } + return false; +} + +void SkeletonDocument::moveComponent(QUuid componentId, QUuid toParentId) +{ + if (componentId == toParentId) + return; + + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "SkeletonComponent not found:" << componentId; + return; + } + + if (component->second.parentId == toParentId) + return; + + if (isDescendantComponent(componentId, toParentId)) + return; + + if (component->second.parentId.isNull()) { + rootComponent.removeChild(componentId); + emit componentChildrenChanged(rootComponent.id); + } else { + auto oldParent = componentMap.find(component->second.parentId); + if (oldParent != componentMap.end()) { + oldParent->second.dirty = true; + oldParent->second.removeChild(componentId); + emit componentChildrenChanged(oldParent->second.id); + } + } + + component->second.parentId = toParentId; + + if (toParentId.isNull()) { + rootComponent.addChild(componentId); + emit componentChildrenChanged(rootComponent.id); + } else { + auto newParent = componentMap.find(toParentId); + if (newParent != componentMap.end()) { + newParent->second.dirty = true; + newParent->second.addChild(componentId); + emit componentChildrenChanged(newParent->second.id); + } + } + + emit skeletonChanged(); +} + +void SkeletonDocument::setPartLockState(QUuid partId, bool locked) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + qDebug() << "Part not found:" << partId; + return; + } + if (part->second.locked == locked) + return; + part->second.locked = locked; + emit partLockStateChanged(partId); + emit optionsChanged(); +} + +void SkeletonDocument::setPartVisibleState(QUuid partId, bool visible) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + qDebug() << "Part not found:" << partId; + return; + } + if (part->second.visible == visible) + return; + part->second.visible = visible; + emit partVisibleStateChanged(partId); + emit optionsChanged(); +} + +void SkeletonDocument::setPartDisableState(QUuid partId, bool disabled) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + qDebug() << "Part not found:" << partId; + return; + } + if (part->second.disabled == disabled) + return; + part->second.disabled = disabled; + part->second.dirty = true; + emit partDisableStateChanged(partId); + emit skeletonChanged(); +} + +void SkeletonDocument::collectComponentDescendantParts(QUuid componentId, std::vector &partIds) const +{ + const SkeletonComponent *component = findComponent(componentId); + if (nullptr == component) + return; + + if (!component->linkToPartId.isNull()) { + partIds.push_back(component->linkToPartId); + return; + } + + for (const auto &childId: component->childrenIds) { + collectComponentDescendantParts(childId, partIds); + } +} + +void SkeletonDocument::collectComponentDescendantComponents(QUuid componentId, std::vector &componentIds) const +{ + const SkeletonComponent *component = findComponent(componentId); + if (nullptr == component) + return; + + if (!component->linkToPartId.isNull()) { + return; + } + + for (const auto &childId: component->childrenIds) { + componentIds.push_back(childId); + collectComponentDescendantComponents(childId, componentIds); + } +} + +void SkeletonDocument::hideOtherComponents(QUuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + std::set partIdSet; + for (const auto &partId: partIds) { + partIdSet.insert(partId); + } + for (const auto &part: partMap) { + if (partIdSet.find(part.first) != partIdSet.end()) + continue; + setPartVisibleState(part.first, false); + } +} + +void SkeletonDocument::lockOtherComponents(QUuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + std::set partIdSet; + for (const auto &partId: partIds) { + partIdSet.insert(partId); + } + for (const auto &part: partMap) { + if (partIdSet.find(part.first) != partIdSet.end()) + continue; + setPartLockState(part.first, true); + } +} + +void SkeletonDocument::hideAllComponents() +{ + for (const auto &part: partMap) { + setPartVisibleState(part.first, false); + } +} + +void SkeletonDocument::showAllComponents() +{ + for (const auto &part: partMap) { + setPartVisibleState(part.first, true); + } +} + +void SkeletonDocument::showOrHideAllComponents() +{ + bool foundVisiblePart = false; + for (const auto &part: partMap) { + if (part.second.visible) { + foundVisiblePart = true; + } + } + if (foundVisiblePart) + hideAllComponents(); + else + showAllComponents(); +} + +void SkeletonDocument::collapseAllComponents() +{ + for (const auto &component: componentMap) { + if (!component.second.linkToPartId.isNull()) + continue; + setComponentExpandState(component.first, false); + } +} + +void SkeletonDocument::expandAllComponents() +{ + for (const auto &component: componentMap) { + if (!component.second.linkToPartId.isNull()) + continue; + setComponentExpandState(component.first, true); + } +} + +void SkeletonDocument::lockAllComponents() +{ + for (const auto &part: partMap) { + setPartLockState(part.first, true); + } +} + +void SkeletonDocument::unlockAllComponents() +{ + for (const auto &part: partMap) { + setPartLockState(part.first, false); + } +} + +void SkeletonDocument::hideDescendantComponents(QUuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + for (const auto &partId: partIds) { + setPartVisibleState(partId, false); + } +} + +void SkeletonDocument::showDescendantComponents(QUuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + for (const auto &partId: partIds) { + setPartVisibleState(partId, true); + } +} + +void SkeletonDocument::lockDescendantComponents(QUuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + for (const auto &partId: partIds) { + setPartLockState(partId, true); + } +} + +void SkeletonDocument::unlockDescendantComponents(QUuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + for (const auto &partId: partIds) { + setPartLockState(partId, false); + } +} + +void SkeletonDocument::scaleNodeByAddRadius(QUuid nodeId, float amount) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + qDebug() << "Find node failed:" << nodeId; + return; + } + if (isPartReadonly(it->second.partId)) + return; + if (radiusLocked) + return; + it->second.setRadius(it->second.radius + amount); + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeRadiusChanged(nodeId); + emit skeletonChanged(); +} + +bool SkeletonDocument::isPartReadonly(QUuid partId) const +{ + const SkeletonPart *part = findPart(partId); + if (nullptr == part) { + qDebug() << "Find part failed:" << partId; + return true; + } + return part->locked || !part->visible; +} + +void SkeletonDocument::moveNodeBy(QUuid nodeId, float x, float y, float z) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + qDebug() << "Find node failed:" << nodeId; + return; + } + if (m_allPositionRelatedLocksEnabled && isPartReadonly(it->second.partId)) + return; + bool changed = false; + if (!(m_allPositionRelatedLocksEnabled && xlocked)) { + it->second.addX(x); + changed = true; + } + if (!(m_allPositionRelatedLocksEnabled && ylocked)) { + it->second.addY(y); + changed = true; + } + if (!(m_allPositionRelatedLocksEnabled && zlocked)) { + it->second.addZ(z); + changed = true; + } + if (!changed) + return; + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeOriginChanged(nodeId); + emit skeletonChanged(); +} + +void SkeletonDocument::moveOriginBy(float x, float y, float z) +{ + if (!(m_allPositionRelatedLocksEnabled && xlocked)) + addOriginX(x); + if (!(m_allPositionRelatedLocksEnabled && ylocked)) + addOriginY(y); + if (!(m_allPositionRelatedLocksEnabled && zlocked)) + addOriginZ(z); + markAllDirty(); + emit originChanged(); + emit skeletonChanged(); +} + +void SkeletonDocument::setNodeOrigin(QUuid nodeId, float x, float y, float z) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + qDebug() << "Find node failed:" << nodeId; + return; + } + if ((m_allPositionRelatedLocksEnabled && isPartReadonly(it->second.partId))) + return; + if (!(m_allPositionRelatedLocksEnabled && xlocked)) + it->second.setX(x); + if (!(m_allPositionRelatedLocksEnabled && ylocked)) + it->second.setY(y); + if (!(m_allPositionRelatedLocksEnabled && zlocked)) + it->second.setZ(z); + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeOriginChanged(nodeId); + emit skeletonChanged(); +} + +void SkeletonDocument::setNodeRadius(QUuid nodeId, float radius) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + qDebug() << "Find node failed:" << nodeId; + return; + } + if (isPartReadonly(it->second.partId)) + return; + if (!radiusLocked) + it->second.setRadius(radius); + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeRadiusChanged(nodeId); + emit skeletonChanged(); +} + +void SkeletonDocument::switchNodeXZ(QUuid nodeId) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + qDebug() << "Find node failed:" << nodeId; + return; + } + if (isPartReadonly(it->second.partId)) + return; + { + float oldX = it->second.getX(); + float oldZ = it->second.getZ(); + it->second.setX(oldZ); + it->second.setZ(oldX); + } + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeOriginChanged(nodeId); + emit skeletonChanged(); +} + +const SkeletonComponent *SkeletonDocument::findComponent(QUuid componentId) const +{ + if (componentId.isNull()) + return &rootComponent; + auto it = componentMap.find(componentId); + if (it == componentMap.end()) + return nullptr; + return &it->second; +} + +void SkeletonDocument::addEdge(QUuid fromNodeId, QUuid toNodeId) +{ + if (findEdgeByNodes(fromNodeId, toNodeId)) { + qDebug() << "Add edge but edge already existed:" << fromNodeId << toNodeId; + return; + } + + const SkeletonNode *fromNode = nullptr; + const SkeletonNode *toNode = nullptr; + bool toPartRemoved = false; + + fromNode = findNode(fromNodeId); + if (nullptr == fromNode) { + qDebug() << "Find node failed:" << fromNodeId; + return; + } + + if (isPartReadonly(fromNode->partId)) + return; + + toNode = findNode(toNodeId); + if (nullptr == toNode) { + qDebug() << "Find node failed:" << toNodeId; + return; + } + + if (isPartReadonly(toNode->partId)) + return; + + QUuid toPartId = toNode->partId; + + auto fromPart = partMap.find(fromNode->partId); + if (fromPart == partMap.end()) { + qDebug() << "Find part failed:" << fromNode->partId; + return; + } + + fromPart->second.dirty = true; + + if (fromNode->partId != toNode->partId) { + toPartRemoved = true; + std::vector toGroup; + std::set visitMap; + joinNodeAndNeiborsToGroup(&toGroup, toNodeId, &visitMap); + for (auto nodeIdIt = toGroup.begin(); nodeIdIt != toGroup.end(); nodeIdIt++) { + auto nodeIt = nodeMap.find(*nodeIdIt); + if (nodeIt == nodeMap.end()) { + qDebug() << "Find node failed:" << *nodeIdIt; + continue; + } + nodeIt->second.partId = fromNode->partId; + fromPart->second.nodeIds.push_back(nodeIt->first); + for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + qDebug() << "Find edge failed:" << *edgeIdIt; + continue; + } + edgeIt->second.partId = fromNode->partId; + } + } + } + + SkeletonEdge edge; + edge.partId = fromNode->partId; + edge.nodeIds.push_back(fromNode->id); + edge.nodeIds.push_back(toNodeId); + edgeMap[edge.id] = edge; + + nodeMap[toNodeId].edgeIds.push_back(edge.id); + nodeMap[fromNode->id].edgeIds.push_back(edge.id); + + emit edgeAdded(edge.id); + + if (toPartRemoved) { + updateLinkedPart(toPartId, fromNode->partId); + removePart(toPartId); + } + + emit skeletonChanged(); +} + +void SkeletonDocument::updateLinkedPart(QUuid oldPartId, QUuid newPartId) +{ + for (auto &partIt: partMap) { + if (partIt.second.cutFaceLinkedId == oldPartId) { + partIt.second.dirty = true; + partIt.second.setCutFaceLinkedId(newPartId); + } + } + std::set dirtyPartIds; + for (auto &nodeIt: nodeMap) { + if (nodeIt.second.cutFaceLinkedId == oldPartId) { + dirtyPartIds.insert(nodeIt.second.partId); + nodeIt.second.setCutFaceLinkedId(newPartId); + } + } + for (const auto &partId: dirtyPartIds) { + SkeletonPart *part = (SkeletonPart *)findPart(partId); + if (nullptr == part) + continue; + part->dirty = true; + } +} + +void SkeletonDocument::enableAllPositionRelatedLocks() +{ + m_allPositionRelatedLocksEnabled = true; +} + +void SkeletonDocument::disableAllPositionRelatedLocks() +{ + m_allPositionRelatedLocksEnabled = false; +} + +void SkeletonDocument::resetDirtyFlags() +{ + for (auto &part: partMap) { + part.second.dirty = false; + } + for (auto &component: componentMap) { + component.second.dirty = false; + } +} + +void SkeletonDocument::markAllDirty() +{ + for (auto &part: partMap) { + part.second.dirty = true; + } } diff --git a/src/skeletondocument.h b/src/skeletondocument.h index af1b0988..be797cc4 100644 --- a/src/skeletondocument.h +++ b/src/skeletondocument.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "bonemark.h" #include "theme.h" #include "model.h" @@ -183,7 +184,6 @@ public: QUuid deformMapImageId; float hollowThickness; bool countershaded; - bool gridded; QUuid fillMeshLinkedId; bool isPreviewMeshObsolete; QPixmap previewPixmap; @@ -213,7 +213,6 @@ public: deformMapScale(1.0), hollowThickness(0.0), countershaded(false), - gridded(false), isPreviewMeshObsolete(false), smooth(true) { @@ -441,9 +440,147 @@ enum class SkeletonProfile Side }; +class SkeletonComponent +{ +public: + SkeletonComponent() + { + } + SkeletonComponent(const QUuid &withId, const QString &linkData=QString(), const QString &linkDataType=QString()) + { + id = withId.isNull() ? QUuid::createUuid() : withId; + if (!linkData.isEmpty()) { + if ("partId" == linkDataType) { + linkToPartId = QUuid(linkData); + } + } + } + QUuid id; + QString name; + QUuid linkToPartId; + QUuid parentId; + bool expanded = true; + CombineMode combineMode = Preferences::instance().componentCombineMode(); + bool dirty = true; + std::vector childrenIds; + QString linkData() const + { + return linkToPartId.isNull() ? QString() : linkToPartId.toString(); + } + QString linkDataType() const + { + return linkToPartId.isNull() ? QString() : QString("partId"); + } + void addChild(QUuid childId) + { + if (m_childrenIdSet.find(childId) != m_childrenIdSet.end()) + return; + m_childrenIdSet.insert(childId); + childrenIds.push_back(childId); + } + void removeChild(QUuid childId) + { + if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) + return; + m_childrenIdSet.erase(childId); + auto findResult = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (findResult != childrenIds.end()) + childrenIds.erase(findResult); + } + void replaceChild(QUuid childId, QUuid newId) + { + if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) + return; + if (m_childrenIdSet.find(newId) != m_childrenIdSet.end()) + return; + m_childrenIdSet.erase(childId); + m_childrenIdSet.insert(newId); + auto findResult = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (findResult != childrenIds.end()) + *findResult = newId; + } + void moveChildUp(QUuid childId) + { + auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (it == childrenIds.end()) { + qDebug() << "Child not found in list:" << childId; + return; + } + + auto index = std::distance(childrenIds.begin(), it); + if (index == 0) + return; + std::swap(childrenIds[index - 1], childrenIds[index]); + } + void moveChildDown(QUuid childId) + { + auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (it == childrenIds.end()) { + qDebug() << "Child not found in list:" << childId; + return; + } + + auto index = std::distance(childrenIds.begin(), it); + if (index == (int)childrenIds.size() - 1) + return; + std::swap(childrenIds[index], childrenIds[index + 1]); + } + void moveChildToTop(QUuid childId) + { + auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (it == childrenIds.end()) { + qDebug() << "Child not found in list:" << childId; + return; + } + + auto index = std::distance(childrenIds.begin(), it); + if (index == 0) + return; + for (int i = index; i >= 1; i--) + std::swap(childrenIds[i - 1], childrenIds[i]); + } + void moveChildToBottom(QUuid childId) + { + auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (it == childrenIds.end()) { + qDebug() << "Child not found in list:" << childId; + return; + } + + auto index = std::distance(childrenIds.begin(), it); + if (index == (int)childrenIds.size() - 1) + return; + for (int i = index; i <= (int)childrenIds.size() - 2; i++) + std::swap(childrenIds[i], childrenIds[i + 1]); + } +private: + std::set m_childrenIdSet; +}; + class SkeletonDocument : public QObject { Q_OBJECT +signals: + void partAdded(QUuid partId); + void nodeAdded(QUuid nodeId); + void edgeAdded(QUuid edgeId); + void partRemoved(QUuid partId); + void partLockStateChanged(QUuid partId); + void partVisibleStateChanged(QUuid partId); + void partDisableStateChanged(QUuid partId); + void componentNameChanged(QUuid componentId); + void componentChildrenChanged(QUuid componentId); + void componentRemoved(QUuid componentId); + void componentAdded(QUuid componentId); + void componentExpandStateChanged(QUuid componentId); + void nodeRemoved(QUuid nodeId); + void edgeRemoved(QUuid edgeId); + void nodeRadiusChanged(QUuid nodeId); + void nodeOriginChanged(QUuid nodeId); + void edgeReversed(QUuid edgeId); + void originChanged(); + void skeletonChanged(); + void optionsChanged(); public: SkeletonDocumentEditMode editMode = SkeletonDocumentEditMode::Select; bool xlocked = false; @@ -455,6 +592,8 @@ public: std::map partMap; std::map nodeMap; std::map edgeMap; + std::map componentMap; + SkeletonComponent rootComponent; const SkeletonNode *findNode(QUuid nodeId) const; const SkeletonEdge *findEdge(QUuid edgeId) const; @@ -462,6 +601,13 @@ public: const SkeletonEdge *findEdgeByNodes(QUuid firstNodeId, QUuid secondNodeId) const; void findAllNeighbors(QUuid nodeId, std::set &neighbors) const; bool isNodeConnectable(QUuid nodeId) const; + const SkeletonComponent *findComponent(QUuid componentId) const; + const SkeletonComponent *findComponentParent(QUuid componentId) const; + QUuid findComponentParentId(QUuid componentId) const; + void collectComponentDescendantParts(QUuid componentId, std::vector &partIds) const; + void collectComponentDescendantComponents(QUuid componentId, std::vector &componentIds) const; + void resetDirtyFlags(); + void markAllDirty(); virtual bool undoable() const = 0; virtual bool redoable() const = 0; @@ -527,11 +673,71 @@ public slots: virtual void undo() = 0; virtual void redo() = 0; virtual void paste() = 0; + + void removeNode(QUuid nodeId); + void removeEdge(QUuid edgeId); + void removePart(QUuid partId); + void addNodeWithId(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId); + void addNode(float x, float y, float z, float radius, QUuid fromNodeId); + void scaleNodeByAddRadius(QUuid nodeId, float amount); + void moveNodeBy(QUuid nodeId, float x, float y, float z); + void setNodeOrigin(QUuid nodeId, float x, float y, float z); + void setNodeRadius(QUuid nodeId, float radius); + void switchNodeXZ(QUuid nodeId); + void moveOriginBy(float x, float y, float z); + void addEdge(QUuid fromNodeId, QUuid toNodeId); + void moveComponentUp(QUuid componentId); + void moveComponentDown(QUuid componentId); + void moveComponentToTop(QUuid componentId); + void moveComponentToBottom(QUuid componentId); + void renameComponent(QUuid componentId, QString name); + void removeComponent(QUuid componentId); + void addComponent(QUuid parentId); + void moveComponent(QUuid componentId, QUuid toParentId); + void setCurrentCanvasComponentId(QUuid componentId); + void createNewComponentAndMoveThisIn(QUuid componentId); + void createNewChildComponent(QUuid parentComponentId); + void setComponentExpandState(QUuid componentId, bool expanded); + void hideOtherComponents(QUuid componentId); + void lockOtherComponents(QUuid componentId); + void hideAllComponents(); + void showAllComponents(); + void showOrHideAllComponents(); + void collapseAllComponents(); + void expandAllComponents(); + void lockAllComponents(); + void unlockAllComponents(); + void hideDescendantComponents(QUuid componentId); + void showDescendantComponents(QUuid componentId); + void lockDescendantComponents(QUuid componentId); + void unlockDescendantComponents(QUuid componentId); + void setPartLockState(QUuid partId, bool locked); + void setPartVisibleState(QUuid partId, bool visible); + void setPartDisableState(QUuid partId, bool disabled); + void enableAllPositionRelatedLocks(); + void disableAllPositionRelatedLocks(); + bool isPartReadonly(QUuid partId) const; + void breakEdge(QUuid edgeId); + void reduceNode(QUuid nodeId); + void reverseEdge(QUuid edgeId); private: float m_originX = 0; float m_originY = 0; float m_originZ = 0; + + QUuid m_currentCanvasComponentId; + bool m_allPositionRelatedLocksEnabled = true; + + void splitPartByNode(std::vector> *groups, QUuid nodeId); + void joinNodeAndNeiborsToGroup(std::vector *group, QUuid nodeId, std::set *visitMap, QUuid noUseEdgeId=QUuid()); + void splitPartByEdge(std::vector> *groups, QUuid edgeId); + void removePartDontCareComponent(QUuid partId); + void addPartToComponent(QUuid partId, QUuid componentId); + bool isDescendantComponent(QUuid componentId, QUuid suspiciousId); + void removeComponentRecursively(QUuid componentId); + void updateLinkedPart(QUuid oldPartId, QUuid newPartId); + QUuid createNode(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId); }; #endif