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