Changes between Initial Version and Version 1 of FDORfc64


Ignore:
Timestamp:
Sep 24, 2012, 7:32:23 AM (12 years ago)
Author:
danstoica
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • FDORfc64

    v1 v1  
     1= FDO RFC 64 - In-memory Spatial Index =
     2
     3This page contains an change request (RFC) for the FDO Open Source project. 
     4More FDO RFCs can be found on the [wiki:FDORfcs RFCs] page.
     5
     6
     7== Status ==
     8 
     9||RFC Template Version||(1.0)||
     10||Submission Date|| June 13, 2012 ||
     11||Last Modified|| Dan Stoica June 13, 2012 ||
     12||Author||Dan Stoica||
     13||RFC Status||Adopted||
     14||Implementation Status||Prototype||
     15||Proposed Milestone||3.8.0.0||
     16||Assigned PSC guide(s)||Orest Halustchak||
     17||'''Voting History'''|| ||
     18||+1|| ||
     19||+0|| ||
     20||-0|| ||
     21||-1|| ||
     22 
     23== Overview ==
     24
     25This RFC is for adding an in-memory Spatial Index to the FDO Spatial project.
     26
     27== Motivation ==
     28
     29The motivation is the poor performance of the FDO secondary filter. The worst case is Polygon intersect Polygon due to the potential complexity of the filter polygon and the amount of candidate polygons. The algorithm used for each candidate polygon is:
     30
     31    1. check if any points of candidatePoly are inside filter polygon
     32    2. check if any points of filterPoly are inside candidate polygon
     33    3. do pairwise edge intersection
     34
     35Note that all 3 steps are correct, all of them are necessary and point-in-polygon/segment-to-segment tests are tuned for performance. Meaning further fine tuning is not a solution. The root problem is that the filter polygon is traversed entirely for each step and multiple times and this RFC is addressing it.
     36
     37== Proposed Solution ==
     38
     39The solution is to create a Spatial Index for the filter polygon where each segment of the polygon has an entry. This way all the steps 1-3 will benefit by limiting the segments to check to those in the area of interest. For example, the point-in-polygon test will run a spatial query using the X-ray bounding box as search area. Therefore, instead of traversing all the segments, only a few will be processed for X-ray intersections.
     40
     41This RFC describes the Spatial Index API. The implementation of the FDO secondary filter using the Spatial Index will be the topic of a separate RFC.
     42
     43
     44{{{
     45/// \ingroup (enums)
     46/// \brief
     47/// FdoSpatialIndexMode is an enumeration of the types of the Spatial Index
     48enum FdoSpatialIndexMode
     49{
     50    /// Mode #1 - Regular Spatial Index: one entry in the SI for the entire geometry
     51    FdoSpatialIndex_ByGeometriesBoundingBox = 0,
     52
     53    /// Mode #2 - The geometries are broken into segments and each segment has an entry in the SI.
     54    /// The segment index is contiguous over parts and subparts.
     55    FdoSpatialIndex_BySegmentsMultipleFeatures = 1,
     56
     57    /// Mode #3 - Just one geometry is allowed. The geometry is broken into segments
     58    /// and each segment has an entry in the SI. The part and subpart are encoded to allow
     59    /// for sorting and fast processing.
     60    FdoSpatialIndex_BySegmentsSingleFeature = 2
     61};
     62
     63/// \brief
     64/// Spatial Index class.
     65class FdoSpatialIndex : public FdoIDisposable
     66{
     67    friend class FdoSpatialIndexIterator;
     68
     69public:
     70    /// \brief
     71    /// Creates a Spatial Index instance
     72    ///
     73    /// \param mode
     74    /// Input Type of the spatial index
     75    ///
     76    /// \return
     77    /// Returns A spatial index instance
     78    ///
     79    FDO_SPATIAL_API static FdoSpatialIndex* Create(FdoSpatialIndexMode mode = FdoSpatialIndex_ByGeometriesBoundingBox);
     80
     81    /// \brief
     82    /// Retrieves the Spatial index mode set at creation time
     83    ///
     84    /// \return
     85    /// Returns the Spatial index mode set at creation
     86    ///
     87    FDO_SPATIAL_API FdoSpatialIndexMode GetMode();
     88
     89    /// \brief
     90    /// Inserts a feature into the spatial index given a bounding box
     91    ///
     92    /// \remarks
     93    /// Applies only for Mode #1. The objectId is not encoded.
     94    ///
     95    /// \param objectId
     96    /// Input The object identifier
     97    /// \param ext
     98    /// Input A bounding box
     99    ///
     100    /// \return
     101    /// Returns Nothing
     102    ///
     103    FDO_SPATIAL_API void InsertObject(FdoInt64 objectId, FdoIEnvelope *ext);
     104
     105    /// \brief
     106    /// Inserts a feature into the spatial index given a geometry
     107    ///
     108    /// \remarks
     109    /// Applies for Mode #2 and #3. The objectId is encoded as follows:
     110    /// Mode #2:
     111    ///      32 bits (0-31)  - 1-based object identifier
     112    ///      32 bits (32-63) - 1-based segment # (contiguous)
     113    ///
     114    /// Mode #3:
     115    ///      0 bits          - object identifier (will be ignored)
     116    ///      16 bits (0-15)  - part # (for multi-features) max. 65534
     117    ///      16 bits (16-31) - subpart # (e.g. polygons with interior rings) max 65534
     118    ///      32 bits (32-63) - 1-based segment #
     119    ///
     120    /// In Mode #3 a exception will be thrown in case the encoding fails. In this case
     121    /// Mode #2 can be used instead.
     122    ///
     123    /// \param objectId
     124    /// Input The object identifier
     125    /// \param fgfArray
     126    /// Input A geometry in FGF format
     127    ///
     128    /// \return
     129    /// Returns Nothing
     130    ///
     131    FDO_SPATIAL_API void InsertObject(FdoInt32 objectId, FdoByteArray* fgfArray);
     132
     133    /// \brief
     134    /// Erases an entry in the spatial index given the id and a bounding box
     135    ///
     136    /// \remarks
     137    /// In Mode #2 removes all the entries related to the feature identifier.
     138    /// In Mode #3 the spatial index will be emptied.
     139    ///
     140    /// \param objectId
     141    /// Input The object identifier.
     142    /// \param ext
     143    /// Input The bounding box of the feature. It may be NULL in which case
     144    /// the spatial index total extents will be used.
     145    ///
     146    /// \return
     147    /// Returns Nothing
     148    ///
     149    FDO_SPATIAL_API void EraseObject(FdoInt64 objectId, FdoIEnvelope *ext);
     150
     151    /// \brief
     152    /// Returns the extent of the spatial index
     153    ///
     154    /// \return
     155    /// Returns The extents of the spatial index
     156    ///
     157    FDO_SPATIAL_API FdoIEnvelope* GetTotalExtent();
     158
     159    /// \brief
     160    /// Decodes a marker returned by the Spatial index iterator.
     161    /// Applies only for Mode #2, BySegmentsMultipleFeatures.
     162    ///
     163    /// \param marker
     164    /// Input A marker returned by the Spatial index iterator
     165    /// \param objectId
     166    /// Output The object identifier
     167    /// \param iVertex
     168    /// Output The index of the segment in the original geometry, 1-based
     169    ///
     170    /// \return
     171    /// Returns Nothing
     172    ///
     173    FDO_SPATIAL_API void     DecodeMarker(FdoInt64 marker, FdoInt32 &objectId, FdoInt32 &iSegment);
     174
     175    /// \brief
     176    /// Decodes a marker returned by the Spatial index iterator.
     177    /// Applies only for Mode #3, BySegmentsSingleFeature.
     178    ///
     179    /// \param marker
     180    /// Input A marker returned by the Spatial index iterator
     181    /// \param iPart
     182    /// Output The index of the part in a multi-geometry, e.g. a polygon # in a multi-polygon
     183    /// \param iSubPart
     184    /// Output The index of the subpart in a geometry, e.g. a ring # in a polygon
     185    /// \param iVertex
     186    /// Output The index of the segment in the sub-part, 1-based
     187    ///
     188    /// \return
     189    /// Returns Nothing
     190    ///
     191    FDO_SPATIAL_API void     DecodeMarker(FdoInt64 marker, FdoInt32 &iPart, FdoInt32 &iSubPart, FdoInt32 &iSegment);
     192
     193/// \cond DOXYGEN-IGNORE
     194    virtual void Dispose();
     195/// \endcond
     196   
     197protected:
     198    // Constructor
     199    FdoSpatialIndex(FdoSpatialIndexMode mode = FdoSpatialIndex_ByGeometriesBoundingBox);
     200
     201    virtual ~FdoSpatialIndex();
     202};
     203
     204/// \brief
     205/// Spatial Index Iterator class
     206class FdoSpatialIndexIterator
     207{
     208public:
     209    /// \brief
     210    /// Creates a Spatial Index Iterator instance
     211    ///
     212    /// \param si
     213    /// Input A Spatial Index instance
     214    /// \param minx
     215    /// Input The minimim X of the bounding box representing the search area
     216    /// \param miny
     217    /// Input The minimim Y of the bounding box representing the search area
     218    /// \param maxx
     219    /// Input The maximum X of the bounding box representing the search area
     220    /// \param maxy
     221    /// Input The maximum Y of the bounding box representing the search area
     222    ///
     223    /// \return
     224    /// Returns A Spatial Index Iterator instance
     225    ///
     226    FDO_SPATIAL_API FdoSpatialIndexIterator(FdoSpatialIndex* si, double minx, double miny, double maxx, double maxy);
     227
     228        /// \brief
     229        /// Iterator over the features selected in the the search area
     230        ///
     231        /// \return
     232    /// Returns an encoded marker. Zero (0) return value stands for the end of fetch
     233    ///
     234    FDO_SPATIAL_API FdoInt64 GetNextObject();
     235
     236    FDO_SPATIAL_API ~FdoSpatialIndexIterator();
     237};
     238
     239}}}
     240
     241== Remarks ==
     242
     243* The API proposes 3 usage modes. This provides maximum versatility for various scenarios.
     244* Mode 1 implements a regular spatial index, very performant.
     245* For mode 2 and 3 the client code has to implement a segment visitor in order to retrieve a segment from the geometry.
     246* This API is a wrapper over the R-tree implementation located in the Sqlite provider and developed by Traian Stanev.
     247* The location of this API will be FDO Spatial.
     248
     249== How to use this API ==
     250
     251The following code illustrates how to use the Spatial Index and the spatial index iterator.
     252
     253
     254{{{
     255    FdoPtr<FdoSpatialIndex> si;
     256
     257    FdoPtr<FdoFgfGeometryFactory> gf = FdoFgfGeometryFactory::GetInstance();
     258 
     259    /*************************** Test Polygon *************************/
     260    FdoStringP geomText = L"POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0), (1 1, 2 2, 2 1, 1 1), (3 3, 4 4, 4 3, 3 3))";
     261 
     262    FdoPtr<FdoIGeometry> geom = gf->CreateGeometry(geomText);
     263    FdoPtr<FdoByteArray> ba = gf->GetFgf(geom);
     264
     265    // Mode #1: FdoSpatialIndex_ByGeometriesBoundingBox
     266    si = FdoSpatialIndex::Create(FdoSpatialIndex_ByGeometriesBoundingBox);
     267
     268    // Insert the geometry
     269    si->InsertObject(777, ba);
     270
     271    // Query the SI
     272    FdoSpatialIndexIterator iter1(si, 1, 1, 2, 2);
     273
     274    FdoInt32 iPart, iSubpart, iSegment;
     275    FdoInt64 marker = 0;
     276
     277    // Get the results
     278    while (marker = iter1.GetNextObject())
     279    {
     280        FdoInt64 fid = marker; // not encoded
     281        // ... do stuff         
     282    }
     283       
     284    // Mode #2: FdoSpatialIndex_BySegmentsMultipleFeatures
     285    si = FdoSpatialIndex::Create(FdoSpatialIndex_BySegmentsMultipleFeatures);
     286    si->InsertObject(777, ba);
     287
     288    FdoSpatialIndexIterator iter2(si, 1, 1, 2, 2);
     289
     290    while (marker = iter2.GetNextObject())
     291    {
     292        FdoInt32 fid;
     293        si->DecodeMarker(marker, fid, iSegment);
     294        // ... do stuff
     295    }
     296       
     297    // Mode #3: FdoSpatialIndex_BySegmentsSingleFeature
     298    si = FdoSpatialIndex::Create(FdoSpatialIndex_BySegmentsSingleFeature);
     299    si->InsertObject(0, ba); // FeatId = 0
     300
     301    FdoSpatialIndexIterator iter3(si, 1, 1, 2, 2);
     302
     303    while (marker = iter3.GetNextObject())
     304    {
     305        si->DecodeMarker(marker, iPart, iSubpart, iSegment);
     306        // ... do stuff
     307    }
     308}}}
     309
     310== Managed FDO API ==
     311
     312The FDO Managed Interfaces will be updated if required in a similar manner to reflect the proposed changes.
     313
     314 
     315== Test Plan ==
     316
     317    * Add unit test to test the API in all modes and primary filtering with boundary conditions.
     318
     319== !Funding/Resources ==
     320
     321Autodesk to provide resources/funding.
     322