Breaking change. All intersections are now treaded as a loop.

--HG--
branch : develop
This commit is contained in:
Roman Telezhynskyi 2019-08-07 12:25:22 +03:00
parent c2d194c23f
commit bcea1b69fa
5 changed files with 710 additions and 768 deletions

View File

@ -27,6 +27,7 @@
- New feature "Hide piece's main path". - New feature "Hide piece's main path".
- Allow controlling priority selecting pieces in layout. - Allow controlling priority selecting pieces in layout.
- No scissors on tiled PDF bottom row. - No scissors on tiled PDF bottom row.
- All intersections are now treaded as a loop.
# Version 0.6.2 (unreleased) # Version 0.6.2 (unreleased)
- [#903] Bug in tool Cut Spline path. - [#903] Bug in tool Cut Spline path.

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<pattern labelPrefix="en">
<!--Pattern created with Valentina v0.7.0.0a (https://valentinaproject.bitbucket.io/).-->
<version>0.8.5</version>
<unit>cm</unit>
<description/>
<notes/>
<measurements/>
<increments/>
<previewCalculations/>
<draw name="Pattern piece 1">
<calculation>
<point id="1" mx="0.132292" my="0.264583" name="A" showLabel="true" type="single" x="0.79375" y="1.05833"/>
<point angle="0" basePoint="1" id="2" length="6" lineColor="black" mx="0.132292" my="0.264583" name="A1" showLabel="true" type="endLine" typeLine="hair"/>
<point angle="180" basePoint="1" id="3" length="6" lineColor="black" mx="0.132292" my="0.264583" name="A2" showLabel="true" type="endLine" typeLine="hair"/>
<point angle="90" basePoint="1" id="4" length="3.7" lineColor="black" mx="0.132292" my="0.264583" name="A3" showLabel="true" type="endLine" typeLine="hair"/>
<spline aScale="0" angle1="75.4653" angle2="180.572" color="black" id="5" length1="3.44539" length2="2.79047" penStyle="hair" point1="3" point4="4" type="simpleInteractive"/>
<spline aScale="0" angle1="0.535754" angle2="113.25" color="black" id="6" length1="3.24281" length2="2.80818" penStyle="hair" point1="4" point4="2" type="simpleInteractive"/>
<operation id="7" p1Line="3" p2Line="2" suffix="a1" type="flippingByLine">
<source>
<item idObject="5"/>
<item idObject="6"/>
</source>
<destination>
<item idObject="8"/>
<item idObject="9"/>
</destination>
</operation>
</calculation>
<modeling>
<point id="10" idObject="3" inUse="false" mx="0.132292" my="0.264583" showLabel="true" type="modeling"/>
<spline id="11" idObject="5" inUse="false" type="modelingSpline"/>
<point id="12" idObject="4" inUse="false" mx="0.132292" my="0.264583" showLabel="true" type="modeling"/>
<spline id="13" idObject="6" inUse="false" type="modelingSpline"/>
<point id="14" idObject="2" inUse="false" mx="0.132292" my="0.264583" showLabel="true" type="modeling"/>
<spline id="15" idObject="9" inUse="false" type="modelingSpline"/>
<spline id="16" idObject="8" inUse="false" type="modelingSpline"/>
</modeling>
<details>
<detail forbidFlipping="false" forceFlipping="false" hideMainPath="false" id="17" mx="0" my="0" name="Detail" seamAllowance="true" version="2" width="1.05">
<data annotation="" foldPosition="" fontSize="0" height="1" letter="" mx="0" my="0" onFold="false" orientation="" quantity="1" rotation="0" rotationWay="" tilt="" visible="false" width="1"/>
<patternInfo fontSize="0" height="1" mx="0" my="0" rotation="0" visible="false" width="1"/>
<grainline arrows="0" length="1" mx="0" my="0" rotation="90" visible="false"/>
<nodes>
<node angle="1" idObject="10" type="NodePoint"/>
<node idObject="11" reverse="0" type="NodeSpline"/>
<node idObject="12" type="NodePoint"/>
<node idObject="13" reverse="0" type="NodeSpline"/>
<node angle="1" idObject="14" type="NodePoint"/>
<node idObject="15" reverse="1" type="NodeSpline"/>
<node idObject="16" reverse="1" type="NodeSpline"/>
</nodes>
</detail>
</details>
<groups/>
</draw>
</pattern>

View File

@ -52,136 +52,13 @@ const qreal VSAPoint::maxPassmarkLength = (10/*mm*/ / 25.4) * PrintDPI;
namespace namespace
{ {
//---------------------------------------------------------------------------------------------------------------------
// Do we create a point outside of a path? // Do we create a point outside of a path?
inline bool IsOutsidePoint(QPointF p1, QPointF p2, QPointF px) inline bool IsOutsidePoint(QPointF p1, QPointF p2, QPointF px)
{ {
return qAbs(QLineF(p1, p2).angle() - QLineF(p1, px).angle()) < 0.001; return qAbs(QLineF(p1, p2).angle() - QLineF(p1, px).angle()) < 0.001;
} }
//---------------------------------------------------------------------------------------------------------------------
QVector<QPointF> SubPath(const QVector<QPointF> &path, int startIndex, int endIndex)
{
if (path.isEmpty()
|| startIndex < 0 || startIndex >= path.size()
|| endIndex < 0 || endIndex >= path.size()
|| startIndex == endIndex)
{
return path;
}
QVector<QPointF> subPath;
int i = startIndex - 1;
do
{
++i;
if (i >= path.size())
{
i = 0;
}
subPath.append(path.at(i));
} while (i != endIndex);
return subPath;
}
//---------------------------------------------------------------------------------------------------------------------
bool Crossing(const QVector<QPointF> &sub1, const QVector<QPointF> &sub2)
{
if (sub1.isEmpty() || sub2.isEmpty())
{
return false;
}
const QRectF sub1Rect = QPolygonF(sub1).boundingRect();
const QRectF sub2Rect = QPolygonF(sub2).boundingRect();
if (not sub1Rect.intersects(sub2Rect))
{
return false;
}
QPainterPath sub1Path;
sub1Path.setFillRule(Qt::WindingFill);
sub1Path.moveTo(sub1.at(0));
for (qint32 i = 1; i < sub1.count(); ++i)
{
sub1Path.lineTo(sub1.at(i));
}
sub1Path.lineTo(sub1.at(0));
QPainterPath sub2Path;
sub2Path.setFillRule(Qt::WindingFill);
sub2Path.moveTo(sub2.at(0));
for (qint32 i = 1; i < sub2.count(); ++i)
{
sub2Path.lineTo(sub2.at(i));
}
sub2Path.lineTo(sub2.at(0));
if (not sub1Path.intersects(sub2Path))
{
return false;
}
else
{
return true;
}
}
//---------------------------------------------------------------------------------------------------------------------
bool CheckIntersection(const QVector<QPointF> &points, int i, int iNext, int j, int jNext, const QPointF &crossPoint)
{
QVector<QPointF> sub1 = SubPath(points, iNext, j);
sub1.append(crossPoint);
sub1 = VAbstractPiece::CorrectEquidistantPoints(sub1, false);
const qreal sub1Sum = VAbstractPiece::SumTrapezoids(sub1);
QVector<QPointF> sub2 = SubPath(points, jNext, i);
sub2.append(crossPoint);
sub2 = VAbstractPiece::CorrectEquidistantPoints(sub2, false);
const qreal sub2Sum = VAbstractPiece::SumTrapezoids(sub2);
if (sub1Sum < 0 && sub2Sum < 0)
{
if (Crossing(sub1, sub2))
{
return true;
}
}
else
{
if (not Crossing(sub1, sub2))
{
return true;
}
}
return false;
}
//---------------------------------------------------------------------------------------------------------------------
bool ParallelCrossPoint(const QLineF &line1, const QLineF &line2, QPointF &point)
{
const bool l1p1el2p1 = (line1.p1() == line2.p1());
const bool l1p2el2p2 = (line1.p2() == line2.p2());
const bool l1p1el2p2 = (line1.p1() == line2.p2());
const bool l1p2el2p1 = (line1.p2() == line2.p1());
if (l1p2el2p2 || l1p2el2p1)
{
point = line1.p2();
return true;
}
else if (l1p1el2p1 || l1p1el2p2)
{
point = line1.p1();
return true;
}
else
{
point = QPointF();
return false;
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
Q_DECL_CONSTEXPR qreal PointPosition(const QPointF &p, const QLineF &line) Q_DECL_CONSTEXPR qreal PointPosition(const QPointF &p, const QLineF &line)
{ {
@ -335,7 +212,11 @@ QVector<QPointF> AngleByIntersection(const QVector<QPointF> &points, QPointF p1,
else else
{ {
QLineF allowance(p2, px); QLineF allowance(p2, px);
//allowance.setLength(allowance.length()-accuracyPointOnLine*2.);
//allowance.setAngle(allowance.angle()-0.1); // avoid optimization
pointsIntr.append(allowance.p2()); pointsIntr.append(allowance.p2());
//allowance = QLineF(p2, px);
allowance.setLength(allowance.length() + localWidth * 3.); allowance.setLength(allowance.length() + localWidth * 3.);
pointsIntr.append(allowance.p2()); pointsIntr.append(allowance.p2());
pointsIntr.append(bigLine2.p2()); pointsIntr.append(bigLine2.p2());
@ -652,7 +533,7 @@ qreal AngleBetweenBisectors(const QLineF &b1, const QLineF &b2)
#if !defined(V_NO_ASSERT) #if !defined(V_NO_ASSERT)
// Use for writing tests // Use for writing tests
void DumpVector(const QVector<QPointF> &points) void DumpVector(const QVector<QPointF> &points)
{ {
QTemporaryFile temp; // Go to tmp folder to find dump QTemporaryFile temp; // Go to tmp folder to find dump
temp.setAutoRemove(false); // Remove dump manually temp.setAutoRemove(false); // Remove dump manually
if (temp.open()) if (temp.open())
@ -1031,6 +912,11 @@ QVector<QPointF> VAbstractPiece::Equidistant(QVector<VSAPoint> points, qreal wid
break; break;
case PieceNodeAngle::ByPointsIntersection: case PieceNodeAngle::ByPointsIntersection:
Rollback(QLineF(points.last(), points.at(1))); Rollback(QLineF(points.last(), points.at(1)));
if (ekvPoints.size() > 2)
{ // Fix for the rule of main path
ekvPoints.removeAt(ekvPoints.size()-1);
ekvPoints.prepend(ekvPoints.at(ekvPoints.size()-1));
}
break; break;
case PieceNodeAngle::BySecondEdgeRightAngle: case PieceNodeAngle::BySecondEdgeRightAngle:
if (not ekvPoints.isEmpty()) if (not ekvPoints.isEmpty())
@ -1097,7 +983,6 @@ QVector<QPointF> VAbstractPiece::Equidistant(QVector<VSAPoint> points, qreal wid
const bool removeFirstAndLast = false; const bool removeFirstAndLast = false;
ekvPoints = CheckLoops(CorrectEquidistantPoints(ekvPoints, removeFirstAndLast));//Result path can contain loops ekvPoints = CheckLoops(CorrectEquidistantPoints(ekvPoints, removeFirstAndLast));//Result path can contain loops
ekvPoints = CheckLoops(CorrectEquidistantPoints(ekvPoints, removeFirstAndLast));//Result path can contain loops
// DumpVector(ekvPoints); // Uncomment for dumping test data // DumpVector(ekvPoints); // Uncomment for dumping test data
return ekvPoints; return ekvPoints;
} }
@ -1146,6 +1031,8 @@ qreal VAbstractPiece::SumTrapezoids(const QVector<QPointF> &points)
*/ */
QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points) QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
{ {
// DumpVector(points); // Uncomment for dumping test data
int count = points.size(); int count = points.size();
/*If we got less than 4 points no need seek loops.*/ /*If we got less than 4 points no need seek loops.*/
if (count < 4) if (count < 4)
@ -1164,8 +1051,8 @@ QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
qint32 i, j, jNext = 0; qint32 i, j, jNext = 0;
for (i = 0; i < count; ++i) for (i = 0; i < count; ++i)
{ {
/*Last three points no need check.*/ /*Last three points no need to check.*/
/*Triangle has not contain loops*/ /*Triangle can not contain a loop*/
if (i > count-3) if (i > count-3)
{ {
ekvPoints.append(points.at(i)); ekvPoints.append(points.at(i));
@ -1206,54 +1093,24 @@ QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
// For closed path last point is equal to first. Using index of the first. // For closed path last point is equal to first. Using index of the first.
pathClosed && jNext == count-1 ? AddUniqueIndex(0) : AddUniqueIndex(jNext); pathClosed && jNext == count-1 ? AddUniqueIndex(0) : AddUniqueIndex(jNext);
const QLineF::IntersectType intersect = line1.intersect(line2, &crosPoint); if (uniqueVertices.size() == 4)
if (intersect == QLineF::NoIntersection) {// Lines are not neighbors
{ // According to the documentation QLineF::NoIntersection indicates that the lines do not intersect; const QLineF::IntersectType intersect = line1.intersect(line2, &crosPoint);
// i.e. they are parallel. But parallel also mean they can be on the same line. if (intersect == QLineF::NoIntersection)
// Method IsPointOnLineviaPDP will check it. { // According to the documentation QLineF::NoIntersection indicates that the lines do not intersect;
if (VGObject::IsPointOnLineviaPDP(points.at(j), points.at(i), points.at(i+1)) // i.e. they are parallel. But parallel also mean they can be on the same line.
// Lines are not neighbors // Method IsLineSegmentOnLineSegment will check it.
&& uniqueVertices.size() == 4) if (VGObject::IsLineSegmentOnLineSegment(line1, line2))
{ {// Now we really sure that segments are on the same line and have real intersections.
// Left to catch case where segments are on the same line, but do not have real intersections. status = ParallelIntersection;
QLineF tmpLine1 = line1;
QLineF tmpLine2 = line2;
tmpLine1.setAngle(tmpLine1.angle()+90);
QPointF tmpCrosPoint;
const QLineF::IntersectType tmpIntrs1 = tmpLine1.intersect(tmpLine2, &tmpCrosPoint);
tmpLine1 = line1;
tmpLine2.setAngle(tmpLine2.angle()+90);
const QLineF::IntersectType tmpIntrs2 = tmpLine1.intersect(tmpLine2, &tmpCrosPoint);
if (tmpIntrs1 == QLineF::BoundedIntersection || tmpIntrs2 == QLineF::BoundedIntersection)
{ // Now we really sure that lines are on the same lines and have real intersections.
QPointF cPoint;
const bool caseFlag = ParallelCrossPoint(line1, line2, cPoint);
if (not caseFlag || CheckIntersection(points, i, i+1, j, jNext, cPoint))
{
status = ParallelIntersection;
break;
}
}
}
}
else if (intersect == QLineF::BoundedIntersection)
{
if (uniqueVertices.size() == 4)
{ // Break, but not if lines are neighbors
if ((line1.p1() != crosPoint
&& line1.p2() != crosPoint
&& line2.p1() != crosPoint
&& line2.p2() != crosPoint) || CheckIntersection(points, i, i+1, j, jNext, crosPoint))
{
status = BoundedIntersection;
break; break;
} }
} }
else if (intersect == QLineF::BoundedIntersection)
{
status = BoundedIntersection;
break;
}
} }
status = NoIntersection; status = NoIntersection;
} }
@ -1278,7 +1135,8 @@ QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
default: default:
break; break;
} }
} }
// DumpVector(ekvPoints); // Uncomment for dumping test data
return ekvPoints; return ekvPoints;
} }

File diff suppressed because it is too large Load Diff

View File

@ -168,6 +168,9 @@ private:
QVector<VSAPoint> InputPointsIssue923Test6_6(); QVector<VSAPoint> InputPointsIssue923Test6_6();
QVector<QPointF> OutputPointsIssue923Test6_6(); QVector<QPointF> OutputPointsIssue923Test6_6();
QVector<VSAPoint> InputLoopByIntersectionTest();
QVector<QPointF> OutputLoopByIntersectionTest();
QVector<VSAPoint> InputPointsIssue937Case1() const; QVector<VSAPoint> InputPointsIssue937Case1() const;
QVector<QPointF> OutputPointsIssue937Case1() const; QVector<QPointF> OutputPointsIssue937Case1() const;