1 /**********************************************************************************************
2     Copyright (C) 2014 Oliver Eichler <oliver.eichler@gmx.de>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 **********************************************************************************************/
18 
19 #include "CMainWindow.h"
20 #include "CProjWizard.h"
21 #include "gis/proj_x.h"
22 #include "grid/mitab.h"
23 
24 #include <QtWidgets>
25 
26 struct mitab_entry_t
27 {
28     QString name;
29     int idx;
30 };
31 
mitabLessThan(const mitab_entry_t & s1,const mitab_entry_t & s2)32 static bool mitabLessThan(const mitab_entry_t& s1, const mitab_entry_t& s2)
33 {
34     return s1.name < s2.name;
35 }
36 
CProjWizard(QLineEdit & line)37 CProjWizard::CProjWizard(QLineEdit& line)
38     : QDialog(CMainWindow::getBestWidgetForParent())
39     , line(line)
40 {
41     setupUi(this);
42     QList<mitab_entry_t> list;
43     int idx = 0;
44 
45     for(const MapInfoDatumInfo& di : asDatumInfoList)
46     {
47         mitab_entry_t entry;
48         entry.name = di.pszOGCDatumName;
49         if(!entry.name.isEmpty())
50         {
51             for(const MapInfoSpheroidInfo& si : asSpheroidInfoList)
52             {
53                 if(si.nMapInfoId == di.nEllipsoid)
54                 {
55                     entry.name += tr(" (Spheroid: %1)").arg(si.pszMapinfoName);
56                 }
57             }
58         }
59         entry.idx = idx;
60         list << entry;
61         ++idx;
62     }
63     qSort(list.begin(), list.end(), mitabLessThan);
64 
65     for(const mitab_entry_t& entry : qAsConst(list))
66     {
67         comboDatum->addItem(entry.name, entry.idx);
68     }
69 
70     comboHemisphere->addItem(tr("north"), "");
71     comboHemisphere->addItem(tr("south"), "+south");
72 
73     connect(radioMercator, &QRadioButton::clicked, this, &CProjWizard::slotChange);
74     connect(radioWorldMercator, &QRadioButton::clicked, this, &CProjWizard::slotChange);
75     connect(radioUPSNorth, &QRadioButton::clicked, this, &CProjWizard::slotChange);
76     connect(radioUPSSouth, &QRadioButton::clicked, this, &CProjWizard::slotChange);
77     connect(radioUTM, &QRadioButton::clicked, this, &CProjWizard::slotChange);
78     connect(radioUserDef, &QRadioButton::clicked, this, &CProjWizard::slotChange);
79     connect(lineUserDef, &QLineEdit::textChanged, this, &CProjWizard::slotChange);
80 
81     connect(spinUTMZone, static_cast<void (QSpinBox::*)(int) >(&QSpinBox::valueChanged), this, &CProjWizard::slotChange);
82     connect(comboDatum, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &CProjWizard::slotChange);
83     connect(comboHemisphere, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &CProjWizard::slotChange);
84 
85     QString projstr = line.text();
86     QRegExp re2("\\s*\\+proj=merc \\+a=6378137 \\+b=6378137 \\+lat_ts=0.001 \\+lon_0=0.0 \\+x_0=0.0 \\+y_0=0 \\+k=1.0 \\+units=m \\+nadgrids=@null \\+no_defs");
87     QRegExp re3("\\s*\\+proj=merc\\s(.*)");
88     QRegExp re4("\\s*\\+proj=utm \\+zone=([0-9]+)\\s(.*)");
89 
90     if(re2.exactMatch(projstr))
91     {
92         radioWorldMercator->setChecked(true);
93     }
94     else if(re3.exactMatch(projstr))
95     {
96         radioMercator->setChecked(true);
97         findDatum(re3.cap(1));
98     }
99     else if(re4.exactMatch(projstr))
100     {
101         radioUTM->setChecked(true);
102         spinUTMZone->setValue(re4.cap(1).toInt());
103 
104         QString datum = re4.cap(2);
105         if(datum.startsWith("+south "))
106         {
107             datum = datum.mid(7);
108             comboHemisphere->setCurrentIndex(1);
109         }
110 
111         findDatum(datum);
112     }
113 
114     slotChange();
115 }
116 
~CProjWizard()117 CProjWizard::~CProjWizard()
118 {
119 }
120 
121 
findDatum(const QString & str)122 void CProjWizard::findDatum(const QString& str)
123 {
124     QString cmp;
125     for(const MapInfoDatumInfo& di : asDatumInfoList)
126     {
127         cmp.clear();
128         if(di.pszOGCDatumName != QString())
129         {
130             for(const MapInfoSpheroidInfo& si : asSpheroidInfoList)
131             {
132                 if(si.nMapInfoId == di.nEllipsoid)
133                 {
134                     cmp += QString("+a=%1 +b=%2 ").arg(si.dfA, 0, 'f', 4).arg(si.dfA * (1.0 - (1.0 / si.dfInvFlattening)), 0, 'f', 4);
135                     cmp += QString("+towgs84=%1,%2,%3,%4,%5,%6,%7 ").arg(di.dfShiftX).arg(di.dfShiftY).arg(di.dfShiftZ).arg(di.dfDatumParm0).arg(di.dfDatumParm1).arg(di.dfDatumParm2).arg(di.dfDatumParm3);
136                     cmp += "+units=m  +no_defs";
137                     break;
138                 }
139             }
140         }
141 
142         if(cmp == str)
143         {
144             comboDatum->setCurrentIndex(comboDatum->findText(di.pszOGCDatumName));
145             break;
146         }
147     }
148 }
149 
150 
slotChange()151 void CProjWizard::slotChange()
152 {
153     QString str;
154     if(radioMercator->isChecked())
155     {
156         str += "+proj=merc ";
157     }
158     else if(radioWorldMercator->isChecked())
159     {
160         str += "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.001 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";
161         labelResult->setText(str);
162         return;
163     }
164     else if(radioUPSNorth->isChecked())
165     {
166         str += "EPSG:32661";
167     }
168     else if(radioUPSSouth->isChecked())
169     {
170         str += "EPSG:32761";
171     }
172     else if(radioUTM->isChecked())
173     {
174         str += QString("+proj=utm +zone=%1 %2 ").arg(spinUTMZone->value()).arg(comboHemisphere->itemData(comboHemisphere->currentIndex()).toString());
175     }
176     else if(radioUserDef->isChecked())
177     {
178         str += lineUserDef->text() + " ";
179     }
180 
181     int idx = comboDatum->itemData(comboDatum->currentIndex()).toInt();
182     const MapInfoDatumInfo& di = asDatumInfoList[idx];
183     if(di.pszOGCDatumName != QString())
184     {
185         for(const MapInfoSpheroidInfo& si : asSpheroidInfoList)
186         {
187             if(si.nMapInfoId == di.nEllipsoid)
188             {
189                 str += QString("+a=%1 +b=%2 ").arg(si.dfA, 0, 'f', 4).arg(si.dfA * (1.0 - (1.0 / si.dfInvFlattening)), 0, 'f', 4);
190                 str += QString("+towgs84=%1,%2,%3,%4,%5,%6,%7 ").arg(di.dfShiftX).arg(di.dfShiftY).arg(di.dfShiftZ).arg(di.dfDatumParm0).arg(di.dfDatumParm1).arg(di.dfDatumParm2).arg(di.dfDatumParm3);
191                 str += "+units=m  +no_defs";
192                 break;
193             }
194         }
195     }
196 
197     labelResult->setText(str);
198 }
199 
200 
accept()201 void CProjWizard::accept()
202 {
203     if (CProjWizard::validProjStr(labelResult->text(), true))
204     {
205         line.setText(labelResult->text());
206         line.setCursorPosition(0);
207         QDialog::accept();
208     }
209 }
210 
211 
validProjStr(const QString projStr,bool allowLonLatToo)212 bool CProjWizard::validProjStr(const QString projStr, bool allowLonLatToo)
213 {
214     return CProj::validProjStr(projStr, allowLonLatToo, [](const QString& msg){
215         QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), msg, QMessageBox::Abort, QMessageBox::Abort);
216     });
217 }
218 
219 
220