|
QGIS API Documentation
master-6227475
|
00001 /*************************************************************************** 00002 * Copyright (C) 2010 by Sergey Yakushev * 00003 * yakushevs <at> list.ru * 00004 * * 00005 * * 00006 * This program is free software; you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation; either version 2 of the License, or * 00009 * (at your option) any later version. * 00010 ***************************************************************************/ 00011 00017 #include "qgslinevectorlayerdirector.h" 00018 #include "qgsgraphbuilderintr.h" 00019 00020 // Qgis includes 00021 #include <qgsvectorlayer.h> 00022 #include <qgsvectordataprovider.h> 00023 #include <qgspoint.h> 00024 #include <qgsgeometry.h> 00025 #include <qgsdistancearea.h> 00026 00027 // QT includes 00028 #include <QString> 00029 #include <QtAlgorithms> 00030 00031 //standard includes 00032 #include <limits> 00033 #include <algorithm> 00034 00035 class QgsPointCompare 00036 { 00037 public: 00038 QgsPointCompare( double tolerance ) : 00039 mTolerance( tolerance ) 00040 { } 00041 00042 bool operator()( const QgsPoint& p1, const QgsPoint& p2 ) const 00043 { 00044 if ( mTolerance <= 0 ) 00045 return p1.x() == p2.x() ? p1.y() < p2.y() : p1.x() < p2.x(); 00046 00047 double tx1 = ceil( p1.x() / mTolerance ); 00048 double tx2 = ceil( p2.x() / mTolerance ); 00049 if ( tx1 == tx2 ) 00050 return ceil( p1.y() / mTolerance ) < ceil( p2.y() / mTolerance ); 00051 return tx1 < tx2; 00052 } 00053 00054 private: 00055 double mTolerance; 00056 }; 00057 00058 template <typename RandIter, typename Type, typename CompareOp > RandIter my_binary_search( RandIter begin, RandIter end, Type val, CompareOp comp ) 00059 { 00060 // result if not found 00061 RandIter not_found = end; 00062 00063 while ( true ) 00064 { 00065 RandIter avg = begin + ( end - begin ) / 2; 00066 if ( begin == avg || end == avg ) 00067 { 00068 if ( !comp( *begin, val ) && !comp( val, *begin ) ) 00069 return begin; 00070 if ( !comp( *end, val ) && !comp( val, *end ) ) 00071 return end; 00072 00073 return not_found; 00074 } 00075 if ( comp( val, *avg ) ) 00076 end = avg; 00077 else if ( comp( *avg, val ) ) 00078 begin = avg; 00079 else 00080 return avg; 00081 } 00082 00083 return not_found; 00084 } 00085 00086 struct TiePointInfo 00087 { 00088 QgsPoint mTiedPoint; 00089 double mLength; 00090 QgsPoint mFirstPoint; 00091 QgsPoint mLastPoint; 00092 }; 00093 00094 bool TiePointInfoCompare( const TiePointInfo& a, const TiePointInfo& b ) 00095 { 00096 if ( a.mFirstPoint == b.mFirstPoint ) 00097 return a.mLastPoint.x() == b.mLastPoint.x() ? a.mLastPoint.y() < b.mLastPoint.y() : a.mLastPoint.x() < b.mLastPoint.x(); 00098 00099 return a.mFirstPoint.x() == b.mFirstPoint.x() ? a.mFirstPoint.y() < b.mFirstPoint.y() : a.mFirstPoint.x() < b.mFirstPoint.x(); 00100 } 00101 00102 QgsLineVectorLayerDirector::QgsLineVectorLayerDirector( QgsVectorLayer *myLayer, 00103 int directionFieldId, 00104 const QString& directDirectionValue, 00105 const QString& reverseDirectionValue, 00106 const QString& bothDirectionValue, 00107 int defaultDirection 00108 ) 00109 { 00110 mVectorLayer = myLayer; 00111 mDirectionFieldId = directionFieldId; 00112 mDirectDirectionValue = directDirectionValue; 00113 mReverseDirectionValue = reverseDirectionValue; 00114 mDefaultDirection = defaultDirection; 00115 mBothDirectionValue = bothDirectionValue; 00116 } 00117 00118 QgsLineVectorLayerDirector::~QgsLineVectorLayerDirector() 00119 { 00120 00121 } 00122 00123 QString QgsLineVectorLayerDirector::name() const 00124 { 00125 return QString( "Vector line" ); 00126 } 00127 00128 void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints, 00129 QVector< QgsPoint >& tiedPoint ) const 00130 { 00131 QgsVectorLayer *vl = mVectorLayer; 00132 00133 if ( vl == NULL ) 00134 return; 00135 00136 int featureCount = ( int ) vl->featureCount() * 2; 00137 int step = 0; 00138 00139 QgsCoordinateTransform ct; 00140 ct.setSourceCrs( vl->crs() ); 00141 if ( builder->coordinateTransformationEnabled() ) 00142 { 00143 ct.setDestCRS( builder->destinationCrs() ); 00144 } 00145 else 00146 { 00147 ct.setDestCRS( vl->crs() ); 00148 } 00149 00150 tiedPoint = QVector< QgsPoint >( additionalPoints.size(), QgsPoint( 0.0, 0.0 ) ); 00151 00152 TiePointInfo tmpInfo; 00153 tmpInfo.mLength = std::numeric_limits<double>::infinity(); 00154 00155 QVector< TiePointInfo > pointLengthMap( additionalPoints.size(), tmpInfo ); 00156 QVector< TiePointInfo >::iterator pointLengthIt; 00157 00158 //Graph's points; 00159 QVector< QgsPoint > points; 00160 00161 QgsFeatureIterator fit = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ); 00162 00163 // begin: tie points to the graph 00164 QgsAttributeList la; 00165 QgsFeature feature; 00166 while ( fit.nextFeature( feature ) ) 00167 { 00168 QgsMultiPolyline mpl; 00169 if ( feature.geometry()->wkbType() == QGis::WKBMultiLineString ) 00170 mpl = feature.geometry()->asMultiPolyline(); 00171 else if ( feature.geometry()->wkbType() == QGis::WKBLineString ) 00172 mpl.push_back( feature.geometry()->asPolyline() ); 00173 00174 QgsMultiPolyline::iterator mplIt; 00175 for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt ) 00176 { 00177 QgsPoint pt1, pt2; 00178 bool isFirstPoint = true; 00179 QgsPolyline::iterator pointIt; 00180 for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt ) 00181 { 00182 pt2 = ct.transform( *pointIt ); 00183 points.push_back( pt2 ); 00184 00185 if ( !isFirstPoint ) 00186 { 00187 int i = 0; 00188 for ( i = 0; i != additionalPoints.size(); ++i ) 00189 { 00190 TiePointInfo info; 00191 if ( pt1 == pt2 ) 00192 { 00193 info.mLength = additionalPoints[ i ].sqrDist( pt1 ); 00194 info.mTiedPoint = pt1; 00195 } 00196 else 00197 { 00198 info.mLength = additionalPoints[ i ].sqrDistToSegment( pt1.x(), pt1.y(), 00199 pt2.x(), pt2.y(), info.mTiedPoint ); 00200 } 00201 00202 if ( pointLengthMap[ i ].mLength > info.mLength ) 00203 { 00204 Q_UNUSED( info.mTiedPoint ); 00205 info.mFirstPoint = pt1; 00206 info.mLastPoint = pt2; 00207 00208 pointLengthMap[ i ] = info; 00209 tiedPoint[ i ] = info.mTiedPoint; 00210 } 00211 } 00212 } 00213 pt1 = pt2; 00214 isFirstPoint = false; 00215 } 00216 } 00217 emit buildProgress( ++step, featureCount ); 00218 } 00219 // end: tie points to graph 00220 00221 // add tied point to graph 00222 int i = 0; 00223 for ( i = 0; i < tiedPoint.size(); ++i ) 00224 { 00225 if ( tiedPoint[ i ] != QgsPoint( 0.0, 0.0 ) ) 00226 { 00227 points.push_back( tiedPoint [ i ] ); 00228 } 00229 } 00230 00231 QgsPointCompare pointCompare( builder->topologyTolerance() ); 00232 00233 qSort( points.begin(), points.end(), pointCompare ); 00234 QVector< QgsPoint >::iterator tmp = std::unique( points.begin(), points.end() ); 00235 points.resize( tmp - points.begin() ); 00236 00237 for ( i = 0;i < points.size();++i ) 00238 builder->addVertex( i, points[ i ] ); 00239 00240 for ( i = 0; i < tiedPoint.size() ; ++i ) 00241 tiedPoint[ i ] = *( my_binary_search( points.begin(), points.end(), tiedPoint[ i ], pointCompare ) ); 00242 00243 qSort( pointLengthMap.begin(), pointLengthMap.end(), TiePointInfoCompare ); 00244 00245 { 00246 // fill attribute list 'la' 00247 QgsAttributeList tmpAttr; 00248 if ( mDirectionFieldId != -1 ) 00249 { 00250 tmpAttr.push_back( mDirectionFieldId ); 00251 } 00252 00253 QList< QgsArcProperter* >::const_iterator it; 00254 QgsAttributeList::const_iterator it2; 00255 00256 for ( it = mProperterList.begin(); it != mProperterList.end(); ++it ) 00257 { 00258 QgsAttributeList tmp = ( *it )->requiredAttributes(); 00259 for ( it2 = tmp.begin(); it2 != tmp.end(); ++it2 ) 00260 { 00261 tmpAttr.push_back( *it2 ); 00262 } 00263 } 00264 qSort( tmpAttr.begin(), tmpAttr.end() ); 00265 00266 int lastAttrId = -1; 00267 for ( it2 = tmpAttr.begin(); it2 != tmpAttr.end(); ++it2 ) 00268 { 00269 if ( *it2 == lastAttrId ) 00270 { 00271 continue; 00272 } 00273 00274 la.push_back( *it2 ); 00275 00276 lastAttrId = *it2; 00277 } 00278 } // end fill attribute list 'la' 00279 00280 // begin graph construction 00281 fit = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( la ) ); 00282 while ( fit.nextFeature( feature ) ) 00283 { 00284 int directionType = mDefaultDirection; 00285 00286 // What direction have feature? 00287 QString str = feature.attribute( mDirectionFieldId ).toString(); 00288 if ( str == mBothDirectionValue ) 00289 { 00290 directionType = 3; 00291 } 00292 else if ( str == mDirectDirectionValue ) 00293 { 00294 directionType = 1; 00295 } 00296 else if ( str == mReverseDirectionValue ) 00297 { 00298 directionType = 2; 00299 } 00300 00301 // begin features segments and add arc to the Graph; 00302 QgsMultiPolyline mpl; 00303 if ( feature.geometry()->wkbType() == QGis::WKBMultiLineString ) 00304 mpl = feature.geometry()->asMultiPolyline(); 00305 else if ( feature.geometry()->wkbType() == QGis::WKBLineString ) 00306 mpl.push_back( feature.geometry()->asPolyline() ); 00307 00308 QgsMultiPolyline::iterator mplIt; 00309 for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt ) 00310 { 00311 QgsPoint pt1, pt2; 00312 00313 bool isFirstPoint = true; 00314 QgsPolyline::iterator pointIt; 00315 for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt ) 00316 { 00317 pt2 = ct.transform( *pointIt ); 00318 00319 if ( !isFirstPoint ) 00320 { 00321 std::map< double, QgsPoint > pointsOnArc; 00322 pointsOnArc[ 0.0 ] = pt1; 00323 pointsOnArc[ pt1.sqrDist( pt2 )] = pt2; 00324 00325 TiePointInfo t; 00326 t.mFirstPoint = pt1; 00327 t.mLastPoint = pt2; 00328 pointLengthIt = my_binary_search( pointLengthMap.begin(), pointLengthMap.end(), t, TiePointInfoCompare ); 00329 00330 if ( pointLengthIt != pointLengthMap.end() ) 00331 { 00332 QVector< TiePointInfo >::iterator it; 00333 for ( it = pointLengthIt; it - pointLengthMap.begin() >= 0; --it ) 00334 { 00335 if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 ) 00336 { 00337 pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint; 00338 } 00339 } 00340 for ( it = pointLengthIt + 1; it != pointLengthMap.end(); ++it ) 00341 { 00342 if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 ) 00343 { 00344 pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint; 00345 } 00346 } 00347 } 00348 00349 std::map< double, QgsPoint >::iterator pointsIt; 00350 QgsPoint pt1; 00351 QgsPoint pt2; 00352 int pt1idx = -1, pt2idx = -1; 00353 bool isFirstPoint = true; 00354 for ( pointsIt = pointsOnArc.begin(); pointsIt != pointsOnArc.end(); ++pointsIt ) 00355 { 00356 pt2 = pointsIt->second; 00357 tmp = my_binary_search( points.begin(), points.end(), pt2, pointCompare ); 00358 pt2 = *tmp; 00359 pt2idx = tmp - points.begin(); 00360 00361 if ( !isFirstPoint && pt1 != pt2 ) 00362 { 00363 double distance = builder->distanceArea()->measureLine( pt1, pt2 ); 00364 QVector< QVariant > prop; 00365 QList< QgsArcProperter* >::const_iterator it; 00366 for ( it = mProperterList.begin(); it != mProperterList.end(); ++it ) 00367 { 00368 prop.push_back(( *it )->property( distance, feature ) ); 00369 } 00370 00371 if ( directionType == 1 || 00372 directionType == 3 ) 00373 { 00374 builder->addArc( pt1idx, pt1, pt2idx, pt2, prop ); 00375 } 00376 if ( directionType == 2 || 00377 directionType == 3 ) 00378 { 00379 builder->addArc( pt2idx, pt2, pt1idx, pt1, prop ); 00380 } 00381 } 00382 pt1idx = pt2idx; 00383 pt1 = pt2; 00384 isFirstPoint = false; 00385 } 00386 } // if ( !isFirstPoint ) 00387 pt1 = pt2; 00388 isFirstPoint = false; 00389 } // for (it = pl.begin(); it != pl.end(); ++it) 00390 } 00391 emit buildProgress( ++step, featureCount ); 00392 } // while( vl->nextFeature(feature) ) 00393 } // makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints, QVector< QgsPoint >& tiedPoint ) 00394