4 #include <QPixmapCache>
9 #define ic2dc(x) ((x) * 180.0 / 0x7FFFFFFF)
11 template<class T
> bool JNXMap::readValue(T
&val
)
15 if (_file
.read((char*)&data
, sizeof(T
)) < (qint64
)sizeof(T
))
18 val
= qFromLittleEndian(data
);
23 bool JNXMap::readString(QByteArray
& ba
)
28 if (!_file
.getChar(&byte
))
37 bool JNXMap::readHeader()
39 qint32 lat1
, lon2
, lat2
, lon1
;
40 quint32 version
, dummy
, levels
;
42 if (!(readValue(version
) && readValue(dummy
) && readValue(lat1
)
43 && readValue(lon2
) && readValue(lat2
) && readValue(lon1
)
44 && readValue(levels
)))
47 if (version
< 3 || version
> 4)
50 _bounds
= RectC(Coordinates(ic2dc(lon1
), ic2dc(lat1
)),
51 Coordinates(ic2dc(lon2
), ic2dc(lat2
)));
52 if (!levels
|| levels
> 32 || !_bounds
.isValid())
55 if (!_file
.seek(version
> 3 ? 0x34 : 0x30))
58 QVector
<Level
> lh(levels
);
59 for (int i
= 0; i
< lh
.count(); i
++) {
62 if (!(readValue(l
.count
) && readValue(l
.offset
) && readValue(l
.scale
)))
66 if (!(readValue(dummy
) && readString(ba
)))
71 _zooms
.reserve(lh
.size());
72 for (int i
= 0; i
< lh
.count(); i
++)
73 _zooms
.append(new Zoom(lh
.at(i
)));
78 bool JNXMap::readTiles()
80 for (int i
= 0; i
< _zooms
.size(); i
++) {
83 if (!_file
.seek(z
->level
.offset
))
86 z
->tiles
= QVector
<Tile
>(z
->level
.count
);
87 for (quint32 j
= 0; j
< z
->level
.count
; j
++) {
88 Tile
&tile
= z
->tiles
[j
];
90 if (!(readValue(tile
.top
) && readValue(tile
.right
)
91 && readValue(tile
.bottom
) && readValue(tile
.left
)
92 && readValue(tile
.width
) && readValue(tile
.height
)
93 && readValue(tile
.size
) && readValue(tile
.offset
)))
96 RectC
llrect(Coordinates(ic2dc(tile
.left
), ic2dc(tile
.top
)),
97 Coordinates(ic2dc(tile
.right
), ic2dc(tile
.bottom
)));
98 RectD
rect(_projection
.ll2xy(llrect
.topLeft()),
99 _projection
.ll2xy(llrect
.bottomRight()));
102 ReferencePoint
tl(PointD(0, 0), rect
.topLeft());
103 ReferencePoint
br(PointD(tile
.width
, tile
.height
),
105 z
->transform
= Transform(tl
, br
);
108 QRectF
trect(z
->transform
.proj2img(rect
.topLeft()),
109 z
->transform
.proj2img(rect
.bottomRight()));
110 tile
.pos
= trect
.topLeft();
112 qreal min
[2], max
[2];
113 min
[0] = trect
.left();
114 min
[1] = trect
.top();
115 max
[0] = trect
.right();
116 max
[1] = trect
.bottom();
117 z
->tree
.Insert(min
, max
, &tile
);
124 void JNXMap::clearTiles()
126 for (int i
= 0; i
< _zooms
.size(); i
++) {
133 JNXMap::JNXMap(const QString
&fileName
, QObject
*parent
)
134 : Map(fileName
, parent
), _file(fileName
), _zoom(0), _mapRatio(1.0),
137 if (!_file
.open(QIODevice::ReadOnly
)) {
138 _errorString
= _file
.errorString();
143 _errorString
= "JNX file format error";
157 void JNXMap::load(const Projection
&in
, const Projection
&out
,
158 qreal deviceRatio
, bool hidpi
)
163 _mapRatio
= hidpi
? deviceRatio
: 1.0;
165 if (_file
.open(QIODevice::ReadOnly
))
169 void JNXMap::unload()
175 QPointF
JNXMap::ll2xy(const Coordinates
&c
)
177 const Zoom
*z
= _zooms
.at(_zoom
);
178 return z
->transform
.proj2img(_projection
.ll2xy(c
)) / _mapRatio
;
181 Coordinates
JNXMap::xy2ll(const QPointF
&p
)
183 const Zoom
*z
= _zooms
.at(_zoom
);
184 return _projection
.xy2ll(z
->transform
.img2proj(p
* _mapRatio
));
187 QRectF
JNXMap::bounds()
189 return QRectF(ll2xy(_bounds
.topLeft()), ll2xy(_bounds
.bottomRight()));
192 int JNXMap::zoomFit(const QSize
&size
, const RectC
&rect
)
195 _zoom
= _zooms
.size() - 1;
197 for (int i
= 1; i
< _zooms
.count(); i
++) {
199 QRect
sbr(QPoint(ll2xy(rect
.topLeft()).toPoint()),
200 QPoint(ll2xy(rect
.bottomRight()).toPoint()));
201 if (sbr
.size().width() >= size
.width() || sbr
.size().height()
214 _zoom
= qMin(_zoom
+ 1, _zooms
.size() - 1);
218 int JNXMap::zoomOut()
220 _zoom
= qMax(_zoom
- 1, 0);
224 QPixmap
JNXMap::pixmap(const Tile
*tile
, QFile
*file
)
228 QString key
= file
->fileName() + "-" + QString::number(tile
->offset
);
229 if (!QPixmapCache::find(key
, &pm
)) {
231 ba
.resize(tile
->size
+ 2);
234 char *data
= ba
.data() + 2;
236 if (!file
->seek(tile
->offset
))
238 if (!file
->read(data
, tile
->size
))
240 pm
= QPixmap::fromImage(QImage::fromData(ba
));
243 QPixmapCache::insert(key
, pm
);
249 bool JNXMap::cb(Tile
*tile
, void *context
)
251 Ctx
*ctx
= static_cast<Ctx
*>(context
);
252 QPixmap
pm(pixmap(tile
, ctx
->file
));
253 pm
.setDevicePixelRatio(ctx
->ratio
);
254 ctx
->painter
->drawPixmap(tile
->pos
/ ctx
->ratio
, pm
);
259 void JNXMap::draw(QPainter
*painter
, const QRectF
&rect
, Flags flags
)
262 const RTree
<Tile
*, qreal
, 2> &tree
= _zooms
.at(_zoom
)->tree
;
263 Ctx
ctx(painter
, &_file
, _mapRatio
);
264 QRectF
rr(rect
.topLeft() * _mapRatio
, rect
.size() * _mapRatio
);
266 qreal min
[2], max
[2];
270 max
[1] = rr
.bottom();
271 tree
.Search(min
, max
, cb
, &ctx
);
274 Map
*JNXMap::create(const QString
&path
, const Projection
&proj
, bool *isDir
)
281 return new JNXMap(path
);