diff --git a/src/document.cpp b/src/document.cpp index 53db9b79..d26c62ea 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -121,7 +121,7 @@ void Document::breakEdge(QUuid edgeId) QVector3D middleOrigin = (firstOrigin + secondOrigin) / 2; float middleRadius = (firstNode->radius + secondNode->radius) / 2; removeEdge(edgeId); - QUuid middleNodeId = createNode(middleOrigin.x(), middleOrigin.y(), middleOrigin.z(), middleRadius, firstNodeId); + QUuid middleNodeId = createNode(QUuid::createUuid(), middleOrigin.x(), middleOrigin.y(), middleOrigin.z(), middleRadius, firstNodeId); if (middleNodeId.isNull()) { qDebug() << "Add middle node failed"; return; @@ -258,10 +258,15 @@ void Document::removeNode(QUuid nodeId) void Document::addNode(float x, float y, float z, float radius, QUuid fromNodeId) { - createNode(x, y, z, radius, fromNodeId); + createNode(QUuid::createUuid(), x, y, z, radius, fromNodeId); } -QUuid Document::createNode(float x, float y, float z, float radius, QUuid 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; @@ -286,7 +291,7 @@ QUuid Document::createNode(float x, float y, float z, float radius, QUuid fromNo if (part != partMap.end()) part->second.dirty = true; } - SkeletonNode node; + SkeletonNode node(nodeId); node.partId = partId; node.setRadius(radius); node.x = x; diff --git a/src/document.h b/src/document.h index a71871e6..8302aa5e 100644 --- a/src/document.h +++ b/src/document.h @@ -519,6 +519,7 @@ public slots: 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); @@ -621,7 +622,7 @@ private: 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(float x, float y, float z, float radius, QUuid fromNodeId); + QUuid createNode(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId); void settleOrigin(); void checkExportReadyState(); void removePartDontCareComponent(QUuid partId); diff --git a/src/meshloader.cpp b/src/meshloader.cpp index d8dab45b..487424a6 100644 --- a/src/meshloader.cpp +++ b/src/meshloader.cpp @@ -296,21 +296,27 @@ void MeshLoader::setHasAmbientOcclusionInImage(bool hasInImage) m_hasAmbientOcclusionInImage = hasInImage; } +void MeshLoader::exportAsObj(QTextStream *textStream) +{ + auto &stream = *textStream; + stream << "# " << Ds3FileReader::m_applicationName << endl; + for (std::vector::const_iterator it = vertices().begin() ; it != vertices().end(); ++it) { + stream << "v " << (*it).x() << " " << (*it).y() << " " << (*it).z() << endl; + } + for (std::vector>::const_iterator it = faces().begin() ; it != faces().end(); ++it) { + stream << "f"; + for (std::vector::const_iterator subIt = (*it).begin() ; subIt != (*it).end(); ++subIt) { + stream << " " << (1 + *subIt); + } + stream << endl; + } +} + void MeshLoader::exportAsObj(const QString &filename) { QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); - stream << "# " << Ds3FileReader::m_applicationName << endl; - for (std::vector::const_iterator it = vertices().begin() ; it != vertices().end(); ++it) { - stream << "v " << (*it).x() << " " << (*it).y() << " " << (*it).z() << endl; - } - for (std::vector>::const_iterator it = faces().begin() ; it != faces().end(); ++it) { - stream << "f"; - for (std::vector::const_iterator subIt = (*it).begin() ; subIt != (*it).end(); ++subIt) { - stream << " " << (1 + *subIt); - } - stream << endl; - } + exportAsObj(&stream); } } diff --git a/src/meshloader.h b/src/meshloader.h index df029f80..a5111475 100644 --- a/src/meshloader.h +++ b/src/meshloader.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "outcome.h" #pragma pack(push) @@ -71,6 +72,7 @@ public: static float m_defaultMetalness; static float m_defaultRoughness; void exportAsObj(const QString &filename); + void exportAsObj(QTextStream *textStream); private: Vertex *m_triangleVertices = nullptr; int m_triangleVertexCount = 0; diff --git a/src/remoteioconnection.cpp b/src/remoteioconnection.cpp index d12dd10d..37ced550 100644 --- a/src/remoteioconnection.cpp +++ b/src/remoteioconnection.cpp @@ -1,7 +1,9 @@ #include #include +#include #include "remoteioconnection.h" #include "bonemark.h" +#include "snapshotxml.h" RemoteIoConnection::RemoteIoConnection(QTcpSocket *tcpSocket) : m_tcpSocket(tcpSocket) @@ -22,6 +24,7 @@ RemoteIoConnection::RemoteIoConnection(QTcpSocket *tcpSocket) : m_commandHandlers["removeedge"] = &RemoteIoConnection::commandRemoveEdge; m_commandHandlers["removepart"] = &RemoteIoConnection::commandRemovePart; m_commandHandlers["addnode"] = &RemoteIoConnection::commandAddNode; + m_commandHandlers["addnodewithid"] = &RemoteIoConnection::commandAddNodeWithId; m_commandHandlers["scalenodebyaddradius"] = &RemoteIoConnection::commandScaleNodeByAddRadius; m_commandHandlers["movenodeby"] = &RemoteIoConnection::commandMoveNodeBy; m_commandHandlers["setnodeorigin"] = &RemoteIoConnection::commandSetNodeOrigin; @@ -30,6 +33,19 @@ RemoteIoConnection::RemoteIoConnection(QTcpSocket *tcpSocket) : m_commandHandlers["switchnodexz"] = &RemoteIoConnection::commandSwitchNodeXZ; m_commandHandlers["moveoriginby"] = &RemoteIoConnection::commandMoveOriginBy; m_commandHandlers["addedge"] = &RemoteIoConnection::commandAddEdge; + m_commandHandlers["setpartlockstate"] = &RemoteIoConnection::commandSetPartLockState; + m_commandHandlers["setpartvisiblestate"] = &RemoteIoConnection::commandSetPartVisibleState; + m_commandHandlers["setpartsubdivstate"] = &RemoteIoConnection::commandSetPartSubdivState; + m_commandHandlers["setpartdisablestate"] = &RemoteIoConnection::commandSetPartDisableState; + m_commandHandlers["setpartxmirrorstate"] = &RemoteIoConnection::commandSetPartXmirrorState; + m_commandHandlers["setpartroundstate"] = &RemoteIoConnection::commandSetPartRoundState; + m_commandHandlers["setpartchamferstate"] = &RemoteIoConnection::commandSetPartChamferState; + m_commandHandlers["getnodepartid"] = &RemoteIoConnection::commandGetNodePartId; + m_commandHandlers["savesnapshot"] = &RemoteIoConnection::commandSaveSnapshot; + m_commandHandlers["getsnapshot"] = &RemoteIoConnection::commandGetSnapshot; + m_commandHandlers["exportasobj"] = &RemoteIoConnection::commandExportAsObj; + m_commandHandlers["new"] = &RemoteIoConnection::commandNew; + m_commandHandlers["setpartcolor"] = &RemoteIoConnection::commandSetPartColor; if (!DocumentWindow::documentWindows().empty()) { connectDocumentWindow(DocumentWindow::documentWindows().begin()->first); @@ -589,6 +605,64 @@ QByteArray RemoteIoConnection::commandAddNode(const QByteArray ¶meters, QStr return QByteArray(); } +QByteArray RemoteIoConnection::commandAddNodeWithId(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId + + int offset = 0; + + auto nodeIdString = nextParameter(parameters, &offset); + QUuid nodeId = QUuid(nodeIdString); + + auto xString = nextParameter(parameters, &offset); + if (xString.isEmpty()) { + *errorMessage = "Must specify x parameter"; + return QByteArray(); + } + float x = xString.toFloat(); + + auto yString = nextParameter(parameters, &offset); + if (yString.isEmpty()) { + *errorMessage = "Must specify y parameter"; + return QByteArray(); + } + float y = yString.toFloat(); + + auto zString = nextParameter(parameters, &offset); + if (zString.isEmpty()) { + *errorMessage = "Must specify z parameter"; + return QByteArray(); + } + float z = zString.toFloat(); + + auto radiusString = nextParameter(parameters, &offset); + if (radiusString.isEmpty()) { + *errorMessage = "Must specify radius parameter"; + return QByteArray(); + } + float radius = radiusString.toFloat(); + + auto fromNodeIdString = nextParameter(parameters, &offset); + QUuid fromNodeId = QUuid(fromNodeIdString); + + if (nullptr != m_currentDocumentWindow->document()->findNode(nodeId)) { + *errorMessage = "The specified nodeId already exists"; + return QByteArray(); + } + + if (!fromNodeId.isNull()) { + if (nullptr == m_currentDocumentWindow->document()->findNode(fromNodeId)) { + *errorMessage = "The specified fromNodeId does not exists"; + return QByteArray(); + } + } + + m_currentDocumentWindow->document()->addNodeWithId(nodeId, x, y, z, radius, fromNodeId); + return QByteArray(); +} + QByteArray RemoteIoConnection::commandScaleNodeByAddRadius(const QByteArray ¶meters, QString *errorMessage) { COMMAND_PRECHECK(); @@ -813,3 +887,272 @@ QByteArray RemoteIoConnection::commandAddEdge(const QByteArray ¶meters, QStr return QByteArray(); } +QByteArray RemoteIoConnection::commandSetPartLockState(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid partId, bool locked + + int offset = 0; + + QUuid partId = QUuid(nextParameter(parameters, &offset)); + if (partId.isNull()) { + *errorMessage = "Must specify partId parameter"; + return QByteArray(); + } + + QString lockedString = nextParameter(parameters, &offset); + if (lockedString.isEmpty()) { + *errorMessage = "Must specify lockState parameter"; + return QByteArray(); + } + bool locked = lockedString.toLower() == "locked"; + + m_currentDocumentWindow->document()->setPartLockState(partId, locked); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandSetPartVisibleState(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid partId, bool visible + + int offset = 0; + + QUuid partId = QUuid(nextParameter(parameters, &offset)); + if (partId.isNull()) { + *errorMessage = "Must specify partId parameter"; + return QByteArray(); + } + + QString visibleString = nextParameter(parameters, &offset); + if (visibleString.isEmpty()) { + *errorMessage = "Must specify visibleState parameter"; + return QByteArray(); + } + bool visible = visibleString.toLower() == "visible"; + + m_currentDocumentWindow->document()->setPartVisibleState(partId, visible); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandSetPartSubdivState(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid partId, bool subdived + + int offset = 0; + + QUuid partId = QUuid(nextParameter(parameters, &offset)); + if (partId.isNull()) { + *errorMessage = "Must specify partId parameter"; + return QByteArray(); + } + + QString subdivString = nextParameter(parameters, &offset); + if (subdivString.isEmpty()) { + *errorMessage = "Must specify subdivState parameter"; + return QByteArray(); + } + bool subdived = subdivString.toLower() == "subdived"; + + m_currentDocumentWindow->document()->setPartSubdivState(partId, subdived); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandSetPartChamferState(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid partId, bool chamfered + + int offset = 0; + + QUuid partId = QUuid(nextParameter(parameters, &offset)); + if (partId.isNull()) { + *errorMessage = "Must specify partId parameter"; + return QByteArray(); + } + + QString chamferString = nextParameter(parameters, &offset); + if (chamferString.isEmpty()) { + *errorMessage = "Must specify chamferState parameter"; + return QByteArray(); + } + bool chamfered = chamferString.toLower() == "chamfered"; + + m_currentDocumentWindow->document()->setPartChamferState(partId, chamfered); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandSetPartRoundState(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid partId, bool rounded + + int offset = 0; + + QUuid partId = QUuid(nextParameter(parameters, &offset)); + if (partId.isNull()) { + *errorMessage = "Must specify partId parameter"; + return QByteArray(); + } + + QString roundString = nextParameter(parameters, &offset); + if (roundString.isEmpty()) { + *errorMessage = "Must specify roundState parameter"; + return QByteArray(); + } + bool rounded = roundString.toLower() == "rounded"; + + m_currentDocumentWindow->document()->setPartRoundState(partId, rounded); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandSetPartDisableState(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid partId, bool disabled + + int offset = 0; + + QUuid partId = QUuid(nextParameter(parameters, &offset)); + if (partId.isNull()) { + *errorMessage = "Must specify partId parameter"; + return QByteArray(); + } + + QString disableString = nextParameter(parameters, &offset); + if (disableString.isEmpty()) { + *errorMessage = "Must specify disableState parameter"; + return QByteArray(); + } + bool disabled = disableString.toLower() == "disabled"; + + m_currentDocumentWindow->document()->setPartDisableState(partId, disabled); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandSetPartXmirrorState(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid partId, bool xMirrored + + int offset = 0; + + QUuid partId = QUuid(nextParameter(parameters, &offset)); + if (partId.isNull()) { + *errorMessage = "Must specify partId parameter"; + return QByteArray(); + } + + QString xMirrorString = nextParameter(parameters, &offset); + if (xMirrorString.isEmpty()) { + *errorMessage = "Must specify xMirrorState parameter"; + return QByteArray(); + } + bool xMirrored = xMirrorString.toLower() == "xmirrored"; + + m_currentDocumentWindow->document()->setPartXmirrorState(partId, xMirrored); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandGetNodePartId(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid nodeId + + // return QUuid partId + + int offset = 0; + + QUuid nodeId = QUuid(nextParameter(parameters, &offset)); + if (nodeId.isNull()) { + *errorMessage = "Must specify nodeId parameter"; + return QByteArray(); + } + + const SkeletonNode *node = m_currentDocumentWindow->document()->findNode(nodeId); + if (nullptr == node) { + *errorMessage = "The specified nodeId not found"; + return QByteArray(); + } + + return node->partId.toString().toUtf8(); +} + +QByteArray RemoteIoConnection::commandSaveSnapshot(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + m_currentDocumentWindow->document()->saveSnapshot(); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandGetSnapshot(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + Snapshot snapshot; + m_currentDocumentWindow->document()->toSnapshot(&snapshot, std::set(), DocumentToSnapshotFor::Nodes); + QString snapshotXml; + QXmlStreamWriter xmlStreamWriter(&snapshotXml); + saveSkeletonToXmlStream(&snapshot, &xmlStreamWriter); + return snapshotXml.toUtf8(); +} + +QByteArray RemoteIoConnection::commandExportAsObj(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + QString obj; + MeshLoader *resultMesh = m_currentDocumentWindow->document()->takeResultMesh(); + if (nullptr != resultMesh) { + QTextStream stream(&obj); + resultMesh->exportAsObj(&stream); + delete resultMesh; + } + return obj.toUtf8(); +} + +QByteArray RemoteIoConnection::commandNew(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + m_currentDocumentWindow->document()->clearHistories(); + m_currentDocumentWindow->document()->reset(); + m_currentDocumentWindow->document()->saveSnapshot(); + return QByteArray(); +} + +QByteArray RemoteIoConnection::commandSetPartColor(const QByteArray ¶meters, QString *errorMessage) +{ + COMMAND_PRECHECK(); + + // QUuid partId, QString colorName + + int offset = 0; + + QUuid partId = QUuid(nextParameter(parameters, &offset)); + if (partId.isNull()) { + *errorMessage = "Must specify partId parameter"; + return QByteArray(); + } + + bool hasColor = false; + QColor color; + QString colorNameString = nextParameter(parameters, &offset); + if (!colorNameString.isEmpty()) { + color = QColor(colorNameString); + hasColor = true; + } + + m_currentDocumentWindow->document()->setPartColorState(partId, hasColor, color); + return QByteArray(); +} diff --git a/src/remoteioconnection.h b/src/remoteioconnection.h index 7794cecd..bdd74cf4 100644 --- a/src/remoteioconnection.h +++ b/src/remoteioconnection.h @@ -48,6 +48,7 @@ private: QByteArray commandRemoveEdge(const QByteArray ¶meters, QString *errorMessage); QByteArray commandRemovePart(const QByteArray ¶meters, QString *errorMessage); QByteArray commandAddNode(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandAddNodeWithId(const QByteArray ¶meters, QString *errorMessage); QByteArray commandScaleNodeByAddRadius(const QByteArray ¶meters, QString *errorMessage); QByteArray commandMoveNodeBy(const QByteArray ¶meters, QString *errorMessage); QByteArray commandSetNodeOrigin(const QByteArray ¶meters, QString *errorMessage); @@ -56,6 +57,19 @@ private: QByteArray commandSwitchNodeXZ(const QByteArray ¶meters, QString *errorMessage); QByteArray commandMoveOriginBy(const QByteArray ¶meters, QString *errorMessage); QByteArray commandAddEdge(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSetPartLockState(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSetPartVisibleState(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSetPartSubdivState(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSetPartDisableState(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSetPartXmirrorState(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSetPartRoundState(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSetPartChamferState(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandGetNodePartId(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSaveSnapshot(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandGetSnapshot(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandExportAsObj(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandNew(const QByteArray ¶meters, QString *errorMessage); + QByteArray commandSetPartColor(const QByteArray ¶meters, QString *errorMessage); }; #endif