vcglib/wrap/qt/outline2_rasterizer.cpp

231 lines
7.1 KiB
C++

#include <wrap/qt/outline2_rasterizer.h>
#include <wrap/qt/col_qt_convert.h>
#include <vcg/space/color4.h>
#include <wrap/qt/col_qt_convert.h>
#include <fstream>
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<Point2f> pointvec = poly.getPoints();
for(size_t i=0;i<pointvec.size();++i) {
Point2f pp=pointvec[i];
pp.Rotate(rotRad);
bb.Add(pp);
}
//create the polygon to print it
QVector<QPointF> points;
vector<Point2f> 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<QPointF> 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<const QRgb*>(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<const QRgb*>(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<const QRgb*>(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<const QRgb*>(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<vector<int> > 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<vector<int> > QtOutline2Rasterizer::rotateGridCWise(vector< vector<int> >& inGrid) {
vector<vector<int> > 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;
}