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