QGIS API Documentation  2.14.11-Essen
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 
QgsPoint transform(const QgsPoint &p, TransformDirection direction=ForwardTransform) const
Transform the point from Source Coordinate System to Destination Coordinate System If the direction i...
Wrapper for iterator of features from vector data provider or vector layer.
virtual void addVertex(int id, const QgsPoint &pt)
add vertex
QgsMultiPolyline asMultiPolyline() const
Return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
void makeGraph(QgsGraphBuilderInterface *builder, const QVector< QgsPoint > &additionalPoints, QVector< QgsPoint > &tiedPoints) const override
Make a graph using RgGraphBuilder.
iterator begin()
void push_back(const T &value)
typedef iterator
void setSourceCrs(const QgsCoordinateReferenceSystem &theCRS)
bool coordinateTransformationEnabled()
get coordinate transformation enabled
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
Determine interface for creating a graph.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QgsPolyline asPolyline() const
Return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
double y() const
Get the y value of the point.
Definition: qgspoint.h:136
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)...
bool TiePointInfoCompare(const TiePointInfo &a, const TiePointInfo &b)
QList< int > QgsAttributeList
double measureLine(const QList< QgsPoint > &points) const
Measures the length of a line with multiple segments.
iterator end()
A class to represent a point.
Definition: qgspoint.h:65
iterator begin()
iterator end()
void setDestCRS(const QgsCoordinateReferenceSystem &theCRS)
bool operator()(const QgsPoint &p1, const QgsPoint &p2) const
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
QgsLineVectorLayerDirector(QgsVectorLayer *myLayer, int directionFieldId, const QString &directDirectionValue, const QString &reverseDirectionValue, const QString &bothDirectionValue, int defaultDirection)
Class for doing transforms between two map coordinate systems.
virtual ~QgsLineVectorLayerDirector()
Destructor.
void push_back(const T &value)
double topologyTolerance()
get topology tolerance
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
double sqrDist(double x, double y) const
Returns the squared distance between this point and x,y.
Definition: qgspoint.cpp:345
bool nextFeature(QgsFeature &f)
QgsPointCompare(double tolerance)
int size() const
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
QString toString() const
iterator end()
QgsDistanceArea * distanceArea()
get measurement tool
iterator begin()
double x() const
Get the x value of the point.
Definition: qgspoint.h:128
RandIter my_binary_search(RandIter begin, RandIter end, Type val, CompareOp comp)