diff --git a/benchmarks/data/roundmarker05px.kpp b/benchmarks/data/roundmarker05px.kpp new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ m_startPoints; QVector m_endPoints; + QVector m_rectangleLeftLowerCorners; + QVector m_rectangleRightUpperCorners; + + void initCurvePoints(int width, int height); void initLines(int width, int height); + void initRectangles(int width, int height); QString m_dataPath; QString m_outputPath; @@ -62,6 +67,7 @@ inline void benchmarkStroke(QString presetFileName); inline void benchmarkLine(QString presetFileName); inline void benchmarkCircle(QString presetFileName); + inline void benchmarkRectangle(QString presetFileName); private Q_SLOTS: void initTestCase(); @@ -120,6 +126,15 @@ void colorsmudge(); void colorsmudgeRL(); + + void roundMarker(); + void roundMarkerRandomLines(); + void roundMarkerRectangle(); + + void roundMarkerHalfPixel(); + void roundMarkerRandomLinesHalfPixel(); + void roundMarkerRectangleHalfPixel(); + /* void predefinedBrush(); void predefinedBrushRL(); diff --git a/benchmarks/kis_stroke_benchmark.cpp b/benchmarks/kis_stroke_benchmark.cpp --- a/benchmarks/kis_stroke_benchmark.cpp +++ b/benchmarks/kis_stroke_benchmark.cpp @@ -52,6 +52,7 @@ //#define SAVE_OUTPUT static const int LINES = 20; +static const int RECTANGLES = 20; const QString OUTPUT_FORMAT = ".png"; void KisStrokeBenchmark::initTestCase() @@ -76,6 +77,8 @@ initCurvePoints(width, height); // for the lines test initLines(width,height); + // for the rectangles test + initRectangles(width, height); } void KisStrokeBenchmark::init() @@ -114,6 +117,32 @@ } } +void KisStrokeBenchmark::initRectangles(int width, int height) +{ + qreal margin = 0.5; + qreal skip = 0.01; + + qreal marginWidth = margin*width; + qreal marginHeight = margin*height; + + qreal skipWidth = skip*width >= 1 ? skip*width : 1; + qreal skipHeight = skip*width >= 1 ? skip*width : 1; + + // "concentric" rectangles + + for (int i = 0; i < RECTANGLES; i++){ + QPoint corner1 = QPoint(marginWidth + i*skipWidth, marginHeight + i*skipHeight); + QPoint corner2 = QPoint(width - marginWidth - i*skipWidth, height - marginHeight - i*skipHeight); + + if(corner1.x() < corner2.x() && corner1.y() < corner2.y()) { + // if the rectangle is not empty + m_rectangleLeftLowerCorners.append(corner1); + m_rectangleRightUpperCorners.append(corner2); + } + } +} + + void KisStrokeBenchmark::cleanupTestCase() { @@ -327,6 +356,52 @@ benchmarkStroke(presetFileName); } + +void KisStrokeBenchmark::roundMarker() +{ + // Quick Brush engine ( b) Basic - 1 brush, size 40px) + QString presetFileName = "roundmarker40px.kpp"; + benchmarkStroke(presetFileName); +} + +void KisStrokeBenchmark::roundMarkerRandomLines() +{ + // Quick Brush engine ( b) Basic - 1 brush, size 40px) + QString presetFileName = "roundmarker40px.kpp"; + benchmarkRandomLines(presetFileName); +} + +void KisStrokeBenchmark::roundMarkerRectangle() +{ + // Quick Brush engine ( b) Basic - 1 brush, size 40px) + QString presetFileName = "roundmarker40px.kpp"; + benchmarkStroke(presetFileName); +} + + +void KisStrokeBenchmark::roundMarkerHalfPixel() +{ + // Quick Brush engine ( b) Basic - 1 brush, size 0.5px) + QString presetFileName = "roundmarker05px.kpp"; + benchmarkStroke(presetFileName); +} + +void KisStrokeBenchmark::roundMarkerRandomLinesHalfPixel() +{ + // Quick Brush engine ( b) Basic - 1 brush, size 0.5px) + QString presetFileName = "roundmarker05px.kpp"; + benchmarkRandomLines(presetFileName); +} + +void KisStrokeBenchmark::roundMarkerRectangleHalfPixel() +{ + // Quick Brush engine ( b) Basic - 1 brush, size 0.5px) + QString presetFileName = "roundmarker05px.kpp"; + benchmarkStroke(presetFileName); +} + + + /* void KisStrokeBenchmark::predefinedBrush() { @@ -462,6 +537,37 @@ #endif } + + +void KisStrokeBenchmark::benchmarkRectangle(QString presetFileName) +{ + KisPaintOpPresetSP preset = new KisPaintOpPreset(m_dataPath + presetFileName); + bool loadedOk = preset->load(); + if (!loadedOk){ + dbgKrita << "The preset was not loaded correctly. Done."; + return; + }else{ + dbgKrita << "preset : " << presetFileName; + } + m_painter->setPaintOpPreset(preset, m_layer, m_image); + + int rectangleNumber = m_rectangleLeftLowerCorners.size(); // see initRectangles + + QBENCHMARK{ + KisDistanceInformation currentDistance; + for (int i = 0; i < rectangleNumber; i++){ + QPainterPath path; + QRect rect = QRect(m_rectangleLeftLowerCorners[i], m_rectangleRightUpperCorners[i]); + path.addRect(rect); + m_painter->paintPainterPath(path); + } + } + +#ifdef SAVE_OUTPUT + m_layer->paintDevice()->convertToQImage(0).save(m_outputPath + presetFileName + "_rectangle" + OUTPUT_FORMAT); +#endif +} + void KisStrokeBenchmark::benchmarkStroke(QString presetFileName) { KisPaintOpPresetSP preset = new KisPaintOpPreset(m_dataPath + presetFileName); diff --git a/libs/global/kis_algebra_2d.cpp b/libs/global/kis_algebra_2d.cpp --- a/libs/global/kis_algebra_2d.cpp +++ b/libs/global/kis_algebra_2d.cpp @@ -350,12 +350,13 @@ int numSolutions = 0; const qreal D = pow2(b) - 4 * a * c; + const qreal eps = 1e-14; - if (D < 0) { - return 0; - } else if (qFuzzyCompare(D, 0)) { + if (qAbs(D) <= eps) { *x1 = -b / (2 * a); numSolutions = 1; + } else if (D < 0) { + return 0; } else { const qreal sqrt_D = std::sqrt(D); diff --git a/libs/image/kis_marker_painter.h b/libs/image/kis_marker_painter.h --- a/libs/image/kis_marker_painter.h +++ b/libs/image/kis_marker_painter.h @@ -30,6 +30,10 @@ class KRITAIMAGE_EXPORT KisMarkerPainter { public: + /// Any number bigger than this or lower than -this is considered invalid + static const qint32 ValidNumberRangeValue = 2140000000; // bit less than max value of int + + KisMarkerPainter(KisPaintDeviceSP device, const KoColor &color); ~KisMarkerPainter(); @@ -43,6 +47,22 @@ private: struct Private; const QScopedPointer m_d; + + /// This method is to check whether the number is not infinite + /// or negative infinite with some epsilon + /// (@see ValidNumberRangeValue) + /// @param number value entered by the user + /// @return true if number is in range, false otherwise + bool isNumberInValidRange(qint32 number); + + + /// This method is to check whether the rectangle has only valid numbers + /// as values for x, y, height and width. + /// If values are not valid, Sequential Iterator can give incorrect values. + /// (@see isNumberInValidRange, ValidNumberRangeValue) + /// @param number value entered by the user + /// @return true if rect's values is in range, false otherwise + bool isRectInValidRange(const QRect &rect); }; #endif /* __KIS_MARKER_PAINTER_H */ diff --git a/libs/image/kis_marker_painter.cpp b/libs/image/kis_marker_painter.cpp --- a/libs/image/kis_marker_painter.cpp +++ b/libs/image/kis_marker_painter.cpp @@ -44,6 +44,23 @@ { } + + +bool KisMarkerPainter::isNumberInValidRange(qint32 number) +{ + if (number < -ValidNumberRangeValue || number > ValidNumberRangeValue) + return false; + return true; +} + +bool KisMarkerPainter::isRectInValidRange(const QRect &rect) +{ + return isNumberInValidRange(rect.x()) + && isNumberInValidRange(rect.y()) + && isNumberInValidRange(rect.width()) + && isNumberInValidRange(rect.height()); +} + void KisMarkerPainter::fillHalfBrushDiff(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF ¢er, qreal radius) { @@ -63,7 +80,12 @@ boundRect = KisAlgebra2D::cutOffRect(boundRect, plane1); boundRect = KisAlgebra2D::cutOffRect(boundRect, plane2); - KisSequentialIterator it(m_d->device, boundRect.toAlignedRect()); + QRect alignedRect = boundRect.toAlignedRect(); + + KIS_SAFE_ASSERT_RECOVER_RETURN(isRectInValidRange(alignedRect)); + + KisSequentialIterator it(m_d->device, alignedRect); + while (it.nextPixel()) { QPoint pt(it.x(), it.y()); @@ -104,7 +126,11 @@ KisAlgebra2D::OuterCircle outer(center, radius); - KisSequentialIterator it(m_d->device, boundRect.toAlignedRect()); + QRect alignedRect = boundRect.toAlignedRect(); + + KIS_SAFE_ASSERT_RECOVER_RETURN(isRectInValidRange(alignedRect)); + + KisSequentialIterator it(m_d->device, alignedRect); while (it.nextPixel()) { QPoint pt(it.x(), it.y());