Issue #123: Clipping lines

This commit is contained in:
Jakub Melka 2024-02-24 17:56:22 +01:00
parent 6a477bdf04
commit 2e38e41ce9
1 changed files with 134 additions and 2 deletions

View File

@ -104,6 +104,8 @@ private:
NeedsResolve
};
ClipMode resolveClipping(const QLineF& line) const;
ClipMode resolveClipping(const QPointF& point) const;
ClipMode resolveClipping(const QRectF& rect) const;
ClipMode resolveClipping(const QPainterPath& path) const;
@ -430,6 +432,42 @@ void PDFBLPaintEngine::drawLines(const QLine* lines, int lineCount)
for (int i = 0; i < lineCount; ++i)
{
const QLine& line = lines[i];
ClipMode clipMode = resolveClipping(m_currentTransform.map(line));
switch (clipMode)
{
case ClipMode::NoClip:
// Do as normal
break;
case ClipMode::NotVisible:
// Graphics is not visible
return;
case ClipMode::NeedsResolve:
{
QLineF lineF = line.toLineF();
if (m_finalClipPath->isEmpty() || qFuzzyIsNull(lineF.length()))
{
return;
}
QLineF normalVectorLine = lineF.normalVector().unitVector();
QPointF normalVector = normalVectorLine.p2() - normalVectorLine.p1();
qreal widthF = m_currentPen.widthF() * 0.5;
QPainterPath path;
path.moveTo(lineF.p1() + normalVector * widthF);
path.lineTo(lineF.p2() + normalVector * widthF);
path.lineTo(lineF.p2() - normalVector * widthF);
path.lineTo(lineF.p1() - normalVector * widthF);
path.closeSubpath();
drawPathImpl(path, true, false);
return;
}
}
m_blContext->strokeLine(line.x1(), line.y1(), line.x2(), line.y2());
}
}
@ -444,6 +482,41 @@ void PDFBLPaintEngine::drawLines(const QLineF* lines, int lineCount)
for (int i = 0; i < lineCount; ++i)
{
const QLineF& line = lines[i];
ClipMode clipMode = resolveClipping(m_currentTransform.map(line));
switch (clipMode)
{
case ClipMode::NoClip:
// Do as normal
break;
case ClipMode::NotVisible:
// Graphics is not visible
return;
case ClipMode::NeedsResolve:
{
if (m_finalClipPath->isEmpty() || qFuzzyIsNull(line.length()))
{
return;
}
QLineF normalVectorLine = line.normalVector().unitVector();
QPointF normalVector = normalVectorLine.p2() - normalVectorLine.p1();
qreal widthF = m_currentPen.widthF() * 0.5;
QPainterPath path;
path.moveTo(line.p1() + normalVector * widthF);
path.lineTo(line.p2() + normalVector * widthF);
path.lineTo(line.p2() - normalVector * widthF);
path.lineTo(line.p1() - normalVector * widthF);
path.closeSubpath();
drawPathImpl(path, true, false);
return;
}
}
m_blContext->strokeLine(line.x1(), line.y1(), line.x2(), line.y2());
}
}
@ -547,6 +620,12 @@ void PDFBLPaintEngine::drawPoints(const QPointF* points, int pointCount)
for (int i = 0; i < pointCount; ++i)
{
const QPointF& c = points[i];
if (resolveClipping(m_currentTransform.map(c)) == ClipMode::NotVisible)
{
continue;
}
BLEllipse blEllipse(c.x(), c.y(), m_currentPen.widthF() * 0.5, m_currentPen.widthF() * 0.5);
m_blContext->fillEllipse(blEllipse);
}
@ -562,6 +641,12 @@ void PDFBLPaintEngine::drawPoints(const QPoint* points, int pointCount)
for (int i = 0; i < pointCount; ++i)
{
const QPointF& c = points[i];
if (resolveClipping(m_currentTransform.map(c)) == ClipMode::NotVisible)
{
continue;
}
BLEllipse blEllipse(c.x(), c.y(), m_currentPen.widthF() * 0.5, m_currentPen.widthF() * 0.5);
m_blContext->fillEllipse(blEllipse);
}
@ -616,8 +701,6 @@ void PDFBLPaintEngine::drawTextItem(const QPointF& p, const QTextItem& textItem)
currentPosition += glyphPositions[i];
}
m_blContext->save();
setFillRule(path.fillRule());
m_blContext->setFillStyle(BLRgba32(m_currentPen.color().rgba()));
@ -1114,6 +1197,55 @@ void PDFBLPaintEngine::updateClipping(std::optional<QRegion> clipRegion,
}
}
PDFBLPaintEngine::ClipMode PDFBLPaintEngine::resolveClipping(const QLineF& line) const
{
if (!m_currentIsClipEnabled || m_clipSingleRect || !m_finalClipPath.has_value())
{
return ClipMode::NoClip;
}
if (m_finalClipPath->isEmpty())
{
return ClipMode::NotVisible;
}
QRectF clipRect = m_finalClipPathBoundingBox;
qreal minX = qMin(line.x1(), line.x2());
qreal maxX = qMax(line.x1(), line.x2());
qreal minY = qMin(line.y1(), line.y2());
qreal maxY = qMax(line.y1(), line.y2());
QRectF rect(minX, minY, maxX - minX + 1.0, maxY - minY + 1.0);
if (!rect.intersects(clipRect))
{
return ClipMode::NotVisible;
}
return ClipMode::NeedsResolve;
}
PDFBLPaintEngine::ClipMode PDFBLPaintEngine::resolveClipping(const QPointF& point) const
{
if (!m_currentIsClipEnabled || m_clipSingleRect || !m_finalClipPath.has_value())
{
return ClipMode::NoClip;
}
if (m_finalClipPath->isEmpty())
{
return ClipMode::NotVisible;
}
if (!m_finalClipPath->contains(point))
{
return ClipMode::NotVisible;
}
return ClipMode::NoClip;
}
PDFBLPaintEngine::ClipMode PDFBLPaintEngine::resolveClipping(const QRectF& rect) const
{
if (!m_currentIsClipEnabled || m_clipSingleRect || !m_finalClipPath.has_value())