Add part mirror
parent
7437ddb597
commit
44a8ca6351
|
@ -75,55 +75,9 @@ QImage *MeshGenerator::takePartPreview(const QString &partId)
|
|||
return resultImage;
|
||||
}
|
||||
|
||||
void MeshGenerator::resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile)
|
||||
void MeshGenerator::resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile, const QString &partId)
|
||||
{
|
||||
float left = 0;
|
||||
bool leftFirstTime = true;
|
||||
float right = 0;
|
||||
bool rightFirstTime = true;
|
||||
float top = 0;
|
||||
bool topFirstTime = true;
|
||||
float bottom = 0;
|
||||
bool bottomFirstTime = true;
|
||||
float zLeft = 0;
|
||||
bool zLeftFirstTime = true;
|
||||
float zRight = 0;
|
||||
bool zRightFirstTime = true;
|
||||
for (const auto &nodeIt: m_snapshot->nodes) {
|
||||
float radius = valueOfKeyInMapOrEmpty(nodeIt.second, "radius").toFloat();
|
||||
float x = valueOfKeyInMapOrEmpty(nodeIt.second, "x").toFloat();
|
||||
float y = valueOfKeyInMapOrEmpty(nodeIt.second, "y").toFloat();
|
||||
float z = valueOfKeyInMapOrEmpty(nodeIt.second, "z").toFloat();
|
||||
if (leftFirstTime || x - radius < left) {
|
||||
left = x - radius;
|
||||
leftFirstTime = false;
|
||||
}
|
||||
if (topFirstTime || y - radius < top) {
|
||||
top = y - radius;
|
||||
topFirstTime = false;
|
||||
}
|
||||
if (rightFirstTime || x + radius > right) {
|
||||
right = x + radius;
|
||||
rightFirstTime = false;
|
||||
}
|
||||
if (bottomFirstTime || y + radius > bottom) {
|
||||
bottom = y + radius;
|
||||
bottomFirstTime = false;
|
||||
}
|
||||
if (zLeftFirstTime || z - radius < zLeft) {
|
||||
zLeft = z - radius;
|
||||
zLeftFirstTime = false;
|
||||
}
|
||||
if (zRightFirstTime || z + radius > zRight) {
|
||||
zRight = z + radius;
|
||||
zRightFirstTime = false;
|
||||
}
|
||||
}
|
||||
*mainProfile = QRectF(QPointF(left, top), QPointF(right, bottom));
|
||||
*sideProfile = QRectF(QPointF(zLeft, top), QPointF(zRight, bottom));
|
||||
qDebug() << "resolveBoundingBox left:" << left << "top:" << top << "right:" << right << "bottom:" << bottom << " zLeft:" << zLeft << "zRight:" << zRight;
|
||||
qDebug() << "mainHeight:" << mainProfile->height() << "mainWidth:" << mainProfile->width();
|
||||
qDebug() << "sideHeight:" << sideProfile->height() << "sideWidth:" << sideProfile->width();
|
||||
m_snapshot->resolveBoundingBox(mainProfile, sideProfile, partId);
|
||||
}
|
||||
|
||||
void MeshGenerator::process()
|
||||
|
@ -145,6 +99,19 @@ void MeshGenerator::process()
|
|||
float mainProfileMiddleX = mainProfile.x() + mainProfile.width() / 2;
|
||||
float sideProfileMiddleX = sideProfile.x() + sideProfile.width() / 2;
|
||||
float mainProfileMiddleY = mainProfile.y() + mainProfile.height() / 2;
|
||||
float originX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originX").toFloat();
|
||||
float originY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat();
|
||||
float originZ = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat();
|
||||
bool originSettled = false;
|
||||
if (originX > 0 && originY > 0 && originZ > 0) {
|
||||
qDebug() << "Use settled origin: " << originX << originY << originZ << " calculated:" << mainProfileMiddleX << mainProfileMiddleY << sideProfileMiddleX;
|
||||
mainProfileMiddleX = originX;
|
||||
mainProfileMiddleY = originY;
|
||||
sideProfileMiddleX = originZ;
|
||||
originSettled = true;
|
||||
} else {
|
||||
qDebug() << "No settled origin, calculated:" << mainProfileMiddleX << mainProfileMiddleY << sideProfileMiddleX;
|
||||
}
|
||||
|
||||
for (const auto &partIdIt: m_snapshot->partIdList) {
|
||||
const auto &part = m_snapshot->parts.find(partIdIt);
|
||||
|
@ -241,7 +208,19 @@ void MeshGenerator::process()
|
|||
int meshId = meshlite_bmesh_generate_mesh(meshliteContext, bmeshId);
|
||||
if (meshlite_bmesh_error_count(meshliteContext, bmeshId) != 0)
|
||||
broken = true;
|
||||
bool subdived = isTrueValueString(part->second["subdived"]);
|
||||
bool xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(part->second, "xMirrored"));
|
||||
bool zMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(part->second, "zMirrored"));
|
||||
int xMirroredMeshId = 0;
|
||||
int zMirroredMeshId = 0;
|
||||
if (xMirrored || zMirrored) {
|
||||
if (xMirrored) {
|
||||
xMirroredMeshId = meshlite_mirror_in_x(meshliteContext, meshId, 0);
|
||||
}
|
||||
if (zMirrored) {
|
||||
zMirroredMeshId = meshlite_mirror_in_z(meshliteContext, meshId, 0);
|
||||
}
|
||||
}
|
||||
bool subdived = isTrueValueString(valueOfKeyInMapOrEmpty(part->second, "subdived"));
|
||||
if (m_requirePartPreviewMap.find(partIdIt) != m_requirePartPreviewMap.end()) {
|
||||
ModelOfflineRender *render = m_partPreviewRenderMap[partIdIt];
|
||||
int trimedMeshId = meshlite_trim(meshliteContext, meshId, 1);
|
||||
|
@ -255,10 +234,19 @@ void MeshGenerator::process()
|
|||
QImage *image = new QImage(render->toImage(QSize(Theme::previewImageSize, Theme::previewImageSize)));
|
||||
m_partPreviewMap[partIdIt] = image;
|
||||
}
|
||||
if (subdived)
|
||||
if (subdived) {
|
||||
subdivMeshIds.push_back(meshId);
|
||||
else
|
||||
if (xMirroredMeshId)
|
||||
subdivMeshIds.push_back(xMirroredMeshId);
|
||||
if (zMirroredMeshId)
|
||||
subdivMeshIds.push_back(zMirroredMeshId);
|
||||
} else {
|
||||
meshIds.push_back(meshId);
|
||||
if (xMirroredMeshId)
|
||||
meshIds.push_back(xMirroredMeshId);
|
||||
if (zMirroredMeshId)
|
||||
meshIds.push_back(zMirroredMeshId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!subdivMeshIds.empty()) {
|
||||
|
@ -307,8 +295,11 @@ void MeshGenerator::process()
|
|||
QImage *image = new QImage(m_previewRender->toImage(QSize(Theme::previewImageSize, Theme::previewImageSize)));
|
||||
m_preview = image;
|
||||
}
|
||||
int trimedMeshId = meshlite_trim(meshliteContext, mergedMeshId, 1);
|
||||
m_mesh = new Mesh(meshliteContext, trimedMeshId, broken);
|
||||
int finalMeshId = mergedMeshId;
|
||||
if (!originSettled) {
|
||||
finalMeshId = meshlite_trim(meshliteContext, mergedMeshId, 1);
|
||||
}
|
||||
m_mesh = new Mesh(meshliteContext, finalMeshId, broken);
|
||||
}
|
||||
|
||||
if (m_previewRender) {
|
||||
|
|
|
@ -36,7 +36,7 @@ private:
|
|||
std::map<QString, ModelOfflineRender *> m_partPreviewRenderMap;
|
||||
QThread *m_thread;
|
||||
private:
|
||||
void resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile);
|
||||
void resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile, const QString &partId=QString());
|
||||
static bool enableDebug;
|
||||
};
|
||||
|
||||
|
|
|
@ -13,11 +13,16 @@
|
|||
unsigned long SkeletonDocument::m_maxSnapshot = 1000;
|
||||
|
||||
SkeletonDocument::SkeletonDocument() :
|
||||
// public
|
||||
originX(0),
|
||||
originY(0),
|
||||
originZ(0),
|
||||
editMode(SkeletonDocumentEditMode::Select),
|
||||
// private
|
||||
m_resultMeshIsObsolete(false),
|
||||
m_resultMesh(nullptr),
|
||||
m_meshGenerator(nullptr),
|
||||
m_batchChangeRefCount(0),
|
||||
editMode(SkeletonDocumentEditMode::Select)
|
||||
m_resultMesh(nullptr),
|
||||
m_batchChangeRefCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -285,6 +290,11 @@ const SkeletonEdge *SkeletonDocument::findEdgeByNodes(QUuid firstNodeId, QUuid s
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool SkeletonDocument::originSettled() const
|
||||
{
|
||||
return originX > 0 && originY > 0 && originZ > 0;
|
||||
}
|
||||
|
||||
void SkeletonDocument::addEdge(QUuid fromNodeId, QUuid toNodeId)
|
||||
{
|
||||
if (findEdgeByNodes(fromNodeId, toNodeId)) {
|
||||
|
@ -431,6 +441,15 @@ void SkeletonDocument::moveNodeBy(QUuid nodeId, float x, float y, float z)
|
|||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void SkeletonDocument::moveOriginBy(float x, float y, float z)
|
||||
{
|
||||
originX += x;
|
||||
originY += y;
|
||||
originZ += z;
|
||||
emit originChanged();
|
||||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void SkeletonDocument::setNodeOrigin(QUuid nodeId, float x, float y, float z)
|
||||
{
|
||||
auto it = nodeMap.find(nodeId);
|
||||
|
@ -552,6 +571,8 @@ void SkeletonDocument::toSnapshot(SkeletonSnapshot *snapshot, const std::set<QUu
|
|||
part["locked"] = partIt.second.locked ? "true" : "false";
|
||||
part["subdived"] = partIt.second.subdived ? "true" : "false";
|
||||
part["disabled"] = partIt.second.disabled ? "true" : "false";
|
||||
part["xMirrored"] = partIt.second.xMirrored ? "true" : "false";
|
||||
part["zMirrored"] = partIt.second.zMirrored ? "true" : "false";
|
||||
if (!partIt.second.name.isEmpty())
|
||||
part["name"] = partIt.second.name;
|
||||
snapshot->parts[part["id"]] = part;
|
||||
|
@ -591,10 +612,26 @@ void SkeletonDocument::toSnapshot(SkeletonSnapshot *snapshot, const std::set<QUu
|
|||
continue;
|
||||
snapshot->partIdList.push_back(partIdIt.toString());
|
||||
}
|
||||
std::map<QString, QString> canvas;
|
||||
canvas["originX"] = QString::number(originX);
|
||||
canvas["originY"] = QString::number(originY);
|
||||
canvas["originZ"] = QString::number(originZ);
|
||||
snapshot->canvas = canvas;
|
||||
}
|
||||
|
||||
void SkeletonDocument::addFromSnapshot(const SkeletonSnapshot &snapshot)
|
||||
{
|
||||
const auto &originXit = snapshot.canvas.find("originX");
|
||||
const auto &originYit = snapshot.canvas.find("originY");
|
||||
const auto &originZit = snapshot.canvas.find("originZ");
|
||||
if (originXit != snapshot.canvas.end() &&
|
||||
originYit != snapshot.canvas.end() &&
|
||||
originZit != snapshot.canvas.end()) {
|
||||
originX = originXit->second.toFloat();
|
||||
originY = originYit->second.toFloat();
|
||||
originZ = originZit->second.toFloat();
|
||||
}
|
||||
|
||||
std::map<QUuid, QUuid> oldNewIdMap;
|
||||
for (const auto &partKv : snapshot.parts) {
|
||||
SkeletonPart part;
|
||||
|
@ -604,6 +641,8 @@ void SkeletonDocument::addFromSnapshot(const SkeletonSnapshot &snapshot)
|
|||
part.locked = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "locked"));
|
||||
part.subdived = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "subdived"));
|
||||
part.disabled = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "disabled"));
|
||||
part.xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "xMirrored"));
|
||||
part.zMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "zMirrored"));
|
||||
partMap[part.id] = part;
|
||||
}
|
||||
for (const auto &nodeKv : snapshot.nodes) {
|
||||
|
@ -664,11 +703,15 @@ void SkeletonDocument::addFromSnapshot(const SkeletonSnapshot &snapshot)
|
|||
}
|
||||
|
||||
emit partListChanged();
|
||||
emit originChanged();
|
||||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void SkeletonDocument::reset()
|
||||
{
|
||||
originX = 0;
|
||||
originY = 0;
|
||||
originZ = 0;
|
||||
nodeMap.clear();
|
||||
edgeMap.clear();
|
||||
partMap.clear();
|
||||
|
@ -824,6 +867,51 @@ void SkeletonDocument::setPartDisableState(QUuid partId, bool disabled)
|
|||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void SkeletonDocument::settleOrigin()
|
||||
{
|
||||
if (originSettled())
|
||||
return;
|
||||
SkeletonSnapshot snapshot;
|
||||
toSnapshot(&snapshot);
|
||||
QRectF mainProfile;
|
||||
QRectF sideProfile;
|
||||
snapshot.resolveBoundingBox(&mainProfile, &sideProfile);
|
||||
originX = mainProfile.x() + mainProfile.width() / 2;
|
||||
originY = mainProfile.y() + mainProfile.height() / 2;
|
||||
originZ = sideProfile.x() + sideProfile.width() / 2;
|
||||
emit originChanged();
|
||||
}
|
||||
|
||||
void SkeletonDocument::setPartXmirrorState(QUuid partId, bool mirrored)
|
||||
{
|
||||
auto part = partMap.find(partId);
|
||||
if (part == partMap.end()) {
|
||||
qDebug() << "Part not found:" << partId;
|
||||
return;
|
||||
}
|
||||
if (part->second.xMirrored == mirrored)
|
||||
return;
|
||||
part->second.xMirrored = mirrored;
|
||||
settleOrigin();
|
||||
emit partXmirrorStateChanged(partId);
|
||||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void SkeletonDocument::setPartZmirrorState(QUuid partId, bool mirrored)
|
||||
{
|
||||
auto part = partMap.find(partId);
|
||||
if (part == partMap.end()) {
|
||||
qDebug() << "Part not found:" << partId;
|
||||
return;
|
||||
}
|
||||
if (part->second.zMirrored == mirrored)
|
||||
return;
|
||||
part->second.zMirrored = mirrored;
|
||||
settleOrigin();
|
||||
emit partZmirrorStateChanged(partId);
|
||||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void SkeletonDocument::saveSnapshot()
|
||||
{
|
||||
if (m_undoItems.size() + 1 > m_maxSnapshot)
|
||||
|
|
|
@ -68,13 +68,17 @@ public:
|
|||
bool locked;
|
||||
bool subdived;
|
||||
bool disabled;
|
||||
bool xMirrored;
|
||||
bool zMirrored;
|
||||
QImage preview;
|
||||
std::vector<QUuid> nodeIds;
|
||||
SkeletonPart(const QUuid &withId=QUuid()) :
|
||||
visible(true),
|
||||
locked(false),
|
||||
subdived(false),
|
||||
disabled(false)
|
||||
disabled(false),
|
||||
xMirrored(false),
|
||||
zMirrored(false)
|
||||
{
|
||||
id = withId.isNull() ? QUuid::createUuid() : withId;
|
||||
}
|
||||
|
@ -84,6 +88,8 @@ public:
|
|||
locked = other.locked;
|
||||
subdived = other.subdived;
|
||||
disabled = other.disabled;
|
||||
xMirrored = other.xMirrored;
|
||||
zMirrored = other.zMirrored;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -133,7 +139,15 @@ signals:
|
|||
void partVisibleStateChanged(QUuid partId);
|
||||
void partSubdivStateChanged(QUuid partId);
|
||||
void partDisableStateChanged(QUuid partId);
|
||||
void partXmirrorStateChanged(QUuid partId);
|
||||
void partZmirrorStateChanged(QUuid partId);
|
||||
void cleanup();
|
||||
void originChanged();
|
||||
public: // need initialize
|
||||
float originX;
|
||||
float originY;
|
||||
float originZ;
|
||||
SkeletonDocumentEditMode editMode;
|
||||
public:
|
||||
SkeletonDocument();
|
||||
~SkeletonDocument();
|
||||
|
@ -142,7 +156,7 @@ public:
|
|||
std::map<QUuid, SkeletonEdge> edgeMap;
|
||||
std::vector<QUuid> partIds;
|
||||
QImage turnaround;
|
||||
SkeletonDocumentEditMode editMode;
|
||||
QImage preview;
|
||||
void toSnapshot(SkeletonSnapshot *snapshot, const std::set<QUuid> &limitNodeIds=std::set<QUuid>()) const;
|
||||
void fromSnapshot(const SkeletonSnapshot &snapshot);
|
||||
void addFromSnapshot(const SkeletonSnapshot &snapshot);
|
||||
|
@ -151,13 +165,13 @@ public:
|
|||
const SkeletonPart *findPart(QUuid partId) const;
|
||||
const SkeletonEdge *findEdgeByNodes(QUuid firstNodeId, QUuid secondNodeId) const;
|
||||
Mesh *takeResultMesh();
|
||||
QImage preview;
|
||||
void updateTurnaround(const QImage &image);
|
||||
bool hasPastableContentInClipboard() const;
|
||||
bool undoable() const;
|
||||
bool redoable() const;
|
||||
bool isNodeEditable(QUuid nodeId) const;
|
||||
bool isEdgeEditable(QUuid edgeId) const;
|
||||
bool originSettled() const;
|
||||
public slots:
|
||||
void removeNode(QUuid nodeId);
|
||||
void removeEdge(QUuid edgeId);
|
||||
|
@ -167,6 +181,7 @@ public slots:
|
|||
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 moveOriginBy(float x, float y, float z);
|
||||
void addEdge(QUuid fromNodeId, QUuid toNodeId);
|
||||
void setEditMode(SkeletonDocumentEditMode mode);
|
||||
void uiReady();
|
||||
|
@ -176,6 +191,8 @@ public slots:
|
|||
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 saveSnapshot();
|
||||
void undo();
|
||||
void redo();
|
||||
|
@ -190,14 +207,16 @@ private:
|
|||
void splitPartByEdge(std::vector<std::vector<QUuid>> *groups, QUuid edgeId);
|
||||
bool isPartReadonly(QUuid partId) const;
|
||||
QUuid createNode(float x, float y, float z, float radius, QUuid fromNodeId);
|
||||
private:
|
||||
void settleOrigin();
|
||||
private: // need initialize
|
||||
bool m_resultMeshIsObsolete;
|
||||
MeshGenerator *m_meshGenerator;
|
||||
Mesh *m_resultMesh;
|
||||
int m_batchChangeRefCount;
|
||||
private:
|
||||
static unsigned long m_maxSnapshot;
|
||||
std::deque<SkeletonHistoryItem> m_undoItems;
|
||||
std::deque<SkeletonHistoryItem> m_redoItems;
|
||||
int m_batchChangeRefCount;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -360,6 +360,7 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
|||
connect(graphicsWidget, &SkeletonGraphicsWidget::batchChangeBegin, m_document, &SkeletonDocument::batchChangeBegin);
|
||||
connect(graphicsWidget, &SkeletonGraphicsWidget::batchChangeEnd, m_document, &SkeletonDocument::batchChangeEnd);
|
||||
connect(graphicsWidget, &SkeletonGraphicsWidget::breakEdge, m_document, &SkeletonDocument::breakEdge);
|
||||
connect(graphicsWidget, &SkeletonGraphicsWidget::moveOriginBy, m_document, &SkeletonDocument::moveOriginBy);
|
||||
|
||||
connect(graphicsWidget, &SkeletonGraphicsWidget::changeTurnaround, this, &SkeletonDocumentWindow::changeTurnaround);
|
||||
connect(graphicsWidget, &SkeletonGraphicsWidget::save, this, &SkeletonDocumentWindow::save);
|
||||
|
@ -374,6 +375,7 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
|||
connect(m_document, &SkeletonDocument::nodeOriginChanged, graphicsWidget, &SkeletonGraphicsWidget::nodeOriginChanged);
|
||||
connect(m_document, &SkeletonDocument::partVisibleStateChanged, graphicsWidget, &SkeletonGraphicsWidget::partVisibleStateChanged);
|
||||
connect(m_document, &SkeletonDocument::cleanup, graphicsWidget, &SkeletonGraphicsWidget::removeAllContent);
|
||||
connect(m_document, &SkeletonDocument::originChanged, graphicsWidget, &SkeletonGraphicsWidget::originChanged);
|
||||
|
||||
connect(m_document, &SkeletonDocument::partListChanged, partListWidget, &SkeletonPartListWidget::partListChanged);
|
||||
connect(m_document, &SkeletonDocument::partPreviewChanged, partListWidget, &SkeletonPartListWidget::partPreviewChanged);
|
||||
|
@ -381,6 +383,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
|||
connect(m_document, &SkeletonDocument::partVisibleStateChanged, partListWidget, &SkeletonPartListWidget::partVisibleStateChanged);
|
||||
connect(m_document, &SkeletonDocument::partSubdivStateChanged, partListWidget, &SkeletonPartListWidget::partSubdivStateChanged);
|
||||
connect(m_document, &SkeletonDocument::partDisableStateChanged, partListWidget, &SkeletonPartListWidget::partDisableStateChanged);
|
||||
connect(m_document, &SkeletonDocument::partXmirrorStateChanged, partListWidget, &SkeletonPartListWidget::partXmirrorStateChanged);
|
||||
connect(m_document, &SkeletonDocument::partZmirrorStateChanged, partListWidget, &SkeletonPartListWidget::partZmirrorStateChanged);
|
||||
connect(m_document, &SkeletonDocument::cleanup, partListWidget, &SkeletonPartListWidget::partListChanged);
|
||||
|
||||
connect(m_document, &SkeletonDocument::skeletonChanged, m_document, &SkeletonDocument::generateMesh);
|
||||
|
|
|
@ -16,22 +16,28 @@
|
|||
|
||||
SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument *document) :
|
||||
m_document(document),
|
||||
m_backgroundItem(nullptr),
|
||||
m_turnaroundChanged(false),
|
||||
m_turnaroundLoader(nullptr),
|
||||
m_dragStarted(false),
|
||||
m_moveStarted(false),
|
||||
m_cursorNodeItem(nullptr),
|
||||
m_cursorEdgeItem(nullptr),
|
||||
m_addFromNodeItem(nullptr),
|
||||
m_moveStarted(false),
|
||||
m_hoveredNodeItem(nullptr),
|
||||
m_hoveredEdgeItem(nullptr),
|
||||
m_lastAddedX(0),
|
||||
m_lastAddedY(0),
|
||||
m_lastAddedZ(0),
|
||||
m_lastAddedX(false),
|
||||
m_lastAddedY(false),
|
||||
m_lastAddedZ(false),
|
||||
m_selectionItem(nullptr),
|
||||
m_rangeSelectionStarted(false),
|
||||
m_mouseEventFromSelf(false),
|
||||
m_lastRot(0)
|
||||
m_moveHappened(false),
|
||||
m_lastRot(0),
|
||||
m_mainOriginItem(nullptr),
|
||||
m_sideOriginItem(nullptr),
|
||||
m_hoveredOriginItem(nullptr),
|
||||
m_checkedOriginItem(nullptr)
|
||||
{
|
||||
setRenderHint(QPainter::Antialiasing, false);
|
||||
setBackgroundBrush(QBrush(QWidget::palette().color(QWidget::backgroundRole()), Qt::SolidPattern));
|
||||
|
@ -60,6 +66,14 @@ SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument *document)
|
|||
m_selectionItem->hide();
|
||||
scene()->addItem(m_selectionItem);
|
||||
|
||||
m_mainOriginItem = new SkeletonGraphicsOriginItem(SkeletonProfile::Main);
|
||||
m_mainOriginItem->hide();
|
||||
scene()->addItem(m_mainOriginItem);
|
||||
|
||||
m_sideOriginItem = new SkeletonGraphicsOriginItem(SkeletonProfile::Side);
|
||||
m_sideOriginItem->hide();
|
||||
scene()->addItem(m_sideOriginItem);
|
||||
|
||||
scene()->setSceneRect(rect());
|
||||
|
||||
setMouseTracking(true);
|
||||
|
@ -432,19 +446,30 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent *event)
|
|||
SkeletonDocumentEditMode::Add == m_document->editMode) {
|
||||
SkeletonGraphicsNodeItem *newHoverNodeItem = nullptr;
|
||||
SkeletonGraphicsEdgeItem *newHoverEdgeItem = nullptr;
|
||||
SkeletonGraphicsOriginItem *newHoverOriginItem = nullptr;
|
||||
QList<QGraphicsItem *> items = scene()->items(mouseEventScenePos(event));
|
||||
for (auto it = items.begin(); it != items.end(); it++) {
|
||||
QGraphicsItem *item = *it;
|
||||
if (item->data(0) == "node") {
|
||||
newHoverNodeItem = (SkeletonGraphicsNodeItem *)item;
|
||||
break;
|
||||
} else if (item->data(0) == "edge") {
|
||||
newHoverEdgeItem = (SkeletonGraphicsEdgeItem *)item;
|
||||
} else if (item->data(0) == "origin") {
|
||||
newHoverOriginItem = (SkeletonGraphicsOriginItem *)item;
|
||||
}
|
||||
}
|
||||
if (newHoverNodeItem) {
|
||||
newHoverEdgeItem = nullptr;
|
||||
}
|
||||
if (newHoverOriginItem != m_hoveredOriginItem) {
|
||||
if (nullptr != m_hoveredOriginItem) {
|
||||
m_hoveredOriginItem->setHovered(false);
|
||||
}
|
||||
m_hoveredOriginItem = newHoverOriginItem;
|
||||
if (nullptr != m_hoveredOriginItem) {
|
||||
m_hoveredOriginItem->setHovered(true);
|
||||
}
|
||||
}
|
||||
if (newHoverNodeItem != m_hoveredNodeItem) {
|
||||
if (nullptr != m_hoveredNodeItem) {
|
||||
m_hoveredNodeItem->setHovered(false);
|
||||
|
@ -481,18 +506,28 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent *event)
|
|||
}
|
||||
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode) {
|
||||
if (m_moveStarted && !m_rangeSelectionSet.empty()) {
|
||||
QPointF mouseScenePos = mouseEventScenePos(event);
|
||||
float byX = mouseScenePos.x() - m_lastScenePos.x();
|
||||
float byY = mouseScenePos.y() - m_lastScenePos.y();
|
||||
if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) {
|
||||
rotateSelected(byX);
|
||||
} else {
|
||||
moveSelected(byX, byY);
|
||||
if (m_moveStarted) {
|
||||
if (m_checkedOriginItem) {
|
||||
QPointF mouseScenePos = mouseEventScenePos(event);
|
||||
float byX = mouseScenePos.x() - m_lastScenePos.x();
|
||||
float byY = mouseScenePos.y() - m_lastScenePos.y();
|
||||
moveCheckedOrigin(byX, byY);
|
||||
m_lastScenePos = mouseScenePos;
|
||||
m_moveHappened = true;
|
||||
return true;
|
||||
} else if (!m_rangeSelectionSet.empty()) {
|
||||
QPointF mouseScenePos = mouseEventScenePos(event);
|
||||
float byX = mouseScenePos.x() - m_lastScenePos.x();
|
||||
float byY = mouseScenePos.y() - m_lastScenePos.y();
|
||||
if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) {
|
||||
rotateSelected(byX);
|
||||
} else {
|
||||
moveSelected(byX, byY);
|
||||
}
|
||||
m_lastScenePos = mouseScenePos;
|
||||
m_moveHappened = true;
|
||||
return true;
|
||||
}
|
||||
m_lastScenePos = mouseScenePos;
|
||||
m_moveHappened = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,6 +564,19 @@ void SkeletonGraphicsWidget::rotateSelected(int degree)
|
|||
}
|
||||
}
|
||||
|
||||
void SkeletonGraphicsWidget::moveCheckedOrigin(float byX, float byY)
|
||||
{
|
||||
if (!m_checkedOriginItem)
|
||||
return;
|
||||
byX = sceneRadiusToUnified(byX);
|
||||
byY = sceneRadiusToUnified(byY);
|
||||
if (SkeletonProfile::Main == m_checkedOriginItem->profile()) {
|
||||
emit moveOriginBy(byX, byY, 0);
|
||||
} else {
|
||||
emit moveOriginBy(0, byY, byX);
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonGraphicsWidget::moveSelected(float byX, float byY)
|
||||
{
|
||||
if (m_rangeSelectionSet.empty())
|
||||
|
@ -760,8 +808,25 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent *event)
|
|||
return true;
|
||||
}
|
||||
} else if (SkeletonDocumentEditMode::Select == m_document->editMode) {
|
||||
//if (m_mouseEventFromSelf) {
|
||||
bool processed = false;
|
||||
bool processed = false;
|
||||
if (m_hoveredOriginItem != m_checkedOriginItem) {
|
||||
if (m_checkedOriginItem) {
|
||||
m_checkedOriginItem->setChecked(false);
|
||||
m_checkedOriginItem->setHovered(false);
|
||||
}
|
||||
m_checkedOriginItem = m_hoveredOriginItem;
|
||||
if (m_checkedOriginItem) {
|
||||
m_checkedOriginItem->setChecked(true);
|
||||
}
|
||||
}
|
||||
if (m_checkedOriginItem) {
|
||||
if (!m_moveStarted) {
|
||||
m_moveStarted = true;
|
||||
m_lastScenePos = mouseEventScenePos(event);
|
||||
m_moveHappened = false;
|
||||
processed = true;
|
||||
}
|
||||
} else {
|
||||
if ((nullptr == m_hoveredNodeItem || m_rangeSelectionSet.find(m_hoveredNodeItem) == m_rangeSelectionSet.end()) &&
|
||||
(nullptr == m_hoveredEdgeItem || m_rangeSelectionSet.find(m_hoveredEdgeItem) == m_rangeSelectionSet.end())) {
|
||||
if (!QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) {
|
||||
|
@ -792,10 +857,10 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent *event)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (processed) {
|
||||
return true;
|
||||
}
|
||||
//}
|
||||
}
|
||||
if (processed) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -938,24 +1003,44 @@ bool SkeletonGraphicsWidget::keyPress(QKeyEvent *event)
|
|||
emit groupOperationAdded();
|
||||
}
|
||||
} else if (event->key() == Qt::Key_Left) {
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode && hasSelection()) {
|
||||
moveSelected(-1, 0);
|
||||
emit groupOperationAdded();
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode) {
|
||||
if (m_checkedOriginItem) {
|
||||
moveCheckedOrigin(-1, 0);
|
||||
emit groupOperationAdded();
|
||||
} else if (hasSelection()) {
|
||||
moveSelected(-1, 0);
|
||||
emit groupOperationAdded();
|
||||
}
|
||||
}
|
||||
} else if (event->key() == Qt::Key_Right) {
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode && hasSelection()) {
|
||||
moveSelected(1, 0);
|
||||
emit groupOperationAdded();
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode) {
|
||||
if (m_checkedOriginItem) {
|
||||
moveCheckedOrigin(1, 0);
|
||||
emit groupOperationAdded();
|
||||
} else if (hasSelection()) {
|
||||
moveSelected(1, 0);
|
||||
emit groupOperationAdded();
|
||||
}
|
||||
}
|
||||
} else if (event->key() == Qt::Key_Up) {
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode && hasSelection()) {
|
||||
moveSelected(0, -1);
|
||||
emit groupOperationAdded();
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode) {
|
||||
if (m_checkedOriginItem) {
|
||||
moveCheckedOrigin(0, -1);
|
||||
emit groupOperationAdded();
|
||||
} else if (hasSelection()) {
|
||||
moveSelected(0, -1);
|
||||
emit groupOperationAdded();
|
||||
}
|
||||
}
|
||||
} else if (event->key() == Qt::Key_Down) {
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode && hasSelection()) {
|
||||
moveSelected(0, 1);
|
||||
emit groupOperationAdded();
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode) {
|
||||
if (m_checkedOriginItem) {
|
||||
moveCheckedOrigin(0, 1);
|
||||
emit groupOperationAdded();
|
||||
} else if (hasSelection()) {
|
||||
moveSelected(0, 1);
|
||||
emit groupOperationAdded();
|
||||
}
|
||||
}
|
||||
} else if (event->key() == Qt::Key_BracketLeft) {
|
||||
if (SkeletonDocumentEditMode::Select == m_document->editMode && hasSelection()) {
|
||||
|
@ -971,6 +1056,19 @@ bool SkeletonGraphicsWidget::keyPress(QKeyEvent *event)
|
|||
return false;
|
||||
}
|
||||
|
||||
void SkeletonGraphicsWidget::originChanged()
|
||||
{
|
||||
if (!m_document->originSettled()) {
|
||||
m_mainOriginItem->hide();
|
||||
m_sideOriginItem->hide();
|
||||
return;
|
||||
}
|
||||
m_mainOriginItem->setOrigin(scenePosFromUnified(QPointF(m_document->originX, m_document->originY)));
|
||||
m_sideOriginItem->setOrigin(scenePosFromUnified(QPointF(m_document->originZ, m_document->originY)));
|
||||
m_mainOriginItem->show();
|
||||
m_sideOriginItem->show();
|
||||
}
|
||||
|
||||
void SkeletonGraphicsWidget::nodeAdded(QUuid nodeId)
|
||||
{
|
||||
const SkeletonNode *node = m_document->findNode(nodeId);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QGraphicsLineItem>
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QGraphicsPolygonItem>
|
||||
#include <QThread>
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
|
@ -15,6 +16,88 @@
|
|||
#include "theme.h"
|
||||
#include "util.h"
|
||||
|
||||
class SkeletonGraphicsOriginItem : public QGraphicsPolygonItem
|
||||
{
|
||||
public:
|
||||
SkeletonGraphicsOriginItem(SkeletonProfile profile=SkeletonProfile::Unknown) :
|
||||
m_profile(profile),
|
||||
m_hovered(false),
|
||||
m_checked(false)
|
||||
{
|
||||
setData(0, "origin");
|
||||
}
|
||||
void updateAppearance()
|
||||
{
|
||||
QColor color = Theme::white;
|
||||
|
||||
switch (m_profile)
|
||||
{
|
||||
case SkeletonProfile::Unknown:
|
||||
break;
|
||||
case SkeletonProfile::Main:
|
||||
color = Theme::red;
|
||||
break;
|
||||
case SkeletonProfile::Side:
|
||||
color = Theme::green;
|
||||
break;
|
||||
}
|
||||
|
||||
QColor penColor = color;
|
||||
penColor.setAlphaF(m_checked ? Theme::checkedAlpha : Theme::normalAlpha);
|
||||
QPen pen(penColor);
|
||||
pen.setWidth(0);
|
||||
setPen(pen);
|
||||
|
||||
QColor brushColor = color;
|
||||
brushColor.setAlphaF((m_checked || m_hovered) ? Theme::checkedAlpha : Theme::normalAlpha);
|
||||
QBrush brush(brushColor);
|
||||
setBrush(brush);
|
||||
}
|
||||
void setOrigin(QPointF point)
|
||||
{
|
||||
m_origin = point;
|
||||
QPolygonF triangle;
|
||||
const int triangleRadius = 10;
|
||||
triangle.append(QPointF(point.x() - triangleRadius, point.y()));
|
||||
triangle.append(QPointF(point.x() + triangleRadius, point.y()));
|
||||
triangle.append(QPointF(point.x(), point.y() - triangleRadius));
|
||||
triangle.append(QPointF(point.x() - triangleRadius, point.y()));
|
||||
setPolygon(triangle);
|
||||
updateAppearance();
|
||||
}
|
||||
QPointF origin()
|
||||
{
|
||||
return m_origin;
|
||||
}
|
||||
SkeletonProfile profile()
|
||||
{
|
||||
return m_profile;
|
||||
}
|
||||
void setHovered(bool hovered)
|
||||
{
|
||||
m_hovered = hovered;
|
||||
updateAppearance();
|
||||
}
|
||||
void setChecked(bool checked)
|
||||
{
|
||||
m_checked = checked;
|
||||
updateAppearance();
|
||||
}
|
||||
bool checked()
|
||||
{
|
||||
return m_checked;
|
||||
}
|
||||
bool hovered()
|
||||
{
|
||||
return m_hovered;
|
||||
}
|
||||
private:
|
||||
SkeletonProfile m_profile;
|
||||
bool m_hovered;
|
||||
bool m_checked;
|
||||
QPointF m_origin;
|
||||
};
|
||||
|
||||
class SkeletonGraphicsSelectionItem : public QGraphicsRectItem
|
||||
{
|
||||
public:
|
||||
|
@ -271,6 +354,7 @@ signals:
|
|||
void open();
|
||||
void exportResult();
|
||||
void breakEdge(QUuid edgeId);
|
||||
void moveOriginBy(float x, float y, float z);
|
||||
public:
|
||||
SkeletonGraphicsWidget(const SkeletonDocument *document);
|
||||
std::map<QUuid, std::pair<SkeletonGraphicsNodeItem *, SkeletonGraphicsNodeItem *>> nodeItemMap;
|
||||
|
@ -327,6 +411,8 @@ public slots:
|
|||
void zoomSelected(float delta);
|
||||
void scaleSelected(float delta);
|
||||
void moveSelected(float byX, float byY);
|
||||
void moveCheckedOrigin(float byX, float byY);
|
||||
void originChanged();
|
||||
private slots:
|
||||
void turnaroundImageReady();
|
||||
private:
|
||||
|
@ -344,15 +430,13 @@ private:
|
|||
bool isSingleNodeSelected();
|
||||
void addItemToRangeSelection(QGraphicsItem *item);
|
||||
void removeItemFromRangeSelection(QGraphicsItem *item);
|
||||
private:
|
||||
QGraphicsPixmapItem *m_backgroundItem;
|
||||
private: //need initalize
|
||||
const SkeletonDocument *m_document;
|
||||
QGraphicsPixmapItem *m_backgroundItem;
|
||||
bool m_turnaroundChanged;
|
||||
TurnaroundLoader *m_turnaroundLoader;
|
||||
bool m_dragStarted;
|
||||
QPoint m_lastGlobalPos;
|
||||
bool m_moveStarted;
|
||||
QPointF m_lastScenePos;
|
||||
SkeletonGraphicsNodeItem *m_cursorNodeItem;
|
||||
SkeletonGraphicsEdgeItem *m_cursorEdgeItem;
|
||||
SkeletonGraphicsNodeItem *m_addFromNodeItem;
|
||||
|
@ -362,12 +446,19 @@ private:
|
|||
float m_lastAddedY;
|
||||
float m_lastAddedZ;
|
||||
SkeletonGraphicsSelectionItem *m_selectionItem;
|
||||
QPointF m_rangeSelectionStartPos;
|
||||
bool m_rangeSelectionStarted;
|
||||
std::set<QGraphicsItem *> m_rangeSelectionSet;
|
||||
bool m_mouseEventFromSelf;
|
||||
bool m_moveHappened;
|
||||
int m_lastRot;
|
||||
SkeletonGraphicsOriginItem *m_mainOriginItem;
|
||||
SkeletonGraphicsOriginItem *m_sideOriginItem;
|
||||
SkeletonGraphicsOriginItem *m_hoveredOriginItem;
|
||||
SkeletonGraphicsOriginItem *m_checkedOriginItem;
|
||||
private:
|
||||
std::set<QGraphicsItem *> m_rangeSelectionSet;
|
||||
QPoint m_lastGlobalPos;
|
||||
QPointF m_lastScenePos;
|
||||
QPointF m_rangeSelectionStartPos;
|
||||
};
|
||||
|
||||
class SkeletonGraphicsContainerWidget : public QWidget
|
||||
|
|
|
@ -24,6 +24,14 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p
|
|||
updateButton(m_disableButton, QChar(fa::toggleon), false);
|
||||
initButton(m_disableButton);
|
||||
|
||||
m_xMirrorButton = new QPushButton();
|
||||
updateButton(m_xMirrorButton, QChar(fa::quoteleft), false);
|
||||
initButton(m_xMirrorButton);
|
||||
|
||||
m_zMirrorButton = new QPushButton();
|
||||
updateButton(m_zMirrorButton, QChar(fa::quoteright), false);
|
||||
initButton(m_zMirrorButton);
|
||||
|
||||
m_previewLabel = new QLabel;
|
||||
|
||||
QHBoxLayout *miniTopToolLayout = new QHBoxLayout;
|
||||
|
@ -38,6 +46,8 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p
|
|||
miniBottomToolLayout->setSpacing(0);
|
||||
miniBottomToolLayout->setContentsMargins(0, 0, 0, 0);
|
||||
miniBottomToolLayout->addWidget(m_disableButton);
|
||||
miniBottomToolLayout->addWidget(m_xMirrorButton);
|
||||
miniBottomToolLayout->addWidget(m_zMirrorButton);
|
||||
miniBottomToolLayout->addStretch();
|
||||
|
||||
QWidget *hrWidget = new QWidget;
|
||||
|
@ -60,37 +70,61 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p
|
|||
connect(this, &SkeletonPartWidget::setPartVisibleState, m_document, &SkeletonDocument::setPartVisibleState);
|
||||
connect(this, &SkeletonPartWidget::setPartSubdivState, m_document, &SkeletonDocument::setPartSubdivState);
|
||||
connect(this, &SkeletonPartWidget::setPartDisableState, m_document, &SkeletonDocument::setPartDisableState);
|
||||
connect(this, &SkeletonPartWidget::setPartXmirrorState, m_document, &SkeletonDocument::setPartXmirrorState);
|
||||
connect(this, &SkeletonPartWidget::setPartZmirrorState, m_document, &SkeletonDocument::setPartZmirrorState);
|
||||
|
||||
connect(m_lockButton, &QPushButton::clicked, [=]() {
|
||||
if (m_lockButton->text() == QChar(fa::lock)) {
|
||||
emit setPartLockState(m_partId, false);
|
||||
} else {
|
||||
emit setPartLockState(m_partId, true);
|
||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||
if (!part) {
|
||||
qDebug() << "Part not found:" << m_partId;
|
||||
return;
|
||||
}
|
||||
emit setPartLockState(m_partId, !part->locked);
|
||||
});
|
||||
|
||||
connect(m_visibleButton, &QPushButton::clicked, [=]() {
|
||||
if (m_visibleButton->text() == QChar(fa::eye)) {
|
||||
emit setPartVisibleState(m_partId, false);
|
||||
} else {
|
||||
emit setPartVisibleState(m_partId, true);
|
||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||
if (!part) {
|
||||
qDebug() << "Part not found:" << m_partId;
|
||||
return;
|
||||
}
|
||||
emit setPartVisibleState(m_partId, !part->visible);
|
||||
});
|
||||
|
||||
connect(m_subdivButton, &QPushButton::clicked, [=]() {
|
||||
if (m_subdivButton->text() == QChar(fa::cube)) {
|
||||
emit setPartSubdivState(m_partId, true);
|
||||
} else {
|
||||
emit setPartSubdivState(m_partId, false);
|
||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||
if (!part) {
|
||||
qDebug() << "Part not found:" << m_partId;
|
||||
return;
|
||||
}
|
||||
emit setPartSubdivState(m_partId, !part->subdived);
|
||||
});
|
||||
|
||||
connect(m_disableButton, &QPushButton::clicked, [=]() {
|
||||
if (m_disableButton->text() == QChar(fa::link)) {
|
||||
emit setPartDisableState(m_partId, true);
|
||||
} else {
|
||||
emit setPartDisableState(m_partId, false);
|
||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||
if (!part) {
|
||||
qDebug() << "Part not found:" << m_partId;
|
||||
return;
|
||||
}
|
||||
emit setPartDisableState(m_partId, !part->disabled);
|
||||
});
|
||||
|
||||
connect(m_xMirrorButton, &QPushButton::clicked, [=]() {
|
||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||
if (!part) {
|
||||
qDebug() << "Part not found:" << m_partId;
|
||||
return;
|
||||
}
|
||||
emit setPartXmirrorState(m_partId, !part->xMirrored);
|
||||
});
|
||||
|
||||
connect(m_zMirrorButton, &QPushButton::clicked, [=]() {
|
||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||
if (!part) {
|
||||
qDebug() << "Part not found:" << m_partId;
|
||||
return;
|
||||
}
|
||||
emit setPartZmirrorState(m_partId, !part->zMirrored);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -172,6 +206,32 @@ void SkeletonPartWidget::updateDisableButton()
|
|||
updateButton(m_disableButton, QChar(fa::link), false);
|
||||
}
|
||||
|
||||
void SkeletonPartWidget::updateXmirrorButton()
|
||||
{
|
||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||
if (!part) {
|
||||
qDebug() << "Part not found:" << m_partId;
|
||||
return;
|
||||
}
|
||||
if (part->xMirrored)
|
||||
updateButton(m_xMirrorButton, QChar(fa::quoteleft), true);
|
||||
else
|
||||
updateButton(m_xMirrorButton, QChar(fa::quoteleft), false);
|
||||
}
|
||||
|
||||
void SkeletonPartWidget::updateZmirrorButton()
|
||||
{
|
||||
const SkeletonPart *part = m_document->findPart(m_partId);
|
||||
if (!part) {
|
||||
qDebug() << "Part not found:" << m_partId;
|
||||
return;
|
||||
}
|
||||
if (part->zMirrored)
|
||||
updateButton(m_zMirrorButton, QChar(fa::quoteright), true);
|
||||
else
|
||||
updateButton(m_zMirrorButton, QChar(fa::quoteright), false);
|
||||
}
|
||||
|
||||
void SkeletonPartWidget::reload()
|
||||
{
|
||||
updatePreview();
|
||||
|
@ -179,6 +239,8 @@ void SkeletonPartWidget::reload()
|
|||
updateVisibleButton();
|
||||
updateSubdivButton();
|
||||
updateDisableButton();
|
||||
updateXmirrorButton();
|
||||
updateZmirrorButton();
|
||||
}
|
||||
|
||||
SkeletonPartListWidget::SkeletonPartListWidget(const SkeletonDocument *document) :
|
||||
|
@ -273,3 +335,25 @@ void SkeletonPartListWidget::partDisableStateChanged(QUuid partId)
|
|||
SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second);
|
||||
widget->updateDisableButton();
|
||||
}
|
||||
|
||||
void SkeletonPartListWidget::partXmirrorStateChanged(QUuid partId)
|
||||
{
|
||||
auto item = m_itemMap.find(partId);
|
||||
if (item == m_itemMap.end()) {
|
||||
qDebug() << "Part item not found:" << partId;
|
||||
return;
|
||||
}
|
||||
SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second);
|
||||
widget->updateXmirrorButton();
|
||||
}
|
||||
|
||||
void SkeletonPartListWidget::partZmirrorStateChanged(QUuid partId)
|
||||
{
|
||||
auto item = m_itemMap.find(partId);
|
||||
if (item == m_itemMap.end()) {
|
||||
qDebug() << "Part item not found:" << partId;
|
||||
return;
|
||||
}
|
||||
SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second);
|
||||
widget->updateZmirrorButton();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ signals:
|
|||
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);
|
||||
public:
|
||||
SkeletonPartWidget(const SkeletonDocument *document, QUuid partId);
|
||||
void reload();
|
||||
|
@ -22,6 +24,8 @@ public:
|
|||
void updateVisibleButton();
|
||||
void updateSubdivButton();
|
||||
void updateDisableButton();
|
||||
void updateXmirrorButton();
|
||||
void updateZmirrorButton();
|
||||
private:
|
||||
const SkeletonDocument *m_document;
|
||||
QUuid m_partId;
|
||||
|
@ -30,6 +34,8 @@ private:
|
|||
QPushButton *m_lockButton;
|
||||
QPushButton *m_subdivButton;
|
||||
QPushButton *m_disableButton;
|
||||
QPushButton *m_xMirrorButton;
|
||||
QPushButton *m_zMirrorButton;
|
||||
QLabel *m_nameLabel;
|
||||
private:
|
||||
void initButton(QPushButton *button);
|
||||
|
@ -49,6 +55,8 @@ public slots:
|
|||
void partVisibleStateChanged(QUuid partId);
|
||||
void partSubdivStateChanged(QUuid partId);
|
||||
void partDisableStateChanged(QUuid partId);
|
||||
void partXmirrorStateChanged(QUuid partId);
|
||||
void partZmirrorStateChanged(QUuid partId);
|
||||
private:
|
||||
const SkeletonDocument *m_document;
|
||||
std::map<QUuid, QListWidgetItem *> m_itemMap;
|
||||
|
|
|
@ -1,2 +1,58 @@
|
|||
#include <QDebug>
|
||||
#include "skeletonsnapshot.h"
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
|
||||
void SkeletonSnapshot::resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile, const QString &partId)
|
||||
{
|
||||
float left = 0;
|
||||
bool leftFirstTime = true;
|
||||
float right = 0;
|
||||
bool rightFirstTime = true;
|
||||
float top = 0;
|
||||
bool topFirstTime = true;
|
||||
float bottom = 0;
|
||||
bool bottomFirstTime = true;
|
||||
float zLeft = 0;
|
||||
bool zLeftFirstTime = true;
|
||||
float zRight = 0;
|
||||
bool zRightFirstTime = true;
|
||||
for (const auto &nodeIt: nodes) {
|
||||
if (!partId.isEmpty() && partId != valueOfKeyInMapOrEmpty(nodeIt.second, "partId"))
|
||||
continue;
|
||||
float radius = valueOfKeyInMapOrEmpty(nodeIt.second, "radius").toFloat();
|
||||
float x = valueOfKeyInMapOrEmpty(nodeIt.second, "x").toFloat();
|
||||
float y = valueOfKeyInMapOrEmpty(nodeIt.second, "y").toFloat();
|
||||
float z = valueOfKeyInMapOrEmpty(nodeIt.second, "z").toFloat();
|
||||
if (leftFirstTime || x - radius < left) {
|
||||
left = x - radius;
|
||||
leftFirstTime = false;
|
||||
}
|
||||
if (topFirstTime || y - radius < top) {
|
||||
top = y - radius;
|
||||
topFirstTime = false;
|
||||
}
|
||||
if (rightFirstTime || x + radius > right) {
|
||||
right = x + radius;
|
||||
rightFirstTime = false;
|
||||
}
|
||||
if (bottomFirstTime || y + radius > bottom) {
|
||||
bottom = y + radius;
|
||||
bottomFirstTime = false;
|
||||
}
|
||||
if (zLeftFirstTime || z - radius < zLeft) {
|
||||
zLeft = z - radius;
|
||||
zLeftFirstTime = false;
|
||||
}
|
||||
if (zRightFirstTime || z + radius > zRight) {
|
||||
zRight = z + radius;
|
||||
zRightFirstTime = false;
|
||||
}
|
||||
}
|
||||
*mainProfile = QRectF(QPointF(left, top), QPointF(right, bottom));
|
||||
*sideProfile = QRectF(QPointF(zLeft, top), QPointF(zRight, bottom));
|
||||
qDebug() << "resolveBoundingBox left:" << left << "top:" << top << "right:" << right << "bottom:" << bottom << " zLeft:" << zLeft << "zRight:" << zRight;
|
||||
qDebug() << "mainHeight:" << mainProfile->height() << "mainWidth:" << mainProfile->width();
|
||||
qDebug() << "sideHeight:" << sideProfile->height() << "sideWidth:" << sideProfile->width();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ public:
|
|||
std::map<QString, std::map<QString, QString>> edges;
|
||||
std::map<QString, std::map<QString, QString>> parts;
|
||||
std::vector<QString> partIdList;
|
||||
public:
|
||||
void resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile, const QString &partId=QString());
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
BIN
thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll
vendored
Normal file → Executable file
BIN
thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll
vendored
Normal file → Executable file
Binary file not shown.
BIN
thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll.lib
vendored
Normal file → Executable file
BIN
thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll.lib
vendored
Normal file → Executable file
Binary file not shown.
|
@ -42,6 +42,8 @@ int meshlite_bmesh_error_count(void *context, int bmesh_id);
|
|||
int meshlite_combine_adj_faces(void *context, int mesh_id);
|
||||
int meshlite_combine_coplanar_faces(void *context, int mesh_id);
|
||||
int meshlite_trim(void *context, int mesh_id, int normalize);
|
||||
int meshlite_mirror_in_x(void *context, int mesh_id, float center_x);
|
||||
int meshlite_mirror_in_z(void *context, int mesh_id, float center_z);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
BIN
thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll
vendored
Normal file → Executable file
BIN
thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll
vendored
Normal file → Executable file
Binary file not shown.
BIN
thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll.lib
vendored
Normal file → Executable file
BIN
thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll.lib
vendored
Normal file → Executable file
Binary file not shown.
|
@ -42,6 +42,8 @@ int meshlite_bmesh_error_count(void *context, int bmesh_id);
|
|||
int meshlite_combine_adj_faces(void *context, int mesh_id);
|
||||
int meshlite_combine_coplanar_faces(void *context, int mesh_id);
|
||||
int meshlite_trim(void *context, int mesh_id, int normalize);
|
||||
int meshlite_mirror_in_x(void *context, int mesh_id, float center_x);
|
||||
int meshlite_mirror_in_z(void *context, int mesh_id, float center_z);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue