Proj6.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 #ifndef DRAIN_PROJ6_H_
32 #define DRAIN_PROJ6_H_
33 
34 #include <cstddef>
35 #include <iostream>
36 #include <set>
37 #include <stdexcept>
38 #include <string>
39 
40 #include <proj.h>
41 
42 #include "Dictionary.h"
43 #include "Point.h"
44 // #include "TreeUnordered.h"
45 
46 
47 namespace drain
48 {
49 
50 class Proj6;
51 
52 
53 // Helper class for containing a single (one-way) Proj object and its
54 class Projector {
55 
56  friend class Proj6;
57 
58  static const SprinterLayout projDefLayout; // space-separated, =, no hypens (" ","","=", "","");
59 
60 public:
61 
63 
64  //typedef enum {PROJ4, PROJ6, CRS} version;
65  typedef enum {
66  ACCEPT_CRS, // Do not touch
67  REMOVE_CRS, // Delete "+type=crs" from projDef, warn if EPSG:<code> syntax used
68  FORCE_CRS // Add "+type=crs"
69  } CRS_mode;
70 
71 
73  typedef enum {
74  ORIG, // Supplied, provided by user
75  MODIFIED, // EPSG-converted and filtered
76  // FINAL, //
77  PROJ4, // Final, formulated by projlib
78  PROJ5, // Final, formulated by projlib
79  SIMPLE // Final, simplified for backward compatibility: "+type=crs" and "+init=epsg:..." pruned.
81 
82 
83  inline // NEW 2024: proj_context_create()
84  Projector(const std::string & projDef = "", CRS_mode crs=ACCEPT_CRS) : pjContext(proj_context_create()), pj(nullptr), epsg(0){
85  //Projector(const std::string & projDef = "", CRS_mode crs=ACCEPT_CRS) : pjContext(nullptr), pj(nullptr), epsg(0){
86  if (projDef.empty()){
87  projDefs = {{ORIG,""}, {MODIFIED,""}, {PROJ4,""}, {PROJ5,""}, {SIMPLE,""}};
88  }
89  else {
90  setProjection(projDef, crs);
91  }
92  }
93 
94  inline
95  Projector(PJ_CONTEXT *pjContext, const std::string & projDef = "", CRS_mode crs=ACCEPT_CRS) : pjContext(pjContext), pj(nullptr), epsg(0){
96  if (projDef.empty()){
97  projDefs = {{ORIG,""}, {MODIFIED,""}, {PROJ4,""}, {PROJ5,""}, {SIMPLE,""}};
98  }
99  else {
100  setProjection(projDef, crs);
101  }
102  }
103 
104  inline
105  Projector(const Projector & pr) :
106  pjContext(proj_context_clone(pr.pjContext)), // NEW 2024
107  // pjContext(nullptr), // for safety
108  // TODO: CLONE, in version 7.2.
109  // pjContext(proj_context_clone(pr.pjContext)), // TODO: flag for own CTX => destroy at end
110  pj(proj_clone(pjContext, pr.pj)),
111  // projDefDict(pr.projDefDict),
112  epsg(pr.epsg)
113  {
114  // TODO
115  //projDefs = {{ORIG,"*"}, {CHECKED,"**"}, {FINAL,"***"}, {INTERNAL,"****"}};
116  setProjection(pr.getProjDef(ORIG)); // imitate ?
117  }
118 
119  virtual inline
120  ~Projector(){
121  proj_destroy(pj);
122  proj_context_destroy(pjContext); // NEW 2024
123  }
124 
125  static
126  void getProjDefDict(const std::string & str, ProjDef & dict);
127 
128  static
129  //int extractEPSG(const std::string & projDef);
130  int extractEPSG(const ProjDef & projDefDict);
131 
132  static
133  void getProjDefStr(const ProjDef & dict, std::stringstream & sstr, const std::set<std::string> & excludeKeys = {"+type"});
134 
135  const std::string & getProjDef(PROJDEF_variant v = SIMPLE) const { // For external objects, excluding +init=epsg and +type=crs
136  return projDefs[v];
137  }
138 
139 
140 
142  void clear(){
143  projDefs = {{ORIG,""}, {MODIFIED,""}, {PROJ4,""}, {PROJ5,""}, {SIMPLE,""}};
144  pjContext = nullptr; // TODO: flag for own CTX => destroy at end
145  proj_destroy(pj);
146  pj = nullptr;
147  projDefDict.clear();
148  epsg = 0;
149  }
150 
152 
155  void setProjection(const std::string &str, CRS_mode crs=FORCE_CRS);
156 
158 
161  void setProjection(int epsg, CRS_mode crs=FORCE_CRS);
162 
163  // protect
164  void updateProjectionDefs(CRS_mode crs);
165 
167  inline
168  bool isSet() const {
169  return (pj != nullptr);
170  }
171 
172  // NOTE: compliancy problems Proj.4...6...
173  inline
174  bool isLongLat() const {
175  // TODO: what if not defined.
176  return isLongLat(pj);
177  }
178 
179  inline
180  int getEPSG() const {
181  return epsg;
182  }
183 
184 
185 
187  //static
188  // int filterProjStr(const std::string & src, std::ostream & ostr, CRS_mode crs=ACCEPT_CRS);
189 
190 
191  inline
192  void info(std::ostream & ostr = std::cout, int wkt = -1){
193 
194  for (const auto & entry: projDefs){
195  ostr << entry.first << ": '" << entry.second << "'\n";
196  }
197  info(pj, ostr, wkt);
198  }
199 
200  inline
201  std::string getErrorString() const {
202  int err = proj_context_errno(pjContext);
203  return proj_errno_string(err);
204  //return "Not Impl."; //std::string(pj_strerrno(*pj_get_errno_ref()));
205  };
206 
207 // to-be protected:
208 
210  void info(PJ *pj, std::ostream & ostr = std::cout, int wkt = -1);
211 
212 protected:
213 
214  // const std::string & getProjection(const PJ *prj, std::string & projDef) const;
215  ProjDef projDefDict;
216 
217  mutable
218  std::map<PROJDEF_variant,std::string> projDefs;
219 
220 
222 
226  // PJ * getProjection(const std::string & projStr, CRS_mode crs=ACCEPT_CRS) const;
227 
228  static
229  bool isLongLat(const PJ *prj);
230 
231  PJ_CONTEXT *pjContext;
232  PJ *pj;
233 
234  //mutable
235  //std::string projDef;
236 
237  int epsg;
238 
239 };
240 
256 class Proj6
257 {
258 public:
259 
260  Proj6();
261 
262  Proj6(const Proj6 &p);
263 
264  virtual ~Proj6();
265 
266 
267  static
268  const std::string & getProjVersion();
269 
270  Projector src;
271  Projector dst;
272 
273 
275 
278  inline
279  void setProjectionSrc(const std::string & projDef, Projector::CRS_mode crs=Projector::FORCE_CRS){
280  src.setProjection(projDef, crs);
281  setMapping(true);
282  }
283 
285  inline
286  void setProjectionDst(const std::string & projDef, Projector::CRS_mode crs=Projector::FORCE_CRS){
287  dst.setProjection(projDef, crs);
288  setMapping(true);
289  }
290 
292  inline
293  void setProjections(const std::string & projDefSrc, const std::string & projDefDst){
294  src.setProjection(projDefSrc, Projector::FORCE_CRS);
295  dst.setProjection(projDefDst, Projector::FORCE_CRS);
296  setMapping(false);
297  }
298 
299 
300  //void setMapping(const std::string & proj1, const std::string & proj2);
301 
302 
304 
309  inline
310  const std::string & getProjectionSrc() const {
311  return src.getProjDef();
312  //return getProjection(projSrc, projStrSrc);
313  };
314 
315  inline
316  const std::string & getProjectionDst() const {
317  return dst.getProjDef();
318  //return getProjection(projDst, projStrDst);
319  };
320 
321  inline
322  const Projector & getSrc() const {
323  return src;
324  };
325 
326  inline
327  const Projector & getDst() const {
328  return dst;
329  };
330 
331 
332 protected:
333 
337  template
338  <PJ_DIRECTION D,class POINT_XY>
339  inline
340  void project(POINT_XY & point) const {
341  // void project(drain::Point2D<double> & point) const {
342  // Note: sizeof not needed, future option for arrays.
343  proj_trans_generic(proj, D, &point.x, sizeof(POINT_XY), 1, &point.y, sizeof(POINT_XY), 1, 0, 0, 0, 0, 0, 0);
344  }
345 
346  template
347  <PJ_DIRECTION D>
348  inline
349  void project(double & x, double & y) const {
350  // Note: sizeof not needed, future option for arrays.
351  proj_trans_generic(proj, D, &x, sizeof(double), 1, &y, sizeof(double), 1, 0, 0, 0, 0, 0, 0);
352  }
353 
354 
355 public:
356 
358  inline
359  void projectFwd(double & x, double & y) const {
360  project<PJ_FWD>(x,y);
361  }
362 
364  inline
365  void projectFwd(double x, double y, double & x2, double & y2) const {
366  x2 = x;
367  y2 = y;
368  project<PJ_FWD>(x2,y2);
369  }
370 
372  inline
373  void projectFwd(drain::Point2D<double> & point) const {
374  project<PJ_FWD>(point);
375  }
376 
377  // Inverse projection (in-place)
378  inline
379  void projectInv(double & x, double & y) const {
380  project<PJ_INV>(x,y);
381  }
382 
383  // Inverse projection
384  inline
385  void projectInv(double x, double y, double & x2, double & y2) const {
386  x2 = x;
387  y2 = y;
388  project<PJ_INV>(x2,y2);
389  }
390 
391  // Inverse projection. Example implementation of project<>() .
392  inline
393  void projectInv(drain::Point2D<double> & point) const {
394  project<PJ_INV>(point);
395  }
396 
397 
399  /*
400  inline
401  void projectFwdOLD(double & x, double & y) const {
402  PJ_COORD coord;
403  coord.lp.lam = x;
404  coord.lp.phi = y;
405  proj_trans_array(proj, PJ_DIRECTION::PJ_FWD, 1, &coord);
406  x = coord.xy.x;
407  y = coord.xy.y;
408  };
409  */
410 
412  /*
413  inline
414  void projectFwdOLD(const double & x, const double & y,double & x2, double & y2) const {
415 
416  PJ_COORD coord;
417  coord.lp.lam = x;
418  coord.lp.phi = y;
419 
420  proj_trans_array(proj, PJ_DIRECTION::PJ_FWD, 1, &coord);
421  x2 = coord.xy.x;
422  y2 = coord.xy.y;
423 
424  }
425  */
426 
429 
430 
432  /*
433  inline
434  void projectInvOLD(double & x, double & y) const
435  {
436 
437  PJ_COORD coord;
438  coord.xy.x = x;
439  coord.xy.y = y;
440 
441  proj_trans_array(proj, PJ_DIRECTION::PJ_INV, 1, &coord);
442  x = coord.lp.lam;
443  y = coord.lp.phi;
444 
445  };
446  */
447 
449  /*
450  inline
451  void projectInvOLD(const double & x2, const double & y2, double & x, double & y) const
452  {
453 
454  PJ_COORD coord;
455  coord.xy.x = x2;
456  coord.xy.y = y2;
457 
458  proj_trans_array(proj, PJ_DIRECTION::PJ_INV, 1, &coord);
459  x = coord.lp.lam;
460  y = coord.lp.phi;
461 
462  };
463  */
464 
465 
466  inline
467  void debug(std::ostream & ostr = std::cout, int wkt = -1){
468 
469  ostr << "SRC:\n";
470  src.info(ostr, wkt);
471  ostr << std::endl;
472 
473  ostr << "DST:\n";
474  dst.info(ostr, wkt);
475  ostr << std::endl;
476  }
477 
478 
479 
481  inline
482  bool isLongLat() const {
483  return dst.isLongLat();
484  }
485 
486  inline
487  bool isSet() const {
488  return (src.isSet() && dst.isSet());
489  }
490 
491  inline
492  std::string getErrorString() const {
493  int err = proj_context_errno(pjContext);
494  return proj_errno_string(err);
495  //return "Not Impl."; //std::string(pj_strerrno(*pj_get_errno_ref()));
496  };
497 
498 
499 
501 
513  // static short int pickEpsgCodeOLD(const std::string & projDef, std::list<std::string> & projArgs);
514 
515 protected:
516 
517  PJ_CONTEXT *pjContext = nullptr; // = proj_context_create();
518  PJ *proj = nullptr; // two-way
519 
520  // typedef drain::Dictionary<int, std::string> epsg_dict_t;
521  void setMapping(bool lenient);
522 
523 
524 
525 
526 
527 };
528 
529 DRAIN_TYPENAME(Proj6);
530 
531 std::ostream & operator<<(std::ostream & ostr, const Proj6 &p);
532 
533 } // drain
534 
535 
536 #endif /*PROJ4_H_*/
537 
Definition: Proj6.h:257
void setProjectionDst(const std::string &projDef, Projector::CRS_mode crs=Projector::FORCE_CRS)
Sets destination projection.
Definition: Proj6.h:286
void setProjectionSrc(const std::string &projDef, Projector::CRS_mode crs=Projector::FORCE_CRS)
Sets source projection.
Definition: Proj6.h:279
PJ_CONTEXT * pjContext
Detect EPSG code from "+init=epsg:EPSG" argument.
Definition: Proj6.h:517
bool isLongLat() const
Check if destination projection is longitude-latitude degrees.
Definition: Proj6.h:482
void setProjections(const std::string &projDefSrc, const std::string &projDefDst)
Sets source and destination projection.
Definition: Proj6.h:293
void projectFwd(double x, double y, double &x2, double &y2) const
Forward projection.
Definition: Proj6.h:365
void project(POINT_XY &point) const
Definition: Proj6.h:340
void debug(std::ostream &ostr=std::cout, int wkt=-1)
Forward projection.
Definition: Proj6.h:467
void projectFwd(double &x, double &y) const
Forward projection (in-place)
Definition: Proj6.h:359
void projectFwd(drain::Point2D< double > &point) const
Forward projection. Example implementation of project<>() .
Definition: Proj6.h:373
const std::string & getProjectionSrc() const
Returns the projection std::string applied by the last setProjection call.
Definition: Proj6.h:310
Definition: Proj6.h:54
void info(std::ostream &ostr=std::cout, int wkt=-1)
Prunes "+init=epsg:<...>" and optionally "+type=crs" codes.
Definition: Proj6.h:192
bool isSet() const
Returns true, if PJ object has been set.
Definition: Proj6.h:168
PROJDEF_variant
Each projector has three (3) versions of project definition.
Definition: Proj6.h:73
void setProjection(const std::string &str, CRS_mode crs=FORCE_CRS)
Sets projection defined as Proj string.
Definition: Proj6.cpp:70
void clear()
Deletes projection object and clears all the metadata.
Definition: Proj6.h:142
Definition: DataSelector.cpp:1277
Definition: Sprinter.h:137