featurecache_patch.diff

initial patch (probably not working with current trunk anymore) - Martin Dobias, 2010-11-12 01:01 AM

Download (120 KB)

View differences:

python/core/qgsvectorlayer.sip (working copy)
449 449
   */
450 450
  virtual void updateExtents();
451 451

  
452
  /**
453
   * Fetch the specified feature from provider, if it is cached. This
454
   * must be called every time the provider data change outside vector layer control.
455
   * @param featureId id of feature that should be reloaded
456
   * @param rectFrom hint of rectangle, where the feature resided. If not provided,
457
   *             whole cache will be searched for the id.
458
   * @param rectTo hint of rectangle, where the feature resides now. If not provided,
459
   *             all provider features will be searched for the id.
460
  **/
461
  void recacheFeature( int featureId, QgsRectangle rectFrom=QgsRectangle(), QgsRectangle rectTo=QgsRectangle() );
462
    
463
  /**
464
   * Fetch features from specified rectangle from provider, if it is cached. This
465
   * must be called every time the provider data change outside vector layer control.
466
   * @param rect rectangle containing changed features. All features within
467
   *             the rectangle will be reloaded.
468
  **/
469
  void recacheFeatures( QgsRectangle rect );
470

  
452 471
signals:
453 472

  
454 473
  /** This signal is emited when selection was changed */
src/app/qgsoptions.cpp (working copy)
140 140
  cbxHideSplash->setChecked( settings.value( "/qgis/hideSplash", false ).toBool() );
141 141
  cbxAttributeTableDocked->setChecked( settings.value( "/qgis/dockAttributeTable", false ).toBool() );
142 142

  
143
  //features cache mode
144
  QString cacheMode = settings.value( "qgis/vectorLayerCacheMode", "heuristics" ).toString();
145
  if ( cacheMode == "all" )
146
    radCacheAll->setChecked(true);
147
  else if ( cacheMode == "nothing" )
148
    radCacheNothing->setChecked(true);
149
  else
150
    radCacheHeuristics->setChecked(true);
151
  
143 152
  //set the colour for selections
144 153
  int myRed = settings.value( "/qgis/default_selection_color_red", 255 ).toInt();
145 154
  int myGreen = settings.value( "/qgis/default_selection_color_green", 255 ).toInt();
......
345 354
  settings.setValue( "qgis/capitaliseLayerName", capitaliseCheckBox->isChecked() );
346 355
  settings.setValue( "qgis/askToSaveProjectChanges", chbAskToSaveProjectChanges->isChecked() );
347 356
  settings.setValue( "qgis/warnOldProjectVersion", chbWarnOldProjectVersion->isChecked() );
348

  
357
  
358
  settings.setValue( "qgis/vectorLayerCacheMode",
359
    radCacheNothing->isChecked() ? "nothing" : (
360
      radCacheAll->isChecked() ? "all" : "heuristics"
361
    )
362
  );
363
  
349 364
  //overlay placement method
350 365
  int overlayIndex = mOverlayAlgorithmComboBox->currentIndex();
351 366
  if ( overlayIndex == 1 )
src/core/qgsvectorlayer.cpp (working copy)
71 71
#include "qgsvectoroverlay.h"
72 72
#include "qgslogger.h"
73 73
#include "qgsmaplayerregistry.h"
74
#include "qgsfeaturecache.h"
74 75

  
75 76
#ifdef Q_WS_X11
76 77
#include "qgsclipper.h"
......
107 108
    mActiveCommand( NULL )
108 109
{
109 110
  mActions = new QgsAttributeAction;
111
  
112
  mFeatureCache=new QgsFeatureCache;
110 113

  
111 114
  // if we're given a provider type, try to create and bind one to this layer
112 115
  if ( ! mProviderKey.isEmpty() )
......
167 170

  
168 171
  delete mLabel;
169 172

  
173
#ifdef ENABLE_GEOMETRYCACHE
170 174
  // Destroy any cached geometries and clear the references to them
171 175
  deleteCachedGeometries();
176
#endif
172 177

  
178
  delete mFeatureCache;
179

  
173 180
  delete mActions;
174 181

  
175 182
  //delete remaining overlays
......
687 694

  
688 695
    if ( mEditable )
689 696
    {
697
#ifdef ENABLE_GEOMETRYCACHE
690 698
      // Destroy all cached geometries and clear the references to them
691 699
      deleteCachedGeometries();
692 700
      mCachedGeometriesRect = rendererContext.extent();
701
#endif
693 702
      vertexMarker = currentVertexMarkerType();
694 703
      mVertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
695 704
    }
......
699 708
    int featureCount = 0;
700 709
    QgsFeature fet;
701 710
    QgsAttributeList attributes = mRenderer->classificationAttributes();
702
    select( attributes, rendererContext.extent() );
711
    
712
    QgsRectangle renderExtent=rendererContext.extent();
713
    
714
    //apply cache mode
715
    QSettings settings;
716
    QString cacheMode=settings.value( "qgis/vectorLayerCacheMode", "heuristics" ).toString();
717
    if ( cacheMode == "heuristics" )
718
      mFeatureCache->setCacheMode(QgsFeatureCache::CACHE_HEURISTICS);
719
    else if ( cacheMode == "all" )
720
      mFeatureCache->setCacheMode(QgsFeatureCache::CACHE_ALL);
721
    else
722
      mFeatureCache->setCacheMode(QgsFeatureCache::CACHE_NOTHING);
723
    
724
    mFeatureCache->applyCurrentCacheMode(renderExtent);
725
    
726
    select( attributes, renderExtent);
703 727

  
728
    if ( !mFeatureCache->isSelectValid() )
729
    {
730
#ifdef LIMIT_CACHED_EXTENT
731
      if ( mDataProvider->extent() == mFeatureCache->getCachedRectangle() )
732
      {
733
        //everything is cached already, retrieve selected part
734
        //note: this will fail, if requested classification attributes changed
735
        mFeatureCache->makeSelectValid();
736
      }
737
      -
738
      if ( !mFeatureCache->isSelectValid() )
739
      {
740
        //cache still invalid, we'll have to refill the cache
741
        
742
        if ( renderExtent.contains( mDataProvider->extent() ) )
743
        {
744
          //only cache as big rectangle as the provider can provide
745
          select( attributes, mDataProvider->extent() );
746
        }
747
#endif        
748
        mFeatureCache->clear();
749
#ifdef LIMIT_CACHED_EXTENT
750
      }
751
#endif
752
    }
753
    
704 754
    try
705 755
    {
706 756
      while ( nextFeature( fet ) )
707 757
      {
758
        if ( !mFeatureCache->isInitialized() )
759
        {
760
          mFeatureCache->insert( fet );
761
        }
708 762

  
709 763
        if ( rendererContext.renderingStopped() )
710 764
        {
......
736 790

  
737 791
        if ( mEditable )
738 792
        {
793
#ifdef ENABLE_GEOMETRYCACHE
739 794
          // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
740 795
          mCachedGeometries[fet.id()] = *fet.geometry();
796
#endif
741 797

  
742 798
          if ( !mVertexMarkerOnlyForSelection || sel )
743 799
          {
......
770 826

  
771 827
        ++featureCount;
772 828
      }
829

  
830
      if ( !mFeatureCache->isInitialized() )
831
      {
832
        mFeatureCache->setAsInitialized();
833
      }
773 834
    }
774 835
    catch ( QgsCsException &cse )
775 836
    {
......
787 848

  
788 849
  if ( mEditable )
789 850
  {
851
#ifdef ENABLE_GEOMETRYCACHE
790 852
    QgsDebugMsg( QString( "Cached %1 geometries." ).arg( mCachedGeometries.count() ) );
853
#endif
791 854
  }
792 855

  
793 856
  return TRUE; // Assume success always
794 857
}
795 858

  
859
#ifdef ENABLE_GEOMETRYCACHE
796 860
void QgsVectorLayer::deleteCachedGeometries()
797 861
{
798 862
  // Destroy any cached geometries
799 863
  mCachedGeometries.clear();
800 864
  mCachedGeometriesRect = QgsRectangle();
801 865
}
866
#endif
802 867

  
803 868
void QgsVectorLayer::drawVertexMarker( int x, int y, QPainter& p, QgsVectorLayer::VertexMarkerType type )
804 869
{
......
1193 1258
    mFetchChangedGeomIt = mChangedGeometries.begin();
1194 1259
  }
1195 1260

  
1261
  QgsAttributeList attrToSelect;
1262

  
1196 1263
  //look in the normal features of the provider
1197 1264
  if ( mFetchAttributes.size() > 0 )
1198 1265
  {
......
1208 1275
        provAttributes << *it;
1209 1276
      }
1210 1277

  
1211
      mDataProvider->select( provAttributes, rect, fetchGeometries, useIntersect );
1278
      attrToSelect=provAttributes;
1212 1279
    }
1213 1280
    else
1214
      mDataProvider->select( mFetchAttributes, rect, fetchGeometries, useIntersect );
1281
      attrToSelect=mFetchAttributes;
1215 1282
  }
1216 1283
  else
1217 1284
  {
1218
    mDataProvider->select( QgsAttributeList(), rect, fetchGeometries, useIntersect );
1285
    attrToSelect=QgsAttributeList();
1219 1286
  }
1287
  
1288
  bool cacheSelectSuccessful;
1289
  if ( rect == QgsRectangle() )
1290
  {
1291
    //we can't give QgsRectangle() to feature cache's select(), as it would only select
1292
    //extent of cache - instead of extent of the real data
1293
    cacheSelectSuccessful=mFeatureCache->select(
1294
      attrToSelect, mDataProvider->extent(), fetchGeometries, useIntersect
1295
    );
1296
  }
1297
  else
1298
  {
1299
    cacheSelectSuccessful=mFeatureCache->select(
1300
      attrToSelect, rect, fetchGeometries, useIntersect
1301
    );
1302
  }
1303
  
1304
  if ( ! cacheSelectSuccessful )
1305
    mDataProvider->select( attrToSelect, rect, fetchGeometries, useIntersect );
1220 1306
}
1221 1307

  
1222 1308
bool QgsVectorLayer::nextFeature( QgsFeature &f )
1223 1309
{
1224
  if ( !mFetching )
1310
  if ( !mFetching && !mFeatureCache->isSelectValid() )
1225 1311
    return false;
1226 1312

  
1227 1313
  if ( mEditable )
......
1320 1406
    // no more added features
1321 1407
  }
1322 1408

  
1323
  while ( dataProvider()->nextFeature( f ) )
1409
  while ( true )
1324 1410
  {
1411
    if ( mFeatureCache->isSelectValid() ) {
1412
      if ( !mFeatureCache->nextFeature ( f ) )
1413
        break;
1414
    }
1415
    else
1416
    {
1417
      if ( !dataProvider()->nextFeature( f ) )
1418
        break;
1419
    }
1420

  
1325 1421
    if ( mFetchConsidered.contains( f.id() ) )
1326 1422
      continue;
1327 1423

  
......
1400 1496
    }
1401 1497
  }
1402 1498

  
1499
  bool gotFeature;
1500
  
1403 1501
  // regular features
1404 1502
  if ( fetchAttributes )
1405 1503
  {
1406
    if ( mDataProvider->featureAtId( featureId, f, fetchGeometries, mDataProvider->attributeIndexes() ) )
1504
    if ( !(
1505
      mFeatureCache->isInitialized() &&
1506
      mFeatureCache->areAttributesCached( mDataProvider->attributeIndexes() ) &&
1507
      mFeatureCache->featureAtId( featureId, f, fetchGeometries, true )
1508
    ) )
1407 1509
    {
1510
      //feature not in cache, try the provider
1511
      gotFeature=mDataProvider->featureAtId( featureId, f, fetchGeometries, mDataProvider->attributeIndexes() );
1512
    }
1513
    else
1514
    {
1515
      gotFeature=true;
1516
    }
1517
    
1518
    if ( gotFeature )
1519
    {
1408 1520
      updateFeatureAttributes( f );
1409 1521
      return true;
1410 1522
    }
1411 1523
  }
1412 1524
  else
1413 1525
  {
1414
    if ( mDataProvider->featureAtId( featureId, f, fetchGeometries, QgsAttributeList() ) )
1526
    if ( !( mFeatureCache->isInitialized() && mFeatureCache->featureAtId( featureId, f, fetchGeometries, false ) ) )
1415 1527
    {
1528
      //feature not in cache, try the provider
1529
      gotFeature=mDataProvider->featureAtId( featureId, f, fetchGeometries, QgsAttributeList() );
1530
    }
1531
    else
1532
    {
1533
      gotFeature=true;
1534
    }
1535
    
1536
    if ( gotFeature )
1537
    {
1416 1538
      return true;
1417 1539
    }
1418 1540
  }
......
1448 1570
  // and add to the known added features.
1449 1571
  f.setFeatureId( addedIdLowWaterMark );
1450 1572
  editFeatureAdd( f );
1573
#ifdef ENABLE_GEOMETRYCACHE
1451 1574
  mCachedGeometries[f.id()] = *f.geometry();
1575
#endif
1452 1576

  
1453 1577
  setModified( true );
1454 1578

  
......
1471 1595
  if ( mDataProvider )
1472 1596
  {
1473 1597
    QgsGeometry geometry;
1598

  
1474 1599
    if ( !mChangedGeometries.contains( atFeatureId ) )
1475 1600
    {
1476 1601
      // first time this geometry has changed since last commit
1602
#ifdef ENABLE_GEOMETRYCACHE
1477 1603
      if ( !mCachedGeometries.contains( atFeatureId ) )
1478 1604
      {
1479 1605
        return false;
1480 1606
      }
1481 1607
      geometry = mCachedGeometries[atFeatureId];
1482 1608
      //mChangedGeometries[atFeatureId] = mCachedGeometries[atFeatureId];
1609
#else
1610
      QgsFeature f;
1611

  
1612
      if ( !featureAtId( atFeatureId, f, true, false ) )
1613
      {
1614
        return false;
1615
      }
1616
      geometry=*(f.geometry());
1617
#endif
1483 1618
    }
1484 1619
    else
1485 1620
    {
1486 1621
      geometry = mChangedGeometries[atFeatureId];
1487 1622
    }
1488 1623
    geometry.insertVertex( x, y, beforeVertex );
1624
#ifdef ENABLE_GEOMETRYCACHE
1489 1625
    mCachedGeometries[atFeatureId] = geometry;
1626
#endif
1490 1627
    editGeometryChange( atFeatureId, geometry );
1491 1628

  
1492 1629
    setModified( true, true ); // only geometry was changed
......
1510 1647
    if ( !mChangedGeometries.contains( atFeatureId ) )
1511 1648
    {
1512 1649
      // first time this geometry has changed since last commit
1650
#ifdef ENABLE_GEOMETRYCACHE
1513 1651
      if ( !mCachedGeometries.contains( atFeatureId ) )
1514 1652
      {
1515 1653
        return false;
1516 1654
      }
1517 1655
      geometry = mCachedGeometries[atFeatureId];
1518 1656
      //mChangedGeometries[atFeatureId] = mCachedGeometries[atFeatureId];
1657
#else
1658
      QgsFeature f;
1659

  
1660
      if ( !featureAtId( atFeatureId, f, true, false ) )
1661
      {
1662
        return false;
1663
      }
1664
      geometry=*(f.geometry());
1665
#endif
1519 1666
    }
1520 1667
    else
1521 1668
    {
......
1523 1670
    }
1524 1671

  
1525 1672
    geometry.moveVertex( x, y, atVertex );
1673
#ifdef ENABLE_GEOMETRYCACHE
1526 1674
    mCachedGeometries[atFeatureId] = geometry;
1675
#endif
1527 1676
    editGeometryChange( atFeatureId, geometry );
1528 1677

  
1529 1678
    setModified( true, true ); // only geometry was changed
......
1547 1696
    if ( !mChangedGeometries.contains( atFeatureId ) )
1548 1697
    {
1549 1698
      // first time this geometry has changed since last commit
1699
#ifdef ENABLE_GEOMETRYCACHE
1550 1700
      if ( !mCachedGeometries.contains( atFeatureId ) )
1551 1701
      {
1552 1702
        return false;
1553 1703
      }
1554 1704
      geometry = mCachedGeometries[atFeatureId];
1705
#else
1706
      QgsFeature f;
1707

  
1708
      if ( !featureAtId( atFeatureId, f, true, false ) )
1709
      {
1710
        return false;
1711
      }
1712
      geometry=*(f.geometry());
1713
#endif
1555 1714
    }
1556 1715
    else
1557 1716
    {
......
1559 1718
    }
1560 1719

  
1561 1720
    geometry.deleteVertex( atVertex );
1721
#ifdef ENABLE_GEOMETRYCACHE
1562 1722
    mCachedGeometries[atFeatureId] = geometry;
1723
#endif
1563 1724
    editGeometryChange( atFeatureId, geometry );
1564 1725

  
1565 1726
    setModified( true, true ); // only geometry was changed
......
1657 1818
    QgsGeometry geom = *changedIt;
1658 1819
    int returnValue = geom.addIsland( ring );
1659 1820
    editGeometryChange( selectedFeatureId, geom );
1821
#ifdef ENABLE_GEOMETRYCACHE
1660 1822
    mCachedGeometries[selectedFeatureId] = geom;
1823
#endif
1661 1824
    return returnValue;
1662 1825
  }
1663 1826

  
1664 1827
  //look if id of selected feature belongs to an added feature
1665
  /*
1666 1828
  for ( QgsFeatureList::iterator addedIt = mAddedFeatures.begin(); addedIt != mAddedFeatures.end(); ++addedIt )
1667 1829
  {
1668 1830
    if ( addedIt->id() == selectedFeatureId )
1669 1831
    {
1670
      return addedIt->geometry()->addIsland( ring );
1671
      mCachedGeometries[selectedFeatureId] = *addedIt->geometry();
1832
      QgsGeometry translateGeom( *( addedIt->geometry() ) );
1833
   
1834
      int errorCode = translateGeom.addIsland( ring );
1835
      if ( errorCode == 0 )
1836
      {
1837
        editGeometryChange( selectedFeatureId, translateGeom );
1838
        setModified( true, true );
1839
      }
1840
      
1841
      return errorCode;
1672 1842
    }
1673 1843
  }
1674
  */
1675 1844

  
1845
#ifdef ENABLE_GEOMETRYCACHE
1676 1846
  //is the feature contained in the view extent (mCachedGeometries) ?
1677 1847
  QgsGeometryMap::iterator cachedIt = mCachedGeometries.find( selectedFeatureId );
1678 1848
  if ( cachedIt != mCachedGeometries.end() )
......
1688 1858
  }
1689 1859
  else //maybe the selected feature has been moved outside the visible area and therefore is not contained in mCachedGeometries
1690 1860
  {
1861
#endif
1691 1862
    QgsFeature f;
1692 1863
    QgsGeometry* fGeom = 0;
1693 1864
    if ( featureAtId( selectedFeatureId, f, true, false ) )
1694 1865
    {
1695 1866
      fGeom = f.geometryAndOwnership();
1867

  
1696 1868
      if ( fGeom )
1697 1869
      {
1698 1870
        int errorCode = fGeom->addIsland( ring );
1699 1871
        editGeometryChange( selectedFeatureId, *fGeom );
1700 1872
        setModified( true, true );
1701 1873
        delete fGeom;
1874
        
1702 1875
        return errorCode;
1703 1876
      }
1704 1877
    }
1878
#ifdef ENABLE_GEOMETRYCACHE
1705 1879
  }
1880
#endif
1706 1881

  
1707 1882
  return 6; //geometry not found
1708 1883
}
......
1720 1895
  }
1721 1896

  
1722 1897
  //look if id of selected feature belongs to an added feature
1723
  /*
1724 1898
  for ( QgsFeatureList::iterator addedIt = mAddedFeatures.begin(); addedIt != mAddedFeatures.end(); ++addedIt )
1725 1899
  {
1726 1900
    if ( addedIt->id() == featureId )
1727 1901
    {
1728
      return addedIt->geometry()->translate( dx, dy );
1902
      QgsGeometry translateGeom( *( addedIt->geometry() ) );
1903
   
1904
      int errorCode = translateGeom.translate( dx, dy );
1905
      if ( errorCode == 0 )
1906
      {
1907
        editGeometryChange( featureId, translateGeom );
1908
        setModified( true, true );
1909
      }
1910
      
1911
      return errorCode;
1729 1912
    }
1730 1913
  }
1731
  */
1732 1914

  
1915
#ifdef ENABLE_GEOMETRYCACHE
1733 1916
  //else look in mCachedGeometries to make access faster
1734 1917
  QgsGeometryMap::iterator cachedIt = mCachedGeometries.find( featureId );
1735 1918
  if ( cachedIt != mCachedGeometries.end() )
......
1742 1925
    }
1743 1926
    return errorCode;
1744 1927
  }
1928
#endif
1745 1929

  
1746 1930
  //else get the geometry from provider (may be slow)
1747 1931
  QgsFeature f;
......
1827 2011
    {
1828 2012
      //change this geometry
1829 2013
      editGeometryChange( select_it->id(), *( select_it->geometry() ) );
2014
#ifdef ENABLE_GEOMETRYCACHE
1830 2015
      //update of cached geometries is necessary because we use addTopologicalPoints() later
1831 2016
      mCachedGeometries[select_it->id()] = *( select_it->geometry() );
2017
#endif
1832 2018

  
1833 2019
      //insert new features
1834 2020
      for ( int i = 0; i < newGeometries.size(); ++i )
......
2621 2807
  }
2622 2808

  
2623 2809
  editGeometryChange( fid, *geom );
2810
#ifdef ENABLE_GEOMETRYCACHE
2624 2811
  mCachedGeometries[fid] = *geom;
2812
#endif
2813

  
2625 2814
  setModified( true, true );
2626 2815
  return true;
2627 2816
}
......
3030 3219
    }
3031 3220
  }
3032 3221

  
3222
#ifdef ENABLE_GEOMETRYCACHE
3033 3223
  deleteCachedGeometries();
3224
#endif
3034 3225

  
3035 3226
  if ( success )
3036 3227
  {
......
3040 3231
    mUpdatedFields.clear();
3041 3232
    mMaxUpdatedIndex = -1;
3042 3233
    undoStack()->clear();
3234
    mFeatureCache->clear();
3235

  
3043 3236
    emit editingStopped();
3044 3237
  }
3045 3238

  
......
3100 3293
    mMaxUpdatedIndex = -1;
3101 3294
  }
3102 3295

  
3296
#ifdef ENABLE_GEOMETRYCACHE
3103 3297
  deleteCachedGeometries();
3298
#endif
3104 3299

  
3300
  //TODO: is this needed here? I think not
3301
  //mFeatureCache->clear();
3302
  
3105 3303
  mEditable = false;
3106 3304
  emit editingStopped();
3107 3305

  
......
3311 3509
  {
3312 3510
    return 1;
3313 3511
  }
3314

  
3512
  
3315 3513
  QList<QgsFeature> featureList;
3316 3514
  QgsRectangle searchRect( startPoint.x() - snappingTolerance, startPoint.y() - snappingTolerance,
3317 3515
                           startPoint.x() + snappingTolerance, startPoint.y() + snappingTolerance );
......
3320 3518
  int n = 0;
3321 3519
  QgsFeature f;
3322 3520

  
3521
#ifdef ENABLE_GEOMETRYCACHE
3323 3522
  if ( mCachedGeometriesRect.contains( searchRect ) )
3324 3523
  {
3325 3524
    QgsDebugMsg( "Using cached geometries for snapping." );
......
3338 3537
  else
3339 3538
  {
3340 3539
    // snapping outside cached area
3540
#endif
3341 3541

  
3342 3542
    select( QgsAttributeList(), searchRect, true, true );
3343

  
3543
    
3544
    if ( !mFeatureCache->isSelectValid() && ( mDataProvider->extent() == mFeatureCache->getCachedRectangle() ) )
3545
    {
3546
      //everything is cached already, what ain't in cache, ain't nowhere in layer :-)
3547
      mFeatureCache->makeSelectValid();
3548
    }
3549
    
3344 3550
    while ( nextFeature( f ) )
3345 3551
    {
3346 3552
      snapToGeometry( startPoint, f.id(), f.geometry(), sqrSnappingTolerance, snappingResults, snap_to );
3347 3553
      ++n;
3348 3554
    }
3555
#ifdef ENABLE_GEOMETRYCACHE
3349 3556
  }
3557
#endif
3350 3558

  
3351 3559
  return n == 0 ? 2 : 0;
3352 3560
}
......
4077 4285
      }
4078 4286
      else
4079 4287
      {
4080
        // added feature TODO:
4288
        // added feature
4081 4289
        for ( int i = 0; i < mAddedFeatures.size(); i++ )
4082 4290
        {
4083 4291
          if ( mAddedFeatures[i].id() == fid )
......
4096 4304
  // it's not ideal to trigger refresh from here
4097 4305
  triggerRepaint();
4098 4306
}
4307

  
4308
void QgsVectorLayer::recacheFeature( int featureId, QgsRectangle rectFrom, QgsRectangle rectTo )
4309
{
4310
  if ( rectTo==QgsRectangle() )
4311
    rectTo=mDataProvider->extent();
4312

  
4313
  QgsRectangle cachedRect=mFeatureCache->getCachedRectangle();
4314

  
4315
  rectFrom=rectFrom.intersect( &cachedRect );
4316
  rectTo=rectTo.intersect( &cachedRect );
4317

  
4318
  mFeatureCache->remove( featureId, rectFrom );
4319

  
4320
  //now reinsert the feature from provider
4321
  if ( mDataProvider->capabilities() & QgsVectorDataProvider::SelectGeometryAtId )
4322
  {
4323
    //either using existing method
4324
    QgsFeature fet;
4325
    
4326
    mDataProvider->featureAtId( featureId, fet, true, mRenderer->classificationAttributes() );
4327
    mFeatureCache->insert( fet, false );
4328
  }
4329
  else
4330
  {
4331
    //or fallback to search for feature id in specified rectangle
4332
    mDataProvider->select( mRenderer->classificationAttributes(), rectTo );
4333
  
4334
    QgsFeature fet;
4335
    while ( mDataProvider->nextFeature( fet ) )
4336
    {
4337
      if ( fet.id() == featureId )
4338
      {
4339
        mFeatureCache->insert( fet, false );
4340
        mDataProvider->rewind();
4341
        break;
4342
      }
4343
    }
4344
  }
4345
}
4346

  
4347
void QgsVectorLayer::recacheFeatures( QgsRectangle rect )
4348
{
4349
  QgsRectangle cachedRect=mFeatureCache->getCachedRectangle();
4350
  rect=rect.intersect( &cachedRect );
4351

  
4352
  mFeatureCache->remove( rect );
4353
  
4354
  mDataProvider->select( mRenderer->classificationAttributes(), rect );
4355
  
4356
  QgsFeature fet; 
4357
  while ( mDataProvider->nextFeature( fet ) )
4358
  {
4359
    mFeatureCache->insert( fet, false );
4360
  }
4361
}
src/core/qgsfeaturecache.h (revision 0)
1
/***************************************************************************
2
                      qgsfeaturecache.h - Spatial Feature Cache Class
3
                     --------------------------------------
4
 Date                 : 19-Jun-2009
5
 Copyright            : (C) 2009 by Andrej Krutak
6
 email                : andree at andree.sk
7
 ***************************************************************************
8
 *                                                                         *
9
 *   This program is free software; you can redistribute it and/or modify  *
10
 *   it under the terms of the GNU General Public License as published by  *
11
 *   the Free Software Foundation; either version 2 of the License, or     *
12
 *   (at your option) any later version.                                   *
13
 *                                                                         *
14
 ***************************************************************************/
15

  
16
#ifndef QGSFEATURECACHE_H
17
#define QGSFEATURECACHE_H
18

  
19
#include <QHash>
20
#include <QLinkedList>
21
#include "qgsfeature.h"
22
#include "qgis.h"
23
#include "qgsrectangle.h"
24
#include "qgslabel.h"
25
#include "qgsspatialindex.h"
26

  
27
/**
28
 * A feature cache class. Stores inserted features in memory and enables
29
 * efficient selects and feature retrievals.
30
 * 
31
 * Usage of the class:
32
 * 
33
 * After creating the class object, the cache is empty. To fill, one first
34
 * has to specify, what region will be filled - this is done by calling
35
 * select() method, where one specifies rectangle and attributes to be cached.
36
 * The method will obviously fail, because no data are cached yet.
37
 * (Also, until the cache is filled, isInitialized() will return false.)
38
 * 
39
 * After that, insert(feature, true) method has to be called to efficiently
40
 * insert contained features. After all features are inserted, setAsInitialized()
41
 * has to be called. This method efficiently commits all inserted features into
42
 * the cache. After this, the cache is initialized and all subsequent calls
43
 * to select(), using subset of previously specified rectangle and attributes,
44
 * will be successful. Features may then be retrieved by repetetive calls
45
 * of nextFeature().
46
 * 
47
 * One might want to retrieve features even if the requested rectangle doesn't
48
 * completely fit into cached area. In case the requested attributes are
49
 * a subset of cached ones, this is possible - just call makeSelectValid()
50
 * after select(). By calling this, it's possible to retrieve even partial
51
 * cache matches.
52
 * 
53
 * To modify existing cache data, one may use insert(feature, false), and 
54
 * remove() methods, which to immediate changes to the cached data. Note that
55
 * calling these methods for large ammounts of features may be quite slow -
56
 * in case a big part of tree has to be 'edited', it might be much faster
57
 * to clear() the cache and refill it again using previously mentioned method.
58
 *
59
 * There are several cache modes, that change the way cache keeps data stored.
60
 * It's possible to set new mode using setCacheMode(). To apply the mode
61
 * for a specified select, applyCurrentCacheMode() has to be called. The method
62
 * tells cache, what rectangle is currently required by user - according to this
63
 * the cache will determine, what data to discard (if any).
64
**/
65
class CORE_EXPORT QgsFeatureCache
66
{
67
public:
68
  QgsFeatureCache();
69
  ~QgsFeatureCache();
70

  
71
  /**
72
   * Inserts the specified feature to cache.
73
   * @param f feature to be inserted
74
   * @param deferredInsert if true, feature will only be inserted after calling 
75
   *                       setAsInitialized(); otherwise the feature is inserted
76
   *                       immediately (which is pretty costly in case of inserting
77
   *                       more than a few features)
78
   * @returns whether the operation was successful.
79
  **/
80
  bool insert( QgsFeature &f, bool deferredInsert=true );
81

  
82
  /**
83
   * Remove feature with specified id. If rect is specified, it will be
84
   * used as hint to find the feature (it could be e.g. feture's bounding rect.)
85
  **/
86
  bool remove( int featureId, QgsRectangle rect = QgsRectangle() );
87
  
88
  /**
89
   * Remove features intersecting specified rectangle.
90
  **/
91
  bool remove( QgsRectangle rect );
92

  
93
  /**
94
   * Returns, whether the cache is properly initialized (and thus the
95
   * nextFeature() and featureAtId() are usable)
96
  **/
97
  inline bool isInitialized() { return mIsInitialized; }
98
  
99
  /**
100
   * Returns, whether the last called select() left the
101
   * cache in state valid for iteration using nextFeature()
102
  **/
103
  inline bool isSelectValid() { return mSelectValid; }
104

  
105
  /**
106
   * Sets the cache as valid; to be called after it's filled with
107
   * features (@see insertFeature()) and only when the cache was empty before.
108
   * The cache parameters (contained rectangle, attributes) are set to current
109
   * select parameters.
110
  **/
111
  void setAsInitialized();
112

  
113
    /** Clear the cache; also sets it as not valid */
114
  void clear();
115
  
116
  /**
117
   * Select features; returns whether the cache is valid for the specified select
118
   * @param fetchAttributes attributes to fetch
119
   * @param rect rectangle to fetch the features from. If rect==QgsRectangle(),
120
   *             all features in cache are selected.
121
   * @param fetchGeometry also fetch geometries
122
   * @param useIntersect only retrieve features that really (not only their bounding rect) intersect with rectangle
123
   * @returns True, if select was successful (i.e. nextFeature() will return data).
124
  **/
125
  bool select( QgsAttributeList fetchAttributes,
126
                QgsRectangle rect = QgsRectangle(),
127
                bool fetchGeometry = true,
128
                bool useIntersect = false);
129

  
130
  /**
131
   * Make the last selected features fetchable using nextFeature(), if at least selected
132
   * attributes are subset of the the cached ones.
133
  **/
134
  void makeSelectValid();
135

  
136
  /** Retrieve next feature from the select; Returns false if there are no more features. */
137
  bool nextFeature( QgsFeature& feature );
138

  
139
  /** Returns the feature with specified Id. */
140
  bool featureAtId( int featureId, QgsFeature &f, bool fetchGeometries = true, bool fetchAttributes = true );
141
  
142
  /** cache modes */
143
  enum CacheMode {
144
    ///store all inserted features
145
    CACHE_ALL=0,
146
    
147
    /**
148
     * Store features and use heuristics to crop the stored rectangle size at
149
     * selects - and so optimize size of occupied memory.
150
    **/
151
    CACHE_HEURISTICS,
152
    
153
    ///don't store any features
154
    CACHE_NOTHING,
155
  };
156

  
157
  /** Sets cache mode. */
158
  void setCacheMode(CacheMode mode);
159

  
160
  /** Apply current cache mode to currently cached data (using specified rectangle). */
161
  void applyCurrentCacheMode(QgsRectangle const &rect);
162
  
163
  /** Returns cached rectangle. This is the biggest selectable rectangle. */
164
  QgsRectangle getCachedRectangle() { return mCachedRectangle; }
165
  
166
  /** Returns true, if cached attributes are superset of specified attributes list */
167
  bool areAttributesCached(QgsAttributeList list);
168
  
169
private:
170
  /** Filter out cached data outside the specified rectangle */
171
  void filterTo(QgsRectangle const &r);
172
  
173
  /** Contains, whether the cache has been filled for the current select */
174
  bool mIsInitialized;
175

  
176
  /** Holds cached features */
177
  QgsSpatialIndex *mCachedFeatures;
178

  
179
  /** Contains features waiting to be really inserted into tree by setAsInitialized() */
180
  QLinkedList<QgsFeature*> mCachedFeaturesList;
181
  
182
  /** Rectangle that is currently cached */
183
  QgsRectangle mCachedRectangle;
184

  
185
  /** Contains attribute list, that are stored in cached features */
186
  QgsAttributeList mCachedAttributes;
187

  
188
  /** Holds, whether geometries are also cached (alongside attributes) */
189
  bool mCachedIncludingGeometries;
190

  
191
  /** Holds, whether the current select is valid */
192
  bool mSelectValid;
193
  
194
  /** Select parameters - attributes */
195
  QgsAttributeList mSelectedAttributes;
196

  
197
  /** Select parameters - rectangle */
198
  QgsRectangle mSelectedRectangle;;
199

  
200
  /** Select parameters - fetch geometries?*/
201
  bool mSelectedFetchGeometries;
202

  
203
  /** Select parameters - use intersect?*/
204
  bool mSelectedUseIntersect;
205

  
206
  /** List of selected features */
207
  QLinkedList<QgsFeature*> mSelectedFeaturesList;
208

  
209
  /** Select parameters - iterator in the mCachedFeatures */
210
  QLinkedList<QgsFeature*>::iterator mSelectedFeaturesIterator;
211
  
212
  CacheMode mCacheMode;
213
};
214

  
215
#endif //QGSFEATURECACHE_H
src/core/qgsvectorlayer.h (working copy)
44 44
class QgsUndoCommand;
45 45
class QgsVectorDataProvider;
46 46
class QgsVectorOverlay;
47
class QgsFeatureCache;
47 48

  
48 49
class QgsRectangle;
49 50

  
......
511 512
     */
512 513
    virtual void updateExtents();
513 514

  
515
    /**
516
     * Fetch the specified feature from provider, if it is cached. This
517
     * must be called every time the provider data change outside vector layer control.
518
     * @param featureId id of feature that should be reloaded
519
     * @param rectFrom hint of rectangle, where the feature resided. If not provided,
520
     *             whole cache will be searched for the id.
521
     * @param rectTo hint of rectangle, where the feature resides now. If not provided,
522
     *             all provider features will be searched for the id.
523
    **/
524
    void recacheFeature( int featureId, QgsRectangle rectFrom=QgsRectangle(), QgsRectangle rectTo=QgsRectangle() );
525
    
526
    /**
527
     * Fetch features from specified rectangle from provider, if it is cached. This
528
     * must be called every time the provider data change outside vector layer control.
529
     * @param rect rectangle containing changed features. All features within
530
     *             the rectangle will be reloaded.
531
    **/
532
    void recacheFeatures( QgsRectangle rect );
533
    
514 534
  signals:
515 535

  
516 536
    /** This signal is emited when selection was changed */
......
589 609
    /** Goes through all features and finds a free id (e.g. to give it temporarily to a not-commited feature) */
590 610
    int findFreeId();
591 611

  
612
#ifdef ENABLE_GEOMETRYCACHE
592 613
    /**Deletes the geometries in mCachedGeometries*/
593 614
    void deleteCachedGeometries();
615
#endif
594 616

  
595 617
    /** Draws a vertex symbol at (screen) coordinates x, y. (Useful to assist vertex editing.) */
596 618
    void drawVertexMarker( int x, int y, QPainter& p, QgsVectorLayer::VertexMarkerType type );
......
656 678
    /** Flag indicating whether the layer has been modified since the last commit */
657 679
    bool mModified;
658 680

  
681
#ifdef ENABLE_GEOMETRYCACHE
659 682
    /** cache of the committed geometries retrieved *for the current display* */
660 683
    QgsGeometryMap mCachedGeometries;
661 684

  
662 685
    /** extent for which there are cached geometries */
663 686
    QgsRectangle mCachedGeometriesRect;
687
#endif
664 688

  
689
    /** Cache of features (used mainly for displaying of features) */
690
    QgsFeatureCache *mFeatureCache;
691

  
665 692
    /** Set holding the feature IDs that are activated.  Note that if a feature
666 693
        subsequently gets deleted (i.e. by its addition to mDeletedFeatureIds),
667 694
        it always needs to be removed from mSelectedFeatureIds as well.
src/core/spatialindex/tools/ExternalSort.h (working copy)
73 73
      void initializeRuns( std::deque<SmartPointer<TemporaryFile> >& runs );
74 74
      void mergeRuns();
75 75

  
76
#ifndef EXTERNALSORT_SORTUSINGPRIORITYQUEUE
77
      std::vector<PQEntry*> m_buffer;
78
#else
76 79
      std::priority_queue <
77 80
      PQEntry*,
78 81
      std::vector<PQEntry*>,
79 82
      PQEntry::ascendingComparator > m_buffer;
83
#endif
80 84

  
81 85
      unsigned long m_cMaxBufferSize;
82 86
      bool m_bFitsInBuffer;
src/core/spatialindex/tools/ExternalSort.cc (working copy)
27 27
#include "ExternalSort.h"
28 28
#include "qgslogger.h"
29 29

  
30
#include <algorithm>
31

  
30 32
#ifdef _MSC_VER
31 33
#define UNUSED(symbol) symbol
32 34
#else
......
153 155
        m_pTemplateRecord = o->clone();
154 156

  
155 157
      SmartPointer<TemporaryFile> tf;
158
#ifdef EXTERNALSORT_SORTUSINGPRIORITYQUEUE
156 159
      m_buffer.push( new PQEntry( pS, m_pComparator, tf ) );
160
#else
161
      m_buffer.push_back( new PQEntry( pS, m_pComparator, tf ) );
162
#endif
157 163
    }
158 164

  
159 165
    if ( bEOF && runs.size() == 0 )
......
161 167

  
162 168
    if ( ! m_buffer.empty() )
163 169
    {
170
#ifndef EXTERNALSORT_SORTUSINGPRIORITYQUEUE
171
      std::sort(m_buffer.begin(), m_buffer.end());
172
#endif
173

  
164 174
      TemporaryFile* tf = new TemporaryFile();
165 175
      while ( ! m_buffer.empty() )
166 176
      {
177
#ifdef EXTERNALSORT_SORTUSINGPRIORITYQUEUE
167 178
        PQEntry* pqe = m_buffer.top(); m_buffer.pop();
179
#else
180
        PQEntry* pqe = m_buffer.back(); m_buffer.pop_back();
181
#endif
168 182
        tf->storeNextObject( pqe->m_pRecord );
169 183
        delete pqe;
170 184
      }
src/core/spatialindex/qgsspatialindex.cpp (working copy)
22 22
#include "qgslogger.h"
23 23

  
24 24
#include "SpatialIndex.h"
25
#include "spatialindex/SpatialIndexImpl.h"
25 26

  
27
#include "rtree/Node.h"
28
#include "rtree/Leaf.h"
29
#include "rtree/Index.h"
30
#include "rtree/BulkLoader.h"
31

  
32
#include "rtree/RTree.h"
33

  
34
#include <stdexcept>
35

  
26 36
using namespace SpatialIndex;
27 37

  
38
/** Convert rectangle to a region suitable for use in the spatial index library */
39
inline Tools::Geometry::Region rectToRegion( QgsRectangle rect )
40
{
41
  double pt1[2], pt2[2];
42
  pt1[0] = rect.xMinimum();
43
  pt1[1] = rect.yMinimum();
44
  pt2[0] = rect.xMaximum();
45
  pt2[1] = rect.yMaximum();
46
  return Tools::Geometry::Region( pt1, pt2, 2 );
47
}
28 48

  
29
// custom visitor that adds found features to list
49
inline QgsRectangle regionToRect( Tools::Geometry::Region rect )
50
{
51
  return QgsRectangle( rect.getLow(0), rect.getLow(1), rect.getHigh(0), rect.getHigh(1) );
52
}
53

  
54

  
55
/** returns, whether the rectBig contains rectSmall (with specified overflow exceptions) */
56
inline bool RectContainsWithOverflow( QgsRectangle rectBig, QgsRectangle rectSmall,
57
                               bool left, bool right,
58
                               bool over, bool under )
59
{
60
  bool rv=true;
61
  
62
  rv &= left  || !left  && (rectBig.xMinimum() < rectSmall.xMinimum());
63
  rv &= right || !right && (rectBig.xMaximum() > rectSmall.xMaximum());
64
  rv &= over  || !over  && (rectBig.yMinimum() < rectSmall.yMinimum());
65
  rv &= under || !under && (rectBig.yMaximum() > rectSmall.yMaximum());
66
  
67
  return rv;
68
}
69

  
70

  
71

  
72
/**
73
 * Creates a handle (pointer to pointer...) to specified feature. This
74
 * is needed for the RTree, as we can't directly change data node's data
75
 * (without removing and reinserting the node) and also because the data provided
76
 * to RTree is being memcopied (so we can't place a object there - we wouldn't be
77
 * able to delete it nicely later).
78
 * If the target is nonzero, it's an array where address of the
79
 * pointer to feature will be stored. Otherwise the array will be allocated
80
 * by the function.
81
 * @param f Feature to be handled
82
 * @param target if nonzero, it's considered to be a array of size sizeof(byte*),
83
 *               The return value will be stored in this array.
84
 * @returns Handle to the feature (newly allocated or ==target, if target!=0).
85
 *   The return value is an array containing the handle's value. Crazy stuff.
86
**/
87
inline byte* QgsFeaturePtr2ByteArray(QgsFeature* f, byte *target=0)
88
{
89
  //alloc a doublepointer to QgsFeature
90
  //Data (rv) -> fPtrPtr -> QgsFeature (f)
91
  //need to do this, because we can't change contents of Data, once inserted...
92
  
93
  byte* rv;
94
  
95
  if (target==0)
96
    rv=new byte[sizeof(byte*)];
97
  else
98
    rv=target;
99
  
100
  //create link: fPtrPtr -> f
101
  QgsFeature **fPtrPtr=new QgsFeature *;
102
  *fPtrPtr=f;
103
  
104
  //copy fPtrPtr address to rv
105
  memcpy(rv, &fPtrPtr, sizeof(QgsFeature**));
106
  
107
  return rv;
108
}
109

  
110

  
111

  
112
/**
113
 * Inverse operation to QgsFeaturePtr2ByteArray. Also deallocates the specified
114
 * pointer's array. Returns pointer to pointer to the feature referenced by handle.
115
**/
116
inline QgsFeature** ByteArray2QgsFeaturePtr(byte *p)
117
{
118
  QgsFeature** rv;
119
  
120
  //retrieve pointer to fPtrPtr
121
  memcpy(&rv, p, sizeof(QgsFeature**));
122
  
123
  //release received data copy
124
  delete []p;
125
  
126
  return rv;
127
}
128

  
129

  
130

  
131
/** Visitor that adds found features to list */
30 132
class QgisVisitor : public SpatialIndex::IVisitor
31 133
{
32 134
  public:
......
47 149
};
48 150

  
49 151

  
50
QgsSpatialIndex::QgsSpatialIndex()
152

  
153
/** Visitor that's freeing QgsFeature** objects stored in the Rtree. */
154
class QgisFreeMemVisitor : public SpatialIndex::IVisitor
51 155
{
156
  public:
157
    QgisFreeMemVisitor( bool dontDeletePointer=false ):
158
      mOnlyFreeSpecifiedId(false), mDontDeletePointer(dontDeletePointer) {}
159
    
160
    QgisFreeMemVisitor( long onlyFreeId, bool dontDeletePointer=false ):
161
      mOnlyFreeId(onlyFreeId), mOnlyFreeSpecifiedId(true),
162
      mDontDeletePointer(dontDeletePointer) {}
163

  
164
    void visitNode( const INode& n ) {}
165

  
166
    void visitData( const IData& d )
167
    {
168
      if ( mOnlyFreeSpecifiedId && ( d.getIdentifier() != mOnlyFreeId ) )
169
        return;
170
      
171
      long unsigned len;
172
      byte *data;
173
      d.getData(len, &data);
174
      
175
      QgsFeature **ptr=ByteArray2QgsFeaturePtr(data);
176
      
177
      if ( !ptr )
178
        return;
179
      
180
      if (*ptr!=0)
181
      {
182
        delete *ptr;
183
        *ptr=0;
184
      }
185
      
186
      if ( !mDontDeletePointer )
187
        delete ptr;
188
    }
189

  
190
    void visitData( std::vector<const IData*>& v ) {}
191

  
192
  private:
193
    bool mDontDeletePointer;
194
    bool mOnlyFreeSpecifiedId;
195
    long mOnlyFreeId;
196
};
197

  
198

  
199

  
200
/** Visitor storing found features to a QLinkedList. */
201
class QgisFeatureVisitor : public SpatialIndex::IVisitor
202
{
203
  public:
204
    /**
205
     * If unlinkFeatureFromData==true, then the features are also detached from
206
     * the rtree (used e.g. when some features are extracted from tree and
207
     * the tree is deleted afterwards (which erases all contained features))
208
    */
209
    QgisFeatureVisitor( QLinkedList<QgsFeature *> & list, bool unlinkFeatureFromData = false )
210
        : mList( list ), mUnlinkFeatureFromData( unlinkFeatureFromData ) {}
211

  
212
    void visitNode( const INode& n ) {}
213

  
214
    void visitData( const IData& d )
215
    {
216
      long unsigned len;
217
      byte *data;
218
      d.getData(len, &data);
219
      
220
      QgsFeature **f=ByteArray2QgsFeaturePtr(data);
221
      
222
      mList.push_back( *f );
223
      
224
      if ( mUnlinkFeatureFromData )
225
        *f=0;
226
    }
227

  
228
    void visitData( std::vector<const IData*>& v ) {}
229

  
230
  private:
231
    QLinkedList<QgsFeature *>& mList;
232
    
233
    bool mUnlinkFeatureFromData;
234
};
235

  
236

  
237

  
238
/**
239
 * A trivial data stream providing RTree::Data objects from list to ExternalSort.
240
**/
241
class QgisFeatureLinkedListDataStream : public IDataStream
242
{
243
public:
244
  QgisFeatureLinkedListDataStream(QLinkedList<QgsFeature*> &list) : mList(list)
245
    { rewind(); }
246

  
247
  virtual ~QgisFeatureLinkedListDataStream() { }
248

  
249
  virtual IData* getNext()
250
  {
251
    if (!hasNext())
252
      return 0;
253
    
254
    Region r=rectToRegion((*mListIt)->geometry()->boundingBox());
255
    
256
    //We basically create a pointer to feature in list and hand pointer
257
    //to that pointer (=handle) to the caller (most probably it'll be
258
    //the Tools::ExternalSort::initializeRuns ...)
259
    
260
    byte ptr[sizeof(byte*)];
261
    QgsFeaturePtr2ByteArray(*mListIt, ptr);
262
  
263
    RTree::Data* ret = new RTree::Data(
264
      sizeof(byte*), ptr,
265
      r, (*mListIt)->id()
266
    );
267

  
268
    mListIt++;
269
    
270
    return ret;
271
  }
272

  
273
  virtual bool hasNext() throw (Tools::NotSupportedException)
274
    { return mListIt!=mList.end(); }
275

  
276
  virtual long unsigned size() throw (Tools::NotSupportedException)
277
    { throw Tools::NotSupportedException("Operation not supported."); }
278

  
279
  virtual void rewind() throw (Tools::NotSupportedException)
280
    { mListIt=mList.begin(); }
281
  
282
private:
283
  QLinkedList<QgsFeature*> &mList;
284
  QLinkedList<QgsFeature*>::iterator mListIt;
285
};
286

  
287

  
288
/** A strategy pattern class determining maximal bounding rectangle of a rtree */
289
class DetermineIndexedRectStrategy : public IQueryStrategy
290
{
291
public:
292
  QgsRectangle mIndexedRect;
293

  
294
public:
295
  void getNextEntry(const IEntry& entry, long& nextEntry, bool& hasNext)
296
  {
297
    Region region;
298
    
299
    //The first time we are called, entry points to the root. We don't need more.
300
    hasNext = false;
301

  
302
    IShape* ps;
303
    entry.getShape(&ps);
304
    ps->getMBR(region);
305
    delete ps;
306
    
307
    mIndexedRect=regionToRect(region);
308
  }
309
};
310

  
311

  
312
QgsSpatialIndex::QgsSpatialIndex(bool copyFeatures)
313
{
314
  initialize(QLinkedList<QgsFeature*>(), copyFeatures);
315
}
316

  
317

  
318

  
319
QgsSpatialIndex::QgsSpatialIndex(QLinkedList<QgsFeature*> features,
320
  bool copyFeatures )
321
{
322
  initialize(features, copyFeatures);
323
}
324

  
325

  
326

  
327
void QgsSpatialIndex::initialize(QLinkedList<QgsFeature*> features, bool copyFeatures)
328
{
329
  mCopyFeatures=copyFeatures;
330
  
52 331
  // for now only memory manager
53 332
  mStorageManager = StorageManager::createNewMemoryStorageManager();
54 333

  
55 334
  // create buffer
56

  
57 335
  unsigned int capacity = 10;
58 336
  bool writeThrough = false;
59 337
  mStorage = StorageManager::createNewRandomEvictionsBuffer( *mStorageManager, capacity, writeThrough );
60

  
338
  
61 339
  // R-Tree parameters
62 340
  double fillFactor = 0.7;
63 341
  unsigned long indexCapacity = 10;
......
67 345

  
68 346
  // create R-tree
69 347
  long indexId;
348
  
70 349
  mRTree = RTree::createNewRTree( *mStorage, fillFactor, indexCapacity,
71 350
                                  leafCapacity, dimension, variant, indexId );
351
                                  
352
  if (!features.empty()) {
353
    //Bulk load provided features into the empty tree
354
    QgisFeatureLinkedListDataStream stream(features);
355
    
356
    unsigned long bindex = static_cast<unsigned long>( std::floor( static_cast<double>( indexCapacity * fillFactor ) ) );
357
    unsigned long bleaf = static_cast<unsigned long>( std::floor( static_cast<double>( leafCapacity * fillFactor ) ) );
358

  
359
    SpatialIndex::RTree::BulkLoader bl;
360

  
361
    bl.bulkLoadUsingSTR( static_cast<RTree::RTree*>( mRTree ), stream, bindex, bleaf, 50000000 );
362
      
363
    //all features' pointers were added to index, make sure noone else will
364
    //use them,..
365
    features.clear();
366
  }
72 367
}
73 368

  
74
QgsSpatialIndex:: ~QgsSpatialIndex()
369

  
370

  
371
QgsSpatialIndex::~QgsSpatialIndex()
75 372
{
373
  uninitialize();
374
}
375

  
376

  
377

  
378
void QgsSpatialIndex::uninitialize()
379
{
380
  QgisFreeMemVisitor freeingVisitor;
381
  
382
  //free all feature pointers and features in the tree
383
  //TODO: what is maximal range? or how to select all features in rtree?
384
  //
385
  DetermineIndexedRectStrategy getRectStrategy;
386
  mRTree->queryStrategy(getRectStrategy);
387

  
388
  mRTree->intersectsWithQuery(
389
    rectToRegion( getRectStrategy.mIndexedRect ),
390
    freeingVisitor
391
  );
392
    
393
  //delete the rest of index
76 394
  delete mRTree;
77 395
  delete mStorage;
78 396
  delete mStorageManager;
79 397
}
80 398

  
399

  
400

  
81 401
Tools::Geometry::Region QgsSpatialIndex::rectToRegion( QgsRectangle rect )
82 402
{
83
  double pt1[2], pt2[2];
84
  pt1[0] = rect.xMinimum();
85
  pt1[1] = rect.yMinimum();
86
  pt2[0] = rect.xMaximum();
87
  pt2[1] = rect.yMaximum();
88
  return Tools::Geometry::Region( pt1, pt2, 2 );
403
  return ::rectToRegion( rect );
89 404
}
90 405

  
406

  
407

  
91 408
bool QgsSpatialIndex::featureInfo( QgsFeature& f, Tools::Geometry::Region& r, long& id )
92 409
{
93 410
  QgsGeometry *g = f.geometry();
......
99 416
  return true;
100 417
}
101 418

  
419

  
420

  
102 421
bool QgsSpatialIndex::insertFeature( QgsFeature& f )
103 422
{
423
  if (!mCopyFeatures)
424
  {
425
    return insertFeature(&f);
426
  }
427
  else
428
  {
429
    QgsFeature *fP=new QgsFeature(f);
430
    return insertFeature(fP);
431
  }
432
}
433

  
434

  
435

  
436
bool QgsSpatialIndex::insertFeature( QgsFeature* f )
437
{
104 438
  Tools::Geometry::Region r;
105 439
  long id;
106
  if ( !featureInfo( f, r, id ) )
440
  if ( !featureInfo( *f, r, id ) )
107 441
    return false;
108 442

  
109 443
  // TODO: handle possible exceptions correctly
110 444
  try
111 445
  {
112
    mRTree->insertData( 0, 0, r, id );
446
    if (!mCopyFeatures)
447
    {
448
      mRTree->insertData( 0, 0, r, id );
449
    }
450
    else
451
    {
452
      mRTree->insertData( sizeof(QgsFeature*), QgsFeaturePtr2ByteArray(f), r, id );
453
    }
113 454
  }
114 455
  catch ( Tools::Exception &e )
115 456
  {
......
129 470
  return true;
130 471
}
... This diff was truncated because it exceeds the maximum size that can be displayed.