How to create memory shape file using the latest version?

Feb 7, 2011 at 10:55 AM

 

Dear all,

Could anybody advise how to create memory shape file using the latest code? The code I used before you can find below, but it doesn’t work anymore. Thank you,
Igor.

///This code creates a mesh on a screen
private
void btnCreateMemorySHP_Click(object sender, EventArgs e) { Shapefile mwShp = new MapWinGIS.Shapefile(); //string strMeshFile = Path.GetTempPath() + Path.GetRandomFileName() + ".shp"; mwShp.CreateNew("", MapWinGIS.ShpfileType.SHP_POLYLINE); //mwShp.CacheExtents = true; MapWinGIS.Field f = new MapWinGIS.Field(); f.Name = "id"; f.Type = MapWinGIS.FieldType.STRING_FIELD; int fid = 0; mwShp.EditInsertField(f, ref fid, null); mwShp.Key = "GRID"; MapWinGIS.Extents ext = axMap1.Extents as MapWinGIS.Extents; double cs = Math.Abs((ext.yMax -ext.yMin)/10 ); int n = 0, nn = 0, nt = 0; MapWinGIS.Shape s = new MapWinGIS.Shape(); MapWinGIS.Point pm; double yStart = ext.yMin; for (int r = -1; r < 10; r++) { s = new MapWinGIS.Shape(); s.Create(MapWinGIS.ShpfileType.SHP_POLYLINE); s.InsertPart(0, ref n); n++; pm = new MapWinGIS.Point(); pm.x = ext.xMin; pm.y = yStart; nt = 0; s.InsertPoint(pm, ref nt); nt++; pm = new MapWinGIS.Point(); pm.x = ext.xMax; pm.y = yStart; s.InsertPoint(pm, ref nt); if (mwShp.EditInsertShape(s, ref nn)) { nn++; } yStart += cs; } cs = Math.Abs((ext.xMax - ext.xMin) / 10); double xStart = ext.xMin; for (int c = 0; c < 11; c++) { s = new MapWinGIS.Shape(); s.Create(MapWinGIS.ShpfileType.SHP_POLYLINE); s.InsertPart(0, ref n); n++; pm = new MapWinGIS.Point(); pm.x = xStart; pm.y = ext.yMin; nt = 0; s.InsertPoint(pm, ref nt); nt++; pm = new MapWinGIS.Point(); pm.x = xStart; pm.y = ext.yMax; s.InsertPoint(pm, ref nt); if (mwShp.EditInsertShape(s, ref nn)) { nn++; } xStart += cs; } //mwShp.RefreshExtents(); mwShp.StopEditingShapes(true, true, null); mwShp.StopEditingTable(true, null); //mwShp.Save(null); mwShp.Categories.Add("main"); mwShp.DefaultDrawingOptions.LineVisible = true; mwShp.DefaultDrawingOptions.LineWidth = 1.0f; mwShp.DefaultDrawingOptions.LineColor = RGB(Color.Black); mwShp.DefaultDrawingOptions.LineStipple = MapWinGIS.tkDashStyle.dsSolid; mwShp.DefaultDrawingOptions.Visible = true; mwShp.Categories.get_Item(0).DrawingOptions.LineVisible = true; mwShp.Categories.get_Item(0).DrawingOptions.LineWidth = 2.0f; mwShp.Categories.get_Item(0).DrawingOptions.LineColor = RGB(Color.Black); mwShp.Categories.get_Item(0).DrawingOptions.LineStipple = MapWinGIS.tkDashStyle.dsSolid; mwShp.Categories.get_Item(0).DrawingOptions.Visible = true; int handle = axMap1.AddLayer(mwShp, true); axMap1.ZoomToLayer(handle); axMap1.Redraw(); }

 

 

Developer
Feb 9, 2011 at 11:45 PM
Edited Feb 9, 2011 at 11:46 PM

Igor,

There are problems with in-memory shapefile indeed. The code inside ocx was quite messed,  and I made fast patches when something went wrong several times.

But that wasn't the approach to get rid of the problem once and for all. Now I reworked several methods of MapWinGIS quite seriously:

Shapefile.StartEditingShapes

Shapefile.StopEditingShapes

Shapefile.Open

Shapefile.Close

Shapefile.CreateNew

Shapefile.Save

Shapefile.SaveAs.

In some cases the size of procedure reduced twice.

Also Shapefile.SourceType property was added. It's described here: http://mapwingis.codeplex.com/workitem/19911

I tested your code and it's working, as well as editing of shapes in MapWindow4 and my own application.

But I need 1-2 for more testing (running all the test scripts we have) before committing this and other changes.

Thanks,

Sergei

 

 

Feb 16, 2011 at 12:34 AM

Sergei,

 

I have downloaded the latest version (58017) and made some tests, so far so good, new ocx is a bit speedy and in terms of memory using is more efficient.

Update table values and apply category expression work quite good.

just a bit confused with some shapefile class properties and methods which I don't really know how to use, hope I can find some unswers on a forum after some serach. Also would be very pleased if you could point me where to find this information.

UseSpatialIndex, HasSpatialIndex, get_CanUseSpatialIndex, CreateSpatialIndex

EndPointInShapefile,UseQTree, RefreshExtents – looks like there is no difference if this options is activated?

Regards,

Igor.

Developer
Feb 16, 2011 at 11:03 AM
Edited Feb 16, 2011 at 11:05 AM

Igor,

I'm glad to hear that it's working ;)

Some info about the properties:

- all with 'SpatialIndex' postfix - control R-tree spatial index (.mwd, .mwx files). Implemented in IndexSeraching.dll.

It speeds up selection of shapes (drawing routine, SelectiShapes routine). At full scale (all shapefile is visible) it actually slows down the performance.

Shapefile.SpatialIndexMaxAreaPercent property can be used to prevent this. See these 2 related issues:

http://mapwingis.codeplex.com/workitem/20015

http://mapwingis.codeplex.com/workitem/19993

Shapefile.UseQTree - spatial index as well, but implemented inside ocx using quad tree. It's was meant for editing mode, but actually there are problems with it.

It stores indices of shapes. To  make it work properly, shapes should be inserted in the end of shapefile only and not deleted but marked as such.

The part about not deleting the shapes actually gave me some troubles. So I removed this behavior. Perhaps the only way to make quad tree work 

properly now, is to regenerate it after each editing of the shapefile. More work is needed here. Probably it'll be possible to store in qtree 

pointers to ShapeData structures, then we could insert and delete shapes without breaking the tree. Deleted shapes can be stored in separate vector as

described here: http://mapwingis.codeplex.com/workitem/19911 (PREVENTION OF LOSING THE DATA WHILE DISCARDING EDITS).

Shapefile.RefreshExtents - affect the editing mode. While editing shapes the extents of shapefile change. It's quite easy to update them on the fly

in case they became larger (inserting shape), but in opposite case (deleting a shape) there is no fast way to do it. Also user can change coordinates of

the individual points. I can't track such changes at all. Incorrect extents will produce a lot of problems (drawing, selection, zooming to layer). RefreshExtents 

routine is meant to deal with this.

In the fast mode it should be called externally by user when actual changes took place. In the regular mode extents will be refreshed before each redraw

automatically, which is slow but ensures proper drawing and compatibility with older versions (the calling sequence is like this:

Map.DrawNextFrame -> Map.AdjustLayerExtents -> Shapefile.get_Extents).

BeginPointInShapfile, EndPointInShapefile - caches data for fast PointInShapefile tests. I don't like such hasty decisions to speed up a single method.

New fast mode (CShapeData class) is more generalized approach. But we have to live with these 2 all the same ;)

Thanks for your testing,

Sergei

Feb 21, 2011 at 1:28 AM

 

Thanks for clarifications 

Feb 21, 2011 at 2:23 AM

there is one more question: 

How MapWinGis.ShapeFile.FastMode interacts with memory shapefile?

It is strange but if I create memory shape file and set up Fastmode = true in the beginning I don’t see any data on a screen, also if I set to full extent I get the error?

Any advice?

Developer
Feb 23, 2011 at 4:19 PM

Igor, 

could you provide some sample code?

Thanks,

Sergei

Feb 24, 2011 at 2:22 AM

Sergei,

you have this example. please check the example I sent you, find following procedure: btnCreateMemorySHP_Click

and replace the code in the beginning with the following:

        private void btnCreateMemorySHP_Click(object sender, EventArgs e)
        {
            Shapefile mwShp = new MapWinGIS.Shapefile();
            mwShp.CreateNew("", MapWinGIS.ShpfileType.SHP_POLYLINE);
            mwShp.FastMode = true;
            mwShp.CacheExtents = true;

Now run the application and press button "Create Memory Shape File",

so once you done that you can see that nothing appeared on a screen and application stopped working!

if you remove following string of the code: mwShp.FastMode = true; - then application is working fine.

I suppose there is a conflict with other settings like mwShp.CacheExtents etc... is that correct?

Igor.

Jun 3, 2011 at 3:08 PM

There hasn't been much movement on this topic in a few months...

I'm working with MFC and MapWinGIS v4.8.2 trying to create an in-memory shapefile.
Seemingly, it's working with the following code...

When I use:

Interestingly, if I use the Start/Stop editing, as in the following lines:

pShapefile->StartEditingShapes(...);
pShapefile->EditInsertField(...);
pShapefile->StopEditingShapes(...);

immediately after the StopEditingShapes call - if I check the last error code, I get #4: Invalid Filename error message.

int CMyMapApp::CreateShapefile(LPCTSTR sFilename, BOOL isVisible)
{
    VARIANT_BOOL retVal = FALSE;
    int layerHandle = -1;
    BSTR bstrFilename = SysAllocString(sFilename);
    BSTR bstrFieldName;
    HRESULT hr;
    //Declare a shapefile pointer
    MapWinGIS::IShapefilePtr pShapefile;
    //Create an instance of the shapefile
    pShapefile.CreateInstance(__uuidof(MapWinGIS::Shapefile));
    //Check for the last error code
    CheckShapefileError(pShapefile);
    //Declare a field index
    long FieldIndex = 0;
    //Declare a field pointer
    MapWinGIS::IFieldPtr pField;
    //Create an instance of the field
    hr = pField.CreateInstance(__uuidof(MapWinGIS::Field));
    // - Note to reader - Test the return value of hr

    //Add a name to the field
    if (!bstrFilename)
        bstrFieldName = SysAllocString(TEXT("InMemoryFile"));
    else
        bstrFieldName = SysAllocString(sFilename);
    hr = pField->put_Name(bstrFieldName);
    // - Note to reader - Test the return value of hr

    //Edit the shapefile to add the field
    hr = pShapefile->EditInsertField(pField, &FieldIndex, NULL, &retVal);
    // - Note to reader - Test the return value of hr
    layerHandle = m_Map.AddLayer(pShapefile, isVisible);
    return layerHandle;
}

void CMyMapApp::ChechShapefileError(MapWinGIS::IShapefilePtr p)
{
    long ErrorCode = 0;
    BSTR bstrErrorMsg;
    CString sErrorMsg;
    HRESULT hr;

    hr = p->get_LastErrorCode(&ErrorCode);
    // - Note to reader - Test the return value of hr

    if (ErrorCode != 0)
    {
        hr = p->get_ErrorMsg(ErrorCode, &bstrErrorMsg);
        // - Note to reader - Test the return value of hr
        sErrorMsg.Format(TEXT("Shapefile Error [%d]: %s"), ErrorCode, bstrErrorMsg);
        AfxMessageBox(sErrorMsg);
    }
} 
Jun 14, 2011 at 8:04 PM

Sounds like it is not yet setup to support an in memory dbase file.  Any idea if this type of support is planned?

 

-Sam

Developer
Jun 16, 2011 at 11:28 PM

I've committed a possible fix for an issue reported by Igor: http://mapwingis.codeplex.com/SourceControl/changeset/changes/61429

 

Frank,

invalid filename error code is an expected one.

1. You should call Shapefile.CreateNew or Shapefile.CreateNewWithShapeId in the beginning. Otherwise shapefile is uninitialized (Shapefile.get_SourceType = sstUninitialized) and won't work at all. 

2. Shapefile.CreateNew can be called with filename or without it (empty string "").

3. For saving shapefile it's necessary to call Shapefile.SaveAs(Filename). In case filename was specified in Shapefile.CreateNew, it's enough to call either Shapefile.Save or Shapefile.StopEditingShapes.

4. In case no filename was provided in Shapefile.CreateNew, Shapefile.Save and Shapefile.StopEditingShapes will return a described error (Invalid filename).

Let me know if there are other problems with in-memory shapefiles.