-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDF_Proj_Point.cpp
311 lines (272 loc) · 8.46 KB
/
DF_Proj_Point.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
//-*- mode:C++ ; c-basic-offset: 2 -*-
// DFLib: A library of Bearings Only Target Localization algorithms
// Copyright (C) 2009-2015 Thomas V. Russo
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Filename : $RCSfile$
//
// Purpose : Implement a DFLib::Abstract::Point interface such that
// the "user" coordinate system is whatever the user has
// specified with a proj.4 spatial reference system, and the
// "XY" coordinate system is a mercator projection on the
// WGS84 ellipsoid.
//
// Special Notes :
//
// Creator :
//
// Creation Date :
//
// Revision Information:
// ---------------------
//
// Revision Number: $Revision$
//
// Revision Date : $Date$
//
// Current Owner : $Author$
//-------------------------------------------------------------------------
#include "DF_Proj_Point.hpp"
#include "Util_Misc.hpp"
#include <vector>
#include <iostream>
#include <cstdlib>
namespace DFLib
{
namespace Proj
{
// class Point
Point::Point(const std::vector<double> &uPosition,const std::vector<std::string> &projArgs)
: theUserCoords(uPosition),
userDirty(true),
mercDirty(false)
{
// Create the proj.4 stuff. This is highly inefficient, as it should
// live in the base class, not each object. Fix that.
char *mercator_argv[3]={"proj=merc",
"datum=WGS84",
"lat_ts=0"};
int numUserArgs = projArgs.size();
char **user_argv = new char * [numUserArgs];
for (int i=0; i<numUserArgs; ++i)
{
user_argv[i]=new char [projArgs[i].size()+1];
projArgs[i].copy(user_argv[i],projArgs[i].size());
// Null terminate the string!
user_argv[i][projArgs[i].size()] = '\0';
}
if (!(userProj = pj_init(numUserArgs,user_argv)))
{
throw(Util::Exception("Failed to initialize user projection"));
}
if (!(mercProj = pj_init(3,mercator_argv)))
{
throw(Util::Exception("Failed to initialize mercator projection"));
}
// Don't bother trying to force the mercator --- we'll do that if
// we query, because we're setting userDirty to true, just initialize
// to junk.
theMerc.resize(2,0.0);
// Now must free the user_argv junk:
for (int i=0; i<numUserArgs; ++i)
{
delete [] user_argv[i];
}
delete [] user_argv;
}
Point::Point(const Point &right)
{
// Must *COPY* the definition, not the pointer to it!
// Get the text version of the definition
char *theProjDef = pj_get_def(right.userProj,0);
// generate a new projUJ pointer
userProj = pj_init_plus(theProjDef);
free(theProjDef);
theProjDef = pj_get_def(right.mercProj,0);
// generate a new projUJ pointer
mercProj = pj_init_plus(theProjDef);
free(theProjDef);
if (right.mercDirty)
{
// Right's mercator's been changed without its LL being
// updated, so copy its mercator values and say we're dirty.
theMerc=right.theMerc;
mercDirty=true;
userDirty=false;
}
else
{
// Just copy its LL and mark dirty.
theUserCoords=right.theUserCoords;
userDirty=true;
mercDirty=false;
}
}
Point::~Point()
{
pj_free(userProj);
pj_free(mercProj);
}
Point& Point::operator=(const Point& rhs)
{
if (this == &rhs) return *this;
if (userProj)
{
pj_free(userProj);
userProj=0;
}
if (mercProj)
{
pj_free(mercProj);
mercProj=0;
}
char *theProjDef = pj_get_def(rhs.userProj,0);
// generate a new projUJ pointer
userProj = pj_init_plus(theProjDef);
free(theProjDef);
theProjDef = pj_get_def(rhs.mercProj,0);
// generate a new projUJ pointer
mercProj = pj_init_plus(theProjDef);
free(theProjDef);
mercDirty=rhs.mercDirty;
userDirty=rhs.userDirty;
// This is OK, because we're copying the dirty bools, too.
// we have to copy both of these, otherwise we risk copying only the
// ones that haven't been updated for consistency!
theMerc=rhs.theMerc;
theUserCoords=rhs.theUserCoords;
return (*this);
}
void Point::setXY(const std::vector<double> &mPosition)
{
theMerc = mPosition;
// Essential to set userDirty=false, otherwise getXY will try to
// convert ll and we'll be wrong.
mercDirty=true;
userDirty=false;
}
void Point::setUserProj(const std::vector<std::string> &projArgs)
{
int numUserArgs = projArgs.size();
char **user_argv = new char * [numUserArgs];
for (int i=0; i<numUserArgs; ++i)
{
user_argv[i]=new char [projArgs[i].size()+1];
projArgs[i].copy(user_argv[i],projArgs[i].size());
// Null terminate the string!
user_argv[i][projArgs[i].size()] = '\0';
}
// before we clobber userProj, if we have already have valid userProj
// already then we might also have
// valid data, and need to make sure our coordinates are correct in the
// new system:
if (userProj)
{
if (userDirty)
{
userToMerc(); // make sure our mercator coordinates are up-to-date
}
pj_free(userProj); // free the existing projection
userProj = NULL;
}
if (!(userProj = pj_init(numUserArgs,user_argv)))
{
throw(Util::Exception("Failed to initialize user projection"));
}
// Now, we have just changed the projection, so mark mercDirty as if
// we had changed the mercator coordinates ourselves.
mercDirty=true;
// Now must free the user_argv junk:
for (int i=0; i<numUserArgs; ++i)
{
delete [] user_argv[i];
}
delete [] user_argv;
}
bool Point::isUserProjLatLong() const
{
return (pj_is_latlong(userProj));
}
const std::vector<double> & Point::getXY()
{
if (userDirty)
{
// our LL has been changed, so update
userToMerc();
}
return(theMerc);
}
void Point::setUserCoords(const std::vector<double> &llPosition)
{
theUserCoords = llPosition;
// If we set ll, must now trump mercator.
userDirty=true; mercDirty=false;
}
const std::vector<double> & Point::getUserCoords()
{
if (mercDirty)
{
// our XY has been changed, so update
mercToUser();
}
return(theUserCoords);
}
Point * Point::Clone()
{
Point *retPoint;
retPoint = new Point(*this);
return retPoint;
}
void Point::userToMerc()
{
projUV data;
double z;
if (pj_is_latlong(userProj))
{
data.u = theUserCoords[0]*DEG_TO_RAD;
data.v = theUserCoords[1]*DEG_TO_RAD;
}
z=0;
if (pj_transform(userProj,mercProj,1,0,&(data.u),&(data.v),&z) != 0)
{
throw(Util::Exception("Failure converting user coords to Mercator"));
}
theMerc.resize(2);
theMerc[0]=data.u;
theMerc[1]=data.v;
userDirty=false;
}
void Point::mercToUser()
{
projUV data;
double z;
data.u = theMerc[0];
data.v = theMerc[1];
z=0;
if (pj_transform(mercProj,userProj,1,0,&(data.u),&(data.v),&z) != 0)
{
throw(Util::Exception("Failure converting Mercator to LL"));
}
theUserCoords.resize(2);
if (pj_is_latlong(userProj))
{
theUserCoords[0]=data.u*RAD_TO_DEG;
theUserCoords[1]=data.v*RAD_TO_DEG;
}
mercDirty=false;
}
}
}