OTB  10.0.0
Orfeo Toolbox
otbOGRLayerStreamStitchingFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2024 Centre National d'Etudes Spatiales (CNES)
3  *
4  * This file is part of Orfeo Toolbox
5  *
6  * https://www.orfeo-toolbox.org/
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef otbOGRLayerStreamStitchingFilter_hxx
22 #define otbOGRLayerStreamStitchingFilter_hxx
23 
25 #include "itkContinuousIndex.h"
26 
27 #include <iomanip>
28 #include "ogrsf_frmts.h"
29 #include <set>
30 
31 namespace otb
32 {
33 
34 template <class TImage>
36 {
37  m_StreamSize.Fill(0);
38 }
39 
40 template <class TInputImage>
42 {
43  this->Superclass::SetNthInput(0, const_cast<InputImageType*>(input));
44 }
45 
46 template <class TInputImage>
48 {
49  if (this->GetNumberOfInputs() < 1)
50  {
51  return nullptr;
52  }
53 
54  return static_cast<const InputImageType*>(this->Superclass::GetInput(0));
55 }
56 
57 template <class TInputImage>
59 {
60  m_OGRLayer = ogrLayer;
61  this->Modified();
62 }
63 
64 template <class TInputImage>
66 {
67  return m_OGRLayer;
68 }
69 
70 template <class TInputImage>
72 {
73  double dfLength = 0.0;
74  for (int iGeom = 0; iGeom < intersection->getNumGeometries(); iGeom++)
75  {
76  OGRGeometry* geom = intersection->getGeometryRef(iGeom);
77  switch (wkbFlatten(geom->getGeometryType()))
78  {
79  case wkbLinearRing:
80  case wkbLineString:
81  dfLength += ((OGRCurve*)geom)->get_Length();
82  break;
83  case wkbGeometryCollection:
84  dfLength += GetLengthOGRGeometryCollection(dynamic_cast<OGRGeometryCollection*>(geom));
85  break;
86  default:
87  break;
88  }
89  }
90  return dfLength;
91 }
92 template <class TInputImage>
93 void OGRLayerStreamStitchingFilter<TInputImage>::ProcessStreamingLine(bool line, itk::ProgressReporter& progress)
94 {
95  typename InputImageType::ConstPointer inputImage = this->GetInput();
96 
97  // compute the number of stream division in row and column
98  SizeType imageSize = this->GetInput()->GetLargestPossibleRegion().GetSize();
99  unsigned int nbRowStream = static_cast<unsigned int>(imageSize[1] / m_StreamSize[1] + 1);
100  unsigned int nbColStream = static_cast<unsigned int>(imageSize[0] / m_StreamSize[0] + 1);
101 
102  /*unsigned long startReporter;
103  unsigned long stopReporter;
104  if (!line)
105  {
106  startReporter = 0;
107  stopReporter = 50;
108  }
109  else
110  {
111  startReporter = 50;
112  stopReporter = 100;
113  }
114  itk::ProgressReporter progress(this,0,2*nbRowStream*nbColStream,100,startReporter); */
115 
116  for (unsigned int x = 1; x <= nbColStream; x++)
117  {
118  OGRErr errStart = m_OGRLayer.ogr().StartTransaction();
119 
120  if (errStart != OGRERR_NONE)
121  {
122  itkExceptionMacro(<< "Unable to start transaction for OGR layer " << m_OGRLayer.ogr().GetName() << ".");
123  }
124 
125  for (unsigned int y = 1; y <= nbRowStream; y++)
126  {
127 
128  // Compute Stream line
129  OGRLineString streamLine;
130  itk::ContinuousIndex<double, 2> startIndex;
131  itk::ContinuousIndex<double, 2> endIndex;
132  if (!line)
133  {
134  // Treat vertical stream line
135  startIndex[0] = static_cast<double>(m_StreamSize[0] * x) - 0.5;
136  startIndex[1] = static_cast<double>(m_StreamSize[1] * (y - 1)) - 0.5;
137  endIndex = startIndex;
138  endIndex[1] += static_cast<double>(m_StreamSize[1]);
139  }
140  else
141  { // Treat horizontal stream line
142  startIndex[0] = static_cast<double>(m_StreamSize[0] * (x - 1)) - 0.5;
143  startIndex[1] = static_cast<double>(m_StreamSize[1] * y) - 0.5;
144  endIndex = startIndex;
145  endIndex[0] += static_cast<double>(m_StreamSize[0]);
146  }
147  OriginType startPoint;
148  inputImage->TransformContinuousIndexToPhysicalPoint(startIndex, startPoint);
149  OriginType endPoint;
150  inputImage->TransformContinuousIndexToPhysicalPoint(endIndex, endPoint);
151  streamLine.addPoint(startPoint[0], startPoint[1]);
152  streamLine.addPoint(endPoint[0], endPoint[1]);
153 
154 
155  // First we get all the feature that intersect the streaming line of the Upper/left stream
156  std::vector<FeatureStruct> upperStreamFeatureList;
157  upperStreamFeatureList.clear();
158  IndexType UpperLeftCorner;
159  IndexType LowerRightCorner;
160 
161  if (!line)
162  {
163  // Treat Row stream
164  // Compute the spatial filter of the upper stream
165  UpperLeftCorner[0] = x * m_StreamSize[0] - 1 - m_Radius;
166  UpperLeftCorner[1] = m_StreamSize[1] * (y - 1);
167 
168  LowerRightCorner[0] = m_StreamSize[0] * x - 1;
169  LowerRightCorner[1] = m_StreamSize[1] * y - 1;
170  }
171  else
172  { // Treat Column stream
173  // Compute the spatial filter of the left stream
174  UpperLeftCorner[0] = (x - 1) * m_StreamSize[0];
175  UpperLeftCorner[1] = m_StreamSize[1] * y - 1 - m_Radius;
176 
177  LowerRightCorner[0] = m_StreamSize[0] * x - 1;
178  LowerRightCorner[1] = m_StreamSize[1] * y - 1; //-1 to stop just before stream line
179  }
180 
181  OriginType ulCorner;
182  inputImage->TransformIndexToPhysicalPoint(UpperLeftCorner, ulCorner);
183  OriginType lrCorner;
184  inputImage->TransformIndexToPhysicalPoint(LowerRightCorner, lrCorner);
185 
186  m_OGRLayer.SetSpatialFilterRect(ulCorner[0], lrCorner[1], lrCorner[0], ulCorner[1]);
187 
188  std::set<unsigned int> upperFIDs;
189  OGRLayerType::const_iterator featIt = m_OGRLayer.begin();
190  for (; featIt != m_OGRLayer.end(); ++featIt)
191  {
192  FeatureStruct s(m_OGRLayer.GetLayerDefn());
193  s.feat = *featIt;
194  s.fusioned = false;
195  upperStreamFeatureList.push_back(s);
196  upperFIDs.insert((*featIt).GetFID());
197  }
198 
199  // Do the same thing for the lower/right stream
200  std::vector<FeatureStruct> lowerStreamFeatureList;
201  lowerStreamFeatureList.clear();
202 
203  if (!line)
204  {
205  // Compute the spatial filter of the lower stream
206  UpperLeftCorner[0] = x * m_StreamSize[0];
207  UpperLeftCorner[1] = m_StreamSize[1] * (y - 1);
208 
209  LowerRightCorner[0] = m_StreamSize[0] * x + m_Radius;
210  LowerRightCorner[1] = m_StreamSize[1] * y - 1;
211  }
212  else
213  {
214  // Compute the spatial filter of the right stream
215  UpperLeftCorner[0] = (x - 1) * m_StreamSize[0];
216  UpperLeftCorner[1] = m_StreamSize[1] * y;
217 
218  LowerRightCorner[0] = m_StreamSize[0] * x - 1;
219  LowerRightCorner[1] = m_StreamSize[1] * y + m_Radius;
220  }
221 
222  inputImage->TransformIndexToPhysicalPoint(UpperLeftCorner, ulCorner);
223  inputImage->TransformIndexToPhysicalPoint(LowerRightCorner, lrCorner);
224 
225  m_OGRLayer.SetSpatialFilterRect(ulCorner[0], lrCorner[1], lrCorner[0], ulCorner[1]);
226 
227  for (featIt = m_OGRLayer.begin(); featIt != m_OGRLayer.end(); ++featIt)
228  {
229  if (upperFIDs.find((*featIt).GetFID()) == upperFIDs.end())
230  {
231  FeatureStruct s(m_OGRLayer.GetLayerDefn());
232  s.feat = *featIt;
233  s.fusioned = false;
234  lowerStreamFeatureList.push_back(s);
235  }
236  }
237 
238  unsigned int nbUpperPolygons = upperStreamFeatureList.size();
239  unsigned int nbLowerPolygons = lowerStreamFeatureList.size();
240  std::vector<FusionStruct> fusionList;
241  fusionList.clear();
242  for (unsigned int u = 0; u < nbUpperPolygons; u++)
243  {
244  for (unsigned int l = 0; l < nbLowerPolygons; l++)
245  {
246  FeatureStruct upper = upperStreamFeatureList[u];
247  FeatureStruct lower = lowerStreamFeatureList[l];
248  if (!(upper.feat == lower.feat) && upper.feat.GetGeometry()->IsValid() && lower.feat.GetGeometry()->IsValid())
249  {
250  if (ogr::Intersects(*upper.feat.GetGeometry(), *lower.feat.GetGeometry()))
251  {
252  ogr::UniqueGeometryPtr intersection2 = ogr::Intersection(*upper.feat.GetGeometry(), *lower.feat.GetGeometry());
253  ogr::UniqueGeometryPtr intersection = ogr::Intersection(*intersection2, streamLine);
254  // ogr::UniqueGeometryPtr intersection = ogr::Intersection(*upper.feat.GetGeometry(),*lower.feat.GetGeometry());
255  if (intersection)
256  {
257  FusionStruct fusion;
258  fusion.indStream1 = u;
259  fusion.indStream2 = l;
260  fusion.overlap = 0.;
261 
262  if (intersection->getGeometryType() == wkbPolygon)
263  {
264  fusion.overlap = dynamic_cast<OGRPolygon*>(intersection.get())->get_Area();
265  }
266  else if (intersection->getGeometryType() == wkbMultiPolygon)
267  {
268  fusion.overlap = dynamic_cast<OGRMultiPolygon*>(intersection.get())->get_Area();
269  }
270  else if (intersection->getGeometryType() == wkbGeometryCollection)
271  {
272  fusion.overlap = dynamic_cast<OGRGeometryCollection*>(intersection.get())->get_Area();
273  }
274  else if (intersection->getGeometryType() == wkbLineString)
275  {
276  fusion.overlap = dynamic_cast<OGRLineString*>(intersection.get())->get_Length();
277  }
278  else if (intersection->getGeometryType() == wkbMultiLineString)
279  {
280  fusion.overlap = dynamic_cast<OGRMultiLineString*>(intersection.get())->get_Length();
281  }
282 
287  fusionList.push_back(fusion);
288  }
289  }
290  }
291  }
292  }
293  unsigned int fusionListSize = fusionList.size();
294  std::sort(fusionList.begin(), fusionList.end(), SortFeature);
295  for (unsigned int i = 0; i < fusionListSize; i++)
296  {
297  FeatureStruct upper = upperStreamFeatureList.at(fusionList.at(i).indStream1);
298  FeatureStruct lower = lowerStreamFeatureList.at(fusionList.at(i).indStream2);
299  if (!upper.fusioned && !lower.fusioned)
300  {
301  upperStreamFeatureList[fusionList[i].indStream1].fusioned = true;
302  lowerStreamFeatureList[fusionList[i].indStream2].fusioned = true;
303  ogr::UniqueGeometryPtr fusionPolygon = ogr::Union(*upper.feat.GetGeometry(), *lower.feat.GetGeometry());
304  OGRFeatureType fusionFeature(m_OGRLayer.GetLayerDefn());
305  fusionFeature.SetGeometry(fusionPolygon.get());
307 
308  ogr::Field field = upper.feat[0];
309  try
310  {
311  switch (field.GetType())
312  {
313  case OFTInteger64:
314  {
315  fusionFeature[0].SetValue(field.GetValue<GIntBig>());
316  break;
317  }
318  default:
319  {
320  fusionFeature[0].SetValue(field.GetValue<int>());
321  }
322  }
323  m_OGRLayer.CreateFeature(fusionFeature);
324  m_OGRLayer.DeleteFeature(lower.feat.GetFID());
325  m_OGRLayer.DeleteFeature(upper.feat.GetFID());
326  }
327  catch (itk::ExceptionObject& err)
328  {
329  otbWarningMacro(<< "An exception was caught during fusion: " << err);
330  }
331  }
332  }
333 
334  // Update progress
335  progress.CompletedPixel();
336 
337  } // end for x
338 
339  if (m_OGRLayer.ogr().TestCapability("Transactions"))
340  {
341 
342  OGRErr errCommitX = m_OGRLayer.ogr().CommitTransaction();
343  if (errCommitX != OGRERR_NONE)
344  {
345  itkExceptionMacro(<< "Unable to commit transaction for OGR layer " << m_OGRLayer.ogr().GetName() << ".");
346  }
347  }
348  } // end for y
349 }
350 template <class TImage>
352 {
353  if (!m_OGRLayer)
354  {
355  itkExceptionMacro(<< "Input OGR layer is null!");
356  }
357 
358  this->InvokeEvent(itk::StartEvent());
359 
360  typename InputImageType::ConstPointer inputImage = this->GetInput();
361 
362  // compute the number of stream division in row and column
363  SizeType imageSize = this->GetInput()->GetLargestPossibleRegion().GetSize();
364  unsigned int nbRowStream = static_cast<unsigned int>(imageSize[1] / m_StreamSize[1] + 1);
365  unsigned int nbColStream = static_cast<unsigned int>(imageSize[0] / m_StreamSize[0] + 1);
366 
367  itk::ProgressReporter progress(this, 0, 2 * nbRowStream * nbColStream, 100, 0);
368  // Process column
369  this->ProcessStreamingLine(false, progress);
370  // Process row
371  this->ProcessStreamingLine(true, progress);
372 
373  this->InvokeEvent(itk::EndEvent());
374 }
375 
376 
377 } // end namespace otb
378 
379 #endif
double GetLengthOGRGeometryCollection(OGRGeometryCollection *intersection)
void SetOGRLayer(const OGRLayerType &ogrLayer)
void ProcessStreamingLine(bool line, itk::ProgressReporter &progress)
virtual const InputImageType * GetInput(void)
virtual void SetInput(const InputImageType *input)
Geometric object with descriptive fields.
OGRGeometry const * GetGeometry() const
void SetGeometry(OGRGeometry const *geometry)
Encapsulation of OGRField Instances of Field are expected to be built from an existing Feature with w...
OGRFieldType GetType() const
Field type accessor.
Implementation class for Feature iterator. This iterator is a single pass iterator....
Layer of geometric objects.
OTBGdalAdapters_EXPORT bool Intersects(OGRGeometry const &lhs, OGRGeometry const &rhs)
Do these features intersect?
OTBGdalAdapters_EXPORT UniqueGeometryPtr Intersection(OGRGeometry const &lhs, OGRGeometry const &rhs)
Computes intersection.
boost::interprocess::unique_ptr< OGRGeometry, internal::GeometryDeleter > UniqueGeometryPtr
OTBGdalAdapters_EXPORT UniqueGeometryPtr Union(OGRGeometry const &lhs, OGRGeometry const &rhs)
Computes union.
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
#define otbWarningMacro(x)
Definition: otbMacro.h:117