1 /***************************************************************************
2 * Copyright (C) 2010 by Chris Browet *
3 * cbro@semperpax.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include <QtPlugin>
21 #include <QDesktopServices>
22 #include <QPainter>
23 #include <QSettings>
24 #include <QUrl>
25 #include <QMessageBox>
26
27 #include "CadastreFrance.h"
28
29 #include "cadastrewrapper.h"
30 #include "searchdialog.h"
31
32 #include "IImageManager.h"
33
34 static const QUuid theUid ( 0x14a9ff26, 0x634e, 0x4406, 0x94, 0xa5, 0x4c, 0x6d, 0x9c, 0xf0, 0xb1, 0x1d);
35 static const QString theName("Cadastre (France)");
36
getId() const37 QUuid CadastreFranceAdapterFactory::getId() const
38 {
39 return theUid;
40 }
41
getName() const42 QString CadastreFranceAdapterFactory::getName() const
43 {
44 return theName;
45 }
46
47 /**************/
48
CadastreFranceAdapter()49 CadastreFranceAdapter::CadastreFranceAdapter()
50 : theImageManager(0), theMenu(0), theSettings(0)
51 , current_zoom(0), min_zoom(0), max_zoom(6)
52 {
53 loc = QLocale(QLocale::English);
54 loc.setNumberOptions(QLocale::OmitGroupSeparator);
55
56 Resolutions << 16 << 8. << 4. << 2 << 1.0 << 0.5 << 0.2;
57
58 m_isTiled = true;
59 }
60
~CadastreFranceAdapter()61 CadastreFranceAdapter::~CadastreFranceAdapter()
62 {
63 }
64
getId() const65 QUuid CadastreFranceAdapter::getId() const
66 {
67 return theUid;
68 }
69
getName() const70 QString CadastreFranceAdapter::getName() const
71 {
72 return theName;
73 }
74
setSettings(QSettings * aSet)75 void CadastreFranceAdapter::setSettings(QSettings* aSet)
76 {
77 theSettings = aSet;
78 if (theSettings)
79 CadastreWrapper::instance()->setRootCacheDir(QDir(theSettings->value("backgroundImage/CacheDir").toString()));
80 else
81 CadastreWrapper::instance()->setRootCacheDir(QDir(QDir::homePath() + "/.merkaartor/BackgroundCache"));
82 updateMenu();
83 }
84
getHost() const85 QString CadastreFranceAdapter::getHost() const
86 {
87 return "www.cadastre.gouv.fr";
88 }
89
getType() const90 IMapAdapter::Type CadastreFranceAdapter::getType() const
91 {
92 return IMapAdapter::NetworkBackground;
93 }
94
projection() const95 QString CadastreFranceAdapter::projection() const
96 {
97 return m_city.projection();
98 }
99
getBoundingbox() const100 QRectF CadastreFranceAdapter::getBoundingbox() const
101 {
102 double L = qMax(m_city.geometry().width(), m_city.geometry().height());
103 QRectF bb(m_city.geometry());
104 QRectF R = QRectF(QPointF(bb.center().x()-L/2, bb.center().y()-L/2),
105 QPointF(bb.center().x()+L/2, bb.center().y()+L/2));
106 return R;
107 // return QRectF(R.bottomLeft(), R.topRight());
108 }
109
getMenu() const110 QMenu* CadastreFranceAdapter::getMenu() const
111 {
112 return theMenu;
113 }
114
getImageManager()115 IImageManager* CadastreFranceAdapter::getImageManager()
116 {
117 return theImageManager;
118 }
119
setImageManager(IImageManager * anImageManager)120 void CadastreFranceAdapter::setImageManager(IImageManager* anImageManager)
121 {
122 theImageManager = anImageManager;
123 CadastreWrapper::instance()->setNetworkManager(theImageManager->getNetworkManager());
124 theImageManager->setCachePermanent(true);
125 }
126
updateMenu()127 void CadastreFranceAdapter::updateMenu()
128 {
129 delete theMenu;
130 theMenu = new QMenu(0);
131
132 QAction* grabCity = new QAction(tr("Grab City..."), this);
133 connect(grabCity, SIGNAL(triggered()), SLOT(onGrabCity()));
134 theMenu->addAction(grabCity);
135 QAction* tiledToggle = new QAction(tr("Tiled"), this);
136 tiledToggle->setCheckable(true);
137 tiledToggle->setChecked(m_isTiled);
138 connect(tiledToggle, SIGNAL(triggered()), SLOT(toggleTiled()));
139 theMenu->addAction(tiledToggle);
140
141 theMenu->addSeparator();
142
143 QDir cache = CadastreWrapper::instance()->getCacheDir();
144 QFileInfoList fl = cache.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs);
145 foreach (QFileInfo fi, fl) {
146 QSettings sets(fi.absoluteFilePath()+"/cache.ini", QSettings::IniFormat);
147 QAction* cityAct = new QAction(sets.value("name").toString(), this);
148 cityAct->setData(fi.fileName());
149 theMenu->addAction(cityAct);
150 }
151 connect(theMenu, SIGNAL(triggered(QAction*)), SLOT(cityTriggered(QAction*)));
152 }
153
toggleTiled()154 void CadastreFranceAdapter::toggleTiled()
155 {
156 m_isTiled = !m_isTiled;
157 updateMenu();
158 emit(forceRefresh());
159 }
160
onGrabCity()161 void CadastreFranceAdapter::onGrabCity()
162 {
163 if (!theImageManager)
164 return;
165 m_city = City();
166
167 SearchDialog *dial = new SearchDialog();
168 dial->cadastre->setRootCacheDir(QDir(theSettings->value("backgroundImage/CacheDir").toString()));
169 dial->setModal(true);
170 if (dial->exec()) {
171 m_code = dial->cityCode();
172 QString name = dial->cityName();
173 if (!name.isEmpty())
174 initializeCity(name);
175 }
176 delete dial;
177 }
178
cityTriggered(QAction * act)179 void CadastreFranceAdapter::cityTriggered(QAction *act)
180 {
181 QString name = act->text();
182 if (act->data().toString().isEmpty())
183 return;
184 m_code = act->data().toString();
185 if (!theImageManager)
186 return;
187 m_city = City();
188 initializeCity(name);
189 }
190
initializeCity(QString name)191 void CadastreFranceAdapter::initializeCity(QString name)
192 {
193 qDebug() << "Initializing " << name;
194 connect(CadastreWrapper::instance(), SIGNAL(resultsAvailable(QMap<QString,QString>)), this, SLOT(resultsAvailable(QMap<QString,QString>)));
195 QString ville = name.left(name.lastIndexOf('(')-1);
196 m_department = QString("%1").arg(name.mid(name.lastIndexOf('(')+1, name.lastIndexOf(')')-name.lastIndexOf('(')-1).toInt(), 3, 10, QChar('0'));
197 CadastreWrapper::instance()->searchVille(ville, m_department);
198 }
199
resultsAvailable(QMap<QString,QString> results)200 void CadastreFranceAdapter::resultsAvailable(QMap<QString, QString> results)
201 {
202 if (results.size() > 1) {
203 CadastreWrapper::instance()->searchCode(m_code, m_department);
204 return;
205 }
206
207 disconnect(CadastreWrapper::instance(), SIGNAL(resultsAvailable(QMap<QString,QString>)), this, SLOT(resultsAvailable(QMap<QString,QString>)));
208
209 if (!results.size()) {
210 QMessageBox::critical(0, tr("The city cannot be loaded"), tr("Only vectorized cities can be handled by this plugin and the selected one is still in \"Image\" format."));
211 return;
212 }
213
214 m_city = CadastreWrapper::instance()->requestCity(m_code);
215 updateMenu();
216 // if (!CadastreWrapper::instance()->downloadTiles(m_city))
217 // return;
218
219 QDir dir = CadastreWrapper::instance()->getCacheDir();
220 Q_ASSERT(dir.cd(m_city.code()));
221 if (theImageManager)
222 theImageManager->setCacheDir(dir);
223
224 emit(forceZoom());
225 emit(forceProjection());
226 emit(forceRefresh());
227 }
228
isValid(int x,int y,int z) const229 bool CadastreFranceAdapter::isValid(int x, int y, int z) const
230 {
231 // Origin is bottom-left
232 y = getTilesNS(current_zoom)-1 - y;
233
234 if (m_city.code().isEmpty())
235 return false;
236
237 if ((x<0) || (x>=getTilesWE(z)) ||
238 (y<0) || (y>=getTilesNS(z)))
239 {
240 return false;
241 }
242 return true;
243
244 }
245
getQuery(int i,int j,int) const246 QString CadastreFranceAdapter::getQuery(int i, int j, int /* z */) const
247 {
248 qreal tileWidth = getBoundingbox().width() / getTilesWE(current_zoom);
249 qreal tileHeight = getBoundingbox().height() / getTilesNS(current_zoom);
250
251 QPointF ul = QPointF(i*tileWidth+getBoundingbox().topLeft().x(), getBoundingbox().bottomLeft().y()-j*tileHeight);
252 QPointF br = QPointF((i+1)*tileWidth+getBoundingbox().topLeft().x(), getBoundingbox().bottomLeft().y()- (j+1)*tileHeight);
253
254 QUrl theUrl("http://www.cadastre.gouv.fr/scpc/wms?version=1.1&request=GetMap&layers=CDIF:LS3,CDIF:LS2,CDIF:LS1,CDIF:PARCELLE,CDIF:NUMERO,CDIF:PT3,CDIF:PT2,CDIF:PT1,CDIF:LIEUDIT,CDIF:COMMUNE&format=image/png&exception=application/vnd.ogc.se_inimage&styles=LS3_90,LS2_90,LS1_90,PARCELLE_90,NUMERO_90,PT3_90,PT2_90,PT1_90,LIEUDIT_90,COMMUNE_90");
255 theUrl.addQueryItem("WIDTH", QString::number(getTileSizeW()));
256 theUrl.addQueryItem("HEIGHT", QString::number(getTileSizeH()));
257 theUrl.addQueryItem("BBOX", QString()
258 .append(loc.toString(ul.x(),'f',6)).append(",")
259 .append(loc.toString(br.y(),'f',6)).append(",")
260 .append(loc.toString(br.x(),'f',6)).append(",")
261 .append(loc.toString(ul.y(),'f',6))
262 );
263
264 return theUrl.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority);
265 }
266
getQuery(const QRectF &,const QRectF & projBbox,const QRect & size) const267 QString CadastreFranceAdapter::getQuery(const QRectF& , const QRectF& projBbox, const QRect& size) const
268 {
269 if (m_city.code().isEmpty())
270 return QString();
271
272 QUrl theUrl("http://www.cadastre.gouv.fr/scpc/wms?version=1.1&request=GetMap&layers=CDIF:LS3,CDIF:LS2,CDIF:LS1,CDIF:PARCELLE,CDIF:NUMERO,CDIF:PT3,CDIF:PT2,CDIF:PT1,CDIF:LIEUDIT,CDIF:COMMUNE&format=image/png&exception=application/vnd.ogc.se_inimage&styles=LS3_90,LS2_90,LS1_90,PARCELLE_90,NUMERO_90,PT3_90,PT2_90,PT1_90,LIEUDIT_90,COMMUNE_90");
273 theUrl.addQueryItem("WIDTH", QString::number(size.width()));
274 theUrl.addQueryItem("HEIGHT", QString::number(size.height()));
275 theUrl.addQueryItem("BBOX", QString()
276 .append(loc.toString(projBbox.bottomLeft().x(),'f',6)).append(",")
277 .append(loc.toString(projBbox.bottomLeft().y(),'f',6)).append(",")
278 .append(loc.toString(projBbox.topRight().x(),'f',6)).append(",")
279 .append(loc.toString(projBbox.topRight().y(),'f',6))
280 );
281
282 return theUrl.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority);
283 }
284
getPixmap(const QRectF &,const QRectF & projBbox,const QRect & src) const285 QPixmap CadastreFranceAdapter::getPixmap(const QRectF& /*wgs84Bbox*/, const QRectF& projBbox, const QRect& src) const
286 {
287 QPixmap pix(src.size());
288 pix.fill(Qt::transparent);
289 QPainter p(&pix);
290 p.scale(src.width()/projBbox.width(), src.height()/projBbox.height());
291 p.translate(-projBbox.left(), -projBbox.bottom());
292
293 if (!m_city.code().isEmpty()) {
294 QDir dir = CadastreWrapper::instance()->getCacheDir();
295 Q_ASSERT(dir.cd(m_city.code()));
296
297 for (int r=0; r<m_city.tileRows(); ++r) {
298 for (int c=0; c<m_city.tileColumns(); ++c) {
299 QRectF g = QRectF(m_city.tileGeometry(r, c));
300 QRectF inter = g.intersected(projBbox);
301 if (!inter.isNull()) {
302 QImage img(dir.absoluteFilePath(QString("%1-%2.png").arg(r).arg(c)));
303 p.drawImage(g.topLeft(), img);
304 }
305 }
306 }
307 }
308
309 p.end();
310 return pix;
311 }
312
cleanup()313 void CadastreFranceAdapter::cleanup()
314 {
315 }
316
toXML(QXmlStreamWriter & stream)317 bool CadastreFranceAdapter::toXML(QXmlStreamWriter& stream)
318 {
319 Q_UNUSED(stream)
320
321 return true;
322 }
323
fromXML(QXmlStreamReader & stream)324 void CadastreFranceAdapter::fromXML(QXmlStreamReader& stream)
325 {
326 Q_UNUSED(stream)
327 }
328
toPropertiesHtml()329 QString CadastreFranceAdapter::toPropertiesHtml()
330 {
331 return QString();
332 }
333
isTiled() const334 bool CadastreFranceAdapter::isTiled() const
335 {
336 return m_isTiled;
337 }
338
getTilesWE(int zoomlevel) const339 int CadastreFranceAdapter::getTilesWE(int zoomlevel) const
340 {
341 qreal unitPerTile = Resolutions[zoomlevel] * getTileSizeW(); // Size of 1 tile in projected units
342 return qRound(getBoundingbox().width() / unitPerTile);
343 }
344
getTilesNS(int zoomlevel) const345 int CadastreFranceAdapter::getTilesNS(int zoomlevel) const
346 {
347 qreal unitPerTile = Resolutions[zoomlevel] * getTileSizeH(); // Size of 1 tile in projected units
348 return qRound(getBoundingbox().height() / unitPerTile);
349 }
350
getTileSizeW() const351 int CadastreFranceAdapter::getTileSizeW () const
352 {
353 return 256;
354 }
355
getTileSizeH() const356 int CadastreFranceAdapter::getTileSizeH () const
357 {
358 return 256;
359 }
360
zoom_in()361 void CadastreFranceAdapter::zoom_in()
362 {
363 current_zoom = current_zoom < max_zoom ? current_zoom+1 : max_zoom;
364
365 }
zoom_out()366 void CadastreFranceAdapter::zoom_out()
367 {
368 current_zoom = current_zoom > min_zoom ? current_zoom-1 : min_zoom;
369 }
370
getMinZoom(const QRectF &) const371 int CadastreFranceAdapter::getMinZoom(const QRectF &) const
372 {
373 return min_zoom;
374 }
375
getMaxZoom(const QRectF &) const376 int CadastreFranceAdapter::getMaxZoom(const QRectF &) const
377 {
378 return max_zoom;
379 }
380
getAdaptedMinZoom(const QRectF &) const381 int CadastreFranceAdapter::getAdaptedMinZoom(const QRectF &) const
382 {
383 return 0;
384 }
385
getAdaptedMaxZoom(const QRectF &) const386 int CadastreFranceAdapter::getAdaptedMaxZoom(const QRectF &) const
387 {
388 return max_zoom > min_zoom ? max_zoom - min_zoom : min_zoom - max_zoom;
389 }
390
getZoom() const391 int CadastreFranceAdapter::getZoom() const
392 {
393 return current_zoom;
394 }
395
getAdaptedZoom() const396 int CadastreFranceAdapter::getAdaptedZoom() const
397 {
398 return max_zoom < min_zoom ? min_zoom - current_zoom : current_zoom - min_zoom;
399 }
400
getSourceTag() const401 QString CadastreFranceAdapter::getSourceTag () const
402 {
403 return "cadastre-dgi-fr source : Direction G�n�rale des Imp�ts - Cadastre. Mise � jour : 2010";
404 }
405
406 Q_EXPORT_PLUGIN2(MCadastreFranceBackgroundPlugin, CadastreFranceAdapterFactory)
407