Changeset 73 for trunk/src/canvas/qcanvas.cpp
- Timestamp:
- Mar 24, 2006, 12:46:08 AM (19 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/canvas/qcanvas.cpp
r71 r73 49 49 #include <stdlib.h> 50 50 51 //#define QT_NO_CANVAS_ROUNDING_FIX 52 53 #if !defined(QT_NO_TRANSFORMATIONS) && !defined(QT_NO_CANVAS_ROUNDING_FIX) 54 #include <math.h> 55 #endif 56 51 57 class QCanvasData { 52 58 public: … … 108 114 } 109 115 } 116 117 #if !defined(QT_NO_TRANSFORMATIONS) && !defined(QT_NO_CANVAS_ROUNDING_FIX) 118 119 /*! 120 * \internal 121 * 122 * Takes inclusive top left and exclusive bottom right poitns of the given 123 * rectangle, translates it using the given matrix, calculates the bounding 124 * rectangle and converts resulting doubles to integers so that points of the 125 * target raster partially covered by resulting double points are included 126 * to the resulting rectangle. 127 * 128 * Using this function instead of QWMatrix::map(const QRect&) eliminates many 129 * artefacts and distortions seen in canvas views that use world transformation. 130 * When scaling up, this function works merely as QWMatrix::map() with 131 * transformation mode set to Areas, but it also produces correct rectangles 132 * (as necessary to determine affected chunks) in all other cases. 133 */ 134 static 135 QRect mapRectMax( const QWMatrix &m, const QRect &r ) 136 { 137 if ( m.isIdentity() ) { 138 return r; 139 } 140 141 QRect rect = r; 142 143 // make bottom right exclusive 144 ++ rect.rBottom(); 145 ++ rect.rRight(); 146 147 double x1, y1, x2, y2; 148 149 if ( m.m12() == 0.0 && m.m21() == 0.0 ) { 150 // no shear or rotation, map two coords 151 m.map( rect.left(), rect.top(), &x1, &y1 ); 152 m.map( rect.right(), rect.bottom(), &x2, &y2 ); 153 } else { 154 double xl = rect.left(), yt = rect.top(); 155 double xr = rect.right(), yb = rect.bottom(); 156 double x, y; 157 // map four coords and find min/max 158 m.map( xl, yt, &x, &y ); 159 x1 = x; 160 y1 = y; 161 x2 = x; 162 y2 = y; 163 m.map( xr, yt, &x, &y ); 164 x1 = QMIN( x1, x ); 165 y1 = QMIN( y1, y ); 166 x2 = QMAX( x2, x ); 167 y2 = QMAX( y2, y ); 168 m.map( xl, yb, &x, &y ); 169 x1 = QMIN( x1, x ); 170 y1 = QMIN( y1, y ); 171 x2 = QMAX( x2, x ); 172 y2 = QMAX( y2, y ); 173 m.map( xr, yb, &x, &y ); 174 x1 = QMIN( x1, x ); 175 y1 = QMIN( y1, y ); 176 x2 = QMAX( x2, x ); 177 y2 = QMAX( y2, y ); 178 } 179 180 // get integers (partially covered points are included) 181 x1 = floor( x1 ); 182 y1 = floor( y1 ); 183 x2 = ceil( x2 ); 184 y2 = ceil( y2 ); 185 186 // compose the result 187 rect.setCoords( int( x1 ), int( y1 ), int( x2 ), int( y2 ) ); 188 // make bottom right inclusive again 189 -- rect.rBottom(); 190 -- rect.rRight(); 191 192 return rect; 193 } 194 195 /*! 196 * \internal 197 * 198 * Similar to mapRectMax, but with the opposite meaning. Tries to return 199 * a region that is completely inside the given rectangle after transformation. 200 * \a br is the target bounding rectangle (to minimize calculations). 201 * 202 * Using this function to clip out areas of the canvas view not covered by the 203 * canvas eliminates garbage at canvas edges that can be well seen when the 204 * canvas is rotated in the view. 205 */ 206 static 207 QRegion mapRectMin( const QWMatrix &m, const QRect &r, const QRect &br ) 208 { 209 QRegion rgn; 210 211 if ( m.isIdentity() ) { 212 rgn = QRegion( r ); 213 return rgn; 214 } 215 216 if ( m.m12() == 0.0 && m.m21() == 0.0 ) { 217 QRect rect = r; 218 // make bottom right exclusive 219 ++ rect.rBottom(); 220 ++ rect.rRight(); 221 double x1, y1, x2, y2; 222 // no shear or rotation, map two coords 223 m.map( rect.left(), rect.top(), &x1, &y1 ); 224 m.map( rect.right(), rect.bottom(), &x2, &y2 ); 225 // get integers (partially covered points are excluded) 226 x1 = ceil( x1 ); 227 y1 = ceil( y1 ); 228 x2 = floor( x2 ); 229 y2 = floor( y2 ); 230 // compose the result 231 rect.setCoords( int( x1 ), int( y1 ), int( x2 ), int( y2 ) ); 232 // make bottom right inclusive again 233 -- rect.rBottom(); 234 -- rect.rRight(); 235 rgn = QRegion( rect ); 236 } else { 237 // make the rectangle smaller to compensate for differences in 238 // line drawing routines of the underlying OS (when defining regions 239 // from polygons) and by Qt tansformations (when transforming images 240 // or when determining invalid chunks) 241 QPointArray pa( r ); 242 pa = m.map( pa ); 243 rgn = QRegion( pa ); 244 // limit to the bounding rect (expanded to compensate shifts) 245 QRect rect = br; 246 rect.addCoords( -1, 0, 1, 0 ); 247 rgn &= QRegion( rect ); 248 // create a copy of the region and shift each towards other by 1 pixel 249 // to compensate for (clip out) differences in line drawing routines of 250 // the underlying OS (when defining regions from polygons) and in Qt 251 // tansformation routines (when transforming images or when determining 252 // invalid chunks) 253 QRegion rgn2 = rgn; 254 rgn.translate( 1, 0 ); 255 rgn2.translate( -1, 0 ); 256 // take an intersection 257 rgn &= rgn2; 258 } 259 260 return rgn; 261 } 262 263 #endif 110 264 111 265 /* … … 1069 1223 QWMatrix iwm = wm.invert(); 1070 1224 // ivr = covers all chunks in vr 1225 #if !defined(QT_NO_CANVAS_ROUNDING_FIX) 1226 QRect ivr = vr; 1227 if ( wm.m12() != 0.0 || wm.m21() != 0.0 ) { 1228 // compensate for rounding errors happening on the path 1229 // update() -> drawViewArea() after many transformations (can be seen 1230 // when moving items in a canvas view that makes the canvas smaller 1231 // and rotates it to ~270 degress clockwise) 1232 ivr.addCoords( -1, -1, 1, 1 ); 1233 } 1234 ivr = mapRectMax( iwm, ivr ); 1235 #else 1071 1236 QRect ivr = iwm.map(vr); 1237 #endif 1072 1238 QWMatrix twm; 1073 1239 twm.translate(tl.x(),tl.y()); … … 1082 1248 1083 1249 #ifndef QT_NO_TRANSFORMATIONS 1250 #if !defined(QT_NO_CANVAS_ROUNDING_FIX) 1251 QRect cvr = vr; cvr.moveBy(tl.x(),tl.y()); 1252 QRegion ra = mapRectMin( wm * twm, all, cvr ); 1253 #else 1084 1254 #if !defined(Q_WS_PM) 1085 1255 // For translation-only transformation, it is safe to include the right … … 1092 1262 a = QPointArray( all ); 1093 1263 #else 1094 // Polygons on OS/2 already include the right and bottom edges1264 // Polygons in OS/2 already include the right and bottom edges 1095 1265 // (why shouldn't they do that?) Indeed, this important moment is not 1096 1266 // defined in Qt at all. 1097 1267 QPointArray a( all ); 1098 1268 #endif 1099 1100 1269 a = (wm*twm).map(a); 1270 #endif 1101 1271 #else 1102 1272 #if !defined(Q_WS_PM) … … 1107 1277 #endif 1108 1278 if ( view->viewport()->backgroundMode() == NoBackground ) { 1279 #if !defined(QT_NO_CANVAS_ROUNDING_FIX) 1280 p->setClipRegion( QRegion( cvr ) - ra ); 1281 #else 1109 1282 QRect cvr = vr; cvr.moveBy(tl.x(),tl.y()); 1110 1283 p->setClipRegion(QRegion(cvr)-QRegion(a)); 1284 #endif 1111 1285 p->fillRect(vr,view->viewport()->palette() 1112 1286 .brush(QPalette::Active,QColorGroup::Background)); 1113 1287 } 1288 #if !defined(QT_NO_CANVAS_ROUNDING_FIX) 1289 p->setClipRegion( ra ); 1290 #else 1114 1291 p->setClipRegion(a); 1292 #endif 1115 1293 } 1116 1294 … … 1174 1352 if ( !wm.isIdentity() ) { 1175 1353 // r = Visible area of the canvas where there are changes 1354 #if !defined(QT_NO_CANVAS_ROUNDING_FIX) 1355 QRect r = changeBounds( mapRectMax( view->inverseWorldMatrix(), 1356 area ) ); 1357 #else 1176 1358 QRect r = changeBounds(view->inverseWorldMatrix().map(area)); 1359 #endif 1177 1360 if ( !r.isEmpty() ) { 1178 1361 QPainter p(view->viewport()); … … 1180 1363 QPoint tl = view->contentsToViewport(QPoint(0,0)); 1181 1364 p.translate(tl.x(),tl.y()); 1365 #if !defined(QT_NO_CANVAS_ROUNDING_FIX) 1366 drawViewArea( view, &p, mapRectMax( wm, r ), dblbuf ); 1367 #else 1182 1368 drawViewArea( view, &p, wm.map(r), dblbuf ); 1369 #endif 1183 1370 doneareas.append(new QRect(r)); 1184 1371 }
Note:
See TracChangeset
for help on using the changeset viewer.