QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 
36 {
37  public:
38  explicit 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 
129  QVector< QgsPoint >& tiedPoint ) const
130 {
131  QgsVectorLayer *vl = mVectorLayer;
132 
133  if ( !vl )
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;
170  mpl = feature.constGeometry()->asMultiPolyline();
172  mpl.push_back( feature.constGeometry()->asPolyline() );
173 
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 
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;
304  mpl = feature.constGeometry()->asMultiPolyline();
306  mpl.push_back( feature.constGeometry()->asPolyline() );
307 
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  QMap< 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  t.mLength = 0.0;
329  pointLengthIt = my_binary_search( pointLengthMap.begin(), pointLengthMap.end(), t, TiePointInfoCompare );
330 
331  if ( pointLengthIt != pointLengthMap.end() )
332  {
334  for ( it = pointLengthIt; it - pointLengthMap.begin() >= 0; --it )
335  {
336  if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 )
337  {
338  pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint;
339  }
340  }
341  for ( it = pointLengthIt + 1; it != pointLengthMap.end(); ++it )
342  {
343  if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 )
344  {
345  pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint;
346  }
347  }
348  }
349 
351  QgsPoint pt1;
352  QgsPoint pt2;
353  int pt1idx = -1, pt2idx = -1;
354  bool isFirstPoint = true;
355  for ( pointsIt = pointsOnArc.begin(); pointsIt != pointsOnArc.end(); ++pointsIt )
356  {
357  pt2 = *pointsIt;
358  tmp = my_binary_search( points.begin(), points.end(), pt2, pointCompare );
359  pt2 = *tmp;
360  pt2idx = tmp - points.begin();
361 
362  if ( !isFirstPoint && pt1 != pt2 )
363  {
364  double distance = builder->distanceArea()->measureLine( pt1, pt2 );
365  QVector< QVariant > prop;
367  for ( it = mProperterList.begin(); it != mProperterList.end(); ++it )
368  {
369  prop.push_back(( *it )->property( distance, feature ) );
370  }
371 
372  if ( directionType == 1 ||
373  directionType == 3 )
374  {
375  builder->addArc( pt1idx, pt1, pt2idx, pt2, prop );
376  }
377  if ( directionType == 2 ||
378  directionType == 3 )
379  {
380  builder->addArc( pt2idx, pt2, pt1idx, pt1, prop );
381  }
382  }
383  pt1idx = pt2idx;
384  pt1 = pt2;
385  isFirstPoint = false;
386  }
387  } // if ( !isFirstPoint )
388  pt1 = pt2;
389  isFirstPoint = false;
390  } // for (it = pl.begin(); it != pl.end(); ++it)
391  }
392  emit buildProgress( ++step, featureCount );
393  } // while( vl->nextFeature(feature) )
394 } // makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints, QVector< QgsPoint >& tiedPoint )
395 
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:193
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:117
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 a specified x, y coordinate.
Definition: qgspoint.cpp:353
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:185
RandIter my_binary_search(RandIter begin, RandIter end, Type val, CompareOp comp)