Remove unused markpen code

master
huxingyi 2020-12-17 21:24:11 +09:30
parent fac30fc6a4
commit 7817cde381
11 changed files with 16 additions and 866 deletions

View File

@ -439,12 +439,6 @@ HEADERS += src/triangulatefaces.h
SOURCES += src/booleanmesh.cpp SOURCES += src/booleanmesh.cpp
HEADERS += src/booleanmesh.h HEADERS += src/booleanmesh.h
SOURCES += src/imageskeletonextractor.cpp
HEADERS += src/imageskeletonextractor.h
SOURCES += src/contourtopartconverter.cpp
HEADERS += src/contourtopartconverter.h
SOURCES += src/remesher.cpp SOURCES += src/remesher.cpp
HEADERS += src/remesher.h HEADERS += src/remesher.h

View File

@ -1,297 +0,0 @@
#include <QImage>
#include <QPainter>
#include <QPainterPath>
#include <cmath>
#include <QUuid>
#include <cmath>
#include <QTransform>
#include <QGuiApplication>
#include "contourtopartconverter.h"
#include "imageskeletonextractor.h"
#include "util.h"
const float ContourToPartConverter::m_targetImageHeight = 64.0f;
const float ContourToPartConverter::m_minEdgeLength = 0.025;
const float ContourToPartConverter::m_radiusEpsilon = 0.0025;
ContourToPartConverter::ContourToPartConverter(const QPolygonF &mainProfile,
const QPolygonF &sideProfile, const QSizeF &canvasSize) :
m_mainProfile(mainProfile),
m_sideProfile(sideProfile),
m_canvasSize(canvasSize)
{
}
void ContourToPartConverter::process()
{
convert();
emit finished();
}
const Snapshot &ContourToPartConverter::getSnapshot()
{
return m_snapshot;
}
void ContourToPartConverter::extractSkeleton(const QPolygonF &polygon,
std::vector<std::pair<QVector2D, float>> *skeleton)
{
auto originalBoundingBox = polygon.boundingRect();
QPointF polygonTopLeft = originalBoundingBox.topLeft();
float scaleFactor = m_targetImageHeight / originalBoundingBox.height();
QTransform transform;
transform = transform.scale(scaleFactor, scaleFactor);
QPolygonF scaledPolygon = transform.map(polygon);
QRectF boundingBox = scaledPolygon.boundingRect();
QImage *image = new QImage(boundingBox.width() + 4, boundingBox.height() + 4, QImage::Format_Grayscale8);
image->fill(QColor(255, 255, 255));
qreal offsetX = 1 - boundingBox.left();
qreal offsetY = 1 - boundingBox.top();
QPainterPath path;
path.addPolygon(scaledPolygon.translated(offsetX, offsetY));
QPainter painter;
painter.begin(image);
painter.setPen(Qt::PenStyle::NoPen);
painter.fillPath(path, Qt::black);
painter.end();
ImageSkeletonExtractor imageSkeletonExtractor;
imageSkeletonExtractor.setImage(image);
imageSkeletonExtractor.extract();
std::vector<std::pair<int, int>> imageSkeleton;
int imageArea = imageSkeletonExtractor.getArea();
imageSkeletonExtractor.getSkeleton(&imageSkeleton);
const std::set<std::pair<int, int>> &blackPixels = imageSkeletonExtractor.getBlackPixels();
std::vector<std::pair<int, int>> selectedNodes;
if (imageSkeleton.size() >= 2) {
int targetLength = std::ceil(0.5 * (float)imageArea / imageSkeleton.size());
int minLength = m_minEdgeLength * imageSkeleton.size();
if (targetLength < minLength)
targetLength = minLength;
size_t newInsertNum = imageSkeleton.size() / targetLength;
if (newInsertNum < 1)
newInsertNum = 1;
if (newInsertNum > 100)
newInsertNum = 100;
float stepFactor = 1.0 / (newInsertNum + 1);
float factor = stepFactor;
selectedNodes.push_back(imageSkeleton[0]);
for (size_t i = 0; i < newInsertNum && factor < 1.0; factor += stepFactor, ++i) {
size_t index = factor * imageSkeleton.size();
if (index <= 0 || index >= imageSkeleton.size())
continue;
selectedNodes.push_back(imageSkeleton[index]);
}
selectedNodes.push_back(imageSkeleton[imageSkeleton.size() - 1]);
}
std::vector<QVector3D> selectedPositions;
selectedPositions.reserve(selectedNodes.size());
for (const auto &it: selectedNodes)
selectedPositions.push_back(QVector3D(it.first, it.second, 0.0f));
std::vector<QVector3D> selectedDirections;
selectedDirections.reserve(selectedNodes.size());
for (size_t i = 0; i < selectedPositions.size(); ++i) {
QVector3D sumOfDirections;
if (i > 0) {
sumOfDirections += selectedPositions[i] - selectedPositions[i - 1];
}
if (i + 1 < selectedPositions.size()) {
sumOfDirections += selectedPositions[i + 1] - selectedPositions[i];
}
selectedDirections.push_back(sumOfDirections.normalized());
}
std::vector<int> selectedRadius;
selectedRadius.reserve(selectedNodes.size());
for (size_t i = 0; i < selectedDirections.size(); ++i) {
selectedRadius.push_back(calculateNodeRadius(selectedPositions[i], selectedDirections[i],
blackPixels));
}
skeleton->resize(selectedRadius.size());
auto canvasHeight = m_canvasSize.height();
for (size_t i = 0; i < skeleton->size(); ++i) {
const auto &node = selectedNodes[i];
(*skeleton)[i] = std::make_pair(QVector2D(node.first / scaleFactor + polygonTopLeft.x(),
node.second / scaleFactor + polygonTopLeft.y()) / canvasHeight,
selectedRadius[i] / scaleFactor / canvasHeight);
}
}
int ContourToPartConverter::calculateNodeRadius(const QVector3D &node,
const QVector3D &direction,
const std::set<std::pair<int, int>> &black)
{
const QVector3D pointer = {0.0f, 0.0f, 1.0f};
QVector3D offsetDirection = QVector3D::crossProduct(direction, pointer);
int radius = 1;
while (true) {
QVector3D offset = radius * offsetDirection;
QVector3D sidePosition = node + offset;
QVector3D otherSidePosition = node - offset;
if (black.find(std::make_pair((int)sidePosition.x(), (int)sidePosition.y())) == black.end())
break;
if (black.find(std::make_pair((int)otherSidePosition.x(), (int)otherSidePosition.y())) == black.end())
break;
++radius;
}
return radius;
}
void ContourToPartConverter::smoothRadius(std::vector<std::pair<QVector2D, float>> *skeleton)
{
if (skeleton->empty())
return;
std::vector<float> newRadius;
newRadius.reserve(skeleton->size() + 2);
newRadius.push_back(skeleton->front().second);
for (const auto &it: (*skeleton)) {
newRadius.push_back(it.second);
}
newRadius.push_back(skeleton->back().second);
for (size_t h = 0; h < skeleton->size(); ++h) {
size_t i = h + 1;
size_t j = h + 2;
(*skeleton)[h].second = (newRadius[h] +
newRadius[i] + newRadius[j]) / 3;
}
}
void ContourToPartConverter::optimizeNodes()
{
auto oldNodes = m_nodes;
m_nodes.clear();
m_nodes.reserve(oldNodes.size());
for (size_t i = 0; i < oldNodes.size(); ++i) {
if (i > 0 && i + 1 < oldNodes.size()) {
size_t h = i - 1;
size_t j = i + 1;
if (std::abs(oldNodes[i].second - oldNodes[h].second) < m_radiusEpsilon &&
std::abs(oldNodes[i].second - oldNodes[j].second) < m_radiusEpsilon) {
auto degrees = degreesBetweenVectors((oldNodes[i].first - oldNodes[h].first).normalized(),
(oldNodes[j].first - oldNodes[i].first).normalized());
if (degrees < 15)
continue;
}
}
m_nodes.push_back(oldNodes[i]);
}
}
void ContourToPartConverter::alignSkeleton(const std::vector<std::pair<QVector2D, float>> &referenceSkeleton,
std::vector<std::pair<QVector2D, float>> &adjustSkeleton)
{
if (referenceSkeleton.empty() || adjustSkeleton.empty())
return;
float sumOfDistance2 = 0.0;
float reversedSumOfDistance2 = 0.0;
for (size_t i = 0; i < adjustSkeleton.size(); ++i) {
size_t j = ((float)i / adjustSkeleton.size()) * referenceSkeleton.size();
if (j >= referenceSkeleton.size())
continue;
size_t k = referenceSkeleton.size() - 1 - j;
sumOfDistance2 += std::pow(adjustSkeleton[i].first.y() - referenceSkeleton[j].first.y(), 2.0f);
reversedSumOfDistance2 += std::pow(adjustSkeleton[i].first.y() - referenceSkeleton[k].first.y(), 2.0f);
}
if (sumOfDistance2 <= reversedSumOfDistance2)
return;
std::reverse(adjustSkeleton.begin(), adjustSkeleton.end());
}
void ContourToPartConverter::convert()
{
std::vector<std::pair<QVector2D, float>> sideSkeleton;
std::vector<std::pair<QVector2D, float>> mainSkeleton;
auto mainBoundingBox = m_mainProfile.boundingRect();
extractSkeleton(m_sideProfile, &sideSkeleton);
extractSkeleton(m_mainProfile, &mainSkeleton);
smoothRadius(&sideSkeleton);
smoothRadius(&mainSkeleton);
if (!sideSkeleton.empty()) {
alignSkeleton(sideSkeleton, mainSkeleton);
float defaultX = mainBoundingBox.center().x() / m_canvasSize.height();
float area = mainBoundingBox.width() * mainBoundingBox.height();
float mainBoundingBoxWidthHeightOffset = std::abs(mainBoundingBox.width() - mainBoundingBox.height());
float rectRadius = std::sqrt(area) * 0.5;
bool useCalculatedX = mainBoundingBoxWidthHeightOffset >= rectRadius;
m_nodes.reserve(sideSkeleton.size());
for (size_t i = 0; i < sideSkeleton.size(); ++i) {
const auto &it = sideSkeleton[i];
float x = defaultX;
if (useCalculatedX) {
size_t j = ((float)i / sideSkeleton.size()) * mainSkeleton.size();
x = j < mainSkeleton.size() ? mainSkeleton[j].first.x() : defaultX;
}
m_nodes.push_back(std::make_pair(QVector3D(x, it.first.y(), it.first.x()),
it.second));
}
}
optimizeNodes();
nodesToSnapshot();
}
void ContourToPartConverter::nodesToSnapshot()
{
if (m_nodes.empty())
return;
auto partId = QUuid::createUuid();
auto partIdString = partId.toString();
std::map<QString, QString> snapshotPart;
snapshotPart["id"] = partIdString;
snapshotPart["subdived"] = "true";
snapshotPart["rounded"] = "true";
snapshotPart["base"] = "YZ";
m_snapshot.parts[partIdString] = snapshotPart;
auto componentId = QUuid::createUuid();
auto componentIdString = componentId.toString();
std::map<QString, QString> snapshotComponent;
snapshotComponent["id"] = componentIdString;
snapshotComponent["combineMode"] = "Normal";
snapshotComponent["linkDataType"] = "partId";
snapshotComponent["linkData"] = partIdString;
m_snapshot.components[componentIdString] = snapshotComponent;
m_snapshot.rootComponent["children"] = componentIdString;
std::vector<QString> nodeIdStrings;
nodeIdStrings.reserve(m_nodes.size());
for (const auto &it: m_nodes) {
auto nodeId = QUuid::createUuid();
auto nodeIdString = nodeId.toString();
std::map<QString, QString> snapshotNode;
snapshotNode["id"] = nodeIdString;
snapshotNode["x"] = QString::number(it.first.x());
snapshotNode["y"] = QString::number(it.first.y());
snapshotNode["z"] = QString::number(it.first.z());
snapshotNode["radius"] = QString::number(it.second);
snapshotNode["partId"] = partIdString;
m_snapshot.nodes[nodeIdString] = snapshotNode;
nodeIdStrings.push_back(nodeIdString);
}
for (size_t i = 1; i < nodeIdStrings.size(); ++i) {
size_t h = i - 1;
auto edgeId = QUuid::createUuid();
auto edgeIdString = edgeId.toString();
std::map<QString, QString> snapshotEdge;
snapshotEdge["id"] = edgeIdString;
snapshotEdge["from"] = nodeIdStrings[h];
snapshotEdge["to"] = nodeIdStrings[i];
snapshotEdge["partId"] = partIdString;
m_snapshot.edges[edgeIdString] = snapshotEdge;
}
}

View File

@ -1,42 +0,0 @@
#ifndef DUST3D_CONTOUR_TO_PART_CONVERTER_H
#define DUST3D_CONTOUR_TO_PART_CONVERTER_H
#include <QObject>
#include <QPolygonF>
#include <QVector3D>
#include <QVector2D>
#include <set>
#include "snapshot.h"
class ContourToPartConverter : public QObject
{
Q_OBJECT
public:
ContourToPartConverter(const QPolygonF &mainProfile, const QPolygonF &sideProfile, const QSizeF &canvasSize);
const Snapshot &getSnapshot();
signals:
void finished();
public slots:
void process();
private:
QPolygonF m_mainProfile;
QPolygonF m_sideProfile;
QSizeF m_canvasSize;
Snapshot m_snapshot;
static const float m_targetImageHeight;
static const float m_minEdgeLength;
static const float m_radiusEpsilon;
std::vector<std::pair<QVector3D, float>> m_nodes;
void convert();
void extractSkeleton(const QPolygonF &polygon,
std::vector<std::pair<QVector2D, float>> *skeleton);
int calculateNodeRadius(const QVector3D &node,
const QVector3D &direction,
const std::set<std::pair<int, int>> &black);
void nodesToSnapshot();
void smoothRadius(std::vector<std::pair<QVector2D, float>> *skeleton);
void alignSkeleton(const std::vector<std::pair<QVector2D, float>> &referenceSkeleton,
std::vector<std::pair<QVector2D, float>> &adjustSkeleton);
void optimizeNodes();
};
#endif

View File

@ -18,7 +18,6 @@
#include "skeletonside.h" #include "skeletonside.h"
#include "scriptrunner.h" #include "scriptrunner.h"
#include "imageforever.h" #include "imageforever.h"
#include "contourtopartconverter.h"
#include "meshgenerator.h" #include "meshgenerator.h"
unsigned long Document::m_maxSnapshot = 1000; unsigned long Document::m_maxSnapshot = 1000;
@ -391,28 +390,6 @@ void Document::addNode(float x, float y, float z, float radius, QUuid fromNodeId
createNode(QUuid::createUuid(), x, y, z, radius, fromNodeId); createNode(QUuid::createUuid(), x, y, z, radius, fromNodeId);
} }
void Document::addPartByPolygons(const QPolygonF &mainProfile, const QPolygonF &sideProfile, const QSizeF &canvasSize)
{
if (mainProfile.empty() || sideProfile.empty())
return;
QThread *thread = new QThread;
ContourToPartConverter *contourToPartConverter = new ContourToPartConverter(mainProfile, sideProfile, canvasSize);
contourToPartConverter->moveToThread(thread);
connect(thread, &QThread::started, contourToPartConverter, &ContourToPartConverter::process);
connect(contourToPartConverter, &ContourToPartConverter::finished, this, [=]() {
const auto &snapshot = contourToPartConverter->getSnapshot();
if (!snapshot.nodes.empty()) {
addFromSnapshot(snapshot, SnapshotSource::Paste);
saveSnapshot();
}
delete contourToPartConverter;
});
connect(contourToPartConverter, &ContourToPartConverter::finished, thread, &QThread::quit);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
}
void Document::addNodeWithId(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId) void Document::addNodeWithId(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId)
{ {
createNode(nodeId, x, y, z, radius, fromNodeId); createNode(nodeId, x, y, z, radius, fromNodeId);

View File

@ -506,7 +506,6 @@ public slots:
void removeNode(QUuid nodeId); void removeNode(QUuid nodeId);
void removeEdge(QUuid edgeId); void removeEdge(QUuid edgeId);
void removePart(QUuid partId); void removePart(QUuid partId);
void addPartByPolygons(const QPolygonF &mainProfile, const QPolygonF &sideProfile, const QSizeF &canvasSize);
void addNodeWithId(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId); void addNodeWithId(QUuid nodeId, float x, float y, float z, float radius, QUuid fromNodeId);
void addNode(float x, float y, float z, float radius, QUuid fromNodeId); void addNode(float x, float y, float z, float radius, QUuid fromNodeId);
void scaleNodeByAddRadius(QUuid nodeId, float amount); void scaleNodeByAddRadius(QUuid nodeId, float amount);

View File

@ -941,7 +941,6 @@ DocumentWindow::DocumentWindow() :
connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setPartXmirrorState, m_document, &Document::setPartXmirrorState); connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setPartXmirrorState, m_document, &Document::setPartXmirrorState);
connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setPartRoundState, m_document, &Document::setPartRoundState); connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setPartRoundState, m_document, &Document::setPartRoundState);
connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setPartWrapState, m_document, &Document::setPartCutRotation); connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setPartWrapState, m_document, &Document::setPartCutRotation);
connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::addPartByPolygons, m_document, &Document::addPartByPolygons);
connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setXlockState, m_document, &Document::setXlockState); connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setXlockState, m_document, &Document::setXlockState);
connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setYlockState, m_document, &Document::setYlockState); connect(shapeGraphicsWidget, &SkeletonGraphicsWidget::setYlockState, m_document, &Document::setYlockState);

View File

@ -1,260 +0,0 @@
#include <QDebug>
#include <queue>
#include <set>
#include "imageskeletonextractor.h"
// This is an implementation of the following paper:
// <A Fast Parallel Algorithm for Thinning Digital Patterns>
// T. Y. ZHANG and C. Y. SUEN
ImageSkeletonExtractor::~ImageSkeletonExtractor()
{
delete m_image;
delete m_grayscaleImage;
}
void ImageSkeletonExtractor::setImage(QImage *image)
{
delete m_image;
m_image = image;
}
QImage *ImageSkeletonExtractor::takeResultGrayscaleImage()
{
QImage *resultImage = m_grayscaleImage;
m_grayscaleImage = nullptr;
return resultImage;
}
bool ImageSkeletonExtractor::firstSubiterationSatisfied(int i, int j)
{
if (!isBlack(i, j))
return false;
auto blackNeighbors = countBlackNeighbors(i, j);
if (blackNeighbors < 2 || blackNeighbors > 6)
return false;
auto neighborTransitions = countNeighborTransitions(i, j);
if (1 != neighborTransitions)
return false;
if (isBlack(i + neighborOffsets[P2].first, j + neighborOffsets[P2].second) &&
isBlack(i + neighborOffsets[P4].first, j + neighborOffsets[P4].second) &&
isBlack(i + neighborOffsets[P6].first, j + neighborOffsets[P6].second)) {
return false;
}
if (isBlack(i + neighborOffsets[P4].first, j + neighborOffsets[P4].second) &&
isBlack(i + neighborOffsets[P6].first, j + neighborOffsets[P6].second) &&
isBlack(i + neighborOffsets[P8].first, j + neighborOffsets[P8].second)) {
return false;
}
return true;
}
bool ImageSkeletonExtractor::secondSubiterationSatisfied(int i, int j)
{
if (!isBlack(i, j))
return false;
auto blackNeighbors = countBlackNeighbors(i, j);
if (blackNeighbors < 2 || blackNeighbors > 6)
return false;
auto neighborTransitions = countNeighborTransitions(i, j);
if (1 != neighborTransitions)
return false;
if (isBlack(i + neighborOffsets[P2].first, j + neighborOffsets[P2].second) &&
isBlack(i + neighborOffsets[P4].first, j + neighborOffsets[P4].second) &&
isBlack(i + neighborOffsets[P8].first, j + neighborOffsets[P8].second)) {
return false;
}
if (isBlack(i + neighborOffsets[P2].first, j + neighborOffsets[P2].second) &&
isBlack(i + neighborOffsets[P6].first, j + neighborOffsets[P6].second) &&
isBlack(i + neighborOffsets[P8].first, j + neighborOffsets[P8].second)) {
return false;
}
return true;
}
void ImageSkeletonExtractor::calculateAreaAndBlackPixels()
{
m_area = 0;
m_blackPixels.clear();
for (int i = 1; i < (int)m_grayscaleImage->width() - 1; ++i) {
for (int j = 1; j < (int)m_grayscaleImage->height() - 1; ++j) {
if (isBlack(i, j)) {
++m_area;
m_blackPixels.insert({i, j});
}
}
}
}
const std::set<std::pair<int, int>> &ImageSkeletonExtractor::getBlackPixels()
{
return m_blackPixels;
}
int ImageSkeletonExtractor::getArea()
{
return m_area;
}
void ImageSkeletonExtractor::extract()
{
m_grayscaleImage = new QImage(m_image->convertToFormat(QImage::Format_Grayscale8));
calculateAreaAndBlackPixels();
while (true) {
std::vector<std::pair<int, int>> firstSatisfied;
for (int i = 1; i < (int)m_grayscaleImage->width() - 1; ++i) {
for (int j = 1; j < (int)m_grayscaleImage->height() - 1; ++j) {
if (firstSubiterationSatisfied(i, j))
firstSatisfied.push_back(std::make_pair(i, j));
}
}
for (const auto &it: firstSatisfied)
setWhite(it.first, it.second);
std::vector<std::pair<int, int>> secondSatisfied;
for (int i = 1; i < (int)m_grayscaleImage->width() - 1; ++i) {
for (int j = 1; j < (int)m_grayscaleImage->height() - 1; ++j) {
if (secondSubiterationSatisfied(i, j))
secondSatisfied.push_back(std::make_pair(i, j));
}
}
for (const auto &it: secondSatisfied)
setWhite(it.first, it.second);
if (firstSatisfied.empty() && secondSatisfied.empty())
break;
}
}
void ImageSkeletonExtractor::getSkeleton(std::vector<std::pair<int, int>> *skeleton)
{
if (nullptr == m_grayscaleImage)
return;
std::map<std::pair<int, int>, std::vector<std::pair<int, int>>> links;
for (int i = 1; i < (int)m_grayscaleImage->width() - 1; ++i) {
for (int j = 1; j < (int)m_grayscaleImage->height() - 1; ++j) {
if (!isBlack(i, j))
continue;
auto ij = std::make_pair(i, j);
auto p2 = std::make_pair(i + neighborOffsets[P2].first, j + neighborOffsets[P2].second);
bool hasP3 = true;
bool hasP5 = true;
bool hasP7 = true;
bool hasP9 = true;
if (isBlack(p2.first, p2.second)) {
links[ij].push_back(p2);
hasP3 = false;
hasP9 = false;
}
auto p4 = std::make_pair(i + neighborOffsets[P4].first, j + neighborOffsets[P4].second);
if (isBlack(p4.first, p4.second)) {
links[ij].push_back(p4);
hasP3 = false;
hasP5 = false;
}
auto p6 = std::make_pair(i + neighborOffsets[P6].first, j + neighborOffsets[P6].second);
if (isBlack(p6.first, p6.second)) {
links[ij].push_back(p6);
hasP5 = false;
hasP7 = false;
}
auto p8 = std::make_pair(i + neighborOffsets[P8].first, j + neighborOffsets[P8].second);
if (isBlack(p8.first, p8.second)) {
links[ij].push_back(p8);
hasP7 = false;
hasP9 = false;
}
if (hasP3) {
auto p3 = std::make_pair(i + neighborOffsets[P3].first, j + neighborOffsets[P3].second);
if (isBlack(p3.first, p3.second)) {
links[ij].push_back(p3);
}
}
if (hasP5) {
auto p5 = std::make_pair(i + neighborOffsets[P5].first, j + neighborOffsets[P5].second);
if (isBlack(p5.first, p5.second)) {
links[ij].push_back(p5);
}
}
if (hasP7) {
auto p7 = std::make_pair(i + neighborOffsets[P7].first, j + neighborOffsets[P7].second);
if (isBlack(p7.first, p7.second)) {
links[ij].push_back(p7);
}
}
if (hasP9) {
auto p9 = std::make_pair(i + neighborOffsets[P9].first, j + neighborOffsets[P9].second);
if (isBlack(p9.first, p9.second)) {
links[ij].push_back(p9);
}
}
}
}
auto calculateRouteLength = [&](const std::pair<int, int> &branch, const std::pair<int, int> &start) {
std::set<std::pair<int, int>> visited;
visited.insert(branch);
std::queue<std::pair<int, int>> waitPoints;
waitPoints.push(start);
size_t addLength = 0;
while (!waitPoints.empty()) {
auto point = waitPoints.front();
waitPoints.pop();
if (visited.find(point) != visited.end())
continue;
visited.insert(point);
auto findLink = links.find(point);
if (findLink == links.end())
break;
if (findLink->second.size() > 2) {
addLength = links.size(); // This will make sure the branch node is not been removed
break;
}
for (const auto &it: findLink->second) {
if (visited.find(it) != visited.end())
continue;
waitPoints.push(it);
}
}
return visited.size() + addLength;
};
for (auto &it: links) {
if (it.second.size() > 2) {
std::vector<std::pair<std::pair<int, int>, size_t>> routes;
routes.reserve(it.second.size());
for (size_t i = 0; i < it.second.size(); ++i) {
routes.push_back(std::make_pair(it.second[i], calculateRouteLength(it.first, it.second[i])));
}
std::sort(routes.begin(), routes.end(), [](const std::pair<std::pair<int, int>, size_t> &first,
const std::pair<std::pair<int, int>, size_t> &second) {
return first.second < second.second;
});
it.second = std::vector<std::pair<int, int>> {routes[routes.size() - 2].first,
routes[routes.size() - 1].first};
}
}
std::queue<std::pair<int, int>> waitPoints;
for (const auto &it: links) {
if (1 == it.second.size()) {
waitPoints.push(it.first);
break;
}
}
std::set<std::pair<int, int>> visited;
while (!waitPoints.empty()) {
auto point = waitPoints.front();
waitPoints.pop();
if (visited.find(point) != visited.end())
continue;
visited.insert(point);
skeleton->push_back(point);
auto findLink = links.find(point);
if (findLink == links.end())
break;
for (const auto &it: findLink->second) {
if (visited.find(it) != visited.end())
continue;
waitPoints.push(it);
}
}
}

View File

@ -1,89 +0,0 @@
#ifndef DUST3D_IMAGE_SKELETON_EXTRACTOR_H
#define DUST3D_IMAGE_SKELETON_EXTRACTOR_H
#include <QImage>
#include <QObject>
#include <vector>
#include <set>
class ImageSkeletonExtractor : QObject
{
Q_OBJECT
public:
const std::vector<std::pair<int, int>> neighborOffsets = {
{ 0, -1},
{ 1, -1},
{ 1, 0},
{ 1, 1},
{ 0, 1},
{-1, 1},
{-1, 0},
{-1, -1},
};
enum {
P2 = 0,
P3,
P4,
P5,
P6,
P7,
P8,
P9
};
~ImageSkeletonExtractor();
void setImage(QImage *image);
void extract();
QImage *takeResultGrayscaleImage();
void getSkeleton(std::vector<std::pair<int, int>> *skeleton);
int getArea();
const std::set<std::pair<int, int>> &getBlackPixels();
private:
QImage *m_image = nullptr;
QImage *m_grayscaleImage = nullptr;
int m_area = 0;
std::set<std::pair<int, int>> m_blackPixels;
bool isBlack(int i, int j)
{
return QColor(m_grayscaleImage->pixel(i, j)).black() > 0;
}
bool isWhite(int i, int j)
{
return !isBlack(i, j);
}
void setWhite(int i, int j)
{
m_grayscaleImage->setPixel(i, j, qRgb(255, 255, 255));
}
int countNeighborTransitions(int i, int j)
{
int num = 0;
for (size_t m = 0; m < neighborOffsets.size(); ++m) {
size_t n = (m + 1) % neighborOffsets.size();
if (isWhite(i + neighborOffsets[m].first, j + neighborOffsets[m].second) &&
isBlack(i + neighborOffsets[n].first, j + neighborOffsets[n].second)) {
++num;
}
}
return num;
}
int countBlackNeighbors(int i, int j)
{
int num = 0;
for (const auto &it: neighborOffsets) {
if (isBlack(i + it.first, j + it.second))
++num;
}
return num;
}
bool firstSubiterationSatisfied(int i, int j);
bool secondSubiterationSatisfied(int i, int j);
void calculateAreaAndBlackPixels();
};
#endif

View File

@ -429,7 +429,6 @@ enum class SkeletonDocumentEditMode
{ {
Add = 0, Add = 0,
Select, Select,
Mark,
Paint, Paint,
Drag, Drag,
ZoomIn, ZoomIn,

View File

@ -32,9 +32,7 @@ SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument *document)
m_lastAddedY(false), m_lastAddedY(false),
m_lastAddedZ(false), m_lastAddedZ(false),
m_selectionItem(nullptr), m_selectionItem(nullptr),
m_markerItem(nullptr),
m_rangeSelectionStarted(false), m_rangeSelectionStarted(false),
m_markerStarted(false),
m_mouseEventFromSelf(false), m_mouseEventFromSelf(false),
m_moveHappened(false), m_moveHappened(false),
m_lastRot(0), m_lastRot(0),
@ -80,10 +78,6 @@ SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument *document)
m_selectionItem->hide(); m_selectionItem->hide();
scene()->addItem(m_selectionItem); scene()->addItem(m_selectionItem);
m_markerItem = new SkeletonGraphicsMarkerItem();
m_markerItem->hide();
scene()->addItem(m_markerItem);
m_mainOriginItem = new SkeletonGraphicsOriginItem(SkeletonProfile::Main); m_mainOriginItem = new SkeletonGraphicsOriginItem(SkeletonProfile::Main);
m_mainOriginItem->setRotated(m_rotated); m_mainOriginItem->setRotated(m_rotated);
m_mainOriginItem->hide(); m_mainOriginItem->hide();
@ -140,7 +134,6 @@ void SkeletonGraphicsWidget::setBackgroundBlur(float turnaroundOpacity)
void SkeletonGraphicsWidget::shortcutEscape() void SkeletonGraphicsWidget::shortcutEscape()
{ {
if (SkeletonDocumentEditMode::Add == m_document->editMode || if (SkeletonDocumentEditMode::Add == m_document->editMode ||
SkeletonDocumentEditMode::Mark == m_document->editMode ||
SkeletonDocumentEditMode::Paint == m_document->editMode) { SkeletonDocumentEditMode::Paint == m_document->editMode) {
emit setEditMode(SkeletonDocumentEditMode::Select); emit setEditMode(SkeletonDocumentEditMode::Select);
return; return;
@ -762,10 +755,6 @@ void SkeletonGraphicsWidget::updateCursor()
m_cursorNodeItem->hide(); m_cursorNodeItem->hide();
} }
if (SkeletonDocumentEditMode::Mark != m_document->editMode) {
m_markerItem->reset();
}
switch (m_document->editMode) { switch (m_document->editMode) {
case SkeletonDocumentEditMode::Add: case SkeletonDocumentEditMode::Add:
setCursor(QCursor(Theme::awesome()->icon(fa::plus).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize))); setCursor(QCursor(Theme::awesome()->icon(fa::plus).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize)));
@ -773,13 +762,6 @@ void SkeletonGraphicsWidget::updateCursor()
case SkeletonDocumentEditMode::Select: case SkeletonDocumentEditMode::Select:
setCursor(QCursor(Theme::awesome()->icon(fa::mousepointer).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize), Theme::toolIconFontSize / 5, 0)); setCursor(QCursor(Theme::awesome()->icon(fa::mousepointer).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize), Theme::toolIconFontSize / 5, 0));
break; break;
case SkeletonDocumentEditMode::Mark: {
auto pixmap = Theme::awesome()->icon(fa::pencil).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize);
QPixmap replacedPixmap(pixmap.size());
replacedPixmap.fill(m_markerItem->color());
replacedPixmap.setMask(pixmap.createMaskFromColor(Qt::transparent));
setCursor(QCursor(replacedPixmap, Theme::toolIconFontSize / 5, Theme::toolIconFontSize * 4 / 5));
} break;
case SkeletonDocumentEditMode::Paint: case SkeletonDocumentEditMode::Paint:
setCursor(QCursor(Theme::awesome()->icon(fa::paintbrush).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize), Theme::toolIconFontSize * 0.2, Theme::toolIconFontSize * 0.8)); setCursor(QCursor(Theme::awesome()->icon(fa::paintbrush).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize), Theme::toolIconFontSize * 0.2, Theme::toolIconFontSize * 0.8));
break; break;
@ -912,16 +894,6 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent *event)
} }
} }
if (SkeletonDocumentEditMode::Mark == m_document->editMode) {
if (m_markerStarted) {
QPointF mouseScenePos = mouseEventScenePos(event);
m_markerItem->addPoint(mouseScenePos);
if (!m_markerItem->isVisible())
m_markerItem->setVisible(true);
return true;
}
}
if (SkeletonDocumentEditMode::Select == m_document->editMode || if (SkeletonDocumentEditMode::Select == m_document->editMode ||
SkeletonDocumentEditMode::Add == m_document->editMode) { SkeletonDocumentEditMode::Add == m_document->editMode) {
@ -1461,7 +1433,7 @@ void SkeletonGraphicsWidget::rotateAllMainProfileCounterclockwise90DegreeAlongOr
bool SkeletonGraphicsWidget::mouseRelease(QMouseEvent *event) bool SkeletonGraphicsWidget::mouseRelease(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
bool processed = m_dragStarted || m_moveStarted || m_rangeSelectionStarted || m_markerStarted; bool processed = m_dragStarted || m_moveStarted || m_rangeSelectionStarted;
if (m_dragStarted) { if (m_dragStarted) {
m_dragStarted = false; m_dragStarted = false;
updateCursor(); updateCursor();
@ -1476,28 +1448,6 @@ bool SkeletonGraphicsWidget::mouseRelease(QMouseEvent *event)
m_selectionItem->hide(); m_selectionItem->hide();
m_rangeSelectionStarted = false; m_rangeSelectionStarted = false;
} }
if (m_markerStarted) {
auto boundingBox = m_markerItem->polygon().boundingRect();
if (boundingBox.width() * boundingBox.height() > 4) {
const QPolygonF &previousPolygon = m_markerItem->previousPolygon();
if (previousPolygon.empty()) {
m_markerItem->save();
m_markerItem->toggleProfile();
} else {
if (m_markerItem->isMainProfile()) {
emit addPartByPolygons(m_markerItem->polygon(), previousPolygon, sceneRect().size());
} else {
emit addPartByPolygons(previousPolygon, m_markerItem->polygon(), sceneRect().size());
}
m_markerItem->reset();
}
m_markerItem->hide();
updateCursor();
} else {
m_markerItem->clear();
}
m_markerStarted = false;
}
return processed; return processed;
} }
return false; return false;
@ -1641,11 +1591,6 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent *event)
m_rangeSelectionStartPos = mouseEventScenePos(event); m_rangeSelectionStartPos = mouseEventScenePos(event);
m_rangeSelectionStarted = true; m_rangeSelectionStarted = true;
} }
} else if (SkeletonDocumentEditMode::Mark == m_document->editMode) {
if (!m_markerStarted) {
m_markerItem->addPoint(mouseEventScenePos(event));
m_markerStarted = true;
}
} }
} }
return false; return false;
@ -1817,11 +1762,6 @@ void SkeletonGraphicsWidget::shortcutAddMode()
} }
} }
//void SkeletonGraphicsWidget::shortcutMarkMode()
//{
// emit setEditMode(SkeletonDocumentEditMode::Mark);
//}
void SkeletonGraphicsWidget::shortcutUndo() void SkeletonGraphicsWidget::shortcutUndo()
{ {
emit undo(); emit undo();
@ -1908,7 +1848,7 @@ void SkeletonGraphicsWidget::shortcutZoomSelectedBy1()
void SkeletonGraphicsWidget::shortcutRotateSelectedByMinus1() void SkeletonGraphicsWidget::shortcutRotateSelectedByMinus1()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
hasSelection()) { hasSelection()) {
rotateSelected(-1); rotateSelected(-1);
emit groupOperationAdded(); emit groupOperationAdded();
@ -1917,7 +1857,7 @@ void SkeletonGraphicsWidget::shortcutRotateSelectedByMinus1()
void SkeletonGraphicsWidget::shortcutRotateSelectedBy1() void SkeletonGraphicsWidget::shortcutRotateSelectedBy1()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
hasSelection()) { hasSelection()) {
rotateSelected(1); rotateSelected(1);
emit groupOperationAdded(); emit groupOperationAdded();
@ -1926,7 +1866,7 @@ void SkeletonGraphicsWidget::shortcutRotateSelectedBy1()
void SkeletonGraphicsWidget::shortcutMoveSelectedToLeft() void SkeletonGraphicsWidget::shortcutMoveSelectedToLeft()
{ {
if (SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) { if (SkeletonDocumentEditMode::Select == m_document->editMode) {
if (m_checkedOriginItem) { if (m_checkedOriginItem) {
moveCheckedOrigin(-1, 0); moveCheckedOrigin(-1, 0);
emit groupOperationAdded(); emit groupOperationAdded();
@ -1939,7 +1879,7 @@ void SkeletonGraphicsWidget::shortcutMoveSelectedToLeft()
void SkeletonGraphicsWidget::shortcutMoveSelectedToRight() void SkeletonGraphicsWidget::shortcutMoveSelectedToRight()
{ {
if (SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) { if (SkeletonDocumentEditMode::Select == m_document->editMode) {
if (m_checkedOriginItem) { if (m_checkedOriginItem) {
moveCheckedOrigin(1, 0); moveCheckedOrigin(1, 0);
emit groupOperationAdded(); emit groupOperationAdded();
@ -1952,7 +1892,7 @@ void SkeletonGraphicsWidget::shortcutMoveSelectedToRight()
void SkeletonGraphicsWidget::shortcutMoveSelectedToUp() void SkeletonGraphicsWidget::shortcutMoveSelectedToUp()
{ {
if (SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) { if (SkeletonDocumentEditMode::Select == m_document->editMode) {
if (m_checkedOriginItem) { if (m_checkedOriginItem) {
moveCheckedOrigin(0, -1); moveCheckedOrigin(0, -1);
emit groupOperationAdded(); emit groupOperationAdded();
@ -1965,7 +1905,7 @@ void SkeletonGraphicsWidget::shortcutMoveSelectedToUp()
void SkeletonGraphicsWidget::shortcutMoveSelectedToDown() void SkeletonGraphicsWidget::shortcutMoveSelectedToDown()
{ {
if (SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) { if (SkeletonDocumentEditMode::Select == m_document->editMode) {
if (m_checkedOriginItem) { if (m_checkedOriginItem) {
moveCheckedOrigin(0, 1); moveCheckedOrigin(0, 1);
emit groupOperationAdded(); emit groupOperationAdded();
@ -1978,7 +1918,7 @@ void SkeletonGraphicsWidget::shortcutMoveSelectedToDown()
void SkeletonGraphicsWidget::shortcutScaleSelectedByMinus1() void SkeletonGraphicsWidget::shortcutScaleSelectedByMinus1()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
hasSelection()) { hasSelection()) {
scaleSelected(-1); scaleSelected(-1);
emit groupOperationAdded(); emit groupOperationAdded();
@ -1987,7 +1927,7 @@ void SkeletonGraphicsWidget::shortcutScaleSelectedByMinus1()
void SkeletonGraphicsWidget::shortcutScaleSelectedBy1() void SkeletonGraphicsWidget::shortcutScaleSelectedBy1()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
hasSelection()) { hasSelection()) {
scaleSelected(1); scaleSelected(1);
emit groupOperationAdded(); emit groupOperationAdded();
@ -1996,7 +1936,7 @@ void SkeletonGraphicsWidget::shortcutScaleSelectedBy1()
void SkeletonGraphicsWidget::shortcutSwitchProfileOnSelected() void SkeletonGraphicsWidget::shortcutSwitchProfileOnSelected()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
hasSelection()) { hasSelection()) {
switchProfileOnRangeSelection(); switchProfileOnRangeSelection();
} }
@ -2018,7 +1958,7 @@ void SkeletonGraphicsWidget::shortcutShowOrHideSelectedPart()
void SkeletonGraphicsWidget::shortcutEnableOrDisableSelectedPart() void SkeletonGraphicsWidget::shortcutEnableOrDisableSelectedPart()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
!m_lastCheckedPart.isNull()) { !m_lastCheckedPart.isNull()) {
const SkeletonPart *part = m_document->findPart(m_lastCheckedPart); const SkeletonPart *part = m_document->findPart(m_lastCheckedPart);
bool partDisabled = part && part->disabled; bool partDisabled = part && part->disabled;
@ -2029,7 +1969,7 @@ void SkeletonGraphicsWidget::shortcutEnableOrDisableSelectedPart()
void SkeletonGraphicsWidget::shortcutLockOrUnlockSelectedPart() void SkeletonGraphicsWidget::shortcutLockOrUnlockSelectedPart()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
!m_lastCheckedPart.isNull()) { !m_lastCheckedPart.isNull()) {
const SkeletonPart *part = m_document->findPart(m_lastCheckedPart); const SkeletonPart *part = m_document->findPart(m_lastCheckedPart);
bool partLocked = part && part->locked; bool partLocked = part && part->locked;
@ -2040,7 +1980,7 @@ void SkeletonGraphicsWidget::shortcutLockOrUnlockSelectedPart()
void SkeletonGraphicsWidget::shortcutXmirrorOnOrOffSelectedPart() void SkeletonGraphicsWidget::shortcutXmirrorOnOrOffSelectedPart()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
!m_lastCheckedPart.isNull()) { !m_lastCheckedPart.isNull()) {
const SkeletonPart *part = m_document->findPart(m_lastCheckedPart); const SkeletonPart *part = m_document->findPart(m_lastCheckedPart);
bool partXmirrored = part && part->xMirrored; bool partXmirrored = part && part->xMirrored;
@ -2051,7 +1991,7 @@ void SkeletonGraphicsWidget::shortcutXmirrorOnOrOffSelectedPart()
void SkeletonGraphicsWidget::shortcutSubdivedOrNotSelectedPart() void SkeletonGraphicsWidget::shortcutSubdivedOrNotSelectedPart()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
!m_lastCheckedPart.isNull()) { !m_lastCheckedPart.isNull()) {
const SkeletonPart *part = m_document->findPart(m_lastCheckedPart); const SkeletonPart *part = m_document->findPart(m_lastCheckedPart);
bool partSubdived = part && part->subdived; bool partSubdived = part && part->subdived;
@ -2062,7 +2002,7 @@ void SkeletonGraphicsWidget::shortcutSubdivedOrNotSelectedPart()
void SkeletonGraphicsWidget::shortcutChamferedOrNotSelectedPart() void SkeletonGraphicsWidget::shortcutChamferedOrNotSelectedPart()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
!m_lastCheckedPart.isNull()) { !m_lastCheckedPart.isNull()) {
const SkeletonPart *part = m_document->findPart(m_lastCheckedPart); const SkeletonPart *part = m_document->findPart(m_lastCheckedPart);
bool partChamfered = part && part->chamfered; bool partChamfered = part && part->chamfered;
@ -2078,7 +2018,7 @@ void SkeletonGraphicsWidget::shortcutSelectAll()
void SkeletonGraphicsWidget::shortcutRoundEndOrNotSelectedPart() void SkeletonGraphicsWidget::shortcutRoundEndOrNotSelectedPart()
{ {
if ((SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Mark == m_document->editMode) && if ((SkeletonDocumentEditMode::Select == m_document->editMode) &&
!m_lastCheckedPart.isNull()) { !m_lastCheckedPart.isNull()) {
const SkeletonPart *part = m_document->findPart(m_lastCheckedPart); const SkeletonPart *part = m_document->findPart(m_lastCheckedPart);
bool partRounded = part && part->rounded; bool partRounded = part && part->rounded;

View File

@ -124,72 +124,6 @@ public:
} }
}; };
class SkeletonGraphicsMarkerItem : public QGraphicsPolygonItem
{
public:
SkeletonGraphicsMarkerItem()
{
updateAppearance();
}
void addPoint(const QPointF &point)
{
m_polygon.append(point);
setPolygon(m_polygon);
}
void clear()
{
m_polygon.clear();
setPolygon(m_polygon);
}
QColor color()
{
return m_mainProfile ? Theme::red : Theme::green;
}
bool isMainProfile()
{
return m_mainProfile;
}
void toggleProfile()
{
m_mainProfile = !m_mainProfile;
updateAppearance();
}
void save()
{
m_previousPolygon = m_polygon;
clear();
}
const QPolygonF &previousPolygon()
{
return m_previousPolygon;
}
const QPolygonF &polygon()
{
return m_polygon;
}
void reset()
{
m_previousPolygon.clear();
clear();
if (!m_mainProfile) {
m_mainProfile = true;
updateAppearance();
}
}
private:
QPolygonF m_polygon;
QPolygonF m_previousPolygon;
bool m_mainProfile = true;
void updateAppearance()
{
QColor penColor(color());
QPen pen(penColor);
pen.setWidth(2);
pen.setStyle(Qt::SolidLine);
setPen(pen);
}
};
class SkeletonGraphicsNodeItem : public QGraphicsEllipseItem class SkeletonGraphicsNodeItem : public QGraphicsEllipseItem
{ {
public: public:
@ -513,8 +447,6 @@ signals:
void showOrHideAllComponents(); void showOrHideAllComponents();
void shortcutToggleFlatShading(); void shortcutToggleFlatShading();
void shortcutToggleRotation(); void shortcutToggleRotation();
void createGriddedPartsFromNodes(const std::set<QUuid> &nodeIds);
void addPartByPolygons(const QPolygonF &mainProfile, const QPolygonF &sideProfile, const QSizeF &canvasSize);
void loadedTurnaroundImageChanged(); void loadedTurnaroundImageChanged();
public: public:
SkeletonGraphicsWidget(const SkeletonDocument *document); SkeletonGraphicsWidget(const SkeletonDocument *document);
@ -692,9 +624,7 @@ private: //need initialize
float m_lastAddedY; float m_lastAddedY;
float m_lastAddedZ; float m_lastAddedZ;
SkeletonGraphicsSelectionItem *m_selectionItem; SkeletonGraphicsSelectionItem *m_selectionItem;
SkeletonGraphicsMarkerItem *m_markerItem;
bool m_rangeSelectionStarted; bool m_rangeSelectionStarted;
bool m_markerStarted;
bool m_mouseEventFromSelf; bool m_mouseEventFromSelf;
bool m_moveHappened; bool m_moveHappened;
int m_lastRot; int m_lastRot;