QPainterPath SmoothCurveCreator::createSmoothCurve(const QList<QPointF> &points) { QPainterPath path; int len = points.size(); if (len < 2) { return path; } QList<QPointF> firstControlPoints; QList<QPointF> secondControlPoints; calculateControlPoints(points, &firstControlPoints, &secondControlPoints); path.moveTo(points[0].x(), points[0].y()); // Using bezier curve to gelnerate a smooth curve. for (int i = 0; i < len - 1; ++i) { path.cubicTo(firstControlPoints[i], secondControlPoints[i], points[i+1]); } return path; }
void QgsCubicRasterResampler::resample( const QImage& srcImage, QImage& dstImage ) { int nCols = srcImage.width(); int nRows = srcImage.height(); int pos = 0; QRgb px; int *redMatrix = new int[ nCols * nRows ]; int *greenMatrix = new int[ nCols * nRows ]; int *blueMatrix = new int[ nCols * nRows ]; int *alphaMatrix = new int[ nCols * nRows ]; for ( int heightIndex = 0; heightIndex < nRows; ++heightIndex ) { QRgb* scanLine = ( QRgb* )srcImage.constScanLine( heightIndex ); for ( int widthIndex = 0; widthIndex < nCols; ++widthIndex ) { px = scanLine[widthIndex]; int alpha = qAlpha( px ); alphaMatrix[pos] = alpha; redMatrix[pos] = qRed( px ); greenMatrix[pos] = qGreen( px ); blueMatrix[pos] = qBlue( px ); pos++; } } //derivative x double* xDerivativeMatrixRed = new double[ nCols * nRows ]; xDerivativeMatrix( nCols, nRows, xDerivativeMatrixRed, redMatrix ); double* xDerivativeMatrixGreen = new double[ nCols * nRows ]; xDerivativeMatrix( nCols, nRows, xDerivativeMatrixGreen, greenMatrix ); double* xDerivativeMatrixBlue = new double[ nCols * nRows ]; xDerivativeMatrix( nCols, nRows, xDerivativeMatrixBlue, blueMatrix ); double* xDerivativeMatrixAlpha = new double[ nCols * nRows ]; xDerivativeMatrix( nCols, nRows, xDerivativeMatrixAlpha, alphaMatrix ); //derivative y double* yDerivativeMatrixRed = new double[ nCols * nRows ]; yDerivativeMatrix( nCols, nRows, yDerivativeMatrixRed, redMatrix ); double* yDerivativeMatrixGreen = new double[ nCols * nRows ]; yDerivativeMatrix( nCols, nRows, yDerivativeMatrixGreen, greenMatrix ); double* yDerivativeMatrixBlue = new double[ nCols * nRows ]; yDerivativeMatrix( nCols, nRows, yDerivativeMatrixBlue, blueMatrix ); double* yDerivativeMatrixAlpha = new double[ nCols * nRows ]; yDerivativeMatrix( nCols, nRows, yDerivativeMatrixAlpha, alphaMatrix ); //compute output double nSrcPerDstX = ( double ) srcImage.width() / ( double ) dstImage.width(); double nSrcPerDstY = ( double ) srcImage.height() / ( double ) dstImage.height(); double currentSrcRow = nSrcPerDstY / 2.0 - 0.5; double currentSrcCol; int currentSrcColInt; int currentSrcRowInt; int lastSrcColInt = -100; int lastSrcRowInt = -100; //bernstein polynomials double bp0u, bp1u, bp2u, bp3u, bp0v, bp1v, bp2v, bp3v; double u, v; for ( int y = 0; y < dstImage.height(); ++y ) { currentSrcRowInt = floor( currentSrcRow ); v = currentSrcRow - currentSrcRowInt; currentSrcCol = nSrcPerDstX / 2.0 - 0.5; QRgb* scanLine = ( QRgb* )dstImage.scanLine( y ); for ( int x = 0; x < dstImage.width(); ++x ) { currentSrcColInt = floor( currentSrcCol ); u = currentSrcCol - currentSrcColInt; //handle eight edge-cases if (( currentSrcRowInt < 0 || currentSrcRowInt >= ( srcImage.height() - 1 ) || currentSrcColInt < 0 || currentSrcColInt >= ( srcImage.width() - 1 ) ) ) { QRgb px1, px2; //pixels at the border of the source image needs to be handled in a special way if ( currentSrcRowInt < 0 && currentSrcColInt < 0 ) { scanLine[x] = srcImage.pixel( 0, 0 ); } else if ( currentSrcRowInt < 0 && currentSrcColInt >= ( srcImage.width() - 1 ) ) { scanLine[x] = srcImage.pixel( srcImage.width() - 1, 0 ); } else if ( currentSrcRowInt >= ( srcImage.height() - 1 ) && currentSrcColInt >= ( srcImage.width() - 1 ) ) { scanLine[x] = srcImage.pixel( srcImage.width() - 1, srcImage.height() - 1 ); } else if ( currentSrcRowInt >= ( srcImage.height() - 1 ) && currentSrcColInt < 0 ) { scanLine[x] = srcImage.pixel( 0, srcImage.height() - 1 ); } else if ( currentSrcRowInt < 0 ) { px1 = srcImage.pixel( currentSrcColInt, 0 ); px2 = srcImage.pixel( currentSrcColInt + 1, 0 ); scanLine[x] = curveInterpolation( px1, px2, u, xDerivativeMatrixRed[ currentSrcColInt ], xDerivativeMatrixGreen[ currentSrcColInt ], xDerivativeMatrixBlue[ currentSrcColInt ], xDerivativeMatrixAlpha[ currentSrcColInt ], xDerivativeMatrixRed[ currentSrcColInt + 1 ], xDerivativeMatrixGreen[ currentSrcColInt + 1 ], xDerivativeMatrixBlue[ currentSrcColInt + 1 ], xDerivativeMatrixAlpha[ currentSrcColInt + 1 ] ); } else if ( currentSrcRowInt >= ( srcImage.height() - 1 ) ) { int idx = ( srcImage.height() - 1 ) * srcImage.width() + currentSrcColInt; px1 = srcImage.pixel( currentSrcColInt, srcImage.height() - 1 ); px2 = srcImage.pixel( currentSrcColInt + 1, srcImage.height() - 1 ); scanLine[x] = curveInterpolation( px1, px2, u, xDerivativeMatrixRed[ idx ], xDerivativeMatrixGreen[ idx ], xDerivativeMatrixBlue[idx], xDerivativeMatrixAlpha[idx], xDerivativeMatrixRed[ idx + 1 ], xDerivativeMatrixGreen[ idx + 1 ], xDerivativeMatrixBlue[idx + 1], xDerivativeMatrixAlpha[idx + 1] ); } else if ( currentSrcColInt < 0 ) { int idx1 = currentSrcRowInt * srcImage.width(); int idx2 = idx1 + srcImage.width(); px1 = srcImage.pixel( 0, currentSrcRowInt ); px2 = srcImage.pixel( 0, currentSrcRowInt + 1 ); scanLine[x] = curveInterpolation( px1, px2, v, yDerivativeMatrixRed[ idx1 ], yDerivativeMatrixGreen[ idx1 ], yDerivativeMatrixBlue[ idx1], yDerivativeMatrixAlpha[ idx1], yDerivativeMatrixRed[ idx2 ], yDerivativeMatrixGreen[ idx2 ], yDerivativeMatrixBlue[ idx2], yDerivativeMatrixAlpha[ idx2] ); } else if ( currentSrcColInt >= ( srcImage.width() - 1 ) ) { int idx1 = currentSrcRowInt * srcImage.width() + srcImage.width() - 1; int idx2 = idx1 + srcImage.width(); px1 = srcImage.pixel( srcImage.width() - 1, currentSrcRowInt ); px2 = srcImage.pixel( srcImage.width() - 1, currentSrcRowInt + 1 ); scanLine[x] = curveInterpolation( px1, px2, v, yDerivativeMatrixRed[ idx1 ], yDerivativeMatrixGreen[ idx1 ], yDerivativeMatrixBlue[ idx1], yDerivativeMatrixAlpha[ idx1], yDerivativeMatrixRed[ idx2 ], yDerivativeMatrixGreen[ idx2 ], yDerivativeMatrixBlue[ idx2], yDerivativeMatrixAlpha[ idx2] ); } currentSrcCol += nSrcPerDstX; continue; } //first update the control points if necessary if ( currentSrcColInt != lastSrcColInt || currentSrcRowInt != lastSrcRowInt ) { calculateControlPoints( nCols, nRows, currentSrcRowInt, currentSrcColInt, redMatrix, greenMatrix, blueMatrix, alphaMatrix, xDerivativeMatrixRed, xDerivativeMatrixGreen, xDerivativeMatrixBlue, xDerivativeMatrixAlpha, yDerivativeMatrixRed, yDerivativeMatrixGreen, yDerivativeMatrixBlue, yDerivativeMatrixAlpha ); } //bernstein polynomials bp0u = calcBernsteinPolyN3( 0, u ); bp1u = calcBernsteinPolyN3( 1, u ); bp2u = calcBernsteinPolyN3( 2, u ); bp3u = calcBernsteinPolyN3( 3, u ); bp0v = calcBernsteinPolyN3( 0, v ); bp1v = calcBernsteinPolyN3( 1, v ); bp2v = calcBernsteinPolyN3( 2, v ); bp3v = calcBernsteinPolyN3( 3, v ); //then calculate value based on bernstein form of Bezier patch //todo: move into function int r = bp0u * bp0v * cRed00 + bp1u * bp0v * cRed10 + bp2u * bp0v * cRed20 + bp3u * bp0v * cRed30 + bp0u * bp1v * cRed01 + bp1u * bp1v * cRed11 + bp2u * bp1v * cRed21 + bp3u * bp1v * cRed31 + bp0u * bp2v * cRed02 + bp1u * bp2v * cRed12 + bp2u * bp2v * cRed22 + bp3u * bp2v * cRed32 + bp0u * bp3v * cRed03 + bp1u * bp3v * cRed13 + bp2u * bp3v * cRed23 + bp3u * bp3v * cRed33; int g = bp0u * bp0v * cGreen00 + bp1u * bp0v * cGreen10 + bp2u * bp0v * cGreen20 + bp3u * bp0v * cGreen30 + bp0u * bp1v * cGreen01 + bp1u * bp1v * cGreen11 + bp2u * bp1v * cGreen21 + bp3u * bp1v * cGreen31 + bp0u * bp2v * cGreen02 + bp1u * bp2v * cGreen12 + bp2u * bp2v * cGreen22 + bp3u * bp2v * cGreen32 + bp0u * bp3v * cGreen03 + bp1u * bp3v * cGreen13 + bp2u * bp3v * cGreen23 + bp3u * bp3v * cGreen33; int b = bp0u * bp0v * cBlue00 + bp1u * bp0v * cBlue10 + bp2u * bp0v * cBlue20 + bp3u * bp0v * cBlue30 + bp0u * bp1v * cBlue01 + bp1u * bp1v * cBlue11 + bp2u * bp1v * cBlue21 + bp3u * bp1v * cBlue31 + bp0u * bp2v * cBlue02 + bp1u * bp2v * cBlue12 + bp2u * bp2v * cBlue22 + bp3u * bp2v * cBlue32 + bp0u * bp3v * cBlue03 + bp1u * bp3v * cBlue13 + bp2u * bp3v * cBlue23 + bp3u * bp3v * cBlue33; int a = bp0u * bp0v * cAlpha00 + bp1u * bp0v * cAlpha10 + bp2u * bp0v * cAlpha20 + bp3u * bp0v * cAlpha30 + bp0u * bp1v * cAlpha01 + bp1u * bp1v * cAlpha11 + bp2u * bp1v * cAlpha21 + bp3u * bp1v * cAlpha31 + bp0u * bp2v * cAlpha02 + bp1u * bp2v * cAlpha12 + bp2u * bp2v * cAlpha22 + bp3u * bp2v * cAlpha32 + bp0u * bp3v * cAlpha03 + bp1u * bp3v * cAlpha13 + bp2u * bp3v * cAlpha23 + bp3u * bp3v * cAlpha33; scanLine[x] = createPremultipliedColor( r, g, b, a ); lastSrcColInt = currentSrcColInt; currentSrcCol += nSrcPerDstX; } lastSrcRowInt = currentSrcRowInt; currentSrcRow += nSrcPerDstY; } //cleanup memory delete[] redMatrix; delete[] greenMatrix; delete[] blueMatrix; delete[] alphaMatrix; delete[] xDerivativeMatrixRed; delete[] xDerivativeMatrixGreen; delete[] xDerivativeMatrixBlue; delete[] xDerivativeMatrixAlpha; delete[] yDerivativeMatrixRed; delete[] yDerivativeMatrixGreen; delete[] yDerivativeMatrixBlue; delete[] yDerivativeMatrixAlpha; }