Reprojection.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib 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 Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/raster/Reprojection.cpp
22 
23  \brief It contains the algorithm to reproject raster data.
24 */
25 
26 // TerraLib
27 #include "../common/STLUtils.h"
28 #include "../geometry/Coord2D.h"
29 #include "../geometry/Envelope.h"
30 #include "../srs/Converter.h"
31 #include "Band.h"
32 #include "BandProperty.h"
33 #include "Exception.h"
34 #include "Grid.h"
35 #include "Interpolator.h"
36 #include "Raster.h"
37 #include "RasterFactory.h"
38 #include "Reprojection.h"
39 
40 // STL
41 #include <algorithm> // for max and min
42 #include <cstdlib> // for abs
43 
45 
47 
48 te::rst::Raster* te::rst::Reproject(te::rst::Raster const * const rin, int srid, const std::map<std::string, std::string>& routinfo, int m)
49 {
50  return te::rst::Reproject(rin, srid, 1, 1, -1, -1, 0, 0, routinfo, m);
51 }
52 
53 te::rst::Raster* te::rst::Reproject(te::rst::Raster const * const rin, int srid, double llx, double lly, double urx, double ury, const std::map<std::string, std::string>& routinfo, int m)
54 {
55  return te::rst::Reproject(rin, srid, llx, lly, urx, ury, 0, 0, routinfo, m);
56 }
57 
58 te::rst::Raster* te::rst::Reproject(te::rst::Raster const * const rin, int srid, double llx, double lly, double urx, double ury, double resx, double resy, const std::map<std::string, std::string>& routinfo, int m)
59 {
60  if (srid == rin->getSRID())
61  return nullptr;
62 
63  te::srs::Converter* converter = new te::srs::Converter();
64  try
65  {
66  converter->setSourceSRID(rin->getSRID());
67  converter->setTargetSRID(srid);
68  }
69  catch(...)
70  {
71  throw te::rst::Exception("Input/Output SRID not recognized.");
72  }
73 
74  unsigned int ncols = rin->getNumberOfColumns();
75  unsigned int nrows = rin->getNumberOfRows();
76 
77  te::gm::Envelope* roi = new te::gm::Envelope(llx, lly, urx, ury);
78  if (!roi->isValid())
79  {
80  delete roi;
81  roi = nullptr;
82  }
83  else
84  {
85  ncols = static_cast<unsigned int>((urx-llx)/rin->getResolutionX())+1;
86  nrows = static_cast<unsigned int>((ury-lly)/rin->getResolutionY())+1;
87  }
88 
89  te::gm::Envelope* env = rin->getExtent(srid, roi);
90  delete roi;
91 
92  if (resx == 0 || resy == 0)
93  {
94 // maintain the same number of pixels
95  resx = env->getWidth() / ncols;
96  resy = env->getHeight() / nrows;
97  }
98  else
99  {
100  ncols = static_cast<unsigned int>(env->getWidth() / resx) + 1;
101  nrows = static_cast<unsigned int>(env->getHeight() / resy) + 1;
102  }
103 
104  te::rst::Grid* g = new te::rst::Grid(ncols, nrows, resx, resy, env, srid);
105 
106 // copy the band definitions
107  std::vector<te::rst::BandProperty*> bands;
108  for (unsigned int b=0; b<rin->getNumberOfBands(); ++b)
109  {
111  bands.push_back(bb);
112  }
113 
114 // create output raster
115  te::rst::Raster* rout = te::rst::RasterFactory::make(g, bands, routinfo);
116 
117  bool res = InterpolateIn(rin, rout, env, converter, m);
118 
119  if (!res)
120  {
121  delete rout;
122  return nullptr;
123  }
124 
125  return rout;
126 }
127 
128 bool InterpolateIn(te::rst::Raster const * const rin, te::rst::Raster* rout, te::gm::Envelope* box, te::srs::Converter* conv, int m)
129 {
130  te::gm::Coord2D poll = box->getLowerLeft();
131  te::gm::Coord2D pour = box->getUpperRight();
132 
133 // Bring output coordinates to output line/column domain
134  te::gm::Coord2D pxoll = rout->getGrid()->geoToGrid(poll.x, poll.y);
135  te::gm::Coord2D pxour = rout->getGrid()->geoToGrid(pour.x, pour.y);
136 
137 // Round output coordinates to nearest exact pixel
138  int x1 = (int) (pxoll.x-0.5);
139  int y1 = (int) (pxoll.y+0.5);
140  pxoll = te::gm::Coord2D(x1, y1);
141 
142  int x2 = (int)(pxour.x+0.5);
143  int y2 = (int)(pxour.y-0.5);
144  pxour = te::gm::Coord2D(x2, y2);
145 
146  poll = rout->getGrid()->gridToGeo((int)pxoll.x, (int)pxoll.y);
147 
148  te::gm::Coord2D poul = te::gm::Coord2D(poll.x, pour.y);
149  te::gm::Coord2D polr = te::gm::Coord2D(pour.x, poll.y);
150 
151 // Bring coordinates of box four corners to input raster projection
152 
153  te::gm::Coord2D pill(poll);
154  te::gm::Coord2D piur(pour);
155  te::gm::Coord2D piul(poul);
156  te::gm::Coord2D pilr(polr);
157 
158  conv->invert(pill.x,pill.y);
159  conv->invert(piur.x,piur.y);
160  conv->invert(piul.x,piul.y);
161  conv->invert(pilr.x,pilr.y);
162 
163 // Check if linear interpolation may be performed on input raster
164 // Evaluate point at middle of the edges in output domain and check if their
165 // corresponding points belong to the edges in input domain. If they belong,
166 // a linear interpolation may be performed, else divide output image
167 // in four quadrants and try interpolating again.
168 
169  te::gm::Coord2D pou((pour.x-poul.x)/2.+poul.x, poul.y), // upper edge
170  pob((polr.x-poll.x)/2.+poll.x, poll.y), // bottom edge
171  pol(poll.x, (poul.y-poll.y)/2.+poll.y), // left edge
172  por(polr.x, (pour.y-polr.y)/2.+polr.y); // right edge
173 
174 // Evaluate corresponding points in input raster domain
175  te::gm::Coord2D piu(pou); conv->invert(piu.x, piu.y);
176  te::gm::Coord2D pib(pob); conv->invert(pib.x, pib.y);
177  te::gm::Coord2D pil(pol); conv->invert(pil.x, pil.y);
178  te::gm::Coord2D pir(por); conv->invert(pir.x, pir.y);
179 
180 // Check if middle points belong to the edges
181 // If one of them does not belong to corresponding edge, divide output in four quadrants
182  double tol = std::max(rin->getResolutionX(), rin->getResolutionY());
183 
184  if (!IsPointOnLine(piul, piur, piu, tol) ||
185  !IsPointOnLine(pilr, piur, pir, tol) ||
186  !IsPointOnLine(pill, pilr, pib, tol) ||
187  !IsPointOnLine(pill, piul, pil, tol))
188  {
189 // center point
190  te::gm::Coord2D pom((por.x-pol.x)/2.+pol.x, (pou.y-pob.y)/2.+pob.y);
191 
192  te::gm::Envelope quadrantul(pol.x, pol.y, pou.x, pou.y);
193  if(!InterpolateIn(rin,rout,&quadrantul,conv))
194  return false;
195 
196  te::gm::Envelope quadrantur(pom.x, pom.y, pour.x, pour.y);
197  if(!InterpolateIn(rin, rout, &quadrantur, conv))
198  return false;
199 
200  te::gm::Envelope quadrantll(poll.x, poll.y, pom.x, pom.y);
201  if(!InterpolateIn(rin, rout, &quadrantll, conv))
202  return false;
203 
204  te::gm::Envelope quadrantlr(pob.x, pob.y, por.x, por.y);
205  if(!InterpolateIn(rin, rout, &quadrantlr, conv))
206  return false;
207 
208  return true;
209  }
210 
211 // Start linear interpolation on input image.
212  te::gm::Coord2D pxill = rin->getGrid()->geoToGrid(pill.x, pill.y);
213  te::gm::Coord2D pxiul = rin->getGrid()->geoToGrid(piul.x, piul.y);
214  te::gm::Coord2D pxilr = rin->getGrid()->geoToGrid(pilr.x, pilr.y);
215  te::gm::Coord2D pxiur = rin->getGrid()->geoToGrid(piur.x, piur.y);
216 
217 // Evaluate the increments in x and y on both sides of input image
218  x1 = (int)pxoll.x-1;
219  y1 = (int)pxour.y-1;
220 
221  x2 = (int)pxour.x+1;
222  y2 = (int)pxoll.y+1;
223 
224  double dxl((pxill.x-pxiul.x)/(y2-y1)); // x increment at the beginning of line
225  double dyl((pxill.y-pxiul.y)/(y2-y1)); // y increment at the beginning of line
226  double dxr((pxilr.x-pxiur.x)/(y2-y1)); // x increment at the end of line
227  double dyr((pxilr.y-pxiur.y)/(y2-y1)); // Y increment at the end of line
228 
229  // Set initial values for x and y at beginning point on input image
230  double xl = pxiul.x-1; // x at the beginning of the line
231  double yl = pxiul.y-1; // y at the beginning of the line
232 
233  // Set initial values for x and y at end point on input image
234  double xr = pxiur.x+1; // x at the end of the line
235  double yr = pxiur.y+1; // y at the end of the line
236 
237  // Evaluate increments for the first line
238  double dx = (xr-xl)/(x2-x1); // inner loop x increment
239  double dy = (yr-yl)/(x2-x1); // inner loop y increment
240 
241  double x = xl; // round to left pixel
242  double y = yl; // round to left pixel
243 
244  // Create the interpolator
245  te::rst::Interpolator* interpolator = new te::rst::Interpolator(rin, m);
246 
247  int i, j;
248  std::complex<double> value;
249  for (j = y1; j <= y2; ++j)
250  {
251  for (i = x1; i <= x2; ++i)
252  {
253  if( rout->getGrid()->isPointInGrid(i, j) )
254  {
255  for (std::size_t b = 0; b < rin->getNumberOfBands(); ++b)
256  {
257  //rin->getValue((int)(x+0.5), (int)(y+0.5), value, b);
258  interpolator->getValue(x, y, value, b);
259  rout->setValue(i, j, value, b);
260  }
261  }
262  x += dx;
263  y += dy;
264  }
265  xl += dxl;
266  yl += dyl;
267 
268  xr += dxr;
269  yr += dyr;
270 
271  x = xl;
272  y = yl;
273 
274  dx = (xr-xl)/(x2-x1);
275  dy = (yr-yl)/(x2-x1);
276  }
277  return true;
278 }
279 
280 
282 {
283  int px = (int)(p.x/tol);
284  int py = (int)(p.y/tol);
285 
286  int qx = (int)(q.x/tol);
287  int qy = (int)(q.y/tol);
288 
289  int tx = (int)(t.x/tol);
290  int ty = (int)(t.y/tol);
291 
292  int dx = abs(px-qx);
293  int dy = abs(py-qy);
294 
295  if (dx <= 2 && dy <= 2)
296  return true;
297 
298  int q1 = (qy-py)*(tx-px);
299  int q2 = (ty-py)*(qx-px);
300  int q3 = qx-px;
301  int q4 = qy-py;
302 
303  if (q1 == 0 && q2 == 0 && q3 == 0 && q4 == 0)
304  return true;
305 
306  if (abs(q1 - q2) > (std::max(abs(q3), abs(q4))))
307  return false;
308 
309  return true;
310 }
bool isPointInGrid(unsigned int col, unsigned int row) const
Definition: raster/Grid.h:349
An exception class for the Raster module.
virtual void setValue(unsigned int c, unsigned int r, const double value, std::size_t b=0)
Sets the attribute value in a band of a cell.
te::gm::Envelope * getExtent()
Returns the geographic extension of the raster data.
bool IsPointOnLine(te::gm::Coord2D &p, te::gm::Coord2D &q, te::gm::Coord2D &t, double tol)
It gives access to values in one band (dimension) of a raster.
Near neighborhood interpolation method.
double y
y-coordinate.
Definition: Coord2D.h:114
It describes one band (or dimension) of a raster.
It contains the algorithm to reproject raster data.
static te::dt::Date dx(2010, 12, 31)
A raster band description.
Definition: BandProperty.h:61
double x
x-coordinate.
Definition: Coord2D.h:113
unsigned int getNumberOfColumns() const
Returns the raster number of columns.
It interpolates one pixel based on a selected algorithm. Methods currently available are Nearest Neig...
Definition: Interpolator.h:55
bool invert(double *xIn, double *yIn, double *xOut, double *yOut, long numCoord, int coordOffset=1) const
Inverts a vector of coordinates from target SRS to dource SRS.
Definition: Converter.cpp:341
An abstract class for raster data strucutures.
double getWidth() const
It returns the envelope width.
An utility struct for representing 2D coordinates.
Definition: Coord2D.h:40
void getValue(const double &c, const double &r, std::complex< double > &v, const std::size_t &b)
Get the interpolated value at specific band.
Definition: Interpolator.h:93
void geoToGrid(const double &x, const double &y, double &col, double &row) const
Get the grid point associated to a spatial location.
void setSourceSRID(int sourceSRID)
Sets the source SRS identifier.
Definition: Converter.cpp:104
int b
Definition: TsRtree.cpp:32
This is the abstract factory for Rasters.
An Envelope defines a 2D rectangular region.
An abstract class for raster data strucutures.
unsigned int getNumberOfRows() const
Returns the raster number of rows.
virtual std::size_t getNumberOfBands() const =0
Returns the number of bands (dimension of cells attribute values) in the raster.
BandProperty * getProperty()
Returns the band property.
double getResolutionX() const
Returns the raster horizontal (x-axis) resolution.
list bands
Definition: compose.py:2
bool InterpolateIn(te::rst::Raster const *const rin, te::rst::Raster *rout, te::gm::Envelope *box, te::srs::Converter *conv, int m=te::rst::NearestNeighbor)
void setTargetSRID(int targetSRID)
Sets the target SRS identifier.
Definition: Converter.cpp:172
te::gm::Polygon * p
virtual const Band * getBand(std::size_t i) const =0
Returns the raster i-th band.
Grid * getGrid()
It returns the raster grid.
A Converter is responsible for the conversion of coordinates between different Coordinate Systems (CS...
Definition: Converter.h:53
int getSRID() const
Returns the raster spatial reference system identifier.
A rectified grid is the spatial support for raster data.
TERASTEREXPORT te::rst::Raster * Reproject(te::rst::Raster const *const rin, int srid, const std::map< std::string, std::string > &routinfo, int m=te::rst::NearestNeighbor)
Reprojects a raster to another SRS.
static Raster * make()
It creates and returns an empty raster with default raster driver.
void gridToGeo(const double &col, const double &row, double &x, double &y) const
Get the spatial location of a grid point.
double getResolutionY() const
Returns the raster vertical (y-axis) resolution.
Coord2D getUpperRight() const
It returns the upper right coordinate of the envelope.
A rectified grid is the spatial support for raster data.
Definition: raster/Grid.h:68
Coord2D getLowerLeft() const
It returns the lower left coordinate of the envelope.
double getHeight() const
It returns the envelope height.
bool isValid() const
It tells if the rectangle is valid or not.
It interpolates one pixel based on a selected algorithm.