Breaking change. All intersections are now treaded as a loop.
--HG-- branch : develop
This commit is contained in:
parent
c2d194c23f
commit
bcea1b69fa
|
@ -27,6 +27,7 @@
|
|||
- New feature "Hide piece's main path".
|
||||
- Allow controlling priority selecting pieces in layout.
|
||||
- No scissors on tiled PDF bottom row.
|
||||
- All intersections are now treaded as a loop.
|
||||
|
||||
# Version 0.6.2 (unreleased)
|
||||
- [#903] Bug in tool Cut Spline path.
|
||||
|
|
57
src/app/share/collection/bugs/loop_by_intersection.val
Normal file
57
src/app/share/collection/bugs/loop_by_intersection.val
Normal 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>
|
|
@ -52,136 +52,13 @@ const qreal VSAPoint::maxPassmarkLength = (10/*mm*/ / 25.4) * PrintDPI;
|
|||
|
||||
namespace
|
||||
{
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Do we create a point outside of a path?
|
||||
inline bool IsOutsidePoint(QPointF p1, QPointF p2, QPointF px)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -335,7 +212,11 @@ QVector<QPointF> AngleByIntersection(const QVector<QPointF> &points, QPointF p1,
|
|||
else
|
||||
{
|
||||
QLineF allowance(p2, px);
|
||||
//allowance.setLength(allowance.length()-accuracyPointOnLine*2.);
|
||||
//allowance.setAngle(allowance.angle()-0.1); // avoid optimization
|
||||
pointsIntr.append(allowance.p2());
|
||||
|
||||
//allowance = QLineF(p2, px);
|
||||
allowance.setLength(allowance.length() + localWidth * 3.);
|
||||
pointsIntr.append(allowance.p2());
|
||||
pointsIntr.append(bigLine2.p2());
|
||||
|
@ -652,7 +533,7 @@ qreal AngleBetweenBisectors(const QLineF &b1, const QLineF &b2)
|
|||
#if !defined(V_NO_ASSERT)
|
||||
// Use for writing tests
|
||||
void DumpVector(const QVector<QPointF> &points)
|
||||
{
|
||||
{
|
||||
QTemporaryFile temp; // Go to tmp folder to find dump
|
||||
temp.setAutoRemove(false); // Remove dump manually
|
||||
if (temp.open())
|
||||
|
@ -1031,6 +912,11 @@ QVector<QPointF> VAbstractPiece::Equidistant(QVector<VSAPoint> points, qreal wid
|
|||
break;
|
||||
case PieceNodeAngle::ByPointsIntersection:
|
||||
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;
|
||||
case PieceNodeAngle::BySecondEdgeRightAngle:
|
||||
if (not ekvPoints.isEmpty())
|
||||
|
@ -1097,7 +983,6 @@ QVector<QPointF> VAbstractPiece::Equidistant(QVector<VSAPoint> points, qreal wid
|
|||
|
||||
const bool removeFirstAndLast = false;
|
||||
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
|
||||
return ekvPoints;
|
||||
}
|
||||
|
@ -1146,6 +1031,8 @@ qreal VAbstractPiece::SumTrapezoids(const QVector<QPointF> &points)
|
|||
*/
|
||||
QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
|
||||
{
|
||||
// DumpVector(points); // Uncomment for dumping test data
|
||||
|
||||
int count = points.size();
|
||||
/*If we got less than 4 points no need seek loops.*/
|
||||
if (count < 4)
|
||||
|
@ -1164,8 +1051,8 @@ QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
|
|||
qint32 i, j, jNext = 0;
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
/*Last three points no need check.*/
|
||||
/*Triangle has not contain loops*/
|
||||
/*Last three points no need to check.*/
|
||||
/*Triangle can not contain a loop*/
|
||||
if (i > count-3)
|
||||
{
|
||||
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.
|
||||
pathClosed && jNext == count-1 ? AddUniqueIndex(0) : AddUniqueIndex(jNext);
|
||||
|
||||
const QLineF::IntersectType intersect = line1.intersect(line2, &crosPoint);
|
||||
if (intersect == QLineF::NoIntersection)
|
||||
{ // According to the documentation QLineF::NoIntersection indicates that the lines do not intersect;
|
||||
// i.e. they are parallel. But parallel also mean they can be on the same line.
|
||||
// Method IsPointOnLineviaPDP will check it.
|
||||
if (VGObject::IsPointOnLineviaPDP(points.at(j), points.at(i), points.at(i+1))
|
||||
// Lines are not neighbors
|
||||
&& uniqueVertices.size() == 4)
|
||||
{
|
||||
// Left to catch case where segments are on the same line, but do not have real intersections.
|
||||
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;
|
||||
if (uniqueVertices.size() == 4)
|
||||
{// Lines are not neighbors
|
||||
const QLineF::IntersectType intersect = line1.intersect(line2, &crosPoint);
|
||||
if (intersect == QLineF::NoIntersection)
|
||||
{ // According to the documentation QLineF::NoIntersection indicates that the lines do not intersect;
|
||||
// i.e. they are parallel. But parallel also mean they can be on the same line.
|
||||
// Method IsLineSegmentOnLineSegment will check it.
|
||||
if (VGObject::IsLineSegmentOnLineSegment(line1, line2))
|
||||
{// Now we really sure that segments are on the same line and have real intersections.
|
||||
status = ParallelIntersection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (intersect == QLineF::BoundedIntersection)
|
||||
{
|
||||
status = BoundedIntersection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
status = NoIntersection;
|
||||
}
|
||||
|
@ -1278,7 +1135,8 @@ QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// DumpVector(ekvPoints); // Uncomment for dumping test data
|
||||
return ekvPoints;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -168,6 +168,9 @@ private:
|
|||
QVector<VSAPoint> InputPointsIssue923Test6_6();
|
||||
QVector<QPointF> OutputPointsIssue923Test6_6();
|
||||
|
||||
QVector<VSAPoint> InputLoopByIntersectionTest();
|
||||
QVector<QPointF> OutputLoopByIntersectionTest();
|
||||
|
||||
QVector<VSAPoint> InputPointsIssue937Case1() const;
|
||||
QVector<QPointF> OutputPointsIssue937Case1() const;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user