atlas
ProjectionImpl.h
1 /*
2  * (C) Copyright 2013 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation
8  * nor does it submit to any jurisdiction.
9  */
10 
11 #pragma once
12 
13 #include <memory>
14 #include <string>
15 
16 #include "atlas/util/Factory.h"
18 #include "atlas/util/Object.h"
19 #include "atlas/util/Point.h"
20 #include "atlas/util/Rotation.h"
21 
22 namespace eckit {
23 class Parametrisation;
24 class Hash;
25 } // namespace eckit
26 
27 namespace atlas {
28 class Domain;
29 class RectangularLonLatDomain;
30 namespace util {
31 class Config;
32 }
33 } // namespace atlas
34 
35 namespace atlas {
36 namespace projection {
37 namespace detail {
38 
39 class ProjectionImpl : public util::Object {
40 public:
41  using Spec = atlas::util::Config;
42  class Jacobian : public std::array<std::array<double, 2>, 2> {
43  public:
44  static Jacobian identity() {
45  Jacobian id;
46  id[0] = {1.0, 0.0};
47  id[1] = {0.0, 1.0};
48  return id;
49  }
50 
51  Jacobian inverse() const {
52  const Jacobian& jac = *this;
53  Jacobian inv;
54  double det = jac[0][0] * jac[1][1] - jac[0][1] * jac[1][0];
55  inv[0][0] = +jac[1][1] / det;
56  inv[0][1] = -jac[0][1] / det;
57  inv[1][0] = -jac[1][0] / det;
58  inv[1][1] = +jac[0][0] / det;
59  return inv;
60  };
61 
62  Jacobian transpose() const {
63  Jacobian tra = *this;
64  std::swap( tra[0][1], tra[1][0] );
65  return tra;
66  };
67 
68  Jacobian operator-( const Jacobian& jac2 ) const {
69  const Jacobian& jac1 = *this;
70  Jacobian jac;
71  jac[0][0] = jac1[0][0] - jac2[0][0];
72  jac[0][1] = jac1[0][1] - jac2[0][1];
73  jac[1][0] = jac1[1][0] - jac2[1][0];
74  jac[1][1] = jac1[1][1] - jac2[1][1];
75  return jac;
76  }
77 
78  Jacobian operator+( const Jacobian& jac2 ) const {
79  const Jacobian& jac1 = *this;
80  Jacobian jac;
81  jac[0][0] = jac1[0][0] + jac2[0][0];
82  jac[0][1] = jac1[0][1] + jac2[0][1];
83  jac[1][0] = jac1[1][0] + jac2[1][0];
84  jac[1][1] = jac1[1][1] + jac2[1][1];
85  return jac;
86  }
87 
88  double norm() const {
89  const Jacobian& jac = *this;
90  return sqrt( jac[0][0] * jac[0][0] + jac[0][1] * jac[0][1] + jac[1][0] * jac[1][0] +
91  jac[1][1] * jac[1][1] );
92  }
93 
94  Jacobian operator*( const Jacobian& jac2 ) const {
95  const Jacobian& jac1 = *this;
96  Jacobian jac;
97  jac[0][0] = jac1[0][0] * jac2[0][0] + jac1[0][1] * jac2[1][0];
98  jac[0][1] = jac1[0][0] * jac2[0][1] + jac1[0][1] * jac2[1][1];
99  jac[1][0] = jac1[1][0] * jac2[0][0] + jac1[1][1] * jac2[1][0];
100  jac[1][1] = jac1[1][0] * jac2[0][1] + jac1[1][1] * jac2[1][1];
101  return jac;
102  }
103 
104  double dx_dlon() const {
105  const Jacobian& jac = *this;
106  return jac[JDX][JDLON];
107  }
108  double dy_dlon() const {
109  const Jacobian& jac = *this;
110  return jac[JDY][JDLON];
111  }
112  double dx_dlat() const {
113  const Jacobian& jac = *this;
114  return jac[JDX][JDLAT];
115  }
116  double dy_dlat() const {
117  const Jacobian& jac = *this;
118  return jac[JDY][JDLAT];
119  }
120 
121  double dlon_dx() const {
122  const Jacobian& jac = *this;
123  return jac[JDLON][JDX];
124  }
125  double dlon_dy() const {
126  const Jacobian& jac = *this;
127  return jac[JDLON][JDY];
128  }
129  double dlat_dx() const {
130  const Jacobian& jac = *this;
131  return jac[JDLAT][JDX];
132  }
133  double dlat_dy() const {
134  const Jacobian& jac = *this;
135  return jac[JDLAT][JDY];
136  }
137 
138  private:
139  enum
140  {
141  JDX = 0,
142  JDY = 1
143  };
144  enum
145  {
146  JDLON = 0,
147  JDLAT = 1
148  };
149  };
150 
151 public:
152  static const ProjectionImpl* create( const eckit::Parametrisation& p );
153  static const ProjectionImpl* create( const std::string& type, const eckit::Parametrisation& p );
154 
155  ProjectionImpl() = default;
156  virtual ~ProjectionImpl() = default; // destructor should be virtual
157 
158  virtual std::string type() const = 0;
159 
160  virtual void xy2lonlat( double crd[] ) const = 0;
161  virtual void lonlat2xy( double crd[] ) const = 0;
162 
163  virtual Jacobian jacobian( const PointLonLat& ) const = 0;
164 
165  void xy2lonlat( Point2& ) const;
166  void lonlat2xy( Point2& ) const;
167 
168  PointLonLat lonlat( const PointXY& ) const;
169  PointXY xy( const PointLonLat& ) const;
170  virtual PointXYZ xyz( const PointLonLat& ) const;
171 
172  virtual bool strictlyRegional() const = 0;
173  virtual RectangularLonLatDomain lonlatBoundingBox( const Domain& ) const = 0;
174 
175  virtual Spec spec() const = 0;
176 
177  virtual std::string units() const = 0;
178 
179  virtual operator bool() const { return true; }
180 
181  virtual void hash( eckit::Hash& ) const = 0;
182 
183  struct BoundLonLat {
184  operator RectangularLonLatDomain() const;
185  void extend( PointLonLat p, PointLonLat eps );
186 
187  bool crossesDateLine( bool );
188  bool includesNorthPole( bool );
189  bool includesSouthPole( bool );
190 
191  bool crossesDateLine() const { return crossesDateLine_; }
192  bool includesNorthPole() const { return includesNorthPole_; }
193  bool includesSouthPole() const { return includesSouthPole_; }
194 
195  private:
196  PointLonLat min_;
197  PointLonLat max_;
198  bool crossesDateLine_ = false;
199  bool includesNorthPole_ = false;
200  bool includesSouthPole_ = false;
201  bool first_ = true;
202  };
203 
204  struct Normalise {
205  Normalise( const eckit::Parametrisation& );
206  Normalise( double west );
207  void hash( eckit::Hash& ) const;
208  void spec( Spec& ) const;
209  void operator()( double crd[] ) const {
210  if ( normalise_ ) {
211  crd[0] = ( *normalise_ )( crd[0] );
212  }
213  }
214  operator bool() const { return bool( normalise_ ); }
215 
216  private:
217  std::unique_ptr<util::NormaliseLongitude> normalise_;
218  std::vector<double> values_;
219  };
220 
221  struct Derivate {
222  Derivate( const ProjectionImpl& p, PointXY A, PointXY B, double h, double refLongitude = 0. );
223  virtual ~Derivate();
224  virtual PointLonLat d( PointXY ) const = 0;
225 
226  protected:
227  const ProjectionImpl& projection_;
228  const PointXY H_;
229  const double normH_;
230  const double refLongitude_;
231  PointLonLat xy2lonlat( const PointXY& p ) const;
232  };
233 
234  struct DerivateFactory : public util::Factory<DerivateFactory> {
235  static std::string className() { return "DerivateFactory"; }
236  static ProjectionImpl::Derivate* build( const std::string& type, const ProjectionImpl& p, PointXY A, PointXY B,
237  double h, double refLongitude = 0. );
238 
239  protected:
240  using Factory::Factory;
241  virtual ~DerivateFactory();
242  virtual ProjectionImpl::Derivate* make( const ProjectionImpl& p, PointXY A, PointXY B, double h,
243  double refLongitude = 0. ) = 0;
244  };
245 };
246 
247 inline void ProjectionImpl::xy2lonlat( Point2& point ) const {
248  xy2lonlat( point.data() );
249 }
250 
251 inline void ProjectionImpl::lonlat2xy( Point2& point ) const {
252  lonlat2xy( point.data() );
253 }
254 
255 inline PointLonLat ProjectionImpl::lonlat( const PointXY& xy ) const {
256  PointLonLat lonlat( xy );
257  xy2lonlat( lonlat.data() );
258  return lonlat;
259 }
260 
261 inline PointXY ProjectionImpl::xy( const PointLonLat& lonlat ) const {
262  PointXY xy( lonlat );
263  lonlat2xy( xy.data() );
264  return xy;
265 }
266 
267 //---------------------------------------------------------------------------------------------------------------------
268 
269 class Rotated : public util::Rotation {
270 public:
271  using Spec = ProjectionImpl::Spec;
272 
273  Rotated( const PointLonLat& south_pole, double rotation_angle = 0. );
274  Rotated( const eckit::Parametrisation& );
275  virtual ~Rotated() = default;
276 
277  static std::string classNamePrefix() { return "Rotated"; }
278  static std::string typePrefix() { return "rotated_"; }
279 
280  void spec( Spec& ) const;
281 
282  void hash( eckit::Hash& ) const;
283 };
284 
285 class NotRotated {
286 public:
287  using Spec = ProjectionImpl::Spec;
288 
289  NotRotated() = default;
290  NotRotated( const eckit::Parametrisation& ) {}
291  virtual ~NotRotated() = default;
292 
293  static std::string classNamePrefix() { return ""; } // deliberately empty
294  static std::string typePrefix() { return ""; } // deliberately empty
295 
296  void rotate( double* ) const { /* do nothing */
297  }
298  void unrotate( double* ) const { /* do nothing */
299  }
300 
301  bool rotated() const { return false; }
302 
303  void spec( Spec& ) const {}
304 
305  void hash( eckit::Hash& ) const {}
306 };
307 
308 extern "C" {
309 const ProjectionImpl* atlas__Projection__ctor_config( const eckit::Parametrisation* config );
310 void atlas__Projection__type( const ProjectionImpl* This, char*& type, int& size );
311 void atlas__Projection__hash( const ProjectionImpl* This, char*& hash, int& size );
312 ProjectionImpl::Spec* atlas__Projection__spec( const ProjectionImpl* This );
313 }
314 
315 } // namespace detail
316 } // namespace projection
317 } // namespace atlas
Definition: Factory.h:79
Point in arbitrary XYZ-coordinate system.
Definition: Point.h:66
Definition: Rotation.h:26
This file contains classes and functions working on points.
Point in longitude-latitude coordinate system.
Definition: Point.h:103
Definition: Domain.h:130
Definition: Object.h:18
Definition: Domain.h:19
Definition: ProjectionImpl.h:39
Definition: Domain.h:48
Point in arbitrary XY-coordinate system.
Definition: Point.h:40
Contains all atlas classes and methods.
Definition: atlas-grids.cc:33
Definition: ProjectionImpl.h:269
Definition: ProjectionImpl.h:285
Configuration class used to construct various atlas components.
Definition: Config.h:27