File: outline2_rasterizer.cpp

package info (click to toggle)
meshlab 2020.09%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 45,132 kB
  • sloc: cpp: 400,238; ansic: 31,952; javascript: 1,578; sh: 387; yacc: 238; lex: 139; python: 86; makefile: 30
file content (230 lines) | stat: -rw-r--r-- 7,291 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#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;
}