void TransformTest::testEstimateNonIsometric() { // Scaling and translation PassPointList passpoints; passpoints.resize(3); passpoints[0].src_coords = MapCoordF { 128.0, 0.0 }; passpoints[0].dest_coords = MapCoordF { 64.0, 64.0 }; passpoints[1].src_coords = MapCoordF { 256.0, 0.0 }; passpoints[1].dest_coords = MapCoordF { 96.0, 64.0 }; passpoints[2].src_coords = MapCoordF { 128.0, 128.0 }; passpoints[2].dest_coords = MapCoordF { 64.0, 96.0 }; QTransform qt; QVERIFY(passpoints.estimateNonIsometricSimilarityTransform(&qt)); QVERIFY(qt.isTranslating()); QVERIFY(qt.isScaling()); QCOMPARE(int(qt.type()), int(QTransform::TxScale)); QCOMPARE(qt.map(passpoints[0].src_coords), QPointF{passpoints[0].dest_coords}); QCOMPARE(qt.map(passpoints[1].src_coords), QPointF{passpoints[1].dest_coords}); QCOMPARE(qt.map(passpoints[2].src_coords), QPointF{passpoints[2].dest_coords}); auto t = TemplateTransform::fromQTransform(qt); QCOMPARE(t.template_x, MapCoord(32,64).nativeX()); QCOMPARE(t.template_y, MapCoord(32,64).nativeY()); QCOMPARE(t.template_scale_x, 0.25); QCOMPARE(t.template_scale_y, 0.25); QVERIFY(qAbs(t.template_rotation) < 0.000001); // Rotation passpoints[0].src_coords = MapCoordF { 0.0, 0.0 }; passpoints[0].dest_coords = MapCoordF { 0.0, 0.0 }; passpoints[1].src_coords = MapCoordF { 5.0, 0.0 }; passpoints[1].dest_coords = MapCoordF { 4.0, -3.0 }; passpoints[2].src_coords = MapCoordF { 0.0, 5.0 }; passpoints[2].dest_coords = MapCoordF { 3.0, 4.0 }; QVERIFY(passpoints.estimateNonIsometricSimilarityTransform(&qt)); QVERIFY(qt.isRotating()); QCOMPARE(int(qt.type()), int(QTransform::TxRotate)); QCOMPARE(qt.map(passpoints[0].src_coords), QPointF{passpoints[0].dest_coords}); QCOMPARE(qt.map(passpoints[1].src_coords), QPointF{passpoints[1].dest_coords}); QCOMPARE(qt.map(passpoints[2].src_coords), QPointF{passpoints[2].dest_coords}); t = TemplateTransform::fromQTransform(qt); QCOMPARE(t.template_x, 0); QCOMPARE(t.template_y, 0); QCOMPARE(t.template_scale_x, 1.0); QCOMPARE(t.template_scale_y, 1.0); QCOMPARE(t.template_rotation, qAcos(passpoints[1].dest_coords.x() / passpoints[1].src_coords.x())); }
bool PictureShape::saveSvg(SvgSavingContext &context) { KoImageData *imageData = qobject_cast<KoImageData*>(userData()); if (!imageData) { qWarning() << "Picture has no image data. Omitting."; return false; } context.shapeWriter().startElement("image"); context.shapeWriter().addAttribute("id", context.getID(this)); QTransform m = transformation(); if (m.type() == QTransform::TxTranslate) { const QPointF pos = position(); context.shapeWriter().addAttributePt("x", pos.x()); context.shapeWriter().addAttributePt("y", pos.y()); } else { context.shapeWriter().addAttribute("transform", SvgUtil::transformToString(m)); } const QSizeF s = size(); context.shapeWriter().addAttributePt("width", s.width()); context.shapeWriter().addAttributePt("height", s.height()); context.shapeWriter().addAttribute("xlink:href", context.saveImage(imageData)); context.shapeWriter().endElement(); return true; }
void TransformTest::testTransformCombined() { QFETCH(int, type); QFETCH(double, rotation); qint32 dx = -3000; qint32 dy = 16000; qreal scale_x = 4.5; qreal scale_y = 2.5; QTransform qt; // Template::applyTemplateTransform order: translate, rotate, scale qt.translate(dx / 1000.0, dy / 1000.0); qt.rotate(qreal(rotation)); qt.scale(scale_x, scale_y); QVERIFY(qt.isScaling()); QCOMPARE(int(qt.type()), type); auto t = TemplateTransform::fromQTransform(qt); QCOMPARE(t.template_x, dx); QCOMPARE(t.template_y, dy); QCOMPARE(t.template_scale_x, scale_x); QCOMPARE(t.template_scale_y, scale_y); if (rotation <= 180.0) QCOMPARE(t.template_rotation, -qDegreesToRadians(qreal(rotation))); else QCOMPARE(t.template_rotation, -qDegreesToRadians(qreal(rotation - 360.0))); }
QT_BEGIN_NAMESPACE static inline bool qtransform_equals_no_translate(const QTransform &a, const QTransform &b) { if (a.type() <= QTransform::TxTranslate && b.type() <= QTransform::TxTranslate) { return true; } else { // We always use paths for perspective text anyway, so no // point in checking the full matrix... Q_ASSERT(a.type() < QTransform::TxProject); Q_ASSERT(b.type() < QTransform::TxProject); return a.m11() == b.m11() && a.m12() == b.m12() && a.m21() == b.m21() && a.m22() == b.m22(); } }
QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, Qt::TransformationMode mode) const { QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); #ifdef QT_NO_DIRECTFB_SUBSURFACE if (lockFlags()) that->unlockSurface(); #endif if (!dfbSurface || transform.type() != QTransform::TxScale || mode != Qt::FastTransformation) { const QImage *image = that->buffer(); Q_ASSERT(image); const QImage transformed = image->transformed(transform, mode); QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType); data->fromImage(transformed, Qt::AutoColor); return QPixmap(data); } const QSize size = transform.mapRect(QRect(0, 0, w, h)).size(); if (size.isEmpty()) return QPixmap(); QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType); data->setSerialNumber(++global_ser_no); DFBSurfaceBlittingFlags flags = DSBLIT_NOFX; data->alpha = alpha; if (alpha) { flags = DSBLIT_BLEND_ALPHACHANNEL; } data->dfbSurface = screen->createDFBSurface(size, imageFormat, QDirectFBScreen::TrackSurface); if (flags & DSBLIT_BLEND_ALPHACHANNEL) { data->dfbSurface->Clear(data->dfbSurface, 0, 0, 0, 0); } data->dfbSurface->SetBlittingFlags(data->dfbSurface, flags); const DFBRectangle destRect = { 0, 0, size.width(), size.height() }; data->dfbSurface->StretchBlit(data->dfbSurface, dfbSurface, 0, &destRect); data->w = size.width(); data->h = size.height(); data->is_null = (data->w <= 0 || data->h <= 0); #if (Q_DIRECTFB_VERSION >= 0x010000) data->dfbSurface->ReleaseSource(data->dfbSurface); #endif return QPixmap(data); }
void TransformTest::testTransformTranslate() { MapCoord offset { 100.0, 100.0 }; QTransform qt; qt.translate(offset.x(), offset.y()); QVERIFY(qt.isTranslating()); QCOMPARE(int(qt.type()), int(QTransform::TxTranslate)); auto t = TemplateTransform::fromQTransform(qt); QCOMPARE(t.template_x, offset.nativeX()); QCOMPARE(t.template_y, offset.nativeY()); QCOMPARE(t.template_scale_x, 1.0); QCOMPARE(t.template_scale_y, 1.0); QCOMPARE(t.template_rotation, 0.0); }
void TransformTest::testTransformProject() { qreal scale_x = 4.5; qreal scale_y = 2.5; QTransform qt; qt.scale(scale_x, scale_y); QVERIFY(qt.isScaling()); QCOMPARE(int(qt.type()), int(QTransform::TxScale)); auto t = TemplateTransform::fromQTransform(qt); QCOMPARE(t.template_x, 0); QCOMPARE(t.template_y, 0); QCOMPARE(t.template_scale_x, scale_x); QCOMPARE(t.template_scale_y, scale_y); QCOMPARE(t.template_rotation, 0.0); }
void TransformTest::testTransformRotate() { QFETCH(int, type); QFETCH(double, rotation); QTransform qt; qt.rotate(qreal(rotation), Qt::ZAxis); QCOMPARE(int(qt.type()), type); auto t = TemplateTransform::fromQTransform(qt); QCOMPARE(t.template_x, 0); QCOMPARE(t.template_y, 0); QCOMPARE(t.template_scale_x, 1.0); QCOMPARE(t.template_scale_y, 1.0); if (rotation <= 180.0) QCOMPARE(t.template_rotation, -qDegreesToRadians(qreal(rotation))); else QCOMPARE(t.template_rotation, -qDegreesToRadians(qreal(rotation - 360.0))); }
static QTransform preciselyInverted( const QTransform& transform ) { QTransform inverted; switch ( transform.type() ) { case QTransform::TxNone: break; case QTransform::TxTranslate: inverted.translate( -transform.dx(), -transform.dy() ); break; case QTransform::TxScale: inverted.scale( 1.0 / transform.m11(), 1.0 / transform.m22() ); inverted.translate( -transform.dx(), -transform.dy() ); break; default: inverted = transform.inverted(); } return inverted; }
QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, Qt::TransformationMode mode) const { if (!surface || transform.type() != QTransform::TxScale || mode != Qt::FastTransformation) { QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); const QImage *image = that->buffer(); if (image) { // avoid deep copy const QImage transformed = image->transformed(transform, mode); that->unlockDirectFB(); QDirectFBPixmapData *data = new QDirectFBPixmapData(pixelType()); data->fromImage(transformed, Qt::AutoColor); return QPixmap(data); } return QPixmapData::transformed(transform, mode); } int w, h; surface->GetSize(surface, &w, &h); const QSize size = transform.mapRect(QRect(0, 0, w, h)).size(); if (size.isEmpty()) return QPixmap(); QDirectFBPixmapData *data = new QDirectFBPixmapData(pixelType()); data->resize(size.width(), size.height()); IDirectFBSurface *dest = data->surface; dest->SetBlittingFlags(dest, DSBLIT_NOFX); const DFBRectangle srcRect = { 0, 0, w, h }; const DFBRectangle destRect = { 0, 0, size.width(), size.height() }; dest->StretchBlit(dest, surface, &srcRect, &destRect); return QPixmap(data); }
void TransformTest::testTransformIdentity() { // Default QTransform: identity QTransform qt; QVERIFY(qt.isIdentity()); QCOMPARE(int(qt.type()), int(QTransform::TxNone)); // Default TemplateTransform: identity TemplateTransform t; // TemplateTransform list initialization, and assignment t = { 12, -3, 0.1, 2.0, 3.0 }; QCOMPARE(t.template_x, 12); QCOMPARE(t.template_y, -3); QCOMPARE(t.template_scale_x, 2.0); QCOMPARE(t.template_scale_y, 3.0); QCOMPARE(t.template_rotation, 0.1); // Now transfer the identity QTransform to the TemplateTransform t = TemplateTransform::fromQTransform(qt); QCOMPARE(t.template_x, 0); QCOMPARE(t.template_y, 0); QCOMPARE(t.template_scale_x, 1.0); QCOMPARE(t.template_scale_y, 1.0); QCOMPARE(t.template_rotation, 0.0); // Put something different in the QTransform qt.translate(4, 8); qt.rotate(1); qt.scale(2.0, 1.5); QVERIFY(qt.isAffine()); QVERIFY(!qt.isIdentity()); QVERIFY(qt.isTranslating()); QVERIFY(qt.isRotating()); QVERIFY(qt.isScaling()); }
/*! \internal */ void QDeclarativePaintedItem::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { Q_D(QDeclarativePaintedItem); const QRect content = boundingRect().toRect(); if (content.width() <= 0 || content.height() <= 0) return; ++inpaint; const QTransform &x = p->deviceTransform(); QTransform xinv = x.inverted(); QRegion effectiveClip; QRegion sysClip = p->paintEngine()->systemClip(); if (xinv.type() <= QTransform::TxScale && sysClip.numRects() < 5) { // simple transform, region gets no more complicated... effectiveClip = xinv.map(sysClip); } else { // do not make complicated regions... effectiveClip = xinv.mapRect(sysClip.boundingRect()); } QRegion topaint = p->clipRegion(); if (topaint.isEmpty()) { if (effectiveClip.isEmpty()) topaint = QRect(0,0,p->device()->width(),p->device()->height()); else topaint = effectiveClip; } else if (!effectiveClip.isEmpty()) { topaint &= effectiveClip; } topaint &= content; QRegion uncached(content); p->setRenderHints(QPainter::SmoothPixmapTransform, d->smooth); int cachesize=0; for (int i=0; i<d->imagecache.count(); ++i) { QRect area = d->imagecache[i]->area; if (topaint.contains(area)) { QRectF target(area.x(), area.y(), area.width(), area.height()); if (!d->cachefrozen) { if (!d->imagecache[i]->dirty.isNull() && topaint.contains(d->imagecache[i]->dirty)) { #ifdef Q_WS_MAC bool oldSmooth = qt_applefontsmoothing_enabled; qt_applefontsmoothing_enabled = false; #endif QPainter qp(&d->imagecache[i]->image); #ifdef Q_WS_MAC qt_applefontsmoothing_enabled = oldSmooth; #endif qp.setRenderHints(QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform, d->smoothCache); qp.translate(-area.x(), -area.y()); qp.scale(d->contentsScale,d->contentsScale); QRect clip = d->imagecache[i]->dirty; QRect sclip(qFloor(clip.x()/d->contentsScale), qFloor(clip.y()/d->contentsScale), qCeil(clip.width()/d->contentsScale+clip.x()/d->contentsScale-qFloor(clip.x()/d->contentsScale)), qCeil(clip.height()/d->contentsScale+clip.y()/d->contentsScale-qFloor(clip.y()/d->contentsScale))); qp.setClipRect(sclip); if (d->fillColor.isValid()){ if(d->fillColor.alpha() < 255){ // ### Might not work outside of raster paintengine QPainter::CompositionMode prev = qp.compositionMode(); qp.setCompositionMode(QPainter::CompositionMode_Source); qp.fillRect(sclip,d->fillColor); qp.setCompositionMode(prev); }else{ qp.fillRect(sclip,d->fillColor); } } drawContents(&qp, sclip); d->imagecache[i]->dirty = QRect(); } } p->drawPixmap(target.toRect(), d->imagecache[i]->image); topaint -= area; d->imagecache[i]->age=0; } else { d->imagecache[i]->age++; } cachesize += area.width()*area.height(); uncached -= area; } if (!topaint.isEmpty()) { if (!d->cachefrozen) { // Find a sensible larger area, otherwise will paint lots of tiny images. QRect biggerrect = topaint.boundingRect().adjusted(-64,-64,128,128); cachesize += biggerrect.width() * biggerrect.height(); while (d->imagecache.count() && cachesize > d->max_imagecache_size) { int oldest=-1; int age=-1; for (int i=0; i<d->imagecache.count(); ++i) { int a = d->imagecache[i]->age; if (a > age) { oldest = i; age = a; } } cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height(); uncached += d->imagecache[oldest]->area; delete d->imagecache.takeAt(oldest); } const QRegion bigger = QRegion(biggerrect) & uncached; const QVector<QRect> rects = bigger.rects(); for (int i = 0; i < rects.count(); ++i) { const QRect &r = rects.at(i); QPixmap img(r.size()); if (d->fillColor.isValid()) img.fill(d->fillColor); { #ifdef Q_WS_MAC bool oldSmooth = qt_applefontsmoothing_enabled; qt_applefontsmoothing_enabled = false; #endif QPainter qp(&img); #ifdef Q_WS_MAC qt_applefontsmoothing_enabled = oldSmooth; #endif qp.setRenderHints(QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform, d->smoothCache); qp.translate(-r.x(),-r.y()); qp.scale(d->contentsScale,d->contentsScale); QRect sclip(qFloor(r.x()/d->contentsScale), qFloor(r.y()/d->contentsScale), qCeil(r.width()/d->contentsScale+r.x()/d->contentsScale-qFloor(r.x()/d->contentsScale)), qCeil(r.height()/d->contentsScale+r.y()/d->contentsScale-qFloor(r.y()/d->contentsScale))); drawContents(&qp, sclip); } QDeclarativePaintedItemPrivate::ImageCacheItem *newitem = new QDeclarativePaintedItemPrivate::ImageCacheItem; newitem->area = r; newitem->image = img; d->imagecache.append(newitem); p->drawPixmap(r, newitem->image); } } else { const QVector<QRect> rects = uncached.rects(); for (int i = 0; i < rects.count(); ++i) p->fillRect(rects.at(i), Qt::lightGray); } } if (inpaint_clearcache) { clearCache(); inpaint_clearcache = 0; } --inpaint; }