Commit af07f106 authored by hengli's avatar hengli

Updated 3D imagery code. Non-working version.

parent c62170bb
......@@ -2,25 +2,13 @@
#include <cmath>
#include <sstream>
#include <QNetworkReply>
#include <QPixmap>
//for street-maps to:
//http://mt1.google.com/mt?&x=%d&y=%d&z=%d
//for satellite-maps to:
//http://khm.google.com/kh?&x=%d&y=%d&zoom=%d
//for topographic-maps:
//http://mt.google.com/mt?v=app.81&x=%d&y=%d&zoom=%d
const double WGS84_A = 6378137.0;
const double WGS84_ECCSQ = 0.00669437999013;
Imagery::Imagery(QObject* parent)
: QObject(parent)
, networkManager(new QNetworkAccessManager)
Imagery::Imagery()
{
// connect(networkManager.data(), SIGNAL(finished(QNetworkReply*)),
// this, SLOT(downloadFinished(QNetworkReply*)));
}
void
......@@ -32,27 +20,22 @@ Imagery::setImageryType(ImageryType type)
void
Imagery::setOffset(double xOffset, double yOffset)
{
}
void
Imagery::setUrl(std::string url)
{
this->xOffset = xOffset;
this->yOffset = yOffset;
}
void
Imagery::prefetch2D(double windowWidth, double windowHeight,
double zoom, double xOrigin, double yOrigin,
double viewXOffset, double viewYOffset,
const std::string& utmZone)
const QString& utmZone)
{
double x1 = xOrigin + viewXOffset - windowWidth / 2.0 / zoom;
double y1 = yOrigin + viewYOffset - windowHeight / 2.0 / zoom;
double xc = xOrigin + viewXOffset;
double yc = yOrigin + viewYOffset;
double x2 = xOrigin + viewXOffset + windowWidth / 2.0 / zoom;
double y2 = yOrigin + viewYOffset + windowHeight / 2.0 / zoom;
double minX = xOrigin + viewXOffset - windowWidth / 2.0 / zoom;
double minY = yOrigin + viewYOffset - windowHeight / 2.0 / zoom;
double centerX = xOrigin + viewXOffset;
double centerY = yOrigin + viewYOffset;
double maxX = xOrigin + viewXOffset + windowWidth / 2.0 / zoom;
double maxY = yOrigin + viewYOffset + windowHeight / 2.0 / zoom;
double imageResolution;
if (currentImageryType == SATELLITE)
......@@ -68,34 +51,192 @@ Imagery::prefetch2D(double windowWidth, double windowHeight,
}
}
// networkManager->get(QNetworkRequest(QUrl("")));
int32_t minTileX, minTileY, centerTileX, centerTileY, maxTileX, maxTileY;
int32_t zoomLevel;
UTMtoTile(minX, minY, utmZone, imageResolution,
minTileX, maxTileY, zoomLevel);
UTMtoTile(centerX, centerY, utmZone, imageResolution,
centerTileX, centerTileY, zoomLevel);
UTMtoTile(maxX, maxY, utmZone, imageResolution,
maxTileX, minTileY, zoomLevel);
if (maxTileX - minTileX + 1 > 14)
{
minTileX = centerTileX - 7;
maxTileX = centerTileX + 6;
}
if (maxTileY - minTileY + 1 > 14)
{
minTileY = centerTileY - 7;
maxTileY = centerTileY + 6;
}
for (int32_t r = minTileY; r <= maxTileY; ++r)
{
for (int32_t c = minTileX; c <= maxTileX; ++c)
{
QString url = getTileURL(c, r, zoomLevel);
TexturePtr t = textureCache->get(url);
}
}
}
void
Imagery::draw2D(double windowWidth, double windowHeight,
double zoom, double xOrigin, double yOrigin,
double viewXOffset, double viewYOffset,
const std::string& utmZone)
const QString& utmZone)
{
double minX = xOrigin + viewXOffset - windowWidth / 2.0 / zoom * 1.5;
double minY = yOrigin + viewYOffset - windowHeight / 2.0 / zoom * 1.5;
double centerX = xOrigin + viewXOffset;
double centerY = yOrigin + viewYOffset;
double maxX = xOrigin + viewXOffset + windowWidth / 2.0 / zoom * 1.5;
double maxY = yOrigin + viewYOffset + windowHeight / 2.0 / zoom * 1.5;
double imageResolution;
if (currentImageryType == SATELLITE)
{
imageResolution = 1.0;
while (imageResolution * 3.0 / 2.0 < 1.0 / zoom)
{
imageResolution *= 2.0;
}
if (imageResolution > 512.0)
{
imageResolution = 512.0;
}
}
int32_t minTileX, minTileY, centerTileX, centerTileY, maxTileX, maxTileY;
int32_t zoomLevel;
UTMtoTile(minX, minY, utmZone, imageResolution,
minTileX, maxTileY, zoomLevel);
UTMtoTile(centerX, centerY, utmZone, imageResolution,
centerTileX, centerTileY, zoomLevel);
UTMtoTile(maxX, maxY, utmZone, imageResolution,
maxTileX, minTileY, zoomLevel);
if (maxTileX - minTileX + 1 > 14)
{
minTileX = centerTileX - 7;
maxTileX = centerTileX + 6;
}
if (maxTileY - minTileY + 1 > 14)
{
minTileY = centerTileY - 7;
maxTileY = centerTileY + 6;
}
for (int32_t r = minTileY; r <= maxTileY; ++r)
{
for (int32_t c = minTileX; c <= maxTileX; ++c)
{
QString tileURL = getTileURL(c, r, zoomLevel);
double x1, y1, x2, y2, x3, y3, x4, y4;
imageBounds(c, r, imageResolution, x1, y1, x2, y2, x3, y3, x4, y4);
TexturePtr t = textureCache->get(tileURL);
t->draw(x1 - xOrigin, y1 - yOrigin,
x2 - xOrigin, y2 - yOrigin,
x3 - xOrigin, y3 - yOrigin,
x4 - xOrigin, y4 - yOrigin, true);
}
}
}
void
Imagery::prefetch3D(double radius, double imageResolution,
double xOrigin, double yOrigin,
double viewXOffset, double viewYOffset,
const std::string& utmZone)
const QString& utmZone)
{
double minX = xOrigin + viewXOffset - radius;
double minY = yOrigin + viewYOffset - radius;
double centerX = xOrigin + viewXOffset;
double centerY = yOrigin + viewYOffset;
double maxX = xOrigin + viewXOffset + radius;
double maxY = yOrigin + viewYOffset + radius;
int32_t minTileX, minTileY, centerTileX, centerTileY, maxTileX, maxTileY;
int32_t zoomLevel;
UTMtoTile(minX, minY, utmZone, imageResolution,
minTileX, maxTileY, zoomLevel);
UTMtoTile(centerX, centerY, utmZone, imageResolution,
centerTileX, centerTileY, zoomLevel);
UTMtoTile(maxX, maxY, utmZone, imageResolution,
maxTileX, minTileY, zoomLevel);
if (maxTileX - minTileX + 1 > 14)
{
minTileX = centerTileX - 7;
maxTileX = centerTileX + 6;
}
if (maxTileY - minTileY + 1 > 14)
{
minTileY = centerTileY - 7;
maxTileY = centerTileY + 6;
}
for (int32_t r = minTileY; r <= maxTileY; ++r)
{
for (int32_t c = minTileX; c <= maxTileX; ++c)
{
QString url = getTileURL(c, r, zoomLevel);
TexturePtr t = textureCache->get(url);
}
}
}
void
Imagery::draw3D(double radius, double imageResolution,
double xOrigin, double yOrigin,
double viewXOffset, double viewYOffset,
const std::string& utmZone)
const QString& utmZone)
{
double minX = xOrigin + viewXOffset - radius;
double minY = yOrigin + viewYOffset - radius;
double centerX = xOrigin + viewXOffset;
double centerY = yOrigin + viewYOffset;
double maxX = xOrigin + viewXOffset + radius;
double maxY = yOrigin + viewYOffset + radius;
int32_t minTileX, minTileY, centerTileX, centerTileY, maxTileX, maxTileY;
int32_t zoomLevel;
UTMtoTile(minX, minY, utmZone, imageResolution,
minTileX, maxTileY, zoomLevel);
UTMtoTile(centerX, centerY, utmZone, imageResolution,
centerTileX, centerTileY, zoomLevel);
UTMtoTile(maxX, maxY, utmZone, imageResolution,
maxTileX, minTileY, zoomLevel);
if (maxTileX - minTileX + 1 > 14)
{
minTileX = centerTileX - 7;
maxTileX = centerTileX + 6;
}
if (maxTileY - minTileY + 1 > 14)
{
minTileY = centerTileY - 7;
maxTileY = centerTileY + 6;
}
for (int32_t r = minTileY; r <= maxTileY; ++r)
{
for (int32_t c = minTileX; c <= maxTileX; ++c)
{
QString tileURL = getTileURL(c, r, zoomLevel);
double x1, y1, x2, y2, x3, y3, x4, y4;
imageBounds(c, r, imageResolution, x1, y1, x2, y2, x3, y3, x4, y4);
TexturePtr t = textureCache->get(tileURL);
t->draw(x1 - xOrigin, y1 - yOrigin,
x2 - xOrigin, y2 - yOrigin,
x3 - xOrigin, y3 - yOrigin,
x4 - xOrigin, y4 - yOrigin, true);
}
}
}
bool
......@@ -105,24 +246,48 @@ Imagery::update(void)
}
void
Imagery::downloadFinished(QNetworkReply* reply)
Imagery::imageBounds(int32_t x, int32_t y, double imageResolution,
double& x1, double& y1, double& x2, double& y2,
double& x3, double& y3, double& x4, double& y4)
{
if (reply->error() != QNetworkReply::NoError) {
return;
}
QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (attribute.isValid())
{
return;
}
int32_t zoomLevel = 17 - static_cast<int32_t>(rint(log2(imageResolution)));
int32_t numTiles = static_cast<int32_t>(exp2(static_cast<double>(zoomLevel)));
double lon1 = 360.0 * (static_cast<double>(x)
/ static_cast<double>(numTiles)) - 180;
double lon2 = 360.0 * ((static_cast<double>(x + 1))
/ static_cast<double>(numTiles)) - 180;
double lat1 = tileYToLatitude((static_cast<double>(y + 1)
/ static_cast<double>(numTiles))
* 2.0 * M_PI - M_PI);
double lat2 = tileYToLatitude((static_cast<double>(y)
/ static_cast<double>(numTiles))
* 2.0 * M_PI - M_PI);
QString utmZone;
LLtoUTM(lat1, lon1, y1, x1, utmZone);
LLtoUTM(lat1, lon2, y2, x2, utmZone);
LLtoUTM(lat2, lon2, y3, x3, utmZone);
LLtoUTM(lat2, lon1, y4, x4, utmZone);
}
QByteArray jpegData = reply->readAll();
QPixmap pixmap;
pixmap.loadFromData(jpegData);
double
Imagery::tileYToLatitude(double y)
{
double rad = 2.0 * atan(exp(y)) - M_PI / 2.0;
return -rad * 180.0 / M_PI;
}
double
Imagery::latitudeToTileY(double latitude)
{
double rad = latitude * M_PI / 180.0;
return -log(tan(rad) + 1.0 / cos(rad));
}
void
Imagery::UTMtoTile(double northing, double easting, const std::string& utmZone,
Imagery::UTMtoTile(double northing, double easting, const QString& utmZone,
double imageResolution, int32_t& tileX, int32_t& tileY,
int32_t& zoomLevel)
{
......@@ -134,14 +299,12 @@ Imagery::UTMtoTile(double northing, double easting, const std::string& utmZone,
int32_t numTiles = static_cast<int32_t>(exp2(static_cast<double>(zoomLevel)));
double x = longitude / 180.0;
double rad = latitude * M_PI / 180.0;
double y = -log(tan(rad) + 1.0 / cos(rad));
double y = latitudeToTileY(latitude);
tileX = static_cast<int32_t>((x + 1.0) / 2.0 * numTiles);
tileY = static_cast<int32_t>((y + M_PI) / (2.0 * M_PI) * numTiles);
}
char
QChar
Imagery::UTMLetterDesignator(double latitude)
{
// This routine determines the correct UTM letter designator for the given latitude
......@@ -176,7 +339,7 @@ Imagery::UTMLetterDesignator(double latitude)
void
Imagery::LLtoUTM(const double latitude, const double longitude,
double& utmNorthing, double& utmEasting, std::string& utmZone)
double& utmNorthing, double& utmEasting, QString& utmZone)
{
// converts lat/long to UTM coords. Equations from USGS Bulletin 1532
// East Longitudes are positive, West longitudes are negative.
......@@ -214,9 +377,7 @@ Imagery::LLtoUTM(const double latitude, const double longitude,
LongOriginRad = LongOrigin * M_PI / 180.0;
// compute the UTM Zone from the latitude and longitude
std::ostringstream oss;
oss << ZoneNumber << UTMLetterDesignator(latitude);
utmZone = oss.str();
utmZone = QString("%1%2").arg(ZoneNumber).arg(UTMLetterDesignator(latitude));
eccPrimeSquared = WGS84_ECCSQ / (1.0 - WGS84_ECCSQ);
......@@ -259,7 +420,7 @@ Imagery::LLtoUTM(const double latitude, const double longitude,
void
Imagery::UTMtoLL(const double utmNorthing, const double utmEasting,
const std::string& utmZone, double& latitude, double& longitude)
const QString& utmZone, double& latitude, double& longitude)
{
// converts UTM coords to lat/long. Equations from USGS Bulletin 1532
// East Longitudes are positive, West longitudes are negative.
......@@ -281,7 +442,7 @@ Imagery::UTMtoLL(const double utmNorthing, const double utmEasting,
x = utmEasting - 500000.0; //remove 500,000 meter offset for longitude
y = utmNorthing;
std::istringstream iss(utmZone);
std::istringstream iss(utmZone.toStdString());
iss >> ZoneNumber >> ZoneLetter;
if ((ZoneLetter - 'N') >= 0)
{
......@@ -329,3 +490,27 @@ Imagery::UTMtoLL(const double utmNorthing, const double utmEasting,
* D * D * D * D * D / 120.0) / cos(phi1Rad);
longitude = LongOrigin + longitude / M_PI * 180.0;
}
QString
Imagery::getTileURL(int32_t x, int32_t y, int32_t zoomLevel)
{
std::ostringstream oss;
switch (currentImageryType)
{
case MAP:
oss << "http://mt1.google.com/mt?&x=" << x << "&y=" << y <<
"&z=" << zoomLevel;
break;
case SATELLITE:
oss << "http://khm.google.com/kh?&x=" << x << "&y=" << y <<
"&zoom=" << zoomLevel;
break;
default:
{};
}
QString url;
return url;
}
......@@ -2,18 +2,13 @@
#define IMAGERY_H
#include <inttypes.h>
#include <string>
#include <QNetworkAccessManager>
#include <QObject>
#include "Texture.h"
#include "TextureCache.h"
class Imagery : public QObject
class Imagery
{
// Q_OBJECT
public:
explicit Imagery(QObject* parent);
Imagery();
enum ImageryType
{
......@@ -23,49 +18,56 @@ public:
void setImageryType(ImageryType type);
void setOffset(double xOffset, double yOffset);
void setUrl(std::string url);
void prefetch2D(double windowWidth, double windowHeight,
double zoom, double xOrigin, double yOrigin,
double viewXOffset, double viewYOffset,
const std::string& utmZone);
const QString& utmZone);
void draw2D(double windowWidth, double windowHeight,
double zoom, double xOrigin, double yOrigin,
double viewXOffset, double viewYOffset,
const std::string& utmZone);
const QString& utmZone);
void prefetch3D(double radius, double imageResolution,
double xOrigin, double yOrigin,
double viewXOffset, double viewYOffset,
const std::string& utmZone);
const QString& utmZone);
void draw3D(double radius, double imageResolution,
double xOrigin, double yOrigin,
double viewXOffset, double viewYOffset,
const std::string& utmZone);
const QString& utmZone);
bool update(void);
private slots:
void downloadFinished(QNetworkReply* reply);
private:
void UTMtoTile(double northing, double easting, const std::string& utmZone,
void imageBounds(int32_t x, int32_t y, double imageResolution,
double& x1, double& y1, double& x2, double& y2,
double& x3, double& y3, double& x4, double& y4);
double tileYToLatitude(double y);
double latitudeToTileY(double latitude);
void UTMtoTile(double northing, double easting, const QString& utmZone,
double imageResolution, int32_t& tileX, int32_t& tileY,
int32_t& zoomLevel);
char UTMLetterDesignator(double latitude);
QChar UTMLetterDesignator(double latitude);
void LLtoUTM(const double latitude, const double longitude,
double& utmNorthing, double& utmEasting,
std::string& utmZone);
QString& utmZone);
void UTMtoLL(const double utmNorthing, const double utmEasting,
const std::string& utmZone,
const QString& utmZone,
double& latitude, double& longitude);
QString getTileURL(int32_t x, int32_t y, int32_t zoomLevel);
ImageryType currentImageryType;
QScopedPointer<QNetworkAccessManager> networkManager;
QScopedPointer<TextureCache> textureCache;
double xOffset, yOffset;
};
#endif // IMAGERY_H
......@@ -5,6 +5,66 @@ Texture::Texture()
}
QString
Texture::getSourceURL(void)
{
return sourceURL;
}
void
Texture::setID(GLuint id)
{
this->id = id;
}
void
Texture::sync(const WebImagePtr& image)
{
state = static_cast<State>(image->getState());
if (image->getState() != WebImage::UNINITIALIZED &&
sourceURL != image->getSourceURL())
{
sourceURL = image->getSourceURL();
}
if (image->getState() == WebImage::READY && image->getSyncFlag())
{
image->setSyncFlag(false);
if (image->getWidth() != imageWidth ||
image->getHeight() != imageHeight)
{
imageWidth = image->getWidth();
textureWidth = 32;
while (textureWidth < imageWidth)
{
textureWidth *= 2;
}
imageHeight = image->getHeight();
textureHeight = 32;
while (textureHeight < imageHeight)
{
textureHeight *= 2;
}
maxU = static_cast<double>(imageWidth)
/ static_cast<double>(textureWidth);
maxV = static_cast<double>(imageHeight)
/ static_cast<double>(textureHeight);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, 3, textureWidth, textureHeight,
0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
}
glBindTexture(GL_TEXTURE_2D, id);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageWidth, imageHeight,
GL_RGB, GL_UNSIGNED_BYTE, image->getData());
}
}
void
Texture::draw(float x1, float y1, float x2, float y2,
bool smoothInterpolation) const
......@@ -22,7 +82,7 @@ Texture::draw(float x1, float y1, float x2, float y2,
}
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
glBindTexture(GL_TEXTURE_2D, id);
float dx, dy;
if (smoothInterpolation)
......@@ -56,3 +116,56 @@ Texture::draw(float x1, float y1, float x2, float y2,
glDisable(GL_TEXTURE_2D);
}
void
Texture::draw(float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
bool smoothInterpolation) const
{
if (state == REQUESTED)
{
glBegin(GL_LINE_LOOP);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glVertex2f(x4, y4);
glEnd();
return;
}
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, id);
float dx, dy;
if (smoothInterpolation)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
dx = 1.0f / (2.0f * textureWidth);
dy = 1.0f / (2.0f * textureHeight);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
dx = 0.0f;
dy = 0.0f;
}
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(dx, maxV - dy);
glVertex2f(x1, y1);
glTexCoord2f(maxU - dx, maxV - dy);
glVertex2f(x2, y2);
glTexCoord2f(maxU - dx, dy);
glVertex2f(x3, y3);
glTexCoord2f(dx, dy);
glVertex2f(x4, y4);
glEnd();
glDisable(GL_TEXTURE_2D);
}
......@@ -9,13 +9,24 @@
#include <inttypes.h>
#include <QSharedPointer>
#include "WebImage.h"
class Texture
{
public:
Texture();
QString getSourceURL(void);
void setID(GLuint id);
void sync(const WebImagePtr& image);
void draw(float x1, float y1, float x2, float y2,
bool smoothInterpolation) const;
void draw(float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
bool smoothInterpolation) const;
private:
enum State
......@@ -26,8 +37,8 @@ private:
};
State state;
GLuint textureId;
QString sourceURL;
GLuint id;
int32_t textureWidth;
int32_t textureHeight;
......@@ -39,6 +50,6 @@ private:
float maxV;
};
typedef struct QSharedPointer<Texture> TexturePtr;
typedef QSharedPointer<Texture> TexturePtr;
#endif // TEXTURE_H
#include "TextureCache.h"
TextureCache::TextureCache(uint32_t _cacheSize)
: cacheSize(_cacheSize)
, imageCache(new WebImageCache(0, cacheSize))
{
textures.resize(cacheSize);
TexturePtr t;
foreach(t, textures)
{
GLuint id;
glGenTextures(1, &id);
t->setID(id);
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
}
TexturePtr
TextureCache::get(const QString& tileURL)
{
QPair<TexturePtr, int32_t> p1 = lookup(tileURL);
if (!p1.first.isNull())
{
return p1.first;
}
QPair<WebImagePtr, int32_t> p2 = imageCache->lookup(tileURL);
if (!p2.first.isNull())
{
textures[p2.second]->sync(p2.first);
p1 = lookup(tileURL);
return p1.first;
}
return TexturePtr();
}
void
TextureCache::sync(void)
{
if (requireSync())
{
for (int32_t i = 0; i < textures.size(); ++i)
{
textures[i]->sync(imageCache->at(i));
}
}
}
QPair<TexturePtr, int32_t>
TextureCache::lookup(const QString& tileURL)
{
for (int32_t i = 0; i < textures.size(); ++i)
{
if (textures[i]->getSourceURL() == tileURL)
{
return qMakePair(textures[i], i);
}
}
return qMakePair(TexturePtr(), -1);
}
bool
TextureCache::requireSync(void) const
{
for (uint32_t i = 0; i < cacheSize; ++i)
{
if (imageCache->at(i)->getSyncFlag())
{
return true;
}
}
return false;
}
#ifndef TEXTURECACHE_H
#define TEXTURECACHE_H
#include <QVector>
#include "Texture.h"
#include "WebImageCache.h"
class TextureCache
{
public:
explicit TextureCache(uint32_t cacheSize);
TexturePtr get(const QString& tileURL);
void sync(void);
private:
QPair<TexturePtr, int32_t> lookup(const QString& tileURL);
bool requireSync(void) const;
uint32_t cacheSize;
QVector<TexturePtr> textures;
QScopedPointer<WebImageCache> imageCache;
};
#endif // TEXTURECACHE_H
#include "WebImage.h"
WebImage::WebImage()
: state(WebImage::UNINITIALIZED)
, lastReference(0)
, syncFlag(false)
{
}
void
WebImage::clear(void)
{
image.clear();
sourceURL.clear();
state = WebImage::UNINITIALIZED;
lastReference = 0;
}
WebImage::State
WebImage::getState(void) const
{
return state;
}
void
WebImage::setState(State state)
{
this->state = state;
}
QString
WebImage::getSourceURL(void) const
{
return sourceURL;
}
void
WebImage::setSourceURL(const QString& url)
{
sourceURL = url;
}
const uint8_t*
WebImage::getData(void) const
{
return image->bits();
}
int32_t
WebImage::getWidth(void) const
{
return image->width();
}
int32_t
WebImage::getHeight(void) const
{
return image->height();
}
uint64_t
WebImage::getLastReference(void) const
{
return lastReference;
}
void
WebImage::setLastReference(uint64_t value)
{
lastReference = value;
}
bool
WebImage::getSyncFlag(void) const
{
return syncFlag;
}
void
WebImage::setSyncFlag(bool onoff)
{
syncFlag = onoff;
}
#ifndef WEBIMAGE_H
#define WEBIMAGE_H
#include <inttypes.h>
#include <QImage>
#include <QSharedPointer>
class WebImage
{
public:
WebImage();
void clear(void);
enum State
{
UNINITIALIZED = 0,
REQUESTED = 1,
READY = 2
};
State getState(void) const;
void setState(State state);
QString getSourceURL(void) const;
void setSourceURL(const QString& url);
const uint8_t* getData(void) const;
int32_t getWidth(void) const;
int32_t getHeight(void) const;
uint64_t getLastReference(void) const;
void setLastReference(uint64_t value);
bool getSyncFlag(void) const;
void setSyncFlag(bool onoff);
private:
State state;
QString sourceURL;
QSharedPointer<QImage> image;
uint64_t lastReference;
bool syncFlag;
};
typedef QSharedPointer<WebImage> WebImagePtr;
#endif // WEBIMAGE_H
#include "WebImageCache.h"
#include <QNetworkReply>
#include <QPixmap>
WebImageCache::WebImageCache(QObject* parent, uint32_t _cacheSize)
: QObject(parent)
, cacheSize(_cacheSize)
, currentReference(0)
, networkManager(new QNetworkAccessManager)
{
webImages.resize(cacheSize);
connect(networkManager.data(), SIGNAL(finished(QNetworkReply*)),
this, SLOT(downloadFinished(QNetworkReply*)));
}
QPair<WebImagePtr, int32_t>
WebImageCache::lookup(const QString& url)
{
QPair<WebImagePtr, int32_t> p;
for (int32_t i = 0; i < webImages.size(); ++i)
{
if (webImages[i]->getState() != WebImage::UNINITIALIZED &&
webImages[i]->getSourceURL() == url)
{
p.first = webImages[i];
p.second = i;
break;
}
}
if (p.first.isNull())
{
for (int32_t i = 0; i < webImages.size(); ++i)
{
// get uninitialized image
if (webImages[i]->getState() == WebImage::UNINITIALIZED)
{
p.first = webImages[i];
p.second = i;
break;
}
// get oldest image
else if (webImages[i]->getState() == WebImage::READY &&
(p.first.isNull() ||
p.first->getLastReference() < p.first->getLastReference()))
{
p.first = webImages[i];
p.second = i;
}
}
if (p.first.isNull())
{
return qMakePair(WebImagePtr(), -1);
}
else
{
if (p.first->getState() == WebImage::READY)
{
p.first->clear();
}
p.first->setSourceURL(url);
p.first->setLastReference(currentReference);
++currentReference;
p.first->setState(WebImage::REQUESTED);
networkManager->get(QNetworkRequest(QUrl(url)));
return p;
}
}
else
{
if (p.first->getState() == WebImage::READY)
{
p.first->setLastReference(currentReference);
++currentReference;
return p;
}
else
{
return qMakePair(WebImagePtr(), -1);
}
}
}
WebImagePtr
WebImageCache::at(int32_t index) const
{
return webImages[index];
}
void
WebImageCache::downloadFinished(QNetworkReply* reply)
{
if (reply->error() != QNetworkReply::NoError) {
return;
}
QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (attribute.isValid())
{
return;
}
QByteArray imageData = reply->readAll();
QPixmap pixmap;
pixmap.loadFromData(imageData);
// set image, needsSync to true, and state to READY
}
#ifndef WEBIMAGECACHE_H
#define WEBIMAGECACHE_H
#include <QNetworkAccessManager>
#include <QObject>
#include <QPair>
#include "WebImage.h"
class WebImageCache : public QObject
{
Q_OBJECT
public:
WebImageCache(QObject* parent, uint32_t cacheSize);
QPair<WebImagePtr, int32_t> lookup(const QString& url);
WebImagePtr at(int32_t index) const;
private Q_SLOTS:
void downloadFinished(QNetworkReply* reply);
private:
uint32_t cacheSize;
QVector<WebImagePtr> webImages;
uint64_t currentReference;
QScopedPointer<QNetworkAccessManager> networkManager;
};
#endif // WEBIMAGECACHE_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment