All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Vectorizer.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008-2013 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/Vectorizer.cpp
22 
23  \brief It implements the vectorizer, based on TerraLib 4 algorithm.
24 */
25 
26 // TerraLib
27 #include "../common/progress/TaskProgress.h"
28 #include "../common/Translator.h"
29 #include "../geometry/Coord2D.h"
30 #include "../geometry/Envelope.h"
31 #include "../geometry/Line.h"
32 #include "../geometry/LinearRing.h"
33 #include "../geometry/Point.h"
34 #include "../geometry/Polygon.h"
35 #include "../geometry/Utils.h"
36 #include "Band.h"
37 #include "BandProperty.h"
38 #include "Config.h"
39 #include "Grid.h"
40 #include "Vectorizer.h"
42 
43 // STL
44 #include <iostream>
45 
46 te::rst::Vectorizer::Vectorizer(Raster* r, std::size_t b, unsigned int mp)
47  : m_raster(r),
48  m_rasterBand(b),
49  m_maxPolygons(mp),
50  m_rTreePolygons()
51 {
52  assert(b < m_raster->getNumberOfBands());
53 
54 // grid parameters
59 
60 // no data value parameters
62  m_useNoData = (m_noDataValue != std::numeric_limits<double>::max());
63 
64  m_containerPolygons.clear();
66 
67 // setting the directions
69  m_directions[NORTH] = te::gm::Coord2D( 0, -1);
70  m_directions[NORTHEAST] = te::gm::Coord2D( 1, -1);
71  m_directions[EAST] = te::gm::Coord2D( 1, 0);
72  m_directions[SOUTHEAST] = te::gm::Coord2D( 1, 1);
73  m_directions[SOUTH] = te::gm::Coord2D( 0, 1);
74  m_directions[SOUTHWEST] = te::gm::Coord2D(-1, 1);
75  m_directions[WEST] = te::gm::Coord2D(-1, 0);
76 }
77 
79 {
80 }
81 
83 {
84  clear();
85 }
86 
88 {
89  if(this != &rhs)
90  {
91  }
92 
93  return *this;
94 }
95 
96 /*
97 bool te::rst::Vectorizer::CheckParameters(
98  const TePDIParameters& parameters ) const {
99 
100 //Checking for general required parameters
101 
102  //parameter input_image
103  TePDITypes::TePDIRasterPtrType inRaster;
104  if( ! parameters.GetParameter( "rotulated_image", inRaster ) ) {
105 
106  TEAGN_LOGERR( "Missing parameter: rotulated_image" );
107  return false;
108  }
109  if( ! inRaster.isActive() ) {
110 
111  TEAGN_LOGERR( "Invalid parameter: rotulated_image inactive" );
112  return false;
113  }
114  if( inRaster->params().status_ == TeRasterParams::TeNotReady ) {
115 
116  TEAGN_LOGERR( "Invalid parameter: rotulated_image not ready" );
117  return false;
118  }
119 
120 // Checking output_polsets
121 
122  TEAGN_TRUE_OR_RETURN(
123  parameters.CheckParameter< TePDITypes::TePDIPolSetMapPtrType >(
124  "output_polsets" ), "Missing parameter: output_polsets" );
125 
126  TePDITypes::TePDIPolSetMapPtrType output_polsets;
127  parameters.GetParameter( "output_polsets", output_polsets );
128 
129  TEAGN_TRUE_OR_RETURN( output_polsets.isActive(),
130  "Invalid parameter output_polsets : Inactive polygon set pointer" );
131 
132 // Checking channel
133 
134  unsigned int channel = 0;
135 
136  TEAGN_TRUE_OR_RETURN(
137  parameters.GetParameter( "channel", channel ),
138  "Missing parameter: channel" );
139 
140  TEAGN_TRUE_OR_RETURN( ( channel < (unsigned int)inRaster->nBands() ),
141  "Invalid parameter: channel" );
142 
143 // checking rotulated_image data type
144 
145  for( int band = 0 ; band < inRaster->params().nBands() ; ++band ) {
146  TEAGN_TRUE_OR_RETURN(
147  ( inRaster->params().dataType_[ band ] != TeFLOAT ),
148  "Invalid rotulated_image floating point raster data type" );
149  TEAGN_TRUE_OR_RETURN(
150  ( inRaster->params().dataType_[ band ] != TeDOUBLE ),
151  "Invalid rotulated_image floating point raster data type" );
152  }
153 
154  return true;
155 }
156 */
157 
158 bool te::rst::Vectorizer::run(std::vector<te::gm::Geometry*>& polygons)
159 {
160  clear();
161 
162 // creating a new RTree
163  m_rTreePolygons = new te::sam::rtree::Index<unsigned int, 8, 4> (*m_raster->getExtent());
164 
165  double val;
166  int countObjects = 0;
167  std::vector<unsigned int> indexVec;
169 
170 // scanning rotulated image in row order to vectorize the cells
171  te::gm::Coord2D last_line_ll_point;
172  te::gm::Coord2D last_line_ll_point_indexed;
173  te::gm::Coord2D last_line_lr_point;
174  te::gm::Coord2D last_line_lr_point_indexed;
175 
176 std::cout << "raster bbox: " << te::gm::GetGeomFromEnvelope(m_raster->getGrid()->getExtent(), m_raster->getSRID())->toString() << std::endl;
177  for (unsigned int j = 0; j < m_nLines ; j++)
178  {
179  task.pulse();
180 std::cout << "analyzing line " << j << "/" << m_nLines << std::endl;
181 
182 // cleaning the tileindexers that will not be used anymore
183  last_line_ll_point_indexed.x = 0.0;
184  last_line_ll_point_indexed.y = ((double) j) - 1.0;
185 
186  last_line_lr_point_indexed.x = ((double) m_nColumns) - 1.0;
187  last_line_lr_point_indexed.y = ((double) j) - 1.0;
188 
189  last_line_ll_point = m_raster->getGrid()->gridToGeo(last_line_ll_point_indexed.x, last_line_ll_point_indexed.y);
190  last_line_lr_point = m_raster->getGrid()->gridToGeo(last_line_lr_point_indexed.x, last_line_lr_point_indexed.y);
191 
192  te::gm::Envelope last_line_bbox(last_line_ll_point.x, last_line_ll_point.y,
193  last_line_lr_point.x, last_line_lr_point.y);
194 
195  indexVec.clear();
196  m_rTreePolygons->search(last_line_bbox, indexVec);
197 
198  for(unsigned int indexVec_index = 0; indexVec_index < indexVec.size(); indexVec_index++)
199  {
200  te::rst::VectorizerPolygonStructure& curr_pol_struct =
201  m_containerPolygons[indexVec[indexVec_index]];
202  double curr_pol_ll_x = curr_pol_struct.m_polygon.getMBR()->getLowerLeftX();
203  double curr_pol_ll_y = curr_pol_struct.m_polygon.getMBR()->getLowerLeftY();
204 
205  if(m_raster->getGrid()->geoToGrid(curr_pol_ll_x, curr_pol_ll_y).y < j)
206  //if( m_raster->coord2Index(curr_pol_struct.m_polygon.box().lowerLeft() ).y() < j )
207  curr_pol_struct.m_indexer->clear();
208  }
209 
210 // iterating through columns
211  for (unsigned int i = 0; i < m_nColumns; i++)
212  {
213 std::cout << " column " << i << "/" << m_nColumns << std::endl;
214 
215 // verifying if the current point is already inside a polygon generated before
216  te::gm::Coord2D coordMatrix(i, j);
217  te::gm::Coord2D coordWorld = m_raster->getGrid()->gridToGeo(coordMatrix.x, coordMatrix.y);
218  //te::gm::Coord2D coordWorld = m_raster->index2Coord(coordMatrix);
219  te::gm::Envelope boxPoint(coordWorld.x, coordWorld.y, coordWorld.x, coordWorld.y);
220  te::gm::Point pointWorld(coordWorld.x, coordWorld.y);
221 
222  bool exist = false;
223 
224  indexVec.clear();
225  m_rTreePolygons->search(boxPoint, indexVec);
226 
227  m_raster->getValue(i, j, val, m_rasterBand);
228 // val = m_noDataValue;
229 
230  if (!indexVec.empty())
231  {
232  unsigned int indexVec_index = 0;
233 
234  while(indexVec_index < indexVec.size())
235  {
236  assert(indexVec[indexVec_index] < m_containerPolygons.size()); // Invalid cadidates vector index
237 
238  const VectorizerPolygonStructure& pol_str_ref = m_containerPolygons[indexVec[indexVec_index]];
239 
240  if (val == pol_str_ref.m_value)
241  {
242  // if (pol_str_ref.m_indexer->getPolygon().contains(&pointWorld))
243  if (pointWorld.intersects(&pol_str_ref.m_indexer->getPolygon()))
244  //if( TePDIUtils::TeRelation( coordWorld, *( pol_str_ref.m_indexer ) ) == TeINSIDE )
245  {
246  exist = true;
247  break;
248  }
249  }
250 
251  ++indexVec_index;
252  }
253  }
254 
255  if(!exist)
256  {
257 // we found a new class
259 
260  if(detectEdge(i, j, line))
261  {
262  try
263  {
265  poly->add(&line);
266 
267 // verifying if the polygon is a hole of other one
268  unsigned int indexVec_index = 0;
269  while(indexVec_index < indexVec.size())
270  {
271  VectorizerPolygonStructure& pol_struct_ref =
272  m_containerPolygons[indexVec[indexVec_index]];
273  te::rst::TileIndexer& m_indexerref = *(pol_struct_ref.m_indexer);
274  te::gm::Polygon& pol_ref = pol_struct_ref.m_polygon;
275 
276  if (m_indexerref.getPolygon().contains(&pointWorld))
277  {
278  // if( TePDIUtils::TeRelation( coordWorld, m_indexerref ) == TeINSIDE )
279 
280  pol_ref.add(poly->getRingN(0));
281  m_indexerref.addRing(pol_ref.getNumRings() - 1);
282 
283  break;
284  }
285 
286  ++indexVec_index;
287  }
288 // free indexVec
289  indexVec.clear();
290 
291 // inserting the new polygon into tree and container
292  /*if(m_useNoData && (val == m_noDataValue))
293  {
294  poly.objectId( "none" );
295  }
296  else
297  {*/
298  if (val != m_noDataValue)
299  {
300  ++countObjects;
301  /*poly.objectId(Te2String(countObjects));
302  }*/
303 std::cout << "countObjects: " << countObjects << std::endl;
304 std::cout << poly->toString() << std::endl;
305  }
306 
308  m_containerPolygons.push_back(dummy_ps);
309  m_containerPolygons[m_containerPolygons.size() - 1].reset(*poly, (int)val,
310  std::max(
311  (
312  4.0 * poly->getMBR()->getHeight()
313  /
314  (
315  poly->getMBR()->getWidth()
316  *
317  ( (double) poly->operator[](0)->getNPoints() )
318  )
319  )
320  ,
321  m_raster->getResolutionY()
322  )
323  );
324 
325  m_rTreePolygons->insert(*poly->getMBR(), m_containerPolygons.size() - 1);
326  }
327  catch(...)
328  {
329  std::cout << "Error generating polygon - not enough memory" << std::endl;
330 
331 // no more polygons will be generated
332  i = m_nColumns;
333  j = m_nLines;
334  }
335  }
336  else
337  {
338  // no more polygons will be generated
339  i = m_nColumns;
340  j = m_nLines;
341  }
342  if(m_maxPolygons)
343  {
344  if(countObjects >= ((int) m_maxPolygons))
345  {
346  // no more polygons will be generated
347  i = m_nColumns;
348  j = m_nLines;
349  }
350  }
351  }
352  }
353  }
354 
355 // cleaning the tree
356  delete m_rTreePolygons;
357  m_rTreePolygons = 0;
358 
359 // generating output data
360  std::map<double, std::vector<te::gm::Polygon*> > output_polsets;
361  std::map<double, std::vector<te::gm::Polygon*> >::iterator psm_it;
362 
363  std::vector<VectorizerPolygonStructure>::iterator cpit = m_containerPolygons.begin();
364  std::vector<VectorizerPolygonStructure>::iterator cpit_end = m_containerPolygons.end();
365 
366  double value = 0;
367  try
368  {
369  while(cpit != cpit_end)
370  {
371  value = (double) cpit->m_value;
372 
373  if ((!m_useNoData ) || (value != m_noDataValue))
374  {
375  psm_it = output_polsets.find(value);
376 
377  if(psm_it == output_polsets.end())
378  {
379  std::vector<te::gm::Polygon*> dummy_ps;
380  dummy_ps.push_back(&cpit->m_polygon);
381  std::cout << cpit->m_polygon.toString() << std::endl;
382  //dummy_ps.add(cpit->m_polygon);
383 
384  output_polsets[value] = dummy_ps;
385  // (*output_polsets)[value] = dummy_ps;
386  }
387  else
388  psm_it->second.push_back(&cpit->m_polygon);
389  //psm_it->second.add( cpit->m_polygon );
390  }
391  cpit->clear();
392 
393  ++cpit;
394  }
395  }
396  catch(...)
397  {
398  throw("Memory error - error generating output polygons sets map");
399  }
400 
401 // copying polygons to output polygons vector
402  polygons.clear();
403  for (psm_it = output_polsets.begin(); psm_it != output_polsets.end(); ++psm_it)
404  {
405  std::cout << psm_it->second[0]->toString() << std::endl;
406  polygons.push_back(psm_it->second[0]); //???
407  }
408 
409  return true;
410 }
411 
413 {
414 std::cout << "detectEdge(" << i << "," << j << ")" << std::endl;
415  assert(startingEdgeTest(i, j)); // "Starting edge detection error at x = i line = j
416 
417  line.makeEmpty();
418 
419  try
420  {
421 // current polygon pixel values
422  double pol_pixels_value = 0;
423 
424  m_raster->getValue(i, j, pol_pixels_value, m_rasterBand);
425  // pol_pixels_value = m_noDataValue;
426 
427 // generating chain code by following the polygon borders
428  short curr_dir = EAST;
429  short new_dir = EAST;
430  short new_test_start_dir = EAST;
431  short curr_pixel_corner = NORTHWEST;
432 
433  short pinit_leaving_dir = WEST;
434  bool pinit_leaving_dir_set = false;
435 
436  te::gm::Coord2D curr_chain_p = te::gm::Coord2D(0, 0);
437 
438  int curr_x_index = i;
439  int curr_y_index = j;
440  int next_x_index = i;
441  int next_y_index = j;
442 
443  double curr_pixel_value = 0;
444 
445  bool look_for_next_pixel = true;
446  bool next_pixel_found = false;
447  bool must_add_curr_chain_p = false;
448 
449  line.setNumCoordinates(line.getNPoints() + 1);
450  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
451 
452  while(look_for_next_pixel)
453  {
454 // finding the next direction
455  new_test_start_dir = (curr_dir + 6) % 8;
456  new_dir = new_test_start_dir;
457  next_pixel_found = false;
458  do
459  {
460  next_x_index = curr_x_index + (int) m_directions[new_dir].x;
461  next_y_index = curr_y_index + (int) m_directions[new_dir].y;
462 
463  if ((next_x_index > -1) && (next_y_index > -1) &&
464  (next_x_index < (long) m_nColumns ) && (next_y_index < (long) m_nLines))
465  {
466  m_raster->getValue(next_x_index, next_y_index, curr_pixel_value, m_rasterBand);
467  // curr_pixel_value = m_noDataValue;
468 
469  if (curr_pixel_value == pol_pixels_value)
470  {
471  next_pixel_found = true;
472  break;
473  }
474  }
475 
476  new_dir = (new_dir + 2) % 8;
477  } while (new_dir != new_test_start_dir);
478 
479 // generating the polygon line following the current state
480  if (!next_pixel_found)
481  {
482 // there is only one point inside the polygon
483 // that is the last one
484  curr_chain_p.x += m_directions[EAST].x;
485  curr_chain_p.y += m_directions[EAST].y;
486 
487  line.setNumCoordinates(line.getNPoints() + 1);
488  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
489 
490  curr_chain_p.x += m_directions[SOUTH].x;
491  curr_chain_p.y += m_directions[SOUTH].y;
492  line.setNumCoordinates(line.getNPoints() + 1);
493  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
494 
495  curr_chain_p.x += m_directions[WEST].x;
496  curr_chain_p.y += m_directions[WEST].y;
497  line.setNumCoordinates(line.getNPoints() + 1);
498  line.setPoint(line.getNPoints(), curr_chain_p.x, curr_chain_p.y);
499 
500  curr_chain_p.x += m_directions[NORTH].x;
501  curr_chain_p.y += m_directions[NORTH].y;
502  line.setNumCoordinates(line.getNPoints() + 1);
503  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
504 
505  look_for_next_pixel = false;
506  }
507  else if ((curr_x_index == i) && (curr_y_index == j) &&
508  (pinit_leaving_dir == new_dir))
509  {
510 // We are back to the fist pixel again (going to the same direction)
511  switch (curr_pixel_corner)
512  {
513  case NORTHEAST:
514  {
515  curr_chain_p.x += m_directions[SOUTH].x;
516  curr_chain_p.y += m_directions[SOUTH].y;
517 
518  line.setNumCoordinates(line.getNPoints() + 1);
519  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
520 
521  curr_chain_p.x += m_directions[WEST].x;
522  curr_chain_p.y += m_directions[WEST].y;
523  line.setNumCoordinates(line.getNPoints() + 1);
524  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
525 
526  curr_chain_p.x += m_directions[NORTH].x;
527  curr_chain_p.y += m_directions[NORTH].y;
528  line.setNumCoordinates(line.getNPoints() + 1);
529  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
530 
531  break;
532  }
533  case SOUTHEAST:
534  {
535  curr_chain_p.x += m_directions[WEST].x;
536  curr_chain_p.y += m_directions[WEST].y;
537  line.setNumCoordinates(line.getNPoints() + 1);
538  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
539 
540  curr_chain_p.x += m_directions[NORTH].x;
541  curr_chain_p.y += m_directions[NORTH].y;
542  line.setNumCoordinates(line.getNPoints() + 1);
543  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
544 
545  break;
546  }
547  case SOUTHWEST:
548  {
549  curr_chain_p.x += m_directions[NORTH].x;
550  curr_chain_p.y += m_directions[NORTH].y;
551  line.setNumCoordinates(line.getNPoints() + 1);
552  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
553 
554  break;
555  }
556  default:
557  {
558  // error message: "Invalid pixel corner=" + curr_pixel_corner + curr_dir=" + curr_dir;
559  break;
560  }
561  }
562 
563  look_for_next_pixel = false;
564  }
565  else
566  {
567 // updating current chain point and current pixel corner
568  if (curr_dir == new_dir)
569  {
570  curr_chain_p.x += m_directions[curr_dir].x;
571  curr_chain_p.y += m_directions[curr_dir].y;
572 
573  must_add_curr_chain_p = true;
574  }
575  else
576  {
577  if (must_add_curr_chain_p)
578  {
579  line.setNumCoordinates(line.getNPoints() + 1);
580  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
581 
582  must_add_curr_chain_p = false;
583  }
584 
585  switch (new_dir)
586  {
587  case EAST:
588  {
589  switch (curr_pixel_corner)
590  {
591  case NORTHWEST:
592  {
593  curr_chain_p.x += m_directions[EAST].x;
594  curr_chain_p.y += m_directions[EAST].y;
595  line.setNumCoordinates(line.getNPoints() + 1);
596  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
597 
598  break;
599  }
600  case NORTHEAST:
601  {
602  curr_pixel_corner = NORTHWEST;
603  break;
604  }
605  case SOUTHEAST:
606  {
607  curr_chain_p.x += m_directions[WEST].x;
608  curr_chain_p.y += m_directions[WEST].y;
609  line.setNumCoordinates(line.getNPoints() + 1);
610  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
611 
612  curr_chain_p.x += m_directions[NORTH].x;
613  curr_chain_p.y += m_directions[NORTH].y;
614  line.setNumCoordinates(line.getNPoints() + 1);
615  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
616 
617  curr_chain_p.x += m_directions[EAST].x;
618  curr_chain_p.y += m_directions[EAST].y;
619  line.setNumCoordinates(line.getNPoints() + 1);
620  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
621 
622  curr_pixel_corner = NORTHWEST;
623  break;
624  }
625  case SOUTHWEST:
626  {
627  curr_chain_p.x += m_directions[NORTH].x;
628  curr_chain_p.y += m_directions[NORTH].y;
629  line.setNumCoordinates(line.getNPoints() + 1);
630  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
631 
632  curr_chain_p.x += m_directions[EAST].x;
633  curr_chain_p.x += m_directions[EAST].x;
634  line.setNumCoordinates(line.getNPoints() + 1);
635  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
636 
637  curr_pixel_corner = NORTHWEST;
638  break;
639  }
640  default:
641  {
642  throw("Invalid pixel corner");
643  break;
644  }
645  }
646 
647  break;
648  }
649  case SOUTH:
650  {
651  switch (curr_pixel_corner)
652  {
653  case NORTHWEST:
654  {
655  curr_chain_p.x += m_directions[EAST].x;
656  curr_chain_p.y += m_directions[EAST].y;
657  line.setNumCoordinates(line.getNPoints() + 1);
658  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
659 
660  curr_chain_p.x += m_directions[SOUTH].x;
661  curr_chain_p.y += m_directions[SOUTH].y;
662  line.setNumCoordinates(line.getNPoints() + 1);
663  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
664 
665  curr_pixel_corner = NORTHEAST;
666  break;
667  }
668  case NORTHEAST:
669  {
670  curr_chain_p.x += m_directions[SOUTH].x;
671  curr_chain_p.y += m_directions[SOUTH].y;
672  line.setNumCoordinates(line.getNPoints() + 1);
673  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
674 
675  break;
676  }
677  case SOUTHEAST:
678  {
679  curr_pixel_corner = NORTHEAST;
680  break;
681  }
682  case SOUTHWEST:
683  {
684  curr_chain_p.x += m_directions[NORTH].x;
685  curr_chain_p.y += m_directions[NORTH].y;
686  line.setNumCoordinates(line.getNPoints() + 1);
687  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
688 
689  curr_chain_p.x += m_directions[EAST].x;
690  curr_chain_p.y += m_directions[EAST].y;
691  line.setNumCoordinates(line.getNPoints() + 1);
692  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
693 
694  curr_chain_p.x += m_directions[SOUTH].x;
695  curr_chain_p.y += m_directions[SOUTH].y;
696  line.setNumCoordinates(line.getNPoints() + 1);
697  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
698 
699  curr_pixel_corner = NORTHEAST;
700  break;
701  }
702  default:
703  {
704  throw("Invalid pixel corner");
705  break;
706  }
707  }
708 
709  break;
710  }
711  case WEST:
712  {
713  switch (curr_pixel_corner)
714  {
715  case NORTHWEST:
716  {
717  curr_chain_p.x += m_directions[EAST].x;
718  curr_chain_p.y += m_directions[EAST].y;
719  line.setNumCoordinates(line.getNPoints() + 1);
720  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
721 
722  curr_chain_p.x += m_directions[SOUTH].x;
723  curr_chain_p.y += m_directions[SOUTH].y;
724  line.setNumCoordinates(line.getNPoints() + 1);
725  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
726 
727  curr_chain_p.x += m_directions[WEST].x;
728  curr_chain_p.y += m_directions[WEST].y;
729  line.setNumCoordinates(line.getNPoints() + 1);
730  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
731 
732  curr_pixel_corner = SOUTHEAST;
733  break;
734  }
735  case NORTHEAST:
736  {
737  curr_chain_p.x += m_directions[SOUTH].x;
738  curr_chain_p.y += m_directions[SOUTH].y;
739  line.setNumCoordinates(line.getNPoints() + 1);
740  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
741 
742  curr_chain_p.x += m_directions[WEST].x;
743  curr_chain_p.y += m_directions[WEST].y;
744  line.setNumCoordinates(line.getNPoints() + 1);
745  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
746 
747  curr_pixel_corner = SOUTHEAST;
748  break;
749  }
750  case SOUTHEAST:
751  {
752  curr_chain_p.x += m_directions[WEST].x;
753  curr_chain_p.y += m_directions[WEST].y;
754  line.setNumCoordinates(line.getNPoints() + 1);
755  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
756 
757  break;
758  }
759  case SOUTHWEST:
760  {
761  curr_pixel_corner = SOUTHEAST;
762  break;
763  }
764  default:
765  {
766  throw("Invalid pixel corner");
767  break;
768  }
769  }
770 
771  break;
772  }
773  case NORTH:
774  {
775  switch (curr_pixel_corner)
776  {
777  case NORTHWEST:
778  {
779  curr_pixel_corner = SOUTHWEST;
780  break;
781  }
782  case NORTHEAST:
783  {
784  curr_chain_p.x += m_directions[SOUTH].x;
785  curr_chain_p.y += m_directions[SOUTH].y;
786  line.setNumCoordinates(line.getNPoints() + 1);
787  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
788 
789  curr_chain_p.x += m_directions[WEST].x;
790  curr_chain_p.y += m_directions[WEST].y;
791  line.setNumCoordinates(line.getNPoints() + 1);
792  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
793 
794  curr_chain_p.x += m_directions[NORTH].x;
795  curr_chain_p.y += m_directions[NORTH].y;
796  line.setNumCoordinates(line.getNPoints() + 1);
797  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
798 
799  curr_pixel_corner = SOUTHWEST;
800  break;
801  }
802  case SOUTHEAST:
803  {
804  curr_chain_p.x += m_directions[WEST].x;
805  curr_chain_p.y += m_directions[WEST].y;
806  line.setNumCoordinates(line.getNPoints() + 1);
807  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
808 
809  curr_chain_p.x += m_directions[NORTH].x;
810  curr_chain_p.y += m_directions[NORTH].y;
811  line.setNumCoordinates(line.getNPoints() + 1);
812  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
813 
814  curr_pixel_corner = SOUTHWEST;
815  break;
816  }
817  case SOUTHWEST:
818  {
819  curr_chain_p.x += m_directions[NORTH].x;
820  curr_chain_p.y += m_directions[NORTH].y;
821  line.setNumCoordinates(line.getNPoints() + 1);
822  line.setPoint(line.getNPoints() - 1, curr_chain_p.x, curr_chain_p.y);
823 
824  break;
825  }
826  default:
827  {
828  throw("Invalid pixel corner");
829  break;
830  }
831  }
832 
833  break;
834  }
835  default:
836  {
837  throw("Invalid new_dir");
838  break;
839  }
840  }
841  }
842 
843 // updating the leaving direction from the initial point
844  if ((!pinit_leaving_dir_set) && (curr_x_index == i) &&
845  (curr_y_index == j))
846  {
847  pinit_leaving_dir_set = true;
848  pinit_leaving_dir = new_dir;
849  }
850 
851 // updating the current state
852  curr_x_index = next_x_index;
853  curr_y_index = next_y_index;
854 
855  curr_dir = new_dir;
856  }
857  }
858 
859 // changing lines coords to world coords
860  const te::gm::Coord2D chain_init_p = m_raster->getGrid()->gridToGeo(((double) i) - 0.5, ((double) j) - 0.5);
861 
862 std::cout << "linha antes: ";
863 for (unsigned int i = 0; i < line.getNPoints(); i++)
864  std::cout << line.getX(i) << " " << line.getY(i) << ", ";
865 std::cout << std::endl;
866 
867  double min_x = std::numeric_limits<double>::max();
868  double min_y = std::numeric_limits<double>::max();
869  double max_x = ( -1.0 ) * std::numeric_limits<double>::max();
870  double max_y = ( -1.0 ) * std::numeric_limits<double>::max();
871  double tmp_x;
872  double tmp_y;
873 
874  for (unsigned int i = 0; i < line.getNPoints(); i++)
875  {
876  tmp_x = chain_init_p.x + (line.getX(i) * m_resX);
877  tmp_y = chain_init_p.y - (line.getY(i) * m_resY);
878 
879  if (tmp_x < min_x ) min_x = tmp_x;
880  if (tmp_y < min_y ) min_y = tmp_y;
881 
882  if (tmp_x > max_x ) max_x = tmp_x;
883  if (tmp_y > max_y ) max_y = tmp_y;
884 
885  line.setX(i, tmp_x);
886  line.setY(i, tmp_y);
887  }
888 
889 std::cout << "linha depois: ";
890 for (unsigned int i = 0; i < line.getNPoints(); i++)
891  std::cout << line.getX(i) << " " << line.getY(i) << ", ";
892 std::cout << std::endl;
893 
894 // updating the line box
895  // te::gm::Envelope newbox(min_x, min_y, max_x, max_y);
896  // line.setBox( newbox );
897  line.computeMBR(false);
898 
899 // closing the line, if necessary
900  if (line.getNPoints() > 1)
901  {
902  if (line.getStartPoint() != line.getEndPoint())
903  {
904  line.setNumCoordinates(line.getNPoints() + 1);
905  line.setPoint(line.getNPoints() - 1, line.getX(0), line.getY(0));
906  }
907  }
908  }
909  catch(...)
910  {
911  // error message: "Unable to detect edge - not enough memory"
912  line.makeEmpty();
913 
914  return false;
915  }
916 
917  return true;
918 }
919 
920 bool te::rst::Vectorizer::startingEdgeTest(const int& x, const int& y)
921 {
922  int nlines = m_raster->getNumberOfRows();
923  int ncols = m_raster->getNumberOfColumns();
924 
925  assert(y < nlines);
926  assert(x < ncols);
927 
928  if ((x == 0) || (y == 0) ||
929  (x == (ncols - 1)) || (y == (nlines - 1)))
930  return true;
931  else
932  {
933  double test_val = 0;
934  double current_val = 0;
935 
936  m_raster->getValue(x, y, current_val, m_rasterBand);
937  m_raster->getValue(x - 1, y, test_val, m_rasterBand);
938 
939  // assert(current_val != test_val); // "The given point isn't a starting edge [x, y]
940 
941  return true;
942  }
943 }
944 
946 {
947  if (m_rTreePolygons)
948  {
949  delete m_rTreePolygons;
950  m_rTreePolygons = 0;
951  }
952 
953  m_containerPolygons.clear();
954 }
std::size_t getNumRings() const
It returns the number of rings in this CurvePolygon.
Definition: CurvePolygon.h:153
void add(Curve *ring)
It adds the ring to the curve polygon.
Definition: CurvePolygon.h:267
Polygon tile indexing class for optmized geometrical relational tests.
Definition: TileIndexer.h:55
bool detectEdge(long i, long j, te::gm::LineString &line)
Detects an edge of a cell in Raster.
Definition: Vectorizer.cpp:412
Vectorizer(Raster *r, std::size_t b, unsigned int mp=0)
Constructor.
Definition: Vectorizer.cpp:46
#define NORTHEAST
Definition: Vectorizer.h:32
void computeMBR(bool cascade) const
It computes the minimum bounding rectangle for the linestring.
Definition: LineString.cpp:205
double y
y-coordinate.
Definition: Coord2D.h:87
#define SOUTH
Definition: Vectorizer.h:35
It describes one band (or dimension) of a raster.
void setX(std::size_t i, const double &x)
It sets the n-th x coordinate value.
Definition: LineString.cpp:409
unsigned long m_nColumns
The number of columns.
Definition: Vectorizer.h:144
Point * getEndPoint() const
It returns the curve end point.
Definition: LineString.cpp:252
#define WEST
Definition: Vectorizer.h:37
virtual bool intersects(const Geometry *const rhs) const
It returns true if the geometry object spatially intersects rhs geometry.
Definition: Geometry.cpp:243
double x
x-coordinate.
Definition: Coord2D.h:86
unsigned int getNumberOfColumns() const
Returns the raster number of columns.
Definition: Raster.cpp:213
virtual const Band * getBand(std::size_t i) const =0
Returns the raster i-th band.
void makeEmpty()
It clears all the coordinates.
Definition: LineString.cpp:309
Point * getStartPoint() const
The length of this Curve in its associated spatial reference.
Definition: LineString.cpp:246
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
const double & getLowerLeftY() const
It returns a constant refernce to the y coordinate of the lower left corner.
Definition: Envelope.h:400
double getWidth() const
It returns the envelope width.
Definition: Envelope.h:443
#define EAST
Definition: Vectorizer.h:33
te::gm::Polygon m_polygon
The stored polygon instance.
An utility struct for representing 2D coordinates.
Definition: Coord2D.h:40
bool startingEdgeTest(const int &x, const int &y)
Tests if the current point is a edge start.
Definition: Vectorizer.cpp:920
virtual bool contains(const Geometry *const rhs) const
It returns true if this geometry object spatially contains rhs geometry.
Definition: Geometry.cpp:299
double m_noDataValue
Value to indicate elements where there is no data, default is std::numeric_limits::max().
Definition: BandProperty.h:136
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:345
#define SOUTHWEST
Definition: Vectorizer.h:36
#define NORTH
Definition: Vectorizer.h:31
const double & getY(std::size_t i) const
It returns the n-th y coordinate value.
Definition: LineString.cpp:390
unsigned long m_nLines
The number of lines.
Definition: Vectorizer.h:143
double getResolutionY() const
Returns the grid vertical (y-axis) resolution.
Definition: Grid.cpp:259
It implements the vectorizer, based on TerraLib 4 algorithm.
te::sam::rtree::Index< unsigned int, 8, 4 > * m_rTreePolygons
A RTree instance pointer to optimize the searching of points inside already created polygons...
Definition: Vectorizer.h:147
void clear()
Clear all internally allocated resources.
Definition: Vectorizer.cpp:945
#define SOUTHEAST
Definition: Vectorizer.h:34
te::gm::Coord2D m_directions[8]
Directions vector.
Definition: Vectorizer.h:140
TileIndexer * m_indexer
The polygon tile indexer pointer.
A LinearRing is a LineString that is both closed and simple.
Definition: LinearRing.h:53
A polygon container node class.
double m_resX
Resolution X.
Definition: Vectorizer.h:141
std::size_t getNPoints() const
it returns the number of points (vertexes) in the geometry.
LineString is a curve with linear interpolation between points.
Definition: LineString.h:62
bool run(std::vector< te::gm::Geometry * > &polygons)
Returns true if current algorithm implementation runs ok, false otherwise.
Definition: Vectorizer.cpp:158
std::vector< VectorizerPolygonStructure > m_containerPolygons
Vector of all polygons.
Definition: Vectorizer.h:148
A point with x and y coordinate values.
Definition: Point.h:50
void setPoint(std::size_t i, const double &x, const double &y)
It sets the value of the specified point.
Definition: LineString.cpp:352
~Vectorizer()
Destructor.
Definition: Vectorizer.cpp:82
unsigned int m_rasterBand
The raster band to be used.
Definition: Vectorizer.h:145
An Envelope defines a 2D rectangular region.
Definition: Envelope.h:51
An abstract class for raster data strucutures.
Definition: Raster.h:71
unsigned int getNumberOfRows() const
Returns the raster number of rows.
Definition: Raster.cpp:208
const double & getX(std::size_t i) const
It returns the n-th x coordinate value.
Definition: LineString.cpp:384
BandProperty * getProperty()
Returns the band property.
Definition: Band.cpp:370
void setNumCoordinates(std::size_t size)
It reserves room for the number of coordinates in this LineString.
Definition: LineString.cpp:264
double getResolutionX() const
Returns the grid horizontal (x-axis) resolution.
Definition: Grid.cpp:253
double m_resY
Resolution Y.
Definition: Vectorizer.h:142
It implements the vectorizer, based on TerraLib 4 algorithm.
Definition: Vectorizer.h:72
std::size_t getNPoints() const
It returns the number of points (vertexes) in the linestring.
Definition: LineString.h:193
void pulse()
Calls setCurrentStep() function using getCurrentStep() + 1.
It gives access to values in one band (dimension) of a raster.
Grid * getGrid()
It returns the raster grid.
Definition: Raster.cpp:94
void addRing(const unsigned int &ri)
Update the tile index with the information of the supplied ring.
Definition: TileIndexer.cpp:94
void reset(const te::gm::Polygon &p, const int &v, const double &tidy)
Reset the current instance.
void clear()
Clear all internal resources.
Definition: TileIndexer.cpp:82
double m_noDataValue
The used dummy value.
Definition: Vectorizer.h:138
bool m_useNoData
Flag indication for dummy value use (rotulated image).
Definition: Vectorizer.h:137
Polygon is a subclass of CurvePolygon whose rings are defined by linear rings.
Definition: Polygon.h:50
A polygon container node class.
const double & getLowerLeftX() const
It returns a constant reference to the x coordinate of the lower left corner.
Definition: Envelope.h:390
std::string toString() const
It returns the data value in a WKT representation.
Definition: Geometry.h:858
A rectified grid is the spatial support for raster data.
Vectorizer & operator=(const Vectorizer &rhs)
Assignment operator.
Definition: Vectorizer.cpp:87
Configuration flags for the Raster module of TerraLib.
void setY(std::size_t i, const double &y)
It sets the n-th y coordinate value.
Definition: LineString.cpp:415
const te::gm::Polygon & getPolygon() const
Returns the polygon.
double getHeight() const
It returns the envelope height.
Definition: Envelope.h:448
const Envelope * getMBR() const
It returns the minimum bounding rectangle for the geometry in an internal representation.
Definition: Geometry.cpp:103
#define NORTHWEST
Definition: Vectorizer.h:30
TEGEOMEXPORT Geometry * GetGeomFromEnvelope(const Envelope *const e, int srid)
It creates a Geometry (a polygon) from the given envelope.
Definition: Utils.cpp:35
Curve * getRingN(std::size_t i) const
It returns the n-th ring for this curve polygon as a curve.
Definition: CurvePolygon.h:193
Raster * m_raster
The input image.
Definition: Vectorizer.h:139