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