Changed Point-In-Polygon Algorithm. Additional field for saving mirror state.

--HG--
branch : feature
This commit is contained in:
dismine 2015-01-18 20:56:01 +02:00
parent c044b334d7
commit c191059ddd
6 changed files with 122 additions and 35 deletions

View File

@ -40,13 +40,17 @@ enum class LayoutErrors : char
EmptyPaperError
};
//#define LAYOUT_DEBUG // Enable debug mode
#define LAYOUT_DEBUG // Enable debug mode
#ifdef LAYOUT_DEBUG
# define SHOW_VERTICES // Show contour vertices
# define SHOW_DIRECTION // Show contour direction
# define ARRANGED_DETAILS // Show already arranged details
//# define SHOW_CANDIDATE
//# define SHOW_ROTATION
//# define SHOW_COMBINE
//# define SHOW_MIRROR
# define SHOW_BEST
#endif//LAYOUT_DEBUG
#endif // VLAYOUTDEF_H

View File

@ -104,13 +104,13 @@ QVector<QPointF> VLayoutDetail::GetLayoutAllowencePoints() const
}
//---------------------------------------------------------------------------------------------------------------------
QMatrix VLayoutDetail::GetMatrix() const
QTransform VLayoutDetail::GetMatrix() const
{
return d->matrix;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutDetail::SetMatrix(const QMatrix &matrix)
void VLayoutDetail::SetMatrix(const QTransform &matrix)
{
d->matrix = matrix;
}
@ -130,7 +130,7 @@ void VLayoutDetail::SetLayoutWidth(const qreal &value)
//---------------------------------------------------------------------------------------------------------------------
void VLayoutDetail::Translate(qreal dx, qreal dy)
{
QMatrix m;
QTransform m;
m.translate(dx, dy);
d->matrix *= m;
}
@ -138,7 +138,7 @@ void VLayoutDetail::Translate(qreal dx, qreal dy)
//---------------------------------------------------------------------------------------------------------------------
void VLayoutDetail::Rotate(const QPointF &originPoint, qreal degrees)
{
QMatrix m;
QTransform m;
m.translate(originPoint.x(), originPoint.y());
m.rotate(-degrees);
m.translate(-originPoint.x(), -originPoint.y());
@ -156,7 +156,7 @@ void VLayoutDetail::Mirror(const QLineF &edge)
const QLineF axis = QLineF(edge.x2(), edge.y2(), edge.x2() + 100, edge.y2()); // Ox axis
const qreal angle = edge.angleTo(axis);
QMatrix m;
QTransform m;
m.translate(edge.p2().x(), edge.p2().y());
m.rotate(-angle);
m.translate(-edge.p2().x(), -edge.p2().y());
@ -173,6 +173,8 @@ void VLayoutDetail::Mirror(const QLineF &edge)
m.rotate(-(360-angle));
m.translate(-edge.p2().x(), -edge.p2().y());
d->matrix *= m;
d->mirror = !d->mirror;
}
//---------------------------------------------------------------------------------------------------------------------
@ -337,7 +339,7 @@ QVector<QPointF> VLayoutDetail::Map(const QVector<QPointF> &points) const
p.append(d->matrix.map(points.at(i)));
}
if (d->matrix.m22() < 0)
if (d->mirror)
{
QList<QPointF> list = p.toList();
for(int k=0, s=list.size(), max=(s/2); k<max; k++)
@ -405,3 +407,15 @@ QGraphicsItem *VLayoutDetail::GetItem() const
item->setPath(ContourPath());
return item;
}
//---------------------------------------------------------------------------------------------------------------------
bool VLayoutDetail::IsMirror() const
{
return d->mirror;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutDetail::SetMirror(bool value)
{
d->mirror = value;
}

View File

@ -54,12 +54,15 @@ public:
QVector<QPointF> GetLayoutAllowencePoints() const;
void SetLayoutAllowencePoints();
QMatrix GetMatrix() const;
void SetMatrix(const QMatrix &matrix);
QTransform GetMatrix() const;
void SetMatrix(const QTransform &matrix);
qreal GetLayoutWidth() const;
void SetLayoutWidth(const qreal &value);
bool IsMirror() const;
void SetMirror(bool value);
void Translate(qreal dx, qreal dy);
void Rotate(const QPointF &originPoint, qreal degrees);
void Mirror(const QLineF &edge);

View File

@ -32,7 +32,7 @@
#include <QSharedData>
#include <QPointF>
#include <QVector>
#include <QMatrix>
#include <QTransform>
#ifdef Q_CC_GNU
#pragma GCC diagnostic push
@ -44,12 +44,12 @@ class VLayoutDetailData : public QSharedData
public:
VLayoutDetailData()
:contour(QVector<QPointF>()), seamAllowence(QVector<QPointF>()), layoutAllowence(QVector<QPointF>()),
matrix(QMatrix()), layoutWidth(0)
matrix(QMatrix()), layoutWidth(0), mirror(false)
{}
VLayoutDetailData(const VLayoutDetailData &detail)
:QSharedData(detail), contour(detail.contour), seamAllowence(detail.seamAllowence),
layoutAllowence(detail.layoutAllowence), matrix(detail.matrix), layoutWidth(detail.layoutWidth)
layoutAllowence(detail.layoutAllowence), matrix(detail.matrix), layoutWidth(detail.layoutWidth), mirror(false)
{}
~VLayoutDetailData() {}
@ -64,10 +64,12 @@ public:
QVector<QPointF> layoutAllowence;
/** @brief matrix transformation matrix*/
QMatrix matrix;
QTransform matrix;
/** @brief layoutWidth value layout allowence width in pixels. */
qreal layoutWidth;
bool mirror;
};
#ifdef Q_CC_GNU

View File

@ -43,31 +43,33 @@ class BestResult
public:
BestResult();
void NewResult(qint64 square, int i, int j, const QMatrix &matrix);
void NewResult(qint64 square, int i, int j, const QTransform &matrix, bool mirror);
qint64 BestSquare() const;
int GContourEdge() const;
int DetailEdge() const;
QMatrix Matrix() const;
QTransform Matrix() const;
bool ValideResult() const;
bool Mirror() const;
private:
// All nedded information about best result
int resI; // Edge of global contour
int resJ; // Edge of detail
QMatrix resMatrix; // Matrix for rotation and translation detail
QTransform resMatrix; // Matrix for rotation and translation detail
qint64 resSquare; // Best square size (least). For begin set max value.
bool valideResult;
bool resMirror;
};
//===================================================BestResult========================================================
//---------------------------------------------------------------------------------------------------------------------
BestResult::BestResult()
:resI(0), resJ(0), resMatrix(QMatrix()), resSquare(LLONG_MAX),valideResult(false)
:resI(0), resJ(0), resMatrix(QMatrix()), resSquare(LLONG_MAX), valideResult(false), resMirror(false)
{}
//---------------------------------------------------------------------------------------------------------------------
void BestResult::NewResult(qint64 square, int i, int j, const QMatrix &matrix)
void BestResult::NewResult(qint64 square, int i, int j, const QTransform &matrix, bool mirror)
{
if (square <= resSquare && square > 0)
{
@ -76,6 +78,7 @@ void BestResult::NewResult(qint64 square, int i, int j, const QMatrix &matrix)
resMatrix = matrix;
resSquare = square;
valideResult = true;
resMirror = mirror;
}
}
@ -98,7 +101,7 @@ int BestResult::DetailEdge() const
}
//---------------------------------------------------------------------------------------------------------------------
QMatrix BestResult::Matrix() const
QTransform BestResult::Matrix() const
{
return resMatrix;
}
@ -109,6 +112,12 @@ bool BestResult::ValideResult() const
return valideResult;
}
//---------------------------------------------------------------------------------------------------------------------
bool BestResult::Mirror() const
{
return resMirror;
}
//===================================================VLayoutPaper======================================================
//---------------------------------------------------------------------------------------------------------------------
VLayoutPaper::VLayoutPaper()
@ -255,12 +264,12 @@ bool VLayoutPaper::AddToBlankSheet(const VLayoutDetail &detail, bool &stop)
if (SheetContains(rec))
{
bestResult.NewResult(static_cast<qint64>(rec.width()*rec.height()), j, dEdge,
workDetail.GetMatrix());
workDetail.GetMatrix(), workDetail.IsMirror());
}
}
d->frame = d->frame + 2;
for (int angle = 0; angle <= 360; angle = angle+5)
for (int angle = 0; angle <= 360; angle = angle+20)
{
QCoreApplication::processEvents();
@ -278,7 +287,7 @@ bool VLayoutPaper::AddToBlankSheet(const VLayoutDetail &detail, bool &stop)
if (SheetContains(rec))
{
bestResult.NewResult(static_cast<qint64>(rec.width()*rec.height()), j, i,
workDetail.GetMatrix());
workDetail.GetMatrix(), workDetail.IsMirror());
}
}
++d->frame;
@ -317,7 +326,7 @@ bool VLayoutPaper::AddToSheet(const VLayoutDetail &detail, bool &stop)
newGContour.append(newGContour.first());
const QRectF rec = QPolygonF(newGContour).boundingRect();
bestResult.NewResult(static_cast<qint64>(rec.width()*rec.height()), j, dEdge,
workDetail.GetMatrix());
workDetail.GetMatrix(), workDetail.IsMirror());
}
}
d->frame = d->frame + 2;
@ -337,7 +346,9 @@ bool VLayoutPaper::CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge) c
CombineEdges(detail, globalEdge, dEdge);
#ifdef LAYOUT_DEBUG
# ifdef SHOW_COMBINE
DrawDebug(detail, d->frame);
# endif
#endif
switch (Crossing(detail, j, dEdge))
@ -372,8 +383,10 @@ bool VLayoutPaper::CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge) c
if (flagMirror)
{
#ifdef LAYOUT_DEBUG
#ifdef SHOW_MIRROR
DrawDebug(detail, d->frame+1);
#endif
#endif
dEdge = detail.EdgeByPoint(globalEdge.p2());
if (dEdge <= 0)
@ -455,7 +468,8 @@ bool VLayoutPaper::CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, i
}
//---------------------------------------------------------------------------------------------------------------------
VLayoutPaper::CrossingType VLayoutPaper::Crossing(const VLayoutDetail &detail, int globalI, int detailI) const
VLayoutPaper::CrossingType VLayoutPaper::Crossing(const VLayoutDetail &detail, const int &globalI,
const int &detailI) const
{
int globalEdgesCount = EdgesCount();
if (globalEdgesCount == 0)
@ -507,7 +521,7 @@ VLayoutPaper::CrossingType VLayoutPaper::Crossing(const VLayoutDetail &detail, i
}
//---------------------------------------------------------------------------------------------------------------------
VLayoutPaper::InsideType VLayoutPaper::InsideContour(const VLayoutDetail &detail, int detailI) const
VLayoutPaper::InsideType VLayoutPaper::InsideContour(const VLayoutDetail &detail, const int &detailI) const
{
if (detail.EdgesCount() < 3)
{
@ -535,10 +549,35 @@ VLayoutPaper::InsideType VLayoutPaper::InsideContour(const VLayoutDetail &detail
}
else
{
const QPolygonF gPoly = GlobalPolygon();
for(int i = 0; i < lPoints.count(); i++)
const int polyCorners = EdgesCount();
int j = polyCorners-1;
QVector<qreal> constant;
QVector<qreal> multiple;
for(int i=0; i<polyCorners; i++)
{
const QPointF p = lPoints.at(i);
const qreal xi = d->globalContour.at(i).x();
const qreal xj = d->globalContour.at(j).x();
const qreal yi = d->globalContour.at(i).y();
const qreal yj = d->globalContour.at(j).y();
if(qFuzzyCompare(yj, yi))
{
constant.insert(i, xi);
multiple.insert(i, 0);
}
else
{
constant.insert(i, xi - (yi*xj)/(yj-yi) + (yi*xi)/(yj-yi));
multiple.insert(i, (xj-xi)/(yj-yi));
}
j=i;
}
for(int k = 0; k < lPoints.count(); k++)
{
const QPointF p = lPoints.at(k);
if (p.isNull())
{
return InsideType::EdgeError;
@ -546,7 +585,23 @@ VLayoutPaper::InsideType VLayoutPaper::InsideContour(const VLayoutDetail &detail
if (p != detailEdge.p1() && p != detailEdge.p2())
{
if (gPoly.containsPoint(p, Qt::OddEvenFill))
int j = polyCorners-1;
bool oddNodes = false;
for (int i=0; i<polyCorners; i++)
{
const qreal yi = d->globalContour.at(i).y();
const qreal yj = d->globalContour.at(j).y();
if (((yi < p.y() && yj >= p.y()) || (yj < p.y() && yi >= p.y())))
{
oddNodes ^= (p.y() * multiple.at(i) + constant.at(i) < p.x());
}
j=i;
}
if (oddNodes)
{
return InsideType::Inside;
}
@ -570,7 +625,7 @@ bool VLayoutPaper::SheetContains(const QRectF &rect) const
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutPaper::CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge) const
void VLayoutPaper::CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, const int &dEdge) const
{
QLineF detailEdge = detail.Edge(dEdge);
@ -813,6 +868,7 @@ bool VLayoutPaper::SaveResult(const BestResult &bestResult, const VLayoutDetail
{
VLayoutDetail workDetail = detail;
workDetail.SetMatrix(bestResult.Matrix());// Don't forget set matrix
workDetail.SetMirror(bestResult.Mirror());
const QVector<QPointF> newGContour = UniteWithContour(workDetail, bestResult.GContourEdge(),
bestResult.DetailEdge());
if (newGContour.isEmpty())
@ -821,6 +877,12 @@ bool VLayoutPaper::SaveResult(const BestResult &bestResult, const VLayoutDetail
}
d->details.append(workDetail);
d->globalContour = newGContour;
#ifdef LAYOUT_DEBUG
# ifdef SHOW_BEST
DrawDebug(workDetail, UINT_MAX);
# endif
#endif
}
return bestResult.ValideResult(); // Do we have the best result?
@ -852,10 +914,12 @@ void VLayoutPaper::DrawDebug(const VLayoutDetail &detail, int frame) const
paint.drawPath(p);
}
#ifdef SHOW_CANDIDATE
paint.setPen(QPen(Qt::darkGreen, 3, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
p = DrawContour(detail.GetLayoutAllowencePoints());
p.translate(d->paperWidth/2, d->paperHeight/2);
paint.drawPath(p);
#endif
#ifdef ARRANGED_DETAILS
paint.setPen(QPen(Qt::blue, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));

View File

@ -90,12 +90,12 @@ private:
bool CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge) const;
bool CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, int angle) const;
CrossingType Crossing(const VLayoutDetail &detail, int globalI, int detailI) const;
InsideType InsideContour(const VLayoutDetail &detail, int detailI) const;
CrossingType Crossing(const VLayoutDetail &detail, const int &globalI, const int &detailI) const;
InsideType InsideContour(const VLayoutDetail &detail, const int &detailI) const;
qreal CheckSide(const QLineF &edge, const QPointF &p) const;
bool SheetContains(const QRectF &rect) const;
void CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge) const;
void CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, const int &dEdge) const;
void RotateEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge, int angle) const;
QVector<QPointF> UniteWithContour(const VLayoutDetail &detail, int globalI, int detJ) const;