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