Global Mapper v25.0

Shapefile export - no .dbf for Points

nickgoodliff
nickgoodliff Global Mapper UserTrusted User
edited May 2014 in SDK
Hi Mike

Any reason why this code isn't producing a .dbf file?
gMErrorT32_Points = GlobalMapperDLL.GM_ExportVectorEx(storagePath + "_Points.shp",
                GlobalMapperDLL.GM_VectorExportFormat_t32.GM_Export_Shapefile,
                IntPtr.Zero,
                ref ExportRect,
                GlobalMapperDLL.GM_VectorExportFlags_t32.GM_VectorExportFlags_ExportPoints | GlobalMapperDLL.GM_VectorExportFlags_t32.GM_VectorExportFlags_ExportAttrs,
                IntPtr.Zero,
                "");

I get the .shp and .shx but no .dbf, and ONLY when exporting points - exporting lines or areas are working fine.

Using v14.26.0.0

Cheers
Nick

Comments

  • global_mapper
    global_mapper Administrator
    edited April 2014
    Nick,

    Do your point features have any attributes? You are passing in the appropriate flags, but if none of your points had attributes then you wouldn't get a DBF file as there would be nothing to add to it.

    Thanks,

    Mike
    Global Mapper Guru
    geohelp@bluemarblegeo.com
    Blue Marble Geographics for Coordinate Conversion, Image Reprojection and Vector Translation
  • nickgoodliff
    nickgoodliff Global Mapper User Trusted User
    edited April 2014
    Hi Mike

    Right so this is all linked to a big problem I've been having with exporting shapefiles that I have finally been able to fix. The problem is this, and maybe you can shed light on why this has been happening:

    My application processes a product that is made up of 2 polygon layers and a point layer saved as shapefiles. When someone orders this product, my app loops through 3 separate folders to separately load in the each set of tiles, set the cropping polygon for the selected area, and then exports to shapefiles. It always exports the first folder absolutely fine (and can be either of the polygon or point source shapefiles), but invariably (99 times out 100) when it gets to the second folder, it loads these shapefiles then when it gets to exporting the selected area it crashes the whole .NET app with no error message!

    Some edited code:
    {[INDENT]GlobalMapperDLL.GM_SetLicenseKey("", IntPtr.Zero);
    GM_Projection_t gMProjectionT;
    GlobalMapperDLL.GM_Error_t32 gMErrorT32 = GlobalMapperDLL.GM_Error_t32.GM_Error_None;
    gMErrorT32 = GlobalMapperDLL.GM_LoadProjectionFile("Default_Projection.PRJ", out gMProjectionT);
    if (gMErrorT32 != GlobalMapperDLL.GM_Error_t32.GM_Error_None)
    {
        throw new Exception(gMErrorT32.ToString());
    }
    GlobalMapperDLL.GM_SetProjection(ref gMProjectionT);
    GlobalMapperDLL.GM_MessageCallbackDef errorHandler = new GlobalMapperDLL.GM_MessageCallbackDef(ProcessError);
    GlobalMapperDLL.GM_SetMessageCallback(errorHandler);           
    GlobalMapperDLL.GM_SetMiscOption(GlobalMapperDLL.GM_MiscOpt_t32.GM_MiscOpt_AllowUnlimitedECWExportSize, 1);
    
    
    _ProjectionCallbackDelegate = (GlobalMapperDLL.GM_QueryProjectionCallbackDef)SetProjection;
    GlobalMapperDLL.GM_SetQueryProjectionCallback(_ProjectionCallbackDelegate);
    
    
    // Loop through folders to process each layer[/INDENT]
    [INDENT]foreach (var folder in folders)[/INDENT]
    [INDENT]{[/INDENT]
    [INDENT][INDENT]var aFeature = cropPolygon.AreaFeature;[/INDENT]
    [INDENT]GlobalMapperDLL.GM_SetExportCropAreas(ref aFeature, 1, ref gMProjectionT);
    
    // work out the tiles required then load them
    [/INDENT]
    [INDENT]foreach (var tile in tiles)
    {
        LoadLayer(tile.FilePath);
    }
    
    // Export shapefile[/INDENT]
    [INDENT]GlobalMapperDLL.GM_ExportVectorEx(storagePath + "_Areas.shp",[/INDENT]
    [INDENT]                GlobalMapperDLL.GM_VectorExportFormat_t32.GM_Export_Shapefile,[/INDENT]
    [INDENT]                IntPtr.Zero,[/INDENT]
    [INDENT]                ref ExportRect,[/INDENT]
    [INDENT]                GlobalMapperDLL.GM_VectorExportFlags_t32.GM_VectorExportFlags_ExportAreas | GlobalMapperDLL.GM_VectorExportFlags_t32.GM_VectorExportFlags_ExportAttrs,[/INDENT]
    [INDENT]                IntPtr.Zero,[/INDENT]
    [INDENT]                "");[/INDENT]
    [INDENT]GlobalMapperDLL.GM_ExportVectorEx(storagePath + "_Lines.shp",[/INDENT]
    [INDENT]                GlobalMapperDLL.GM_VectorExportFormat_t32.GM_Export_Shapefile,[/INDENT]
    [INDENT]                IntPtr.Zero,[/INDENT]
    [INDENT]                ref ExportRect,[/INDENT]
    [INDENT]                GlobalMapperDLL.GM_VectorExportFlags_t32.GM_VectorExportFlags_ExportLines | GlobalMapperDLL.GM_VectorExportFlags_t32.GM_VectorExportFlags_ExportAttrs,[/INDENT]
    [INDENT]                IntPtr.Zero,[/INDENT]
    [INDENT]                "");[/INDENT]
    [INDENT]GlobalMapperDLL.GM_ExportVectorEx(storagePath + "_Points.shp",[/INDENT]
    [INDENT]                GlobalMapperDLL.GM_VectorExportFormat_t32.GM_Export_Shapefile,[/INDENT]
    [INDENT]                IntPtr.Zero,[/INDENT]
    [INDENT]                ref ExportRect,[/INDENT]
    [INDENT]                GlobalMapperDLL.GM_VectorExportFlags_t32.GM_VectorExportFlags_ExportPoints | GlobalMapperDLL.GM_VectorExportFlags_t32.GM_VectorExportFlags_ExportAttrs,[/INDENT]
    [INDENT]                IntPtr.Zero,[/INDENT]
    [INDENT]                "");[/INDENT]
    
    [/INDENT]
    [INDENT]// Clear layers for next folder[/INDENT]
    [INDENT]    for (int i = 0; i < clsGlobalVARS.LayerHandles.Count; i++)[/INDENT]
                {
                    GlobalMapperDLL.GM_CloseLayer((IntPtr)clsGlobalVARS.LayerHandles[i]);
                }
                clsGlobalVARS.LayerHandles.Clear();
                clsGlobalVARS.LayerInfos.Clear();
                clsGlobalVARS.LayerPtrHandles.Clear();[INDENT]    GlobalMapperDLL.GM_SetExportCropAreas(IntPtr.Zero, 0, IntPtr.Zero);[/INDENT]
    [INDENT]}[/INDENT]
    }
    
    
    public void LoadLayer(string File)
            {
                IntPtr theLayerList;
                UInt32 theNumLayers = 0;
                var LastGMError = GlobalMapperDLL.GM_LoadLayerListEx(File, out theLayerList, out theNumLayers, GlobalMapperDLL.GM_LoadFlags_t32.GM_LoadFlags_UseDefaultProj, "");
                
                // If the layer loaded successfully then get the layer info.
                // User the bounding rectangle in the layer info as the curent
                // view rectangle.
                if (LastGMError == GlobalMapperDLL.GM_Error_t32.GM_Error_None)
                {
                    // Add each layer
                    for (Int32 i = 0; i < theNumLayers; i++)
                    {
                        // Extract the layer handle from the list
                        IntPtr theLayerHandlePtr = (IntPtr)((UInt32)theLayerList + i * IntPtr.Size);
                        IntPtr theLayerHandle;
                        theLayerHandle = (IntPtr)Marshal.PtrToStructure(theLayerHandlePtr, typeof(IntPtr));
    
    
                        // Add the layer
                        // Get the layer info and copy it into our structure
                        GlobalMapperDLLWrapper.GM_LayerInfo_t theLayerInfo = new GlobalMapperDLLWrapper.GM_LayerInfo_t();
                        IntPtr theInfoPtr = GlobalMapperDLL.GM_GetLayerInfo(theLayerHandle);
                        theLayerInfo = (GlobalMapperDLLWrapper.GM_LayerInfo_t)Marshal.PtrToStructure(theInfoPtr, typeof(GlobalMapperDLLWrapper.GM_LayerInfo_t));
                        clsGlobalVARS.LayerInfos.Add(theLayerInfo);
                        clsGlobalVARS.LayerHandles.Add(theLayerHandle);
                        clsGlobalVARS.LayerPtrHandles.Add(theLayerHandlePtr);
                    }
                }
                else
                {
                    throw new Exception(LastGMError.ToString());
                }
            }
    
    

    A lot of that code is refactored in my app, but hopefully you can see the flow. I'm pretty sure the crash is due to some memory issue, and the only way I've been able to fix it is to put a lot of the code that deals with the GlobalMapperDLL into a class that I create each time in the loop, then dispose and create again for the next folder. Not the most efficient way of doing things!

    Cheers
    Nick
  • global_mapper
    global_mapper Administrator
    edited April 2014
    Nick,

    It looks like you are loading an entire folder's worth of Shapefiles, exporting to a new file, then closing them all, then moving to the next folder? How many Shapefiles are in the folder that is failing? It's possible you are filling up memory loading all of those at once. If it's possible for you to use the 64-bit SDK rather than the 32-bit that would allow you to use a lot more memory.

    You might also check that you are closing everything properly at the end by calling GM_GetLoadedLayerList to make sure the SDK doesn't think anything is still loaded.

    Thanks,

    Mike
    Global Mapper Guru
    geohelp@bluemarblegeo.com
    Blue Marble Geographics for Coordinate Conversion, Image Reprojection and Vector Translation
  • nickgoodliff
    nickgoodliff Global Mapper User Trusted User
    edited April 2014
    That is correct, though this happens when there is just one 5 sqkm file (3MB-ish shapefile) used per folder so don't think its memory filling up, and I'm already using 64-bit version. There is never any problem with the loading of the files, it only breaks on this call: GM_ExportVectorEx. The progress bar appears and says 0%, then it hangs for a second before exiting.

    Good tip about the GM_GetLoadedLayerList - it will be interesting if that throws anything up.

    Nick
  • global_mapper
    global_mapper Administrator
    edited April 2014
    Nick,

    Based on that it doesn't sound like memory is the issue. Do you know if your SDK agreement allows you to get the v15 SDK? The first thing I would suggest is trying with the latest SDK. The latest build is at http://www.globalmapper.com/GlobalMapperSDK_v15_latest_beta.zip .

    Thanks,

    Mike
    Global Mapper Guru
    geohelp@bluemarblegeo.com
    Blue Marble Geographics for Coordinate Conversion, Image Reprojection and Vector Translation
  • nickgoodliff
    nickgoodliff Global Mapper User Trusted User
    edited April 2014
    Yes, we are currently trialling v15 to see if it fixes the problem as it was happening with v14, and it is unfortunately happening in v15 aswell.

    My work around is ok for now, but would be great to know why no error message gets returned, just exitting the application.

    Nick
  • nickgoodliff
    nickgoodliff Global Mapper User Trusted User
    edited April 2014
    Right, so I have tracked down the issue! It is in this:
    [COLOR=#333333][FONT=monospace]var aFeature = cropPolygon.AreaFeature;
    [/FONT][/COLOR][COLOR=#333333][FONT=monospace]GlobalMapperDLL.GM_SetExportCropAreas(ref aFeature, 1, ref gMProjectionT);[/FONT][/COLOR]
    

    When I load the area for export, I save the area feature to crop to in my CropPolygon object. If this crop polygon has been set by a shapefile then it works fine, but where it is just a rectangle I create a GM_AreaFeature manually:
        GM_Point_t[] theAreaPoints = new GM_Point_t[Points.Count];
                int i = 0;
                foreach (var point in Points)
                {
                    theAreaPoints[i].mX = point.X;
                    theAreaPoints[i].mY = point.Y;
                    i++;
                }
                unsafe
                {
                    fixed (GM_Point_t* thePointList = &theAreaPoints[0])
                    {
                        GM_AreaFeature_t af = new GM_AreaFeature_t();
                        af.mFeatureInfo.mName = "CropAreaBox";
                        af.mFeatureInfo.mDesc = "CropAreaBox";
                        af.mFeatureInfo.mClass = (ushort)AreaFeatureClass_t16.AFC_UNKNOWN;
                        af.mPointList = (IntPtr)thePointList;
                        af.mNumPoints = 4;
                        AreaFeature = af;
                    }
                }
    

    and this gets saved in the object that is used for each export. Some part of this must get Garbage Collected in between each folder being processed and so when each GM_ExportVectorEx call was made, the pointers to the area feature to crop to were missing and so everything crashed.

    I have changed it to a method whereby this areaFeature gets created dynamically from my points array for each iteration.

    For rectangles, the area feature I am creating is identical to the GM_Rectangle_t that I am using for the World Bounds so I don't really need it, but in the future we will be allowing user-drawn cropping polygons (i.e. not loaded from a shapefile).

    Nick
  • global_mapper
    global_mapper Administrator
    edited April 2014
    Nick,

    The GM_SetExportCropAreas function will make a copy of whatever area(s) you pass in, so you could just call GM_SetExportCropAreas once at the start of the entire operation and that crop should stay in force and you can get rid of the area feature that you are passing in. If you are getting features from a layer (with GM_GetAreaFeature for example) you need to be sure to call GM_FreeAreaFeature when you are done using the structure so the SDK can free the allocated memory.

    Thanks,

    Mike
    Global Mapper Guru
    geohelp@bluemarblegeo.com
    http://www.bluemarblegeo.com/
  • nickgoodliff
    nickgoodliff Global Mapper User Trusted User
    edited May 2014
    Ah yes, I was missing that step to call GM_FreeAreaFeature!

    With regards to setting the Crop Areas once, there is another iteration that I didn't show in my edited code above that loops through an array of crop areas. If a user uploads a shapefile with more than one polygon, each polygon is exported separately so I potentially need to set the crop areas differently at various times.

    Thanks for your help, much appreciated.
    Nick