#include #include #include #include #include using namespace vcg; using namespace std; void QtOutline2Rasterizer::rasterize(RasterizedOutline2 &poly, float scale, int rast_i, int rotationNum, int gutterWidth) { gutterWidth *= 2; // since the brush is centered on the outline multiply the given value by 2 float rotRad = M_PI*2.0f*float(rast_i) / float(rotationNum); //get polygon's BB, rotated according to the input parameter Box2f bb; vector pointvec = poly.getPoints(); for(size_t i=0;i points; vector newpoints = poly.getPoints(); for (size_t i = 0; i < newpoints.size(); i++) { points.push_back(QPointF(newpoints[i].X(), newpoints[i].Y())); } // Compute the raster space size by rounding up the scaled bounding box size // and adding the gutter width. int sizeX = (int)ceil(bb.DimX()*scale); int sizeY = (int)ceil(bb.DimY()*scale); int safetyBuffer = 2; sizeX += (gutterWidth + safetyBuffer); sizeY += (gutterWidth + safetyBuffer); QImage img(sizeX,sizeY,QImage::Format_RGB32); QColor backgroundColor(Qt::transparent); img.fill(backgroundColor); ///SETUP OF DRAWING PROCEDURE QPainter painter; painter.begin(&img); { QBrush br; br.setStyle(Qt::SolidPattern); br.setColor(Qt::yellow); QPen qp; qp.setWidthF(0); qp.setWidth(gutterWidth); qp.setCosmetic(true); qp.setColor(Qt::yellow); qp.setJoinStyle(Qt::MiterJoin); qp.setMiterLimit(0); painter.setBrush(br); painter.setPen(qp); painter.resetTransform(); painter.translate(QPointF(-(bb.min.X()*scale) + (gutterWidth + safetyBuffer)/2.0f, -(bb.min.Y()*scale) + (gutterWidth + safetyBuffer)/2.0f)); painter.rotate(math::ToDeg(rotRad)); painter.scale(scale,scale); painter.drawPolygon(QPolygonF(points)); } painter.end(); // workaround/hack to avoid ``disappearing'' primitives: use a cosmetic pen to // draw the poly boundary. // The proper way to do this would be to use conservative reasterization, which // Qt doesn't seem to support std::vector lines; for (int i = 1; i < points.size(); ++i) { lines.push_back(points[i-1]); lines.push_back(points[i]); } lines.push_back(points.back()); lines.push_back(points.front()); painter.begin(&img); { QBrush br; br.setStyle(Qt::SolidPattern); br.setColor(Qt::yellow); QPen qp; qp.setWidthF(0); qp.setWidth(std::max(1, gutterWidth)); qp.setCosmetic(true); qp.setColor(Qt::yellow); painter.setBrush(br); painter.setPen(qp); painter.resetTransform(); painter.translate(QPointF(-(bb.min.X()*scale) + (gutterWidth + safetyBuffer)/2.0f, -(bb.min.Y()*scale) + (gutterWidth + safetyBuffer)/2.0f)); painter.rotate(math::ToDeg(rotRad)); painter.scale(scale,scale); //painter.drawPoints(QPolygonF(points)); painter.drawLines(lines.data(), lines.size()/2); } painter.end(); // Cropping /* // Slower version int minX = img.width(); int minY = img.height(); int maxX = -1; int maxY = -1; for (int i = 0; i < img.height(); ++i) { const QRgb *line = reinterpret_cast(img.scanLine(i)); for (int j = 0; j < img.width(); ++j) { if (line[j] != backgroundColor.rgb()) { if (j < minX) minX = j; if (j > maxX) maxX = j; if (i < minY) minY = i; if (i > maxY) maxY = i; } } } */ int minX = img.width(); int minY = img.height(); int maxX = 0; int maxY = 0; for (int i = 0; i < img.height(); ++i) { const QRgb *line = reinterpret_cast(img.scanLine(i)); for (int j = 0; j < img.width(); ++j) { if (line[j] != backgroundColor.rgb()) { minY = i; break; } } if (minY < img.height()) break; } for (int i = img.height() - 1; i >= 0; --i) { const QRgb *line = reinterpret_cast(img.scanLine(i)); for (int j = 0; j < img.width(); ++j) { if (line[j] != backgroundColor.rgb()) { maxY = i; break; } } if (maxY > 0) break; } for (int i = minY; i <= maxY; ++i) { const QRgb *line = reinterpret_cast(img.scanLine(i)); for (int j = 0; j < minX; ++j) if (line[j] != backgroundColor.rgb() && j < minX) { minX = j; break; } for (int j = img.width() - 1; j >= maxX; --j) if (line[j] != backgroundColor.rgb() && j > maxX) { maxX = j; break; } } assert (minX <= maxX && minY <= maxY); int imgW = (maxX - minX) + 1; int imgH = (maxY - minY) + 1; { QImage imgcp = img.copy(0, 0, img.width(), img.height()); img = imgcp.copy(minX, minY, imgW, imgH); } //create the first grid, which will then be rotated 3 times. //we will reuse this grid to create the rasterizations corresponding to this one rotated by 90/180/270° vector > tetrisGrid; QRgb yellow = QColor(Qt::yellow).rgb(); tetrisGrid.resize(img.height()); for (int k = 0; k < img.height(); k++) { tetrisGrid[k].resize(img.width(), 0); } for (int y = 0; y < img.height(); y++) { const uchar* line = img.scanLine(y); for(int x = 0; x < img.width(); ++x) { if (((QRgb*)line)[x] == yellow) { tetrisGrid[y][x] = 1; } } } //create the 4 rasterizations (one every 90°) using the discrete representation grid we've just created int rotationOffset = rotationNum/4; for (int j = 0; j < 4; j++) { if (j != 0) { tetrisGrid = rotateGridCWise(tetrisGrid); } //add the grid to the poly's vector of grids poly.getGrids(rast_i + rotationOffset*j) = tetrisGrid; //initializes bottom/left/deltaX/deltaY vectors of the poly, for the current rasterization poly.initFromGrid(rast_i + rotationOffset*j); } } // rotates the grid 90 degree clockwise (by simple swap) // used to lower the cost of rasterization. vector > QtOutline2Rasterizer::rotateGridCWise(vector< vector >& inGrid) { vector > outGrid(inGrid[0].size()); for (size_t i = 0; i < inGrid[0].size(); i++) { outGrid[i].reserve(inGrid.size()); for (size_t j = 0; j < inGrid.size(); j++) { outGrid[i].push_back(inGrid[inGrid.size() - j - 1][i]); } } return outGrid; }