Quantum GIS API Documentation
1.8
|
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 // begin: tie points to the graph 00162 QgsAttributeList la; 00163 vl->select( la ); 00164 QgsFeature feature; 00165 while ( vl->nextFeature( feature ) ) 00166 { 00167 QgsMultiPolyline mpl; 00168 if ( feature.geometry()->wkbType() == QGis::WKBMultiLineString ) 00169 mpl = feature.geometry()->asMultiPolyline(); 00170 else if ( feature.geometry()->wkbType() == QGis::WKBLineString ) 00171 mpl.push_back( feature.geometry()->asPolyline() ); 00172 00173 QgsMultiPolyline::iterator mplIt; 00174 for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt ) 00175 { 00176 QgsPoint pt1, pt2; 00177 bool isFirstPoint = true; 00178 QgsPolyline::iterator pointIt; 00179 for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt ) 00180 { 00181 pt2 = ct.transform( *pointIt ); 00182 points.push_back( pt2 ); 00183 00184 if ( !isFirstPoint ) 00185 { 00186 int i = 0; 00187 for ( i = 0; i != additionalPoints.size(); ++i ) 00188 { 00189 TiePointInfo info; 00190 if ( pt1 == pt2 ) 00191 { 00192 info.mLength = additionalPoints[ i ].sqrDist( pt1 ); 00193 info.mTiedPoint = pt1; 00194 } 00195 else 00196 { 00197 info.mLength = additionalPoints[ i ].sqrDistToSegment( pt1.x(), pt1.y(), 00198 pt2.x(), pt2.y(), info.mTiedPoint ); 00199 } 00200 00201 if ( pointLengthMap[ i ].mLength > info.mLength ) 00202 { 00203 info.mTiedPoint = info.mTiedPoint ; 00204 info.mFirstPoint = pt1; 00205 info.mLastPoint = pt2; 00206 00207 pointLengthMap[ i ] = info; 00208 tiedPoint[ i ] = info.mTiedPoint; 00209 } 00210 } 00211 } 00212 pt1 = pt2; 00213 isFirstPoint = false; 00214 } 00215 } 00216 emit buildProgress( ++step, featureCount ); 00217 } 00218 // end: tie points to graph 00219 00220 // add tied point to graph 00221 int i = 0; 00222 for ( i = 0; i < tiedPoint.size(); ++i ) 00223 { 00224 if ( tiedPoint[ i ] != QgsPoint( 0.0, 0.0 ) ) 00225 { 00226 points.push_back( tiedPoint [ i ] ); 00227 } 00228 } 00229 00230 QgsPointCompare pointCompare( builder->topologyTolerance() ); 00231 00232 qSort( points.begin(), points.end(), pointCompare ); 00233 QVector< QgsPoint >::iterator tmp = std::unique( points.begin(), points.end() ); 00234 points.resize( tmp - points.begin() ); 00235 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 { // fill attribute list 'la' 00246 QgsAttributeList tmpAttr; 00247 if ( mDirectionFieldId != -1 ) 00248 { 00249 tmpAttr.push_back( mDirectionFieldId ); 00250 } 00251 00252 QList< QgsArcProperter* >::const_iterator it; 00253 QgsAttributeList::const_iterator it2; 00254 00255 for ( it = mProperterList.begin(); it != mProperterList.end(); ++it ) 00256 { 00257 QgsAttributeList tmp = ( *it )->requiredAttributes(); 00258 for ( it2 = tmp.begin(); it2 != tmp.end(); ++it2 ) 00259 { 00260 tmpAttr.push_back( *it2 ); 00261 } 00262 } 00263 qSort( tmpAttr.begin(), tmpAttr.end() ); 00264 00265 int lastAttrId = -1; 00266 for ( it2 = tmpAttr.begin(); it2 != tmpAttr.end(); ++it2 ) 00267 { 00268 if ( *it2 == lastAttrId ) 00269 { 00270 continue; 00271 } 00272 00273 la.push_back( *it2 ); 00274 00275 lastAttrId = *it2; 00276 } 00277 } // end fill attribute list 'la' 00278 00279 // begin graph construction 00280 vl->select( la ); 00281 while ( vl->nextFeature( feature ) ) 00282 { 00283 QgsAttributeMap attr = feature.attributeMap(); 00284 int directionType = mDefaultDirection; 00285 QgsAttributeMap::const_iterator it; 00286 // What direction have feature? 00287 for ( it = attr.constBegin(); it != attr.constEnd(); ++it ) 00288 { 00289 if ( it.key() != mDirectionFieldId ) 00290 { 00291 continue; 00292 } 00293 QString str = it.value().toString(); 00294 if ( str == mBothDirectionValue ) 00295 { 00296 directionType = 3; 00297 } 00298 else if ( str == mDirectDirectionValue ) 00299 { 00300 directionType = 1; 00301 } 00302 else if ( str == mReverseDirectionValue ) 00303 { 00304 directionType = 2; 00305 } 00306 } 00307 00308 // begin features segments and add arc to the Graph; 00309 QgsMultiPolyline mpl; 00310 if ( feature.geometry()->wkbType() == QGis::WKBMultiLineString ) 00311 mpl = feature.geometry()->asMultiPolyline(); 00312 else if ( feature.geometry()->wkbType() == QGis::WKBLineString ) 00313 mpl.push_back( feature.geometry()->asPolyline() ); 00314 00315 QgsMultiPolyline::iterator mplIt; 00316 for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt ) 00317 { 00318 QgsPoint pt1, pt2; 00319 00320 bool isFirstPoint = true; 00321 QgsPolyline::iterator pointIt; 00322 for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt ) 00323 { 00324 pt2 = ct.transform( *pointIt ); 00325 00326 if ( !isFirstPoint ) 00327 { 00328 std::map< double, QgsPoint > pointsOnArc; 00329 pointsOnArc[ 0.0 ] = pt1; 00330 pointsOnArc[ pt1.sqrDist( pt2 )] = pt2; 00331 00332 TiePointInfo t; 00333 t.mFirstPoint = pt1; 00334 t.mLastPoint = pt2; 00335 pointLengthIt = my_binary_search( pointLengthMap.begin(), pointLengthMap.end(), t, TiePointInfoCompare ); 00336 00337 if ( pointLengthIt != pointLengthMap.end() ) 00338 { 00339 QVector< TiePointInfo >::iterator it; 00340 for ( it = pointLengthIt; it - pointLengthMap.begin() >= 0; --it ) 00341 { 00342 if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 ) 00343 { 00344 pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint; 00345 } 00346 } 00347 for ( it = pointLengthIt + 1; it != pointLengthMap.end(); ++it ) 00348 { 00349 if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 ) 00350 { 00351 pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint; 00352 } 00353 } 00354 } 00355 00356 std::map< double, QgsPoint >::iterator pointsIt; 00357 QgsPoint pt1; 00358 QgsPoint pt2; 00359 int pt1idx = -1, pt2idx = -1; 00360 bool isFirstPoint = true; 00361 for ( pointsIt = pointsOnArc.begin(); pointsIt != pointsOnArc.end(); ++pointsIt ) 00362 { 00363 pt2 = pointsIt->second; 00364 tmp = my_binary_search( points.begin(), points.end(), pt2, pointCompare ); 00365 pt2 = *tmp; 00366 pt2idx = tmp - points.begin(); 00367 00368 if ( !isFirstPoint && pt1 != pt2 ) 00369 { 00370 double distance = builder->distanceArea()->measureLine( pt1, pt2 ); 00371 QVector< QVariant > prop; 00372 QList< QgsArcProperter* >::const_iterator it; 00373 for ( it = mProperterList.begin(); it != mProperterList.end(); ++it ) 00374 { 00375 prop.push_back(( *it )->property( distance, feature ) ); 00376 } 00377 00378 if ( directionType == 1 || 00379 directionType == 3 ) 00380 { 00381 builder->addArc( pt1idx, pt1, pt2idx, pt2, prop ); 00382 } 00383 if ( directionType == 2 || 00384 directionType == 3 ) 00385 { 00386 builder->addArc( pt2idx, pt2, pt1idx, pt1, prop ); 00387 } 00388 } 00389 pt1idx = pt2idx; 00390 pt1 = pt2; 00391 isFirstPoint = false; 00392 } 00393 } // if ( !isFirstPoint ) 00394 pt1 = pt2; 00395 isFirstPoint = false; 00396 } // for (it = pl.begin(); it != pl.end(); ++it) 00397 } 00398 emit buildProgress( ++step, featureCount ); 00399 } // while( vl->nextFeature(feature) ) 00400 } // makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints, QVector< QgsPoint >& tiedPoint ) 00401