After deleting points,I can't save current layer

Sep 8, 2011 at 3:00 AM

Dear all,

I can delete points in point layer,using these method below:

FeatureLayer.RemoveFeaturesAt Method

FeatureLayer.RemoveSelectedFeatures Method

FeatureSet.RemoveShapeAt Method

FeatureSet.RemoveShapesAt Method

But I can't save it, meeting crash: IndexOutOfRangeException!

Can somebody tell me how to save the point layer after deleting some points?

Jan 18, 2012 at 6:32 PM

I am having fundamental issues such as this and can find no guidance in the discussions or documentation. I know that work is ongoing on higher level aspects of the project (plugins, Framework 4 client, etc.), but fundamental problems with the API (such as being able to correctly add and delete shapes from a featureset) are preventing it from being used.

I would guess that a lot of developers who post basic questions about OutofRange errors that occur when using the API and who get no response probably get discouraged and stop using the API, which is a shame.

I know this is an open source project, so the community should be able to dig into the source and find the source of the problems, but (speaking for myself), the entire class structure is so complicated that I just don't think that it is practical without some guidance. For example, a simple explanation of editmode versus indexmode can be found in bits and pieces in the discussions, but a sufficient understanding of the implications of these modes may only reside in Ted Dunsford's brain.

Please tell me that I'm wrong, but I have a fear that since Ted left that the basic stability of the API has not been looked at very closely. I am NOT criticizing mudnug, because I know he is just one guy and this is a huge project, and he has continued to work hard on it. 

<EDIT>

Rereading the above rant just looked like whining to me, so before posting I downloaded the latest source code, rebuilt everything and pointed my references to the output directory. That was all actually very easy to do. One of my big complaints has been that Intellisense doesn't work with the API libraries. Apparently that is because the project is configured to *not* generate the XML documentation files. I turned that on and "voila", wonderful descriptions of all the methods and parameters! I recommend that in the future these XML files be generated and distributed.

The code is actually well documented, and it is fairly easy to see what EditMode is doing, although its relationship to IndexMode needs more study. I carefully stepped through some simple code to load an existing point shape file, add a point, delete a point, and still have the layer point selection work properly. Here's the code:

 

        Dim lyr As MapPointLayer = GISMap.AddLayer()
        GISMap.Refresh()

        Dim fs As FeatureSet = lyr.DataSet
        'lyr.EditMode = True
        Dim crds(0) As Coordinate
        crds(0) = New Coordinate(0, 0)
        Dim f As New Feature(FeatureType.Point, crds)
        With fs.AddFeature(f)
            .DataRow("Label") = "NEW POINT"
        End With
        fs.InitializeVertices()
        fs.InvalidateVertices()
        fs.Features.RemoveAt(0)
        'fs.Save()
        'lyr.EditMode = False
        fs.InitializeVertices()
        fs.InvalidateVertices()
        GISMap.Refresh()

If I set EditMode to true (a logical assumption), by experimentation it is critical that it be set to False after all feature edits are done and BEFORE the Initialize/InvalidateVertices calls (which are both required). On the other hand, it is not actually necessary to use EditMode at all. If Initialize/InvalidateVertices are not both called, you cannot select the new points that are added. I tried to see if those calls should be automatically included in the AddFeature routine, but that would probably have adverse performance consequences. The problem is, if those routines are not called, it is easy to get index out of bounds errors and there is no good way to understand why. Perhaps some better error trapping in the code?

The moral of the story: API documentation is scarce, but the source is good. I recommend you utilize the code comments by building a help file using Sandcastle and also create and distribute .xml files with the DLLs and PDBs. I wish we had more working examples.

As always, thanks for all your hard work.

Chris

Jan 18, 2012 at 8:09 PM

Although the editing of an existing point file worked well enough, I made minor changes to do the same to a newly created shape file:

        'Dim lyr As MapPointLayer = GISMap.AddLayer()
        'GISMap.Refresh()
        'Dim fs As FeatureSet = lyr.DataSet

        Dim fs As FeatureSet = New FeatureSet(DotSpatial.Topology.FeatureType.Point)
        fs.DataTable = dtControlPoints.Clone 'structure is defined in form load event
        Dim lyr As MapPointLayer = GISMap.Layers.Add(fsControlPoints)

        'lyr.EditMode = True
        Dim crds(0) As Coordinate
        crds(0) = New Coordinate(0, 0)
        Dim f As New Feature(FeatureType.Point, crds)
        'fs.Features.Add(f)
        With fs.AddFeature(f)
            .DataRow("Label") = "NEW POINT"
        End With
        fs.InitializeVertices()
        fs.InvalidateVertices()
        GISMap.Refresh()

        fs.Features.RemoveAt(0)
        'fs.Save()
        'lyr.EditMode = False
        fs.InitializeVertices()
        fs.InvalidateVertices()

        GISMap.Refresh()

An error is thrown at the fs.Features.RemoveAt(0) line. A call is made to FeatureList.ExcludeFeature which removes a row from the attribute table:

        private void ExcludeFeature(IFeature item)
        {
            item.ParentFeatureSet = null;
            _parent.DataTable.Rows.Remove(item.DataRow);
            OnFeatureRemoved(item);
        }

The event handler in turn is:

        private void DataTableRowDeleted(object sender, DataRowChangeEventArgs e)
        {
            Features.Remove(_featureLookup[e.Row]);
            _featureLookup.Remove(e.Row);
        }

...where the exception is thrown because e.Row references an deleted row so it is not found in the _featureLookup dictionary.

This seems like a pretty fundamental bug that I don't see a work-around for. Does anyone have any ideas?

Thanks,

Chris

Jan 18, 2012 at 11:07 PM

I debugged the DS source code to correct some problems associated with deleting points. I am posting the code changes here for mudnug rather than posting them because they are REALLY low-level and I can't promise that my changes won't have negative consequences. However, upon limited testing, at least they allow me to add and remove points without error.

In FeatureSet.cs:

        private void DataTableRowDeleted(object sender, DataRowChangeEventArgs e)
        {
            // Edited by Chris Wilson 1/18/12
            // Following commented out because removal of feature triggers removal of table row, which in turn triggered removal of feature again
            // Features.Remove(_featureLookup[e.Row]);
            _featureLookup.Remove(e.Row);
        }

In FeatureList.cs:

        private void IncludeFeature(IFeature item)
        {
            if (_list.Count == 1)
            {
                _parent.FeatureType = item.FeatureType;
            }
            item.ParentFeatureSet = _parent;
            if (_includeAttributes)
            {
                DataRow row = _parent.DataTable.NewRow();
                if (item.DataRow != null)
                {
                    for (int col = 0; col < _parent.DataTable.Columns.Count; col++)
                    {
                        string name = _parent.DataTable.Columns[col].ColumnName;
                        if (item.ParentFeatureSet.DataTable.Columns.Contains(name))
                        {
                            row[col] = item.DataRow[name];
                        }
                    }
                }
                item.DataRow = row;

                // Edits by Chris Wilson 1/18/12
                // Following line added because the Datatable add call was removed from Add method to fix problem with _featureLookup
                _parent.DataTable.Rows.Add(item.DataRow);
            
            }


            OnFeatureAdded(item);
        }

and...

        public void Add(IFeature item)
        {
            _list.Add(item);

            IncludeFeature(item);

            // Edits by Chris Wilson 1/18/12
            // Original code resulted in a different datarow is assigned to the record such that the
            // _featureLookup key will not be able to be found; in face similar code already exists in IncludeFeature method so it is not needed

            //if (_includeAttributes)
            //{
            //    // Trying to simply add the row will not work if it belongs to a differnet table.
            //    // This method copies values, but creates the new row as part of the parent table.
            //    DataRow dr = _parent.DataTable.NewRow();
            //    foreach (DataColumn dc in _parent.DataTable.Columns)
            //    {
            //        dr[dc] = item.DataRow[dc.ColumnName];
            //    }
            //    _parent.DataTable.Rows.Add(dr);
            //    item.DataRow = dr;
            //}

        }

Please let me know if you encounter any problems with this code and choose to include (or not). I need to know when/if I can revert back to released version.

Thanks,

Chris

Developer
Jan 19, 2012 at 6:41 PM

I agree that there are a number of  fundamental problems with the API. The reality has been, however, that people are using the framework in production scenarios. Because of this, it is time to release a version 1.0, and branch our code so that we can make architectural changes where needed without abandoning those users. We'll also be able to version our documentation.

You will note we are now distributing binaries in three ways:

  1. A Project Template
  2. A Minimal Set of Binaries
  3. An Extended Set of Binaries (with symbols)
  4. Nuget packages

The project is setup so that the XML documentation files are available in cases 1,3,4. Also, if you are building from source and build a release build, you will find that the XML documentation is included.

Please note that you can find the (sandcastle) documentation on the documentation tab.

We certainly want to make it easy to find the documentation that is available. Please let me know if you were unaware of these things or if it is still a challenge to get Intellisense working.

In regards to the apparent bug you have located, I am moving this to a work item and planning to work on this after the 1.0 release (coming this month) as I also feel that this needs to be looked at carefully. Please subscribe to the issue so that you are notified about any updates (and vote it up to let us know it is important to you).

There are thousands of issues (in the FeatureSet class and elsewhere) that Ted intended to address even though they would introduce breaking changes. With the introduction of v1.0, we will plan on more predictably deprecating behavior in the core libraries, so that people that are relying on workarounds will have a clearer migration path.

I will try and create sample code or tutorials for some use cases of which I am aware. There is a lot more I want to do to understand how people are using this software and what problems they are trying to solve with it.

I certainly appreciate the community's contributions and your contributions.

Developer
Jan 19, 2012 at 6:41 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Developer
Jan 20, 2012 at 4:03 PM

Regarding the 1.0 branch, is the intent to fix bugs that are common to 1.0 AND the latest branch?  I would think that would be really tedious.  My guess is that 1.0 will tend to get stale really fast.  But, I guess a Dot Spatial developer that is using 1.0 could monitor bug fixes in the latest and fold those fixes into 1.0 on an as needed basis?  

It might be helpful as things are rearchitected on the latest branch if once a particular rearchitection effort is completed, a release is posted.  That would be a good time for people who want to try and synch their applications that use an older Dot Spatial to the latest to dive in.  What we want to avoid is people trying to synch up in the middle of a rearchitection effort and get it working, then a change of course is made which invalidates the effort.

Just some thoughts.

Kyle

Jan 23, 2012 at 12:48 PM

I also want to re-iterate the point made by Chris: "API documentation is scarce, but the source is good". Over the last couple of months I developed a population-based surveillance system for a clinical trial, that uses DotSpatial to display topology including satellite imagery to locate homesteads in a rural area in Africa. The application uses netbooks and USB GPS equipment to display the location of the field team and allow them to locate homesteads and create new points for those homesteads based on the GPS position. In the course of the development (using C#) I got the Position components to work reliably (including GPS emulation), GDAL to deal with the large (500MB+) satellite images and the whole feature adding, removal process discussed here. The problem is that in the absence of a coherent conceptual level design document, much of this was hit and miss and when something works you often don't know exactly why.

I for one, will certainly follow the future development of DotSpatial with interest - it certainly worked for me and if you can tame it, it provides rich functionality. Keep up the good work.

Kobus

Developer
Jan 23, 2012 at 6:38 PM

@Kyle,

Correct: A DotSpatial developer that is using 1.0 could monitor bug fixes in the latest and fold those fixes into 1.0 on an as needed basis. Since I am working on the development branch, I'll pretty much leave that to other interested parties.

We can also release a set of documentation that describes how to get to the next released version, for those that don't have time to get daily source builds working and want, for example, quarterly updates. To benefit those using the nuget packages -- and everyone that doesn't want to read through a list of breaking changes to find the ones that apply to them -- I'll try to make my breaking changes appear as compiler warnings with instructions.

@Kobus et all,

Feel free to contribute documentation when you feel ready. I am particularly uncertain of how the Positioning (GPS) code is meant to be used.