QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgslinevectorlayerdirector.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2010 by Sergey Yakushev *
3  * yakushevs <at> list.ru *
4  * *
5  * *
6  * This program is free software; you can redistribute it and/or modify *
7  * it under the terms of the GNU General Public License as published by *
8  * the Free Software Foundation; either version 2 of the License, or *
9  * (at your option) any later version. *
10  ***************************************************************************/
11 
18 #include "qgsgraphbuilderintr.h"
19 
20 // Qgis includes
21 #include <qgsvectorlayer.h>
22 #include <qgsvectordataprovider.h>
23 #include <qgspoint.h>
24 #include <qgsgeometry.h>
25 #include <qgsdistancearea.h>
26 
27 // QT includes
28 #include <QString>
29 #include <QtAlgorithms>
30 
31 //standard includes
32 #include <limits>
33 #include <algorithm>
34 
36 {
37  public:
38  QgsPointCompare( double tolerance ) :
39  mTolerance( tolerance )
40  { }
41 
42  bool operator()( const QgsPoint& p1, const QgsPoint& p2 ) const
43  {
44  if ( mTolerance <= 0 )
45  return p1.x() == p2.x() ? p1.y() < p2.y() : p1.x() < p2.x();
46 
47  double tx1 = ceil( p1.x() / mTolerance );
48  double tx2 = ceil( p2.x() / mTolerance );
49  if ( tx1 == tx2 )
50  return ceil( p1.y() / mTolerance ) < ceil( p2.y() / mTolerance );
51  return tx1 < tx2;
52  }
53 
54  private:
55  double mTolerance;
56 };
57 
58 template <typename RandIter, typename Type, typename CompareOp > RandIter my_binary_search( RandIter begin, RandIter end, Type val, CompareOp comp )
59 {
60  // result if not found
61  RandIter not_found = end;
62 
63  while ( true )
64  {
65  RandIter avg = begin + ( end - begin ) / 2;
66  if ( begin == avg || end == avg )
67  {
68  if ( !comp( *begin, val ) && !comp( val, *begin ) )
69  return begin;
70  if ( !comp( *end, val ) && !comp( val, *end ) )
71  return end;
72 
73  return not_found;
74  }
75  if ( comp( val, *avg ) )
76  end = avg;
77  else if ( comp( *avg, val ) )
78  begin = avg;
79  else
80  return avg;
81  }
82 
83  return not_found;
84 }
85 
87 {
89  double mLength;
92 };
93 
94 bool TiePointInfoCompare( const TiePointInfo& a, const TiePointInfo& b )
95 {
96  if ( a.mFirstPoint == b.mFirstPoint )
97  return a.mLastPoint.x() == b.mLastPoint.x() ? a.mLastPoint.y() < b.mLastPoint.y() : a.mLastPoint.x() < b.mLastPoint.x();
98 
99  return a.mFirstPoint.x() == b.mFirstPoint.x() ? a.mFirstPoint.y() < b.mFirstPoint.y() : a.mFirstPoint.x() < b.mFirstPoint.x();
100 }
101 
103  int directionFieldId,
104  const QString& directDirectionValue,
105  const QString& reverseDirectionValue,
106  const QString& bothDirectionValue,
107  int defaultDirection
108  )
109 {
110  mVectorLayer = myLayer;
111  mDirectionFieldId = directionFieldId;
112  mDirectDirectionValue = directDirectionValue;
113  mReverseDirectionValue = reverseDirectionValue;
114  mDefaultDirection = defaultDirection;
115  mBothDirectionValue = bothDirectionValue;
116 }
117 
119 {
120 
121 }
122 
124 {
125  return QString( "Vector line" );
126 }
127 
128 void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints,
129  QVector< QgsPoint >& tiedPoint ) const
130 {
131  QgsVectorLayer *vl = mVectorLayer;
132 
133  if ( vl == NULL )
134  return;
135 
136  int featureCount = ( int ) vl->featureCount() * 2;
137  int step = 0;
138 
140  ct.setSourceCrs( vl->crs() );
141  if ( builder->coordinateTransformationEnabled() )
142  {
143  ct.setDestCRS( builder->destinationCrs() );
144  }
145  else
146  {
147  ct.setDestCRS( vl->crs() );
148  }
149 
150  tiedPoint = QVector< QgsPoint >( additionalPoints.size(), QgsPoint( 0.0, 0.0 ) );
151 
152  TiePointInfo tmpInfo;
153  tmpInfo.mLength = std::numeric_limits<double>::infinity();
154 
155  QVector< TiePointInfo > pointLengthMap( additionalPoints.size(), tmpInfo );
156  QVector< TiePointInfo >::iterator pointLengthIt;
157 
158  //Graph's points;
159  QVector< QgsPoint > points;
160 
161  QgsFeatureIterator fit = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
162 
163  // begin: tie points to the graph
164  QgsAttributeList la;
165  QgsFeature feature;
166  while ( fit.nextFeature( feature ) )
167  {
168  QgsMultiPolyline mpl;
169  if ( feature.geometry()->wkbType() == QGis::WKBMultiLineString )
170  mpl = feature.geometry()->asMultiPolyline();
171  else if ( feature.geometry()->wkbType() == QGis::WKBLineString )
172  mpl.push_back( feature.geometry()->asPolyline() );
173 
174  QgsMultiPolyline::iterator mplIt;
175  for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt )
176  {
177  QgsPoint pt1, pt2;
178  bool isFirstPoint = true;
179  QgsPolyline::iterator pointIt;
180  for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt )
181  {
182  pt2 = ct.transform( *pointIt );
183  points.push_back( pt2 );
184 
185  if ( !isFirstPoint )
186  {
187  int i = 0;
188  for ( i = 0; i != additionalPoints.size(); ++i )
189  {
190  TiePointInfo info;
191  if ( pt1 == pt2 )
192  {
193  info.mLength = additionalPoints[ i ].sqrDist( pt1 );
194  info.mTiedPoint = pt1;
195  }
196  else
197  {
198  info.mLength = additionalPoints[ i ].sqrDistToSegment( pt1.x(), pt1.y(),
199  pt2.x(), pt2.y(), info.mTiedPoint );
200  }
201 
202  if ( pointLengthMap[ i ].mLength > info.mLength )
203  {
204  Q_UNUSED( info.mTiedPoint );
205  info.mFirstPoint = pt1;
206  info.mLastPoint = pt2;
207 
208  pointLengthMap[ i ] = info;
209  tiedPoint[ i ] = info.mTiedPoint;
210  }
211  }
212  }
213  pt1 = pt2;
214  isFirstPoint = false;
215  }
216  }
217  emit buildProgress( ++step, featureCount );
218  }
219  // end: tie points to graph
220 
221  // add tied point to graph
222  int i = 0;
223  for ( i = 0; i < tiedPoint.size(); ++i )
224  {
225  if ( tiedPoint[ i ] != QgsPoint( 0.0, 0.0 ) )
226  {
227  points.push_back( tiedPoint [ i ] );
228  }
229  }
230 
231  QgsPointCompare pointCompare( builder->topologyTolerance() );
232 
233  qSort( points.begin(), points.end(), pointCompare );
234  QVector< QgsPoint >::iterator tmp = std::unique( points.begin(), points.end() );
235  points.resize( tmp - points.begin() );
236 
237  for ( i = 0;i < points.size();++i )
238  builder->addVertex( i, points[ i ] );
239 
240  for ( i = 0; i < tiedPoint.size() ; ++i )
241  tiedPoint[ i ] = *( my_binary_search( points.begin(), points.end(), tiedPoint[ i ], pointCompare ) );
242 
243  qSort( pointLengthMap.begin(), pointLengthMap.end(), TiePointInfoCompare );
244 
245  {
246  // fill attribute list 'la'
247  QgsAttributeList tmpAttr;
248  if ( mDirectionFieldId != -1 )
249  {
250  tmpAttr.push_back( mDirectionFieldId );
251  }
252 
253  QList< QgsArcProperter* >::const_iterator it;
254  QgsAttributeList::const_iterator it2;
255 
256  for ( it = mProperterList.begin(); it != mProperterList.end(); ++it )
257  {
258  QgsAttributeList tmp = ( *it )->requiredAttributes();
259  for ( it2 = tmp.begin(); it2 != tmp.end(); ++it2 )
260  {
261  tmpAttr.push_back( *it2 );
262  }
263  }
264  qSort( tmpAttr.begin(), tmpAttr.end() );
265 
266  int lastAttrId = -1;
267  for ( it2 = tmpAttr.begin(); it2 != tmpAttr.end(); ++it2 )
268  {
269  if ( *it2 == lastAttrId )
270  {
271  continue;
272  }
273 
274  la.push_back( *it2 );
275 
276  lastAttrId = *it2;
277  }
278  } // end fill attribute list 'la'
279 
280  // begin graph construction
281  fit = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( la ) );
282  while ( fit.nextFeature( feature ) )
283  {
284  int directionType = mDefaultDirection;
285 
286  // What direction have feature?
287  QString str = feature.attribute( mDirectionFieldId ).toString();
288  if ( str == mBothDirectionValue )
289  {
290  directionType = 3;
291  }
292  else if ( str == mDirectDirectionValue )
293  {
294  directionType = 1;
295  }
296  else if ( str == mReverseDirectionValue )
297  {
298  directionType = 2;
299  }
300 
301  // begin features segments and add arc to the Graph;
302  QgsMultiPolyline mpl;
303  if ( feature.geometry()->wkbType() == QGis::WKBMultiLineString )
304  mpl = feature.geometry()->asMultiPolyline();
305  else if ( feature.geometry()->wkbType() == QGis::WKBLineString )
306  mpl.push_back( feature.geometry()->asPolyline() );
307 
308  QgsMultiPolyline::iterator mplIt;
309  for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt )
310  {
311  QgsPoint pt1, pt2;
312 
313  bool isFirstPoint = true;
314  QgsPolyline::iterator pointIt;
315  for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt )
316  {
317  pt2 = ct.transform( *pointIt );
318 
319  if ( !isFirstPoint )
320  {
321  std::map< double, QgsPoint > pointsOnArc;
322  pointsOnArc[ 0.0 ] = pt1;
323  pointsOnArc[ pt1.sqrDist( pt2 )] = pt2;
324 
325  TiePointInfo t;
326  t.mFirstPoint = pt1;
327  t.mLastPoint = pt2;
328  pointLengthIt = my_binary_search( pointLengthMap.begin(), pointLengthMap.end(), t, TiePointInfoCompare );
329 
330  if ( pointLengthIt != pointLengthMap.end() )
331  {
332  QVector< TiePointInfo >::iterator it;
333  for ( it = pointLengthIt; it - pointLengthMap.begin() >= 0; --it )
334  {
335  if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 )
336  {
337  pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint;
338  }
339  }
340  for ( it = pointLengthIt + 1; it != pointLengthMap.end(); ++it )
341  {
342  if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 )
343  {
344  pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint;
345  }
346  }
347  }
348 
349  std::map< double, QgsPoint >::iterator pointsIt;
350  QgsPoint pt1;
351  QgsPoint pt2;
352  int pt1idx = -1, pt2idx = -1;
353  bool isFirstPoint = true;
354  for ( pointsIt = pointsOnArc.begin(); pointsIt != pointsOnArc.end(); ++pointsIt )
355  {
356  pt2 = pointsIt->second;
357  tmp = my_binary_search( points.begin(), points.end(), pt2, pointCompare );
358  pt2 = *tmp;
359  pt2idx = tmp - points.begin();
360 
361  if ( !isFirstPoint && pt1 != pt2 )
362  {
363  double distance = builder->distanceArea()->measureLine( pt1, pt2 );
364  QVector< QVariant > prop;
365  QList< QgsArcProperter* >::const_iterator it;
366  for ( it = mProperterList.begin(); it != mProperterList.end(); ++it )
367  {
368  prop.push_back(( *it )->property( distance, feature ) );
369  }
370 
371  if ( directionType == 1 ||
372  directionType == 3 )
373  {
374  builder->addArc( pt1idx, pt1, pt2idx, pt2, prop );
375  }
376  if ( directionType == 2 ||
377  directionType == 3 )
378  {
379  builder->addArc( pt2idx, pt2, pt1idx, pt1, prop );
380  }
381  }
382  pt1idx = pt2idx;
383  pt1 = pt2;
384  isFirstPoint = false;
385  }
386  } // if ( !isFirstPoint )
387  pt1 = pt2;
388  isFirstPoint = false;
389  } // for (it = pl.begin(); it != pl.end(); ++it)
390  }
391  emit buildProgress( ++step, featureCount );
392  } // while( vl->nextFeature(feature) )
393 } // makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints, QVector< QgsPoint >& tiedPoint )
394