diff --git a/docs/interface/menubar.rst b/docs/interface/menubar.rst index 751500f6..7cc823c8 100644 --- a/docs/interface/menubar.rst +++ b/docs/interface/menubar.rst @@ -85,9 +85,9 @@ V Flip ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Flip selected nodes vertically. -Align to Center +Align To ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Align selected nodes vertically with center anchor. Normally, the center anchor(a Triangle) is not show up, you can turn on the Part Mirror to make it visible, then turn Part Mirror off, the center anchor would not gone once showed. +Align selected nodes with center anchor globally or selected nodes' center locally. Normally, the center anchor(a Triangle) is not show up, you can turn on the Part Mirror to make it visible, then turn Part Mirror off, the center anchor would not gone once showed. Mark As ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/meshutil.cpp b/src/meshutil.cpp index ac49575f..efc99789 100644 --- a/src/meshutil.cpp +++ b/src/meshutil.cpp @@ -41,9 +41,16 @@ typename CGAL::Surface_mesh *makeCgalMeshFromMeshlite( assert(vertexArrayLen == vertexCount * 3); std::vector::Vertex_index> vertices; for (int i = 0; i < vertexCount; i++) { - vertices.push_back(mesh->add_vertex(typename Kernel::Point_3(vertexPositions[offset + 0], - vertexPositions[offset + 1], - vertexPositions[offset + 2]))); + float x = vertexPositions[offset + 0]; + float y = vertexPositions[offset + 1]; + float z = vertexPositions[offset + 2]; + if (std::isnan(x) || std::isinf(x)) + x = 0; + if (std::isnan(y) || std::isinf(y)) + y = 0; + if (std::isnan(z) || std::isinf(z)) + z = 0; + vertices.push_back(mesh->add_vertex(typename Kernel::Point_3(x, y, z))); offset += 3; } int faceCount = meshlite_get_face_count(meshlite, meshId); @@ -53,13 +60,15 @@ typename CGAL::Surface_mesh *makeCgalMeshFromMeshlite( while (i < filledLength) { int num = faceVertexNumAndIndices[i++]; assert(num > 0 && num <= MAX_VERTICES_PER_FACE); - std::vector::Vertex_index> faceIndices; + std::vector::Vertex_index> faceVertexIndices; for (int j = 0; j < num; j++) { int index = faceVertexNumAndIndices[i++]; assert(index >= 0 && index < vertexCount); - faceIndices.push_back(vertices[index]); + faceVertexIndices.push_back(vertices[index]); + } + if (faceVertexIndices.size() >= 3) { + mesh->add_face(faceVertexIndices); } - mesh->add_face(faceIndices); } delete[] faceVertexNumAndIndices; delete[] vertexPositions; diff --git a/src/skeletondocumentwindow.cpp b/src/skeletondocumentwindow.cpp index d12c2c98..91d1f084 100644 --- a/src/skeletondocumentwindow.cpp +++ b/src/skeletondocumentwindow.cpp @@ -303,9 +303,33 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() : connect(m_flipVerticallyAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::flipVertically); m_editMenu->addAction(m_flipVerticallyAction); - m_alignToCenterAction = new QAction(tr("Align to Center"), this); - connect(m_alignToCenterAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::alignSelectedToCenter); - m_editMenu->addAction(m_alignToCenterAction); + m_alignToMenu = new QMenu(tr("Align To")); + + m_alignToGlobalCenterAction = new QAction(tr("Global Center"), this); + connect(m_alignToGlobalCenterAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::alignSelectedToGlobalCenter); + m_alignToMenu->addAction(m_alignToGlobalCenterAction); + + m_alignToGlobalVerticalCenterAction = new QAction(tr("Global Vertical Center"), this); + connect(m_alignToGlobalVerticalCenterAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::alignSelectedToGlobalVerticalCenter); + m_alignToMenu->addAction(m_alignToGlobalVerticalCenterAction); + + m_alignToGlobalHorizontalCenterAction = new QAction(tr("Global Horizontal Center"), this); + connect(m_alignToGlobalHorizontalCenterAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::alignSelectedToGlobalHorizontalCenter); + m_alignToMenu->addAction(m_alignToGlobalHorizontalCenterAction); + + m_alignToLocalCenterAction = new QAction(tr("Local Center"), this); + connect(m_alignToLocalCenterAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::alignSelectedToLocalCenter); + m_alignToMenu->addAction(m_alignToLocalCenterAction); + + m_alignToLocalVerticalCenterAction = new QAction(tr("Local Vertical Center"), this); + connect(m_alignToLocalVerticalCenterAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::alignSelectedToLocalVerticalCenter); + m_alignToMenu->addAction(m_alignToLocalVerticalCenterAction); + + m_alignToLocalHorizontalCenterAction = new QAction(tr("Local Horizontal Center"), this); + connect(m_alignToLocalHorizontalCenterAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::alignSelectedToLocalHorizontalCenter); + m_alignToMenu->addAction(m_alignToLocalHorizontalCenterAction); + + m_editMenu->addMenu(m_alignToMenu); m_markAsMenu = new QMenu(tr("Mark As")); @@ -351,7 +375,13 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() : m_pasteAction->setEnabled(m_document->hasPastableContentInClipboard()); m_flipHorizontallyAction->setEnabled(m_graphicsWidget->hasMultipleSelection()); m_flipVerticallyAction->setEnabled(m_graphicsWidget->hasMultipleSelection()); - m_alignToCenterAction->setEnabled(m_graphicsWidget->hasSelection() && m_document->originSettled()); + m_alignToGlobalCenterAction->setEnabled(m_graphicsWidget->hasSelection() && m_document->originSettled()); + m_alignToGlobalVerticalCenterAction->setEnabled(m_graphicsWidget->hasSelection() && m_document->originSettled()); + m_alignToGlobalHorizontalCenterAction->setEnabled(m_graphicsWidget->hasSelection() && m_document->originSettled()); + m_alignToLocalCenterAction->setEnabled(m_graphicsWidget->hasMultipleSelection()); + m_alignToLocalVerticalCenterAction->setEnabled(m_graphicsWidget->hasMultipleSelection()); + m_alignToLocalHorizontalCenterAction->setEnabled(m_graphicsWidget->hasMultipleSelection()); + m_alignToMenu->setEnabled((m_graphicsWidget->hasSelection() && m_document->originSettled()) || m_graphicsWidget->hasMultipleSelection()); m_markAsMenu->setEnabled(m_graphicsWidget->hasNodeSelection()); m_selectAllAction->setEnabled(m_graphicsWidget->hasItems()); m_selectPartAllAction->setEnabled(m_graphicsWidget->hasItems()); diff --git a/src/skeletondocumentwindow.h b/src/skeletondocumentwindow.h index 5b107263..6e15fc1c 100644 --- a/src/skeletondocumentwindow.h +++ b/src/skeletondocumentwindow.h @@ -91,7 +91,15 @@ private: QAction *m_pasteAction; QAction *m_flipHorizontallyAction; QAction *m_flipVerticallyAction; - QAction *m_alignToCenterAction; + + QMenu *m_alignToMenu; + QAction *m_alignToGlobalCenterAction; + QAction *m_alignToGlobalVerticalCenterAction; + QAction *m_alignToGlobalHorizontalCenterAction; + QAction *m_alignToLocalCenterAction; + QAction *m_alignToLocalVerticalCenterAction; + QAction *m_alignToLocalHorizontalCenterAction; + QAction *m_selectAllAction; QAction *m_selectPartAllAction; QAction *m_unselectAllAction; diff --git a/src/skeletongraphicswidget.cpp b/src/skeletongraphicswidget.cpp index d6c03bbc..1a2193ff 100644 --- a/src/skeletongraphicswidget.cpp +++ b/src/skeletongraphicswidget.cpp @@ -176,9 +176,40 @@ void SkeletonGraphicsWidget::showContextMenu(const QPoint &pos) QAction alignToCenterAction(tr("Align to Center"), this); if (hasSelection() && m_document->originSettled()) { - connect(&alignToCenterAction, &QAction::triggered, this, &SkeletonGraphicsWidget::alignSelectedToCenter); + connect(&alignToCenterAction, &QAction::triggered, this, &SkeletonGraphicsWidget::alignSelectedToGlobalVerticalCenter); contextMenu.addAction(&alignToCenterAction); } + QAction alignToLocalCenterAction(tr("Local Center"), this); + QAction alignToLocalVerticalCenterAction(tr("Local Vertical Center"), this); + QAction alignToLocalHorizontalCenterAction(tr("Local Horizontal Center"), this); + QAction alignToGlobalCenterAction(tr("Global Center"), this); + QAction alignToGlobalVerticalCenterAction(tr("Global Vertical Center"), this); + QAction alignToGlobalHorizontalCenterAction(tr("Global Horizontal Center"), this); + if ((hasSelection() && m_document->originSettled()) || hasMultipleSelection()) { + QMenu *subMenu = contextMenu.addMenu(tr("Align To")); + + if (hasMultipleSelection()) { + connect(&alignToLocalCenterAction, &QAction::triggered, this, &SkeletonGraphicsWidget::alignSelectedToLocalCenter); + subMenu->addAction(&alignToLocalCenterAction); + + connect(&alignToLocalVerticalCenterAction, &QAction::triggered, this, &SkeletonGraphicsWidget::alignSelectedToLocalVerticalCenter); + subMenu->addAction(&alignToLocalVerticalCenterAction); + + connect(&alignToLocalHorizontalCenterAction, &QAction::triggered, this, &SkeletonGraphicsWidget::alignSelectedToLocalHorizontalCenter); + subMenu->addAction(&alignToLocalHorizontalCenterAction); + } + + if (hasSelection() && m_document->originSettled()) { + connect(&alignToGlobalCenterAction, &QAction::triggered, this, &SkeletonGraphicsWidget::alignSelectedToGlobalCenter); + subMenu->addAction(&alignToGlobalCenterAction); + + connect(&alignToGlobalVerticalCenterAction, &QAction::triggered, this, &SkeletonGraphicsWidget::alignSelectedToGlobalVerticalCenter); + subMenu->addAction(&alignToGlobalVerticalCenterAction); + + connect(&alignToGlobalHorizontalCenterAction, &QAction::triggered, this, &SkeletonGraphicsWidget::alignSelectedToGlobalHorizontalCenter); + subMenu->addAction(&alignToGlobalHorizontalCenterAction); + } + } QAction markAsNoneAction(tr("None"), this); QAction *markAsActions[SKELETON_BONE_MARK_TYPE_NUM]; @@ -311,7 +342,34 @@ void SkeletonGraphicsWidget::connectSelected() emit groupOperationAdded(); } -void SkeletonGraphicsWidget::alignSelectedToCenter() +void SkeletonGraphicsWidget::alignSelectedToLocal(bool alignToVerticalCenter, bool alignToHorizontalCenter) +{ + if (!hasMultipleSelection()) + return; + std::set nodeItems; + readMergedSkeletonNodeSetFromRangeSelection(&nodeItems); + if (nodeItems.empty()) + return; + if (nodeItems.size() < 2) + return; + emit batchChangeBegin(); + QVector2D center = centerOfNodeItemSet(nodeItems); + for (const auto &it: nodeItems) { + SkeletonGraphicsNodeItem *nodeItem = it; + QPointF nodeOrigin = nodeItem->origin(); + float byX = alignToHorizontalCenter ? sceneRadiusToUnified(center.x() - nodeOrigin.x()) : 0; + float byY = alignToVerticalCenter ? sceneRadiusToUnified(center.y() - nodeOrigin.y()) : 0; + if (SkeletonProfile::Main == nodeItem->profile()) { + emit moveNodeBy(nodeItem->id(), byX, byY, 0); + } else { + emit moveNodeBy(nodeItem->id(), 0, byY, byX); + } + } + emit batchChangeEnd(); + emit groupOperationAdded(); +} + +void SkeletonGraphicsWidget::alignSelectedToGlobal(bool alignToVerticalCenter, bool alignToHorizontalCenter) { if (!m_document->originSettled()) return; @@ -329,15 +387,57 @@ void SkeletonGraphicsWidget::alignSelectedToCenter() continue; } if (SkeletonProfile::Main == nodeItem->profile()) { - emit moveNodeBy(node->id, m_document->originX - node->x, 0, 0); + if (alignToVerticalCenter && alignToHorizontalCenter) { + emit moveNodeBy(node->id, m_document->originX - node->x, m_document->originY - node->y, 0); + } else if (alignToVerticalCenter) { + emit moveNodeBy(node->id, 0, m_document->originY - node->y, 0); + } else if (alignToHorizontalCenter) { + emit moveNodeBy(node->id, m_document->originX - node->x, 0, 0); + } } else { - emit moveNodeBy(node->id, 0, 0, m_document->originZ - node->z); + if (alignToVerticalCenter && alignToHorizontalCenter) { + emit moveNodeBy(node->id, 0, m_document->originY - node->y, m_document->originZ - node->z); + } else if (alignToVerticalCenter) { + emit moveNodeBy(node->id, 0, m_document->originY - node->y, 0); + } else if (alignToHorizontalCenter) { + emit moveNodeBy(node->id, 0, 0, m_document->originZ - node->z); + } } } emit batchChangeEnd(); emit groupOperationAdded(); } +void SkeletonGraphicsWidget::alignSelectedToGlobalVerticalCenter() +{ + alignSelectedToGlobal(true, false); +} + +void SkeletonGraphicsWidget::alignSelectedToGlobalHorizontalCenter() +{ + alignSelectedToGlobal(false, true); +} + +void SkeletonGraphicsWidget::alignSelectedToGlobalCenter() +{ + alignSelectedToGlobal(true, true); +} + +void SkeletonGraphicsWidget::alignSelectedToLocalVerticalCenter() +{ + alignSelectedToLocal(true, false); +} + +void SkeletonGraphicsWidget::alignSelectedToLocalHorizontalCenter() +{ + alignSelectedToLocal(false, true); +} + +void SkeletonGraphicsWidget::alignSelectedToLocalCenter() +{ + alignSelectedToLocal(true, true); +} + void SkeletonGraphicsWidget::updateItems() { for (auto nodeItemIt = nodeItemMap.begin(); nodeItemIt != nodeItemMap.end(); nodeItemIt++) { diff --git a/src/skeletongraphicswidget.h b/src/skeletongraphicswidget.h index d1b1ca86..7b559c71 100644 --- a/src/skeletongraphicswidget.h +++ b/src/skeletongraphicswidget.h @@ -445,7 +445,12 @@ public slots: void moveSelected(float byX, float byY); void moveCheckedOrigin(float byX, float byY); void originChanged(); - void alignSelectedToCenter(); + void alignSelectedToGlobalCenter(); + void alignSelectedToGlobalVerticalCenter(); + void alignSelectedToGlobalHorizontalCenter(); + void alignSelectedToLocalCenter(); + void alignSelectedToLocalVerticalCenter(); + void alignSelectedToLocalHorizontalCenter(); void selectPartAllById(QUuid partId); void addSelectNode(QUuid nodeId); void addSelectEdge(QUuid edgeId); @@ -474,6 +479,8 @@ private: void hoverPart(QUuid partId); void switchProfileOnRangeSelection(); void setItemHoveredOnAllProfiles(QGraphicsItem *item, bool hovered); + void alignSelectedToGlobal(bool alignToVerticalCenter, bool alignToHorizontalCenter); + void alignSelectedToLocal(bool alignToVerticalCenter, bool alignToHorizontalCenter); private: //need initalize const SkeletonDocument *m_document; QGraphicsPixmapItem *m_backgroundItem;