1 #include <wrap/qt/outline2_rasterizer.h>
2 #include <wrap/qt/col_qt_convert.h>
3 #include <vcg/space/color4.h>
4 #include <wrap/qt/col_qt_convert.h>
5
6 #include <fstream>
7
8 using namespace vcg;
9 using namespace std;
10
rasterize(RasterizedOutline2 & poly,float scale,int rast_i,int rotationNum,int gutterWidth)11 void QtOutline2Rasterizer::rasterize(RasterizedOutline2 &poly,
12 float scale,
13 int rast_i,
14 int rotationNum,
15 int gutterWidth)
16 {
17
18 gutterWidth *= 2; // since the brush is centered on the outline multiply the given value by 2
19
20 float rotRad = M_PI*2.0f*float(rast_i) / float(rotationNum);
21
22 //get polygon's BB, rotated according to the input parameter
23 Box2f bb;
24 vector<Point2f> pointvec = poly.getPoints();
25 for(size_t i=0;i<pointvec.size();++i) {
26 Point2f pp=pointvec[i];
27 pp.Rotate(rotRad);
28 bb.Add(pp);
29 }
30
31 //create the polygon to print it
32 QVector<QPointF> points;
33 vector<Point2f> newpoints = poly.getPoints();
34 for (size_t i = 0; i < newpoints.size(); i++) {
35 points.push_back(QPointF(newpoints[i].X(), newpoints[i].Y()));
36 }
37
38 // Compute the raster space size by rounding up the scaled bounding box size
39 // and adding the gutter width.
40 int sizeX = (int)ceil(bb.DimX()*scale);
41 int sizeY = (int)ceil(bb.DimY()*scale);
42 int safetyBuffer = 2;
43 sizeX += (gutterWidth + safetyBuffer);
44 sizeY += (gutterWidth + safetyBuffer);
45
46 QImage img(sizeX,sizeY,QImage::Format_RGB32);
47 QColor backgroundColor(Qt::transparent);
48 img.fill(backgroundColor);
49
50 ///SETUP OF DRAWING PROCEDURE
51 QPainter painter;
52 painter.begin(&img);
53 {
54 QBrush br;
55 br.setStyle(Qt::SolidPattern);
56 br.setColor(Qt::yellow);
57
58 QPen qp;
59 qp.setWidthF(0);
60 qp.setWidth(gutterWidth);
61 qp.setCosmetic(true);
62 qp.setColor(Qt::yellow);
63 qp.setJoinStyle(Qt::MiterJoin);
64 qp.setMiterLimit(0);
65
66 painter.setBrush(br);
67 painter.setPen(qp);
68
69 painter.resetTransform();
70 painter.translate(QPointF(-(bb.min.X()*scale) + (gutterWidth + safetyBuffer)/2.0f, -(bb.min.Y()*scale) + (gutterWidth + safetyBuffer)/2.0f));
71 painter.rotate(math::ToDeg(rotRad));
72 painter.scale(scale,scale);
73
74 painter.drawPolygon(QPolygonF(points));
75 }
76 painter.end();
77
78 // workaround/hack to avoid ``disappearing'' primitives: use a cosmetic pen to
79 // draw the poly boundary.
80 // The proper way to do this would be to use conservative reasterization, which
81 // Qt doesn't seem to support
82 std::vector<QPointF> lines;
83 for (int i = 1; i < points.size(); ++i) {
84 lines.push_back(points[i-1]);
85 lines.push_back(points[i]);
86 }
87 lines.push_back(points.back());
88 lines.push_back(points.front());
89
90 painter.begin(&img);
91 {
92 QBrush br;
93 br.setStyle(Qt::SolidPattern);
94 br.setColor(Qt::yellow);
95
96 QPen qp;
97 qp.setWidthF(0);
98 qp.setWidth(std::max(1, gutterWidth));
99 qp.setCosmetic(true);
100 qp.setColor(Qt::yellow);
101
102 painter.setBrush(br);
103 painter.setPen(qp);
104
105 painter.resetTransform();
106 painter.translate(QPointF(-(bb.min.X()*scale) + (gutterWidth + safetyBuffer)/2.0f, -(bb.min.Y()*scale) + (gutterWidth + safetyBuffer)/2.0f));
107 painter.rotate(math::ToDeg(rotRad));
108 painter.scale(scale,scale);
109
110 //painter.drawPoints(QPolygonF(points));
111 painter.drawLines(lines.data(), lines.size()/2);
112 }
113 painter.end();
114
115 // Cropping
116
117 /*
118 // Slower version
119 int minX = img.width();
120 int minY = img.height();
121 int maxX = -1;
122 int maxY = -1;
123
124 for (int i = 0; i < img.height(); ++i) {
125 const QRgb *line = reinterpret_cast<const QRgb*>(img.scanLine(i));
126 for (int j = 0; j < img.width(); ++j) {
127 if (line[j] != backgroundColor.rgb()) {
128 if (j < minX) minX = j;
129 if (j > maxX) maxX = j;
130 if (i < minY) minY = i;
131 if (i > maxY) maxY = i;
132 }
133 }
134 }
135 */
136
137 int minX = img.width();
138 int minY = img.height();
139 int maxX = 0;
140 int maxY = 0;
141
142 for (int i = 0; i < img.height(); ++i) {
143 const QRgb *line = reinterpret_cast<const QRgb*>(img.scanLine(i));
144 for (int j = 0; j < img.width(); ++j) {
145 if (line[j] != backgroundColor.rgb()) {
146 minY = i;
147 break;
148 }
149 }
150 if (minY < img.height()) break;
151 }
152
153 for (int i = img.height() - 1; i >= 0; --i) {
154 const QRgb *line = reinterpret_cast<const QRgb*>(img.scanLine(i));
155 for (int j = 0; j < img.width(); ++j) {
156 if (line[j] != backgroundColor.rgb()) {
157 maxY = i;
158 break;
159 }
160 }
161 if (maxY > 0) break;
162 }
163
164 for (int i = minY; i <= maxY; ++i) {
165 const QRgb *line = reinterpret_cast<const QRgb*>(img.scanLine(i));
166 for (int j = 0; j < minX; ++j)
167 if (line[j] != backgroundColor.rgb() && j < minX) {
168 minX = j;
169 break;
170 }
171 for (int j = img.width() - 1; j >= maxX; --j)
172 if (line[j] != backgroundColor.rgb() && j > maxX) {
173 maxX = j;
174 break;
175 }
176 }
177
178 assert (minX <= maxX && minY <= maxY);
179
180 int imgW = (maxX - minX) + 1;
181 int imgH = (maxY - minY) + 1;
182
183 {
184 QImage imgcp = img.copy(0, 0, img.width(), img.height());
185 img = imgcp.copy(minX, minY, imgW, imgH);
186 }
187
188 //create the first grid, which will then be rotated 3 times.
189 //we will reuse this grid to create the rasterizations corresponding to this one rotated by 90/180/270°
190 vector<vector<int> > tetrisGrid;
191 QRgb yellow = QColor(Qt::yellow).rgb();
192 tetrisGrid.resize(img.height());
193 for (int k = 0; k < img.height(); k++) {
194 tetrisGrid[k].resize(img.width(), 0);
195 }
196 for (int y = 0; y < img.height(); y++) {
197 const uchar* line = img.scanLine(y);
198 for(int x = 0; x < img.width(); ++x) {
199 if (((QRgb*)line)[x] == yellow) {
200 tetrisGrid[y][x] = 1;
201 }
202 }
203 }
204
205 //create the 4 rasterizations (one every 90°) using the discrete representation grid we've just created
206 int rotationOffset = rotationNum/4;
207 for (int j = 0; j < 4; j++) {
208 if (j != 0) {
209 tetrisGrid = rotateGridCWise(tetrisGrid);
210 }
211 //add the grid to the poly's vector of grids
212 poly.getGrids(rast_i + rotationOffset*j) = tetrisGrid;
213
214 //initializes bottom/left/deltaX/deltaY vectors of the poly, for the current rasterization
215 poly.initFromGrid(rast_i + rotationOffset*j);
216 }
217 }
218
219 // rotates the grid 90 degree clockwise (by simple swap)
220 // used to lower the cost of rasterization.
rotateGridCWise(vector<vector<int>> & inGrid)221 vector<vector<int> > QtOutline2Rasterizer::rotateGridCWise(vector< vector<int> >& inGrid) {
222 vector<vector<int> > outGrid(inGrid[0].size());
223 for (size_t i = 0; i < inGrid[0].size(); i++) {
224 outGrid[i].reserve(inGrid.size());
225 for (size_t j = 0; j < inGrid.size(); j++) {
226 outGrid[i].push_back(inGrid[inGrid.size() - j - 1][i]);
227 }
228 }
229 return outGrid;
230 }
231