diff --git a/libs/image/kis_convolution_painter.cc b/libs/image/kis_convolution_painter.cc index 01349625df..384f59f55f 100644 --- a/libs/image/kis_convolution_painter.cc +++ b/libs/image/kis_convolution_painter.cc @@ -1,188 +1,189 @@ /* * Copyright (c) 2005 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_convolution_painter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_convolution_kernel.h" #include "kis_global.h" #include "kis_image.h" #include "kis_layer.h" #include "kis_paint_device.h" #include "kis_painter.h" #include "KoColorSpace.h" #include #include "kis_types.h" #include "kis_selection.h" #include "kis_convolution_worker.h" #include "kis_convolution_worker_spatial.h" #include "config_convolution.h" #ifdef HAVE_FFTW3 #include "kis_convolution_worker_fft.h" #endif bool KisConvolutionPainter::useFFTImplementation(const KisConvolutionKernelSP kernel) const { bool result = false; #ifdef HAVE_FFTW3 #define THRESHOLD_SIZE 5 result = m_enginePreference == FFTW || (m_enginePreference == NONE && (kernel->width() > THRESHOLD_SIZE || kernel->height() > THRESHOLD_SIZE)); #else Q_UNUSED(kernel); #endif return result; } template KisConvolutionWorker* KisConvolutionPainter::createWorker(const KisConvolutionKernelSP kernel, KisPainter *painter, KoUpdater *progress) { KisConvolutionWorker *worker; #ifdef HAVE_FFTW3 if (useFFTImplementation(kernel)) { worker = new KisConvolutionWorkerFFT(painter, progress); } else { worker = new KisConvolutionWorkerSpatial(painter, progress); } #else Q_UNUSED(kernel); worker = new KisConvolutionWorkerSpatial(painter, progress); #endif return worker; } bool KisConvolutionPainter::supportsFFTW() { #ifdef HAVE_FFTW3 return true; #else return false; #endif } KisConvolutionPainter::KisConvolutionPainter() : KisPainter(), m_enginePreference(NONE) { } KisConvolutionPainter::KisConvolutionPainter(KisPaintDeviceSP device) : KisPainter(device), m_enginePreference(NONE) { } KisConvolutionPainter::KisConvolutionPainter(KisPaintDeviceSP device, KisSelectionSP selection) : KisPainter(device, selection), m_enginePreference(NONE) { } KisConvolutionPainter::KisConvolutionPainter(KisPaintDeviceSP device, TestingEnginePreference enginePreference) : KisPainter(device), m_enginePreference(enginePreference) { } void KisConvolutionPainter::applyMatrix(const KisConvolutionKernelSP kernel, const KisPaintDeviceSP src, QPoint srcPos, QPoint dstPos, QSize areaSize, KisConvolutionBorderOp borderOp) { /** * Force BORDER_IGNORE op for the wraparound mode, * because the paint device has its own special * iterators, which do everything for us. */ if (src->defaultBounds()->wrapAroundMode()) { borderOp = BORDER_IGNORE; } // Determine whether we convolve border pixels, or not. switch (borderOp) { case BORDER_REPEAT: { const QRect boundsRect = src->defaultBounds()->bounds(); const QRect requestedRect = QRect(srcPos, areaSize); QRect dataRect = requestedRect | boundsRect; + KIS_SAFE_ASSERT_RECOVER(boundsRect != KisDefaultBounds().bounds()) { dataRect = requestedRect | src->exactBounds(); } /** * FIXME: Implementation can return empty destination device * on faults and has no way to report this. This will cause a crash * on sequential convolutions inside iteratiors. * * o implementation should do it's work or assert otherwise * (or report the issue somehow) * o check other cases of the switch for the vulnerability */ if(dataRect.isValid()) { KisConvolutionWorker *worker; worker = createWorker(kernel, this, progressUpdater()); worker->execute(kernel, src, srcPos, dstPos, areaSize, dataRect); delete worker; } break; } case BORDER_IGNORE: default: { KisConvolutionWorker *worker; worker = createWorker(kernel, this, progressUpdater()); worker->execute(kernel, src, srcPos, dstPos, areaSize, QRect()); delete worker; } } } bool KisConvolutionPainter::needsTransaction(const KisConvolutionKernelSP kernel) const { return !useFFTImplementation(kernel); } diff --git a/libs/image/kis_edge_detection_kernel.cpp b/libs/image/kis_edge_detection_kernel.cpp index a15a6b9fb8..7872414e08 100644 --- a/libs/image/kis_edge_detection_kernel.cpp +++ b/libs/image/kis_edge_detection_kernel.cpp @@ -1,659 +1,651 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_edge_detection_kernel.h" -#include "kis_convolution_kernel.h" #include "kis_global.h" -#include +#include "kis_convolution_kernel.h" +#include #include #include -#include -#include +#include #include +#include #include -KisEdgeDetectionKernel::KisEdgeDetectionKernel() {} +KisEdgeDetectionKernel::KisEdgeDetectionKernel() +{ + +} /* * This code is very similar to the gaussian kernel code, except unlike the gaussian code, * edge-detection kernels DO use the diagonals. * Except for the simple mode. We implement the simple mode because it is an analog to * the old sobel filter. */ Eigen::Matrix KisEdgeDetectionKernel::createHorizontalMatrix(qreal radius, FilterType type, bool reverse) { int kernelSize = kernelSizeFromRadius(radius); Eigen::Matrix matrix(kernelSize, kernelSize); KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1); const int center = kernelSize / 2; - if (type == Prewit) { + if (type==Prewit) { for (int x = 0; x < kernelSize; x++) { - for (int y = 0; y < kernelSize; y++) { + for (int y=0; y KisEdgeDetectionKernel::createVerticalMatrix(qreal radius, FilterType type, bool reverse) { int kernelSize = kernelSizeFromRadius(radius); Eigen::Matrix matrix(kernelSize, kernelSize); KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1); const int center = kernelSize / 2; - if (type == Prewit) { + if (type==Prewit) { for (int y = 0; y < kernelSize; y++) { - for (int x = 0; x < kernelSize; x++) { + for (int x=0; x matrix = createHorizontalMatrix(radius, type, reverse); if (denormalize) { return KisConvolutionKernel::fromMatrix(matrix, 0.5, 1); } else { return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum()); } } KisConvolutionKernelSP KisEdgeDetectionKernel::createVerticalKernel(qreal radius, KisEdgeDetectionKernel::FilterType type, bool denormalize, bool reverse) { Eigen::Matrix matrix = createVerticalMatrix(radius, type, reverse); if (denormalize) { return KisConvolutionKernel::fromMatrix(matrix, 0.5, 1); } else { return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum()); } } int KisEdgeDetectionKernel::kernelSizeFromRadius(qreal radius) { return qMax((int)(2 * ceil(sigmaFromRadius(radius)) + 1), 3); } qreal KisEdgeDetectionKernel::sigmaFromRadius(qreal radius) { return 0.3 * radius + 0.3; } void KisEdgeDetectionKernel::applyEdgeDetection(KisPaintDeviceSP device, - const QRect& rect, + const QRect &rect, qreal xRadius, qreal yRadius, KisEdgeDetectionKernel::FilterType type, - const QBitArray& channelFlags, - KoUpdater* progressUpdater, + const QBitArray &channelFlags, + KoUpdater *progressUpdater, FilterOutput output, bool writeToAlpha) { QPoint srcTopLeft = rect.topLeft(); KisPainter finalPainter(device); finalPainter.setChannelFlags(channelFlags); finalPainter.setProgress(progressUpdater); if (output == pythagorean || output == radian) { KisPaintDeviceSP x_denormalised = new KisPaintDevice(device->colorSpace()); KisPaintDeviceSP y_denormalised = new KisPaintDevice(device->colorSpace()); x_denormalised->prepareClone(device); y_denormalised->prepareClone(device); + KisConvolutionKernelSP kernelHorizLeftRight = KisEdgeDetectionKernel::createHorizontalKernel(xRadius, type); KisConvolutionKernelSP kernelVerticalTopBottom = KisEdgeDetectionKernel::createVerticalKernel(yRadius, type); qreal horizontalCenter = qreal(kernelHorizLeftRight->width()) / 2.0; qreal verticalCenter = qreal(kernelVerticalTopBottom->height()) / 2.0; KisConvolutionPainter horizPainterLR(x_denormalised); horizPainterLR.setChannelFlags(channelFlags); horizPainterLR.setProgress(progressUpdater); - horizPainterLR.applyMatrix(kernelHorizLeftRight, - device, + horizPainterLR.applyMatrix(kernelHorizLeftRight, device, srcTopLeft - QPoint(0, ceil(horizontalCenter)), srcTopLeft - QPoint(0, ceil(horizontalCenter)), - rect.size() + QSize(0, 2 * ceil(horizontalCenter)), - BORDER_REPEAT); + rect.size() + QSize(0, 2 * ceil(horizontalCenter)), BORDER_REPEAT); + KisConvolutionPainter verticalPainterTB(y_denormalised); verticalPainterTB.setChannelFlags(channelFlags); verticalPainterTB.setProgress(progressUpdater); - verticalPainterTB.applyMatrix(kernelVerticalTopBottom, - device, + verticalPainterTB.applyMatrix(kernelVerticalTopBottom, device, srcTopLeft - QPoint(0, ceil(verticalCenter)), srcTopLeft - QPoint(0, ceil(verticalCenter)), - rect.size() + QSize(0, 2 * ceil(verticalCenter)), - BORDER_REPEAT); + rect.size() + QSize(0, 2 * ceil(verticalCenter)), BORDER_REPEAT); KisSequentialIterator yItterator(y_denormalised, rect); KisSequentialIterator xItterator(x_denormalised, rect); KisSequentialIterator finalIt(device, rect); const int pixelSize = device->colorSpace()->pixelSize(); const int channels = device->colorSpace()->channelCount(); const int alphaPos = device->colorSpace()->alphaPos(); KIS_SAFE_ASSERT_RECOVER_RETURN(alphaPos >= 0); QVector yNormalised(channels); QVector xNormalised(channels); QVector finalNorm(channels); - while (yItterator.nextPixel() && xItterator.nextPixel() && finalIt.nextPixel()) { + while(yItterator.nextPixel() && xItterator.nextPixel() && finalIt.nextPixel()) { device->colorSpace()->normalisedChannelsValue(yItterator.rawData(), yNormalised); device->colorSpace()->normalisedChannelsValue(xItterator.rawData(), xNormalised); device->colorSpace()->normalisedChannelsValue(finalIt.rawData(), finalNorm); if (output == pythagorean) { - for (int c = 0; c < channels; c++) { - finalNorm[c] = 2 * sqrt(((xNormalised[c] - 0.5) * (xNormalised[c] - 0.5)) + - ((yNormalised[c] - 0.5) * (yNormalised[c] - 0.5))); + for (int c = 0; ccolorSpace()); qreal alpha = 0; - for (int c = 0; c < (channels - 1); c++) { - alpha = alpha + finalNorm[c]; + for (int c = 0; c<(channels-1); c++) { + alpha = alpha+finalNorm[c]; } - alpha = qMin(alpha / (channels - 1), col.opacityF()); + alpha = qMin(alpha/(channels-1), col.opacityF()); col.setOpacity(alpha); memcpy(finalIt.rawData(), col.data(), pixelSize); } else { quint8* f = finalIt.rawData(); finalNorm[alphaPos] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(f, finalNorm); memcpy(finalIt.rawData(), f, pixelSize); } + } } else { KisConvolutionKernelSP kernel; qreal center = 0; bool denormalize = !writeToAlpha; if (output == xGrowth) { kernel = KisEdgeDetectionKernel::createHorizontalKernel(xRadius, type, denormalize); center = qreal(kernel->width()) / 2.0; } else if (output == xFall) { kernel = KisEdgeDetectionKernel::createHorizontalKernel(xRadius, type, denormalize, true); center = qreal(kernel->width()) / 2.0; } else if (output == yGrowth) { kernel = KisEdgeDetectionKernel::createVerticalKernel(yRadius, type, denormalize); center = qreal(kernel->height()) / 2.0; - } else { // yFall + } else { //yFall kernel = KisEdgeDetectionKernel::createVerticalKernel(yRadius, type, denormalize, true); center = qreal(kernel->height()) / 2.0; } if (writeToAlpha) { KisPaintDeviceSP denormalised = new KisPaintDevice(device->colorSpace()); denormalised->prepareClone(device); KisConvolutionPainter kernelP(denormalised); kernelP.setChannelFlags(channelFlags); kernelP.setProgress(progressUpdater); - kernelP.applyMatrix(kernel, - device, + kernelP.applyMatrix(kernel, device, srcTopLeft - QPoint(0, ceil(center)), srcTopLeft - QPoint(0, ceil(center)), - rect.size() + QSize(0, 2 * ceil(center)), - BORDER_REPEAT); + rect.size() + QSize(0, 2 * ceil(center)), BORDER_REPEAT); KisSequentialIterator iterator(denormalised, rect); KisSequentialIterator finalIt(device, rect); const int pixelSize = device->colorSpace()->pixelSize(); const int channels = device->colorSpace()->colorChannelCount(); QVector normalised(channels); while (iterator.nextPixel() && finalIt.nextPixel()) { device->colorSpace()->normalisedChannelsValue(iterator.rawData(), normalised); KoColor col(finalIt.rawData(), device->colorSpace()); qreal alpha = 0; - for (int c = 0; c < channels; c++) { - alpha = alpha + normalised[c]; + for (int c = 0; ccolorSpace()->setOpacity(finalIt.rawData(), 1.0, numConseqPixels); } } } } void KisEdgeDetectionKernel::applyCannyEdgeDetection(KisPaintDeviceSP _device, const QRect& rect, qreal xRadius, qreal yRadius, const QBitArray& channelFlags, KoUpdater* progressUpdater, int thresholdMax, int thresholdMin) { QPoint srcTopLeft = rect.topLeft(); auto bounds = _device->defaultBounds(); auto device = KisPainter::convertToAlphaAsGray(_device); device->setDefaultBounds(bounds); KisPaintDeviceSP x_denormalised = new KisPaintDevice(device->colorSpace()); KisPaintDeviceSP y_denormalised = new KisPaintDevice(device->colorSpace()); x_denormalised->prepareClone(device); y_denormalised->prepareClone(device); KisConvolutionKernelSP kernelHorizLeftRight = KisEdgeDetectionKernel::createHorizontalKernel(xRadius, KisEdgeDetectionKernel::SobelVector); KisConvolutionKernelSP kernelVerticalTopBottom = KisEdgeDetectionKernel::createVerticalKernel(yRadius, KisEdgeDetectionKernel::SobelVector); qreal horizontalCenter = qreal(kernelHorizLeftRight->width()) / 2.0; qreal verticalCenter = qreal(kernelVerticalTopBottom->height()) / 2.0; KisConvolutionPainter horizPainterLR(x_denormalised); horizPainterLR.setChannelFlags(channelFlags); horizPainterLR.setProgress(progressUpdater); horizPainterLR.applyMatrix(kernelHorizLeftRight, device, srcTopLeft - QPoint(0, ceil(horizontalCenter)), srcTopLeft - QPoint(0, ceil(horizontalCenter)), rect.size() + QSize(0, 2 * ceil(horizontalCenter)), BORDER_REPEAT); KisConvolutionPainter verticalPainterTB(y_denormalised); verticalPainterTB.setChannelFlags(channelFlags); verticalPainterTB.setProgress(progressUpdater); verticalPainterTB.applyMatrix(kernelVerticalTopBottom, device, srcTopLeft - QPoint(0, ceil(verticalCenter)), srcTopLeft - QPoint(0, ceil(verticalCenter)), rect.size() + QSize(0, 2 * ceil(verticalCenter)), BORDER_REPEAT); KisSequentialIterator yIterator(y_denormalised, rect); KisSequentialIterator xIterator(x_denormalised, rect); KisSequentialIterator sobelIterator(device, rect); QVector yNormalised(1); QVector xNormalised(1); QVector finalNorm(1); while (yIterator.nextPixel() && xIterator.nextPixel() && sobelIterator.nextPixel()) { device->colorSpace()->normalisedChannelsValue(yIterator.rawData(), yNormalised); device->colorSpace()->normalisedChannelsValue(xIterator.rawData(), xNormalised); device->colorSpace()->normalisedChannelsValue(sobelIterator.rawData(), finalNorm); finalNorm[0] = 2 * sqrt(((xNormalised[0] - 0.5) * (xNormalised[0] - 0.5)) + ((yNormalised[0] - 0.5) * (yNormalised[0] - 0.5))); quint8* f = sobelIterator.rawData(); device->colorSpace()->fromNormalisedChannelsValue(f, finalNorm); memcpy(sobelIterator.rawData(), f, device->colorSpace()->pixelSize()); } KisRandomAccessorSP randomSobel = device->createRandomAccessorNG(rect.x(), rect.y()); KisRandomConstAccessorSP gx_iter = x_denormalised->createRandomConstAccessorNG(rect.x(), rect.y()); KisRandomConstAccessorSP gy_iter = x_denormalised->createRandomConstAccessorNG(rect.x(), rect.y()); for (int x = rect.x() + 1; x < rect.x() + rect.width() - 1; x++) { for (int y = rect.y() + 1; y < rect.y() + rect.height() - 1; y++) { randomSobel->moveTo(x, y); const float current = *randomSobel->rawData(); float firstIntensity, secondIntensity; gx_iter->moveTo(x, y); gy_iter->moveTo(x, y); const float direction = atan2(*gx_iter->rawDataConst(), *gy_iter->rawDataConst()); if (direction <= 1 || direction > 7) { randomSobel->moveTo(x + 1, y); firstIntensity = *randomSobel->rawData(); randomSobel->moveTo(x - 1, y); secondIntensity = *randomSobel->rawData(); } if (direction > 1 || direction <= 3) { randomSobel->moveTo(x + 1, y + 1); firstIntensity = *randomSobel->rawData(); randomSobel->moveTo(x - 1, y - 1); secondIntensity = *randomSobel->rawData(); } if (direction > 3 || direction <= 5) { randomSobel->moveTo(x, y + 1); firstIntensity = *randomSobel->rawData(); randomSobel->moveTo(x, y - 1); secondIntensity = *randomSobel->rawData(); } if (direction > 5 || direction <= 7) { randomSobel->moveTo(x + 1, y - 1); firstIntensity = *randomSobel->rawData(); randomSobel->moveTo(x - 1, y + 1); secondIntensity = *randomSobel->rawData(); } randomSobel->moveTo(x, y); if (2 * current <= (firstIntensity + secondIntensity)) { quint8* temp = new quint8(); finalNorm[0] = 0.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); } } } for (int x = rect.x() + 1; x < rect.x() + rect.width() - 1; x++) { for (int y = rect.y() + 1; y < rect.y() + rect.height() - 1; y++) { randomSobel->moveTo(x, y); quint8 intensity = *randomSobel->rawData(); if (intensity < thresholdMin) { quint8* temp = new quint8(); finalNorm[0] = 0.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); } else if (intensity < thresholdMax) { randomSobel->moveTo(x + 1, y); quint8 intensity = *randomSobel->rawData(); if (intensity > thresholdMax) { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); continue; } randomSobel->moveTo(x - 1, y); intensity = *randomSobel->rawData(); if (intensity > thresholdMax) { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); continue; } randomSobel->moveTo(x, y + 1); intensity = *randomSobel->rawData(); if (intensity > thresholdMax) { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); continue; } randomSobel->moveTo(x, y - 1); intensity = *randomSobel->rawData(); if (intensity > thresholdMax) { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); continue; } randomSobel->moveTo(x + 1, y + 1); intensity = *randomSobel->rawData(); if (intensity > thresholdMax) { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); continue; } randomSobel->moveTo(x - 1, y - 1); intensity = *randomSobel->rawData(); if (intensity > thresholdMax) { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); continue; } randomSobel->moveTo(x + 1, y - 1); intensity = *randomSobel->rawData(); if (intensity > thresholdMax) { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); continue; } randomSobel->moveTo(x - 1, y + 1); intensity = *randomSobel->rawData(); if (intensity > thresholdMax) { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); continue; } } else { quint8* temp = new quint8(); finalNorm[0] = 1.0; device->colorSpace()->fromNormalisedChannelsValue(temp, finalNorm); memcpy(randomSobel->rawData(), temp, device->pixelSize()); } } } KisPainter::copyAreaOptimized(rect.topLeft(), device, _device, rect); } void KisEdgeDetectionKernel::convertToNormalMap(KisPaintDeviceSP device, - const QRect& rect, + const QRect &rect, qreal xRadius, qreal yRadius, KisEdgeDetectionKernel::FilterType type, int channelToConvert, QVector channelOrder, QVector channelFlip, - const QBitArray& channelFlags, - KoUpdater* progressUpdater) + const QBitArray &channelFlags, + KoUpdater *progressUpdater) { QPoint srcTopLeft = rect.topLeft(); KisPainter finalPainter(device); finalPainter.setChannelFlags(channelFlags); finalPainter.setProgress(progressUpdater); KisPaintDeviceSP x_denormalised = new KisPaintDevice(device->colorSpace()); KisPaintDeviceSP y_denormalised = new KisPaintDevice(device->colorSpace()); x_denormalised->prepareClone(device); y_denormalised->prepareClone(device); - KisConvolutionKernelSP kernelHorizLeftRight = - KisEdgeDetectionKernel::createHorizontalKernel(yRadius, type, true, !channelFlip[1]); - KisConvolutionKernelSP kernelVerticalTopBottom = - KisEdgeDetectionKernel::createVerticalKernel(xRadius, type, true, !channelFlip[0]); + KisConvolutionKernelSP kernelHorizLeftRight = KisEdgeDetectionKernel::createHorizontalKernel(yRadius, type, true, !channelFlip[1]); + KisConvolutionKernelSP kernelVerticalTopBottom = KisEdgeDetectionKernel::createVerticalKernel(xRadius, type, true, !channelFlip[0]); qreal horizontalCenter = qreal(kernelHorizLeftRight->width()) / 2.0; qreal verticalCenter = qreal(kernelVerticalTopBottom->height()) / 2.0; KisConvolutionPainter horizPainterLR(y_denormalised); horizPainterLR.setChannelFlags(channelFlags); horizPainterLR.setProgress(progressUpdater); - horizPainterLR.applyMatrix(kernelHorizLeftRight, - device, + horizPainterLR.applyMatrix(kernelHorizLeftRight, device, srcTopLeft - QPoint(ceil(horizontalCenter), 0), srcTopLeft - QPoint(ceil(horizontalCenter), 0), - rect.size() + QSize(2 * ceil(horizontalCenter), 0), - BORDER_REPEAT); + rect.size() + QSize(2 * ceil(horizontalCenter), 0), BORDER_REPEAT); + KisConvolutionPainter verticalPainterTB(x_denormalised); verticalPainterTB.setChannelFlags(channelFlags); verticalPainterTB.setProgress(progressUpdater); - verticalPainterTB.applyMatrix(kernelVerticalTopBottom, - device, + verticalPainterTB.applyMatrix(kernelVerticalTopBottom, device, srcTopLeft - QPoint(0, ceil(verticalCenter)), srcTopLeft - QPoint(0, ceil(verticalCenter)), - rect.size() + QSize(0, 2 * ceil(verticalCenter)), - BORDER_REPEAT); + rect.size() + QSize(0, 2 * ceil(verticalCenter)), BORDER_REPEAT); KisSequentialIterator yItterator(y_denormalised, rect); KisSequentialIterator xItterator(x_denormalised, rect); KisSequentialIterator finalIt(device, rect); const int pixelSize = device->colorSpace()->pixelSize(); const int channels = device->colorSpace()->channelCount(); const int alphaPos = device->colorSpace()->alphaPos(); KIS_SAFE_ASSERT_RECOVER_RETURN(alphaPos >= 0); QVector yNormalised(channels); QVector xNormalised(channels); QVector finalNorm(channels); - while (yItterator.nextPixel() && xItterator.nextPixel() && finalIt.nextPixel()) { + while(yItterator.nextPixel() && xItterator.nextPixel() && finalIt.nextPixel()) { device->colorSpace()->normalisedChannelsValue(yItterator.rawData(), yNormalised); device->colorSpace()->normalisedChannelsValue(xItterator.rawData(), xNormalised); qreal z = 1.0; - if (channelFlip[2] == true) { - z = -1.0; + if (channelFlip[2]==true){ + z=-1.0; } - QVector3D normal = - QVector3D((xNormalised[channelToConvert] - 0.5) * 2, (yNormalised[channelToConvert] - 0.5) * 2, z); + QVector3D normal = QVector3D((xNormalised[channelToConvert]-0.5)*2, (yNormalised[channelToConvert]-0.5)*2, z); normal.normalize(); finalNorm.fill(1.0); - for (int c = 0; c < 3; c++) { - finalNorm[device->colorSpace()->channels().at(channelOrder[c])->displayPosition()] = - (normal[channelOrder[c]] / 2) + 0.5; + for (int c = 0; c<3; c++) { + finalNorm[device->colorSpace()->channels().at(channelOrder[c])->displayPosition()] = (normal[channelOrder[c]]/2)+0.5; } - finalNorm[alphaPos] = 1.0; + finalNorm[alphaPos]= 1.0; quint8* pixel = finalIt.rawData(); device->colorSpace()->fromNormalisedChannelsValue(pixel, finalNorm); memcpy(finalIt.rawData(), pixel, pixelSize); + } } diff --git a/libs/image/kis_edge_detection_kernel.h b/libs/image/kis_edge_detection_kernel.h index ce1f6e7092..dbc5704473 100644 --- a/libs/image/kis_edge_detection_kernel.h +++ b/libs/image/kis_edge_detection_kernel.h @@ -1,162 +1,153 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_EDGE_DETECTION_KERNEL_H #define KIS_EDGE_DETECTION_KERNEL_H -#include "kis_types.h" #include "kritaimage_export.h" +#include "kis_types.h" #include class QRect; class KRITAIMAGE_EXPORT KisEdgeDetectionKernel { - public: +public: KisEdgeDetectionKernel(); - enum FilterType - { - Simple, // A weird simple method used in our old sobel filter - Prewit, // The simpler prewitt detection, which doesn't smooth. - SobelVector // Sobel does smooth. The creation of bigger kernels is based on an approach regarding vectors. + enum FilterType { + Simple, //A weird simple method used in our old sobel filter + Prewit, //The simpler prewitt detection, which doesn't smooth. + SobelVector //Sobel does smooth. The creation of bigger kernels is based on an approach regarding vectors. }; - enum FilterOutput - { + enum FilterOutput { pythagorean, xGrowth, xFall, yGrowth, yFall, radian }; /** * @brief createHorizontalMatrix * @param radius the radius. 1 makes a 3x3 kernel. * @param type One of the entries in the enum Filtertype * @param reverse which direction the gradient goes. * The horizontal gradient by default detects the rightmost edges. * Reversed it selects the leftmost edges. * @return */ - static Eigen::Matrix createHorizontalMatrix(qreal radius, - FilterType type, - bool reverse = false); + static Eigen::Matrix + createHorizontalMatrix(qreal radius, FilterType type, bool reverse = false); /** * @brief createVerticalMatrix * @param radius the radius. 1 makes a 3x3 kernel. * @param type One of the entries in the enum Filtertype * @param reverse which direction the gradient goes. * The vertical gradient by default detects the topmost edges. * Reversed it selects the bottommost edges. * @return */ - static Eigen::Matrix createVerticalMatrix(qreal radius, - FilterType type, - bool reverse = false); + static Eigen::Matrix + createVerticalMatrix(qreal radius, FilterType type, bool reverse = false); - static KisConvolutionKernelSP createHorizontalKernel(qreal radius, - FilterType type, - bool denormalize = true, - bool reverse = false); + static KisConvolutionKernelSP + createHorizontalKernel(qreal radius, FilterType type, bool denormalize = true, bool reverse = false); - static KisConvolutionKernelSP createVerticalKernel(qreal radius, - FilterType type, - bool denormalize = true, - bool reverse = false); + static KisConvolutionKernelSP + createVerticalKernel(qreal radius, FilterType type, bool denormalize = true, bool reverse = false); static int kernelSizeFromRadius(qreal radius); static qreal sigmaFromRadius(qreal radius); /** * @brief applyEdgeDetection * This applies the edge detection filter to the device. * @param device the device to apply to. * @param rect the affected rect. * @param xRadius the radius of the horizontal sampling, radius of 0 is effectively disabling it. * @param yRadius the radius of the vertical sampling, refius of 0 is effectively disabling it. * @param type the type can be prewitt, sobel or simple, each of which * have a different sampling for the eventual edge detection. * @param channelFlags the affected channels. * @param progressUpdater the progress updater if it exists. * @param output the output mode. * @param writeToAlpha whether or not to have the result applied to the transparency than the color channels, * this is useful for fringe effects. */ static void applyEdgeDetection(KisPaintDeviceSP device, - const QRect& rect, - qreal xRadius, - qreal yRadius, - FilterType type, - const QBitArray& channelFlags, - KoUpdater* progressUpdater, - FilterOutput output = pythagorean, - bool writeToAlpha = false); + const QRect& rect, + qreal xRadius, qreal yRadius, + FilterType type, + const QBitArray &channelFlags, + KoUpdater *progressUpdater, + FilterOutput output = pythagorean, + bool writeToAlpha = false); /** * @brief applyCannyEdgeDetection * This applies the canny edge detection filter to the device. * @param device the device to apply to. * @param rect the affected rect. * @param xRadius the radius of the horizontal sampling, radius of 0 is effectively disabling it. * @param yRadius the radius of the vertical sampling, refius of 0 is effectively disabling it. * @param channelFlags the affected channels. * @param progressUpdater the progress updater if it exists. * @param writeToAlpha whether or not to have the result applied to the transparency than the color channels, * this is useful for fringe effects. */ static void applyCannyEdgeDetection(KisPaintDeviceSP device, const QRect& rect, qreal xRadius, qreal yRadius, const QBitArray& channelFlags, KoUpdater* progressUpdater, int thresholdMax, int thresholdMin); /** * @brief converToNormalMap * Convert a channel of the device to a normal map. The channel will be interpreted as a heightmap. * @param device the device * @param rect the rectangle to apply this to. * @param xRadius the xradius * @param yRadius the yradius * @param type the edge detection filter. * @param channelToConvert the channel to use as a grayscale. * @param channelOrder the order in which the xyz coordinates ought to be written to the pixels. * @param channelFlip whether to flip the channels * @param channelFlags the channel flags * @param progressUpdater */ static void convertToNormalMap(KisPaintDeviceSP device, - const QRect& rect, - qreal xRadius, - qreal yRadius, - FilterType type, - int channelToConvert, - QVector channelOrder, - QVector channelFlip, - const QBitArray& channelFlags, - KoUpdater* progressUpdater); + const QRect & rect, + qreal xRadius, + qreal yRadius, + FilterType type, + int channelToConvert, + QVector channelOrder, + QVector channelFlip, + const QBitArray &channelFlags, + KoUpdater *progressUpdater); }; #endif // KIS_EDGE_DETECTION_KERNEL_H diff --git a/plugins/filters/edgedetection/kis_edge_detection_filter.cpp b/plugins/filters/edgedetection/kis_edge_detection_filter.cpp index 94541cab63..23dc3cea3a 100644 --- a/plugins/filters/edgedetection/kis_edge_detection_filter.cpp +++ b/plugins/filters/edgedetection/kis_edge_detection_filter.cpp @@ -1,185 +1,168 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_edge_detection_filter.h" #include "kis_wdg_edge_detection.h" +#include #include #include -#include -#include #include +#include -#include "kis_lod_transform.h" #include #include +#include #include #include -#include +#include "kis_lod_transform.h" #include -#include #include +#include -K_PLUGIN_FACTORY_WITH_JSON(KritaEdgeDetectionFilterFactory, - "kritaedgedetection.json", - registerPlugin();) +K_PLUGIN_FACTORY_WITH_JSON(KritaEdgeDetectionFilterFactory, "kritaedgedetection.json", registerPlugin();) -KritaEdgeDetectionFilter::KritaEdgeDetectionFilter(QObject* parent, const QVariantList&) +KritaEdgeDetectionFilter::KritaEdgeDetectionFilter(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(KisFilterSP(new KisEdgeDetectionFilter())); } -KritaEdgeDetectionFilter::~KritaEdgeDetectionFilter() {} +KritaEdgeDetectionFilter::~KritaEdgeDetectionFilter() +{ +} -KisEdgeDetectionFilter::KisEdgeDetectionFilter() - : KisFilter(id(), FiltersCategoryEdgeDetectionId, i18n("&Edge Detection...")) +KisEdgeDetectionFilter::KisEdgeDetectionFilter(): KisFilter(id(), FiltersCategoryEdgeDetectionId, i18n("&Edge Detection...")) { setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsLevelOfDetail(true); setColorSpaceIndependence(FULLY_INDEPENDENT); setShowConfigurationWidget(true); } -void KisEdgeDetectionFilter::processImpl(KisPaintDeviceSP device, - const QRect& rect, - const KisFilterConfigurationSP config, - KoUpdater* progressUpdater) const +void KisEdgeDetectionFilter::processImpl(KisPaintDeviceSP device, const QRect &rect, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const { Q_ASSERT(device != 0); KisFilterConfigurationSP configuration = config ? config : new KisFilterConfiguration(id().id(), 1); KisLodTransformScalar t(device); QVariant value; configuration->getProperty("horizRadius", value); - qreal horizontalRadius = t.scale(value.toFloat()); + float horizontalRadius = t.scale(value.toFloat()); configuration->getProperty("vertRadius", value); - qreal verticalRadius = t.scale(value.toFloat()); + float verticalRadius = t.scale(value.toFloat()); QBitArray channelFlags; if (configuration) { channelFlags = configuration->channelFlags(); } if (config->getString("type") == "canny") { KisFilterSP gaussian = KisFilterRegistry::instance()->get("gaussian blur"); KisFilterConfigurationSP gaussianConf = gaussian->defaultConfiguration(); gaussian->process(device, rect, gaussianConf, progressUpdater); int max = configuration->getInt("max_threshold", 200); int min = configuration->getInt("min_threshold", 100); KisEdgeDetectionKernel::applyCannyEdgeDetection( device, rect, horizontalRadius, verticalRadius, channelFlags, progressUpdater, max, min); return; } KisEdgeDetectionKernel::FilterType type = KisEdgeDetectionKernel::SobelVector; - if (config->getString("type") == "prewitt") { type = KisEdgeDetectionKernel::Prewit; - } - - if (config->getString("type") == "simple") { + } else if (config->getString("type") == "simple") { type = KisEdgeDetectionKernel::Simple; } KisEdgeDetectionKernel::FilterOutput output = KisEdgeDetectionKernel::pythagorean; if (config->getString("output") == "xGrowth") { output = KisEdgeDetectionKernel::xGrowth; } else if (config->getString("output") == "xFall") { output = KisEdgeDetectionKernel::xFall; } else if (config->getString("output") == "yGrowth") { output = KisEdgeDetectionKernel::yGrowth; } else if (config->getString("output") == "yFall") { output = KisEdgeDetectionKernel::yFall; } else if (config->getString("output") == "radian") { output = KisEdgeDetectionKernel::radian; } KisEdgeDetectionKernel::applyEdgeDetection(device, rect, horizontalRadius, verticalRadius, type, channelFlags, progressUpdater, output, config->getBool("transparency", false)); } KisFilterConfigurationSP KisEdgeDetectionFilter::defaultConfiguration() const { KisFilterConfigurationSP config = factoryConfiguration(); config->setProperty("horizRadius", 1); config->setProperty("vertRadius", 1); config->setProperty("type", "prewitt"); config->setProperty("output", "pythagorean"); config->setProperty("lockAspect", true); config->setProperty("transparency", false); return config; } -KisConfigWidget* KisEdgeDetectionFilter::createConfigurationWidget(QWidget* parent, - const KisPaintDeviceSP dev, - bool) const +KisConfigWidget *KisEdgeDetectionFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev, bool) const { Q_UNUSED(dev); return new KisWdgEdgeDetection(parent); } -QRect KisEdgeDetectionFilter::neededRect(const QRect& rect, const KisFilterConfigurationSP _config, int lod) const +QRect KisEdgeDetectionFilter::neededRect(const QRect &rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; /** * NOTE: integer division by two is done on purpose, * because the kernel size is always odd */ - const int halfWidth = _config->getProperty("horizRadius", value) - ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 - : 5; - const int halfHeight = _config->getProperty("vertRadius", value) - ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 - : 5; + const int halfWidth = _config->getProperty("horizRadius", value) ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5; + const int halfHeight = _config->getProperty("vertRadius", value) ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5; return rect.adjusted(-halfWidth * 2, -halfHeight * 2, halfWidth * 2, halfHeight * 2); } -QRect KisEdgeDetectionFilter::changedRect(const QRect& rect, const KisFilterConfigurationSP _config, int lod) const +QRect KisEdgeDetectionFilter::changedRect(const QRect &rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; - const int halfWidth = _config->getProperty("horizRadius", value) - ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 - : 5; - const int halfHeight = _config->getProperty("vertRadius", value) - ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 - : 5; + const int halfWidth = _config->getProperty("horizRadius", value) ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5; + const int halfHeight = _config->getProperty("vertRadius", value) ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5; - return rect.adjusted(-halfWidth, -halfHeight, halfWidth, halfHeight); + return rect.adjusted( -halfWidth, -halfHeight, halfWidth, halfHeight); } #include "kis_edge_detection_filter.moc" diff --git a/plugins/tools/selectiontools/KisMagneticWorker.cc b/plugins/tools/selectiontools/KisMagneticWorker.cc index 17b14cb820..8a21ac8069 100644 --- a/plugins/tools/selectiontools/KisMagneticWorker.cc +++ b/plugins/tools/selectiontools/KisMagneticWorker.cc @@ -1,284 +1,282 @@ /* * Copyright (c) 2019 Kuntal Majumder * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisMagneticWorker.h" -#include -#include -#include -#include #include -#include #include +#include +#include -#include -#include #include +#include +#include #include #include #include "KisMagneticGraph.h" -struct DistanceMap -{ +struct DistanceMap { typedef VertexDescriptor key_type; typedef double data_type; typedef std::pair value_type; - explicit DistanceMap(double const& dval) + explicit DistanceMap(double const &dval) : m_default(dval) - {} + { } - data_type& operator[](key_type const& k) + data_type &operator [] (key_type const &k) { if (m.find(k) == m.end()) m[k] = m_default; return m[k]; } - private: +private: std::map m; - data_type const m_default; + data_type const m_default; }; -struct PredecessorMap -{ +struct PredecessorMap { PredecessorMap() = default; - PredecessorMap(PredecessorMap const& that) = default; + PredecessorMap(PredecessorMap const &that) = default; typedef VertexDescriptor key_type; typedef VertexDescriptor value_type; typedef boost::read_write_property_map_tag category; - VertexDescriptor& operator[](VertexDescriptor v) { return m_map[v]; } + VertexDescriptor &operator [] (VertexDescriptor v) + { + return m_map[v]; + } std::map m_map; }; -VertexDescriptor get(PredecessorMap const& m, VertexDescriptor v) +VertexDescriptor get(PredecessorMap const &m, VertexDescriptor v) { auto found = m.m_map.find(v); return found != m.m_map.end() ? found->second : v; } -void put(PredecessorMap& m, VertexDescriptor key, VertexDescriptor value) +void put(PredecessorMap &m, VertexDescriptor key, VertexDescriptor value) { m.m_map[key] = value; } double EuclideanDistance(VertexDescriptor p1, VertexDescriptor p2) { return std::sqrt(std::pow(p1.y - p2.y, 2) + std::pow(p1.x - p2.x, 2)); } class AStarHeuristic : public boost::astar_heuristic { - private: +private: VertexDescriptor m_goal; - public: - explicit AStarHeuristic(VertexDescriptor goal) - : m_goal(goal) - {} +public: + explicit AStarHeuristic(VertexDescriptor goal) : + m_goal(goal) + { } - double operator()(VertexDescriptor v) { return EuclideanDistance(v, m_goal); } + double operator () (VertexDescriptor v) + { + return EuclideanDistance(v, m_goal); + } }; -struct GoalFound -{}; +struct GoalFound { }; class AStarGoalVisitor : public boost::default_astar_visitor { - public: - explicit AStarGoalVisitor(VertexDescriptor goal) - : m_goal(goal) - {} +public: + explicit AStarGoalVisitor(VertexDescriptor goal) : m_goal(goal){ } - void examine_vertex(VertexDescriptor u, KisMagneticGraph const& g) + void examine_vertex(VertexDescriptor u, KisMagneticGraph const &g) { Q_UNUSED(g) if (u == m_goal) { throw GoalFound(); } } - private: +private: VertexDescriptor m_goal; }; -struct WeightMap -{ +struct WeightMap { typedef std::pair key_type; typedef double data_type; typedef std::pair value_type; WeightMap() = default; - explicit WeightMap(const KisMagneticGraph& g) - : m_graph(g) - {} + explicit WeightMap(const KisMagneticGraph &g) : + m_graph(g) + { } - data_type& operator[](key_type const& k) + data_type &operator [] (key_type const &k) { if (m_map.find(k) == m_map.end()) { double edge_gradient = (m_graph.getIntensity(k.first) + m_graph.getIntensity(k.second)) / 2; m_map[k] = EuclideanDistance(k.first, k.second) + 255.0 - edge_gradient; } return m_map[k]; } - private: +private: std::map m_map; - KisMagneticGraph m_graph; + KisMagneticGraph m_graph; }; KisMagneticLazyTiles::KisMagneticLazyTiles(KisPaintDeviceSP dev) { m_dev = KisPainter::convertToAlphaAsGray(dev); QSize s = dev->defaultBounds()->bounds().size(); - m_tileSize = KritaUtils::optimalPatchSize(); - m_tilesPerRow = (int)std::ceil((double)s.width() / (double)m_tileSize.width()); - int tilesPerColumn = (int)std::ceil((double)s.height() / (double)m_tileSize.height()); + m_tileSize = KritaUtils::optimalPatchSize(); + m_tilesPerRow = (int) std::ceil((double) s.width() / (double) m_tileSize.width()); + int tilesPerColumn = (int) std::ceil((double) s.height() / (double) m_tileSize.height()); m_dev->setDefaultBounds(dev->defaultBounds()); for (int i = 0; i < tilesPerColumn; i++) { for (int j = 0; j < m_tilesPerRow; j++) { - int width = std::min(s.width() - j * m_tileSize.width(), m_tileSize.width()); + int width = std::min(s.width() - j * m_tileSize.width(), m_tileSize.width()); int height = std::min(s.height() - i * m_tileSize.height(), m_tileSize.height()); - QRect temp(j * m_tileSize.width(), i * m_tileSize.height(), width, height); + QRect temp(j *m_tileSize.width(), i *m_tileSize.height(), width, height); m_tiles.push_back(temp); } } m_radiusRecord = QVector(m_tiles.size(), -1); } -void KisMagneticLazyTiles::filter(qreal radius, QRect& rect) +void KisMagneticLazyTiles::filter(qreal radius, QRect &rect) { - auto divide = [](QPoint p, QSize s) { return QPoint(p.x() / s.width(), p.y() / s.height()); }; + auto divide = [](QPoint p, QSize s){ + return QPoint(p.x() / s.width(), p.y() / s.height()); + }; QPoint firstTile = divide(rect.topLeft(), m_tileSize); - QPoint lastTile = divide(rect.bottomRight(), m_tileSize); + QPoint lastTile = divide(rect.bottomRight(), m_tileSize); for (int i = firstTile.y(); i <= lastTile.y(); i++) { for (int j = firstTile.x(); j <= lastTile.x(); j++) { int currentTile = i * m_tilesPerRow + j; if (radius != m_radiusRecord[currentTile]) { QRect bounds = m_tiles[currentTile]; KisGaussianKernel::applyTightLoG(m_dev, bounds, radius, -1.0, QBitArray(), nullptr); KisLazyFillTools::normalizeAlpha8Device(m_dev, bounds); m_radiusRecord[currentTile] = radius; } } } } -KisMagneticWorker::KisMagneticWorker(const KisPaintDeviceSP& dev) - : m_lazyTileFilter(dev) -{} +KisMagneticWorker::KisMagneticWorker(const KisPaintDeviceSP &dev) : + m_lazyTileFilter(dev) +{ } QVector KisMagneticWorker::computeEdge(int bounds, QPoint begin, QPoint end, qreal radius) { QRect rect; - KisAlgebra2D::accumulateBounds(QVector{ begin, end }, &rect); + KisAlgebra2D::accumulateBounds(QVector { begin, end }, &rect); rect = kisGrowRect(rect, bounds); m_lazyTileFilter.filter(radius, rect); VertexDescriptor goal(end); VertexDescriptor start(begin); m_graph = new KisMagneticGraph(m_lazyTileFilter.device(), rect); // How many maps does it require? - // Take a look here, if it doesn't make sense, - // https://www.boost.org/doc/libs/1_70_0/libs/graph/doc/astar_search.html + // Take a look here, if it doesn't make sense, https://www.boost.org/doc/libs/1_70_0/libs/graph/doc/astar_search.html PredecessorMap pmap; DistanceMap dmap(std::numeric_limits::max()); dmap[start] = 0; std::map rmap; std::map cmap; std::map imap; WeightMap wmap(*m_graph); AStarHeuristic heuristic(goal); QVector result; try { boost::astar_search_no_init( - *m_graph, - start, - heuristic, + *m_graph, start, heuristic, boost::visitor(AStarGoalVisitor(goal)) - .distance_map(boost::associative_property_map(dmap)) - .predecessor_map(boost::ref(pmap)) - .weight_map(boost::associative_property_map(wmap)) - .vertex_index_map(boost::associative_property_map>(imap)) - .rank_map(boost::associative_property_map>(rmap)) - .color_map(boost::associative_property_map>(cmap)) - .distance_combine(std::plus()) - .distance_compare(std::less())); - } catch (GoalFound const&) { + .distance_map(boost::associative_property_map(dmap)) + .predecessor_map(boost::ref(pmap)) + .weight_map(boost::associative_property_map(wmap)) + .vertex_index_map(boost::associative_property_map >(imap)) + .rank_map(boost::associative_property_map >(rmap)) + .color_map(boost::associative_property_map > + (cmap)) + .distance_combine(std::plus()) + .distance_compare(std::less()) + ); + } catch (GoalFound const &) { for (VertexDescriptor u = goal; u != start; u = pmap[u]) { result.push_front(QPointF(u.x, u.y)); } } result.push_front(QPoint(start.x, start.y)); return result; } // KisMagneticWorker::computeEdge qreal KisMagneticWorker::intensity(QPoint pt) { return m_graph->getIntensity(VertexDescriptor(pt)); } void KisMagneticWorker::saveTheImage(vQPointF points) { QImage img = m_lazyTileFilter.device()->convertToQImage(nullptr, m_lazyTileFilter.device()->exactBounds()); const QPointF offset = m_lazyTileFilter.device()->exactBounds().topLeft(); - for (QPointF& pt : points) { + for (QPointF &pt : points) { pt -= offset; } img = img.convertToFormat(QImage::Format_ARGB32); QPainter gc(&img); QPainterPath path; for (int i = 0; i < points.size(); i++) { if (i == 0) { path.moveTo(points[i]); } else { path.lineTo(points[i]); } } gc.setPen(Qt::blue); gc.drawPath(path); gc.setPen(Qt::green); gc.drawEllipse(points[0], 3, 3); gc.setPen(Qt::red); gc.drawEllipse(points[points.count() - 1], 2, 2); - for (QRect& r : m_lazyTileFilter.tiles()) { + for (QRect &r : m_lazyTileFilter.tiles() ) { gc.drawRect(r); } img.save("result.png"); } // KisMagneticWorker::saveTheImage