QGIS API Documentation  2.15.0-Master (972fc9f)
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 #include <qgswkbtypes.h>
27 
28 // QT includes
29 #include <QString>
30 #include <QtAlgorithms>
31 
33 {
34  public:
35  explicit QgsPointCompare( double tolerance )
36  : mTolerance( tolerance )
37  { }
38 
39  bool operator()( const QgsPoint& p1, const QgsPoint& p2 ) const
40  {
41  if ( mTolerance <= 0 )
42  return p1.x() == p2.x() ? p1.y() < p2.y() : p1.x() < p2.x();
43 
44  double tx1 = ceil( p1.x() / mTolerance );
45  double tx2 = ceil( p2.x() / mTolerance );
46  if ( tx1 == tx2 )
47  return ceil( p1.y() / mTolerance ) < ceil( p2.y() / mTolerance );
48  return tx1 < tx2;
49  }
50 
51  private:
52  double mTolerance;
53 };
54 
55 template <typename RandIter, typename Type, typename CompareOp > RandIter my_binary_search( RandIter begin, RandIter end, Type val, CompareOp comp )
56 {
57  // result if not found
58  RandIter not_found = end;
59 
60  while ( true )
61  {
62  RandIter avg = begin + ( end - begin ) / 2;
63  if ( begin == avg || end == avg )
64  {
65  if ( !comp( *begin, val ) && !comp( val, *begin ) )
66  return begin;
67  if ( !comp( *end, val ) && !comp( val, *end ) )
68  return end;
69 
70  return not_found;
71  }
72  if ( comp( val, *avg ) )
73  end = avg;
74  else if ( comp( *avg, val ) )
75  begin = avg;
76  else
77  return avg;
78  }
79 
80  return not_found;
81 }
82 
84 {
86  double mLength;
89 };
90 
91 bool TiePointInfoCompare( const TiePointInfo& a, const TiePointInfo& b )
92 {
93  if ( a.mFirstPoint == b.mFirstPoint )
94  return a.mLastPoint.x() == b.mLastPoint.x() ? a.mLastPoint.y() < b.mLastPoint.y() : a.mLastPoint.x() < b.mLastPoint.x();
95 
96  return a.mFirstPoint.x() == b.mFirstPoint.x() ? a.mFirstPoint.y() < b.mFirstPoint.y() : a.mFirstPoint.x() < b.mFirstPoint.x();
97 }
98 
100  int directionFieldId,
101  const QString& directDirectionValue,
102  const QString& reverseDirectionValue,
103  const QString& bothDirectionValue,
104  int defaultDirection
105  )
106 {
107  mVectorLayer = myLayer;
108  mDirectionFieldId = directionFieldId;
109  mDirectDirectionValue = directDirectionValue;
110  mReverseDirectionValue = reverseDirectionValue;
111  mDefaultDirection = defaultDirection;
112  mBothDirectionValue = bothDirectionValue;
113 }
114 
116 {
117 
118 }
119 
121 {
122  return QString( "Vector line" );
123 }
124 
126  QVector< QgsPoint >& tiedPoint ) const
127 {
128  QgsVectorLayer *vl = mVectorLayer;
129 
130  if ( !vl )
131  return;
132 
133  int featureCount = ( int ) vl->featureCount() * 2;
134  int step = 0;
135 
137  ct.setSourceCrs( vl->crs() );
138  if ( builder->coordinateTransformationEnabled() )
139  {
140  ct.setDestCRS( builder->destinationCrs() );
141  }
142  else
143  {
144  ct.setDestCRS( vl->crs() );
145  }
146 
147  tiedPoint = QVector< QgsPoint >( additionalPoints.size(), QgsPoint( 0.0, 0.0 ) );
148 
149  TiePointInfo tmpInfo;
150  tmpInfo.mLength = std::numeric_limits<double>::infinity();
151 
152  QVector< TiePointInfo > pointLengthMap( additionalPoints.size(), tmpInfo );
153  QVector< TiePointInfo >::iterator pointLengthIt;
154 
155  //Graph's points;
156  QVector< QgsPoint > points;
157 
158  QgsFeatureIterator fit = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
159 
160  // begin: tie points to the graph
161  QgsAttributeList la;
162  QgsFeature feature;
163  while ( fit.nextFeature( feature ) )
164  {
165  QgsMultiPolyline mpl;
167  mpl = feature.constGeometry()->asMultiPolyline();
169  mpl.push_back( feature.constGeometry()->asPolyline() );
170 
172  for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt )
173  {
174  QgsPoint pt1, pt2;
175  bool isFirstPoint = true;
176  QgsPolyline::iterator pointIt;
177  for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt )
178  {
179  pt2 = ct.transform( *pointIt );
180  points.push_back( pt2 );
181 
182  if ( !isFirstPoint )
183  {
184  int i = 0;
185  for ( i = 0; i != additionalPoints.size(); ++i )
186  {
187  TiePointInfo info;
188  if ( pt1 == pt2 )
189  {
190  info.mLength = additionalPoints[ i ].sqrDist( pt1 );
191  info.mTiedPoint = pt1;
192  }
193  else
194  {
195  info.mLength = additionalPoints[ i ].sqrDistToSegment( pt1.x(), pt1.y(),
196  pt2.x(), pt2.y(), info.mTiedPoint );
197  }
198 
199  if ( pointLengthMap[ i ].mLength > info.mLength )
200  {
201  Q_UNUSED( info.mTiedPoint );
202  info.mFirstPoint = pt1;
203  info.mLastPoint = pt2;
204 
205  pointLengthMap[ i ] = info;
206  tiedPoint[ i ] = info.mTiedPoint;
207  }
208  }
209  }
210  pt1 = pt2;
211  isFirstPoint = false;
212  }
213  }
214  emit buildProgress( ++step, featureCount );
215  }
216  // end: tie points to graph
217 
218  // add tied point to graph
219  int i = 0;
220  for ( i = 0; i < tiedPoint.size(); ++i )
221  {
222  if ( tiedPoint[ i ] != QgsPoint( 0.0, 0.0 ) )
223  {
224  points.push_back( tiedPoint [ i ] );
225  }
226  }
227 
228  QgsPointCompare pointCompare( builder->topologyTolerance() );
229 
230  qSort( points.begin(), points.end(), pointCompare );
231  QVector< QgsPoint >::iterator tmp = std::unique( points.begin(), points.end() );
232  points.resize( tmp - points.begin() );
233 
234  for ( i = 0;i < points.size();++i )
235  builder->addVertex( i, points[ i ] );
236 
237  for ( i = 0; i < tiedPoint.size() ; ++i )
238  tiedPoint[ i ] = *( my_binary_search( points.begin(), points.end(), tiedPoint[ i ], pointCompare ) );
239 
240  qSort( pointLengthMap.begin(), pointLengthMap.end(), TiePointInfoCompare );
241 
242  {
243  // fill attribute list 'la'
244  QgsAttributeList tmpAttr;
245  if ( mDirectionFieldId != -1 )
246  {
247  tmpAttr.push_back( mDirectionFieldId );
248  }
249 
252 
253  for ( it = mProperterList.begin(); it != mProperterList.end(); ++it )
254  {
255  QgsAttributeList tmp = ( *it )->requiredAttributes();
256  for ( it2 = tmp.begin(); it2 != tmp.end(); ++it2 )
257  {
258  tmpAttr.push_back( *it2 );
259  }
260  }
261  qSort( tmpAttr.begin(), tmpAttr.end() );
262 
263  int lastAttrId = -1;
264  for ( it2 = tmpAttr.begin(); it2 != tmpAttr.end(); ++it2 )
265  {
266  if ( *it2 == lastAttrId )
267  {
268  continue;
269  }
270 
271  la.push_back( *it2 );
272 
273  lastAttrId = *it2;
274  }
275  } // end fill attribute list 'la'
276 
277  // begin graph construction
278  fit = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( la ) );
279  while ( fit.nextFeature( feature ) )
280  {
281  int directionType = mDefaultDirection;
282 
283  // What direction have feature?
284  QString str = feature.attribute( mDirectionFieldId ).toString();
285  if ( str == mBothDirectionValue )
286  {
287  directionType = 3;
288  }
289  else if ( str == mDirectDirectionValue )
290  {
291  directionType = 1;
292  }
293  else if ( str == mReverseDirectionValue )
294  {
295  directionType = 2;
296  }
297 
298  // begin features segments and add arc to the Graph;
299  QgsMultiPolyline mpl;
301  mpl = feature.constGeometry()->asMultiPolyline();
303  mpl.push_back( feature.constGeometry()->asPolyline() );
304 
306  for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt )
307  {
308  QgsPoint pt1, pt2;
309 
310  bool isFirstPoint = true;
311  QgsPolyline::iterator pointIt;
312  for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt )
313  {
314  pt2 = ct.transform( *pointIt );
315 
316  if ( !isFirstPoint )
317  {
318  QMap< double, QgsPoint > pointsOnArc;
319  pointsOnArc[ 0.0 ] = pt1;
320  pointsOnArc[ pt1.sqrDist( pt2 )] = pt2;
321 
322  TiePointInfo t;
323  t.mFirstPoint = pt1;
324  t.mLastPoint = pt2;
325  t.mLength = 0.0;
326  pointLengthIt = my_binary_search( pointLengthMap.begin(), pointLengthMap.end(), t, TiePointInfoCompare );
327 
328  if ( pointLengthIt != pointLengthMap.end() )
329  {
331  for ( it = pointLengthIt; it - pointLengthMap.begin() >= 0; --it )
332  {
333  if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 )
334  {
335  pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint;
336  }
337  }
338  for ( it = pointLengthIt + 1; it != pointLengthMap.end(); ++it )
339  {
340  if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 )
341  {
342  pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint;
343  }
344  }
345  }
346 
348  QgsPoint pt1;
349  QgsPoint pt2;
350  int pt1idx = -1, pt2idx = -1;
351  bool isFirstPoint = true;
352  for ( pointsIt = pointsOnArc.begin(); pointsIt != pointsOnArc.end(); ++pointsIt )
353  {
354  pt2 = *pointsIt;
355  tmp = my_binary_search( points.begin(), points.end(), pt2, pointCompare );
356  pt2 = *tmp;
357  pt2idx = tmp - points.begin();
358 
359  if ( !isFirstPoint && pt1 != pt2 )
360  {
361  double distance = builder->distanceArea()->measureLine( pt1, pt2 );
362  QVector< QVariant > prop;
364  for ( it = mProperterList.begin(); it != mProperterList.end(); ++it )
365  {
366  prop.push_back(( *it )->property( distance, feature ) );
367  }
368 
369  if ( directionType == 1 ||
370  directionType == 3 )
371  {
372  builder->addArc( pt1idx, pt1, pt2idx, pt2, prop );
373  }
374  if ( directionType == 2 ||
375  directionType == 3 )
376  {
377  builder->addArc( pt2idx, pt2, pt1idx, pt1, prop );
378  }
379  }
380  pt1idx = pt2idx;
381  pt1 = pt2;
382  isFirstPoint = false;
383  }
384  } // if ( !isFirstPoint )
385  pt1 = pt2;
386  isFirstPoint = false;
387  } // for (it = pl.begin(); it != pl.end(); ++it)
388  }
389  emit buildProgress( ++step, featureCount );
390  } // while( vl->nextFeature(feature) )
391 } // makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints, QVector< QgsPoint >& tiedPoint )
392 
Wrapper for iterator of features from vector data provider or vector layer.
virtual void addVertex(int id, const QgsPoint &pt)
add vertex
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
void makeGraph(QgsGraphBuilderInterface *builder, const QVector< QgsPoint > &additionalPoints, QVector< QgsPoint > &tiedPoints) const override
Make a graph using RgGraphBuilder.
bool operator()(const QgsPoint &p1, const QgsPoint &p2) const
iterator begin()
void push_back(const T &value)
typedef iterator
void setSourceCrs(const QgsCoordinateReferenceSystem &theCRS)
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QgsMultiPolyline asMultiPolyline() const
Return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
bool coordinateTransformationEnabled()
get coordinate transformation enabled
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
Determine interface for creating a graph.
QgsPoint transform(const QgsPoint &p, TransformDirection direction=ForwardTransform) const
Transform the point from Source Coordinate System to Destination Coordinate System If the direction i...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Definition: qgspoint.cpp:353
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
QgsCoordinateReferenceSystem & destinationCrs()
get destinaltion Crs
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
virtual void addArc(int pt1id, const QgsPoint &pt1, int pt2id, const QgsPoint &pt2, const QVector< QVariant > &properties)
add arc
void resize(int size)
QString name() const override
return Director name
This class wraps a request for features to a vector layer (or directly its vector data provider)...
double measureLine(const QList< QgsPoint > &points) const
Measures the length of a line with multiple segments.
bool TiePointInfoCompare(const TiePointInfo &a, const TiePointInfo &b)
QList< int > QgsAttributeList
iterator end()
A class to represent a point.
Definition: qgspoint.h:117
iterator begin()
iterator end()
void setDestCRS(const QgsCoordinateReferenceSystem &theCRS)
QgsPolyline asPolyline() const
Return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
QgsLineVectorLayerDirector(QgsVectorLayer *myLayer, int directionFieldId, const QString &directDirectionValue, const QString &reverseDirectionValue, const QString &bothDirectionValue, int defaultDirection)
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
Class for doing transforms between two map coordinate systems.
virtual ~QgsLineVectorLayerDirector()
Destructor.
void push_back(const T &value)
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
double topologyTolerance()
get topology tolerance
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
bool nextFeature(QgsFeature &f)
QgsPointCompare(double tolerance)
int size() const
Represents a vector layer which manages a vector based data sets.
QString toString() const
iterator end()
QgsDistanceArea * distanceArea()
get measurement tool
iterator begin()
RandIter my_binary_search(RandIter begin, RandIter end, Type val, CompareOp comp)