Global Mapper v25.0

Select Features

Rod K
Rod K Global Mapper User
edited April 2010 in SDK
I would like to highlight features on the map meeting a specific query criteria and am looking for a code sample to demonstrate how to do this.

In my example, I have a custom layer with point features. I maintain the attributes and ids for these features in a database and create the point feature with its mFeatureInfo.mName assigned to a unique integer using the following:
                    //create point
                    GM_PointFeature_t point = new GM_PointFeature_t();
                    point.mPointStyle.mSymbolName = symbol;
                    point.mPointStyle.mScale = 0.5F;
                    point.mPointStyle.mDrawLabel = 0;

                    point.mPos.mX = x;
                    point.mPos.mY = y;

                    point.mFeatureInfo.mName = id.ToString();  //unique int

                    // Add the point to the custom layer
                    LastGMError = GlobalMapperDLL.GM_AddPointToVectorLayer(layer, ref point, 0);

For this sample, I would like to select a set of features, for example, id's 1,5,25 and 100 and based on that selection highlight those features on the map with a specific selection color.

Thank you for any help or suggestions, or sample code related to this!

Rod

Comments

  • global_mapper
    global_mapper Administrator
    edited April 2010
    Rod,

    What you should do is use the GM_GetPointFeature function to iterate through all of the features in a layer to find those matching particular attributes, then when you find the desired ones use GM_SetPointFeatureDrawStyle to change the drawing style to your desired selected style.

    Let me know if I can be of further assistance.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • Rod K
    Rod K Global Mapper User
    edited April 2010
    Thank you Mike,

    I'm part way there, but hung up on the following. I'll post my sample code back for others once I get it all working. For updating the style I'm getting the following error:

    Error 14 'GlobalMapperDLLWrapper.GlobalMapperDLL' does not contain a definition for 'GM_SetPointFeatureDrawStyle'



    foreach (int fid in foundFeatures)
    {
    pPoint = GlobalMapperDLL.GM_GetPointFeature(pLayer, fid);
    LastGMError = GlobalMapperDLL.GM_SetPointFeatureDrawStyle(pLayer, pPoint, pStyle);
    }


    Here is the function reference information:

    // Sets the drawing style to use for a given point feature
    GM_DLL_EXPORTED GM_Error_t32 __stdcall GM_SetPointFeatureDrawStyle
    (
    GM_LayerHandle_t32 aLayer, // Layer the point is in
    uint32 aPointIndex, // Index of point in layer
    const GM_PointStyle_t* aPointStyle // New style to use for point
    );


    How do I call this function?
  • global_mapper
    global_mapper Administrator
    edited April 2010
    The C# and VB.NET (which are you using?) sample applications only have sample implementations of some functions. If you let me know if you are in C# or VB.NET I can provide the sample call you would need to add if you have trouble. The only tricky parameter is the aPointStyle one, which you could define as 'ByRef' of type GM_PointStyle_t if you don't ever need to pass in NULL to reset the style, but if you do need it to allow NULL, define it as IntPtr as pass your value in that way.

    Let me know if I can be of further assistance.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • Rod K
    Rod K Global Mapper User
    edited April 2010
    I'm using the C# SDK. A sample of how to call GM_SetPointFeatureDrawStyle would be wonderful!

    Rod
  • global_mapper
    global_mapper Administrator
    edited April 2010
    Rod,

    I have attached an updated C# SDK sample that includes a declaration for the GM_SetPointFeatureDrawStyle function.

    Let me know if I can be of further assistance.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • Rod K
    Rod K Global Mapper User
    edited April 2010
    Thank you Mike! I'm now getting a compile error on the third argument which I'm supplying to the GM_SetPointFeatureDrawStyle() function. My goal is to get the current style for the selected features and change the draw symbol to one with a different color to show the user the selected features with a "selection color". I've created and saved the new style, and I'm attempting to assign that. Since the mPointStyle property of my point is of GM_PointStlye_t type, I capture that and change its mSymbolName property. However, when I try to use this to assign the new draw style, I'm getting a type mismatch for the third argument. The function is looking for an IntPtr while I have a GM_PointStyle_t. Can you show me how I would get an IntPtr to this style instead?

                    //create selected style
                    GM_PointStyle_t style = new GM_PointStyle_t();
    
    
                    foreach (uint fid in foundFeatures)
                    {
                        pPoint = GlobalMapperDLL.GM_GetPointFeature(pLayer, fid);
                        point = (GM_PointFeature_t)Marshal.PtrToStructure(pPoint, point.GetType());
                        style = point.mPointStyle;
                        style.mSymbolName = "Seismic Survey - Planned Source [selected]";
                        LastGMError = GlobalMapperDLL.GM_SetPointFeatureDrawStyle(pLayer, fid, style);
    
                        point.mPointStyle.mSymbolName = "Seismic Survey - Planned Source [selected]";
                        
                    }
    
  • global_mapper
    global_mapper Administrator
    edited April 2010
    There are a couple of ways to get an IntPtr from an object in C#. The easiest is probably just to use the 'fixed' declaration to get a fixed pointer to the object in memory, then pass that. It should look something like the following:

    fixed ( GM_PointStyle_t* theStylePtr = &style )
    {
    LastGMError = GlobalMapperDLL.GM_SetPointFeatureDrawStyle(pLayer, fid, theStylePtr);

    }

    Let me know if I can be of further assistance.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • Rod K
    Rod K Global Mapper User
    edited April 2010
    Mike, Thank you for your help with this! I'm still getting the following C# compiler error
    Cannot take the address of, get the size of, or declare a pointer to a managed type ('GlobalMapperDLLWrapper.GM_PointStyle_t')

    Here is a reference that provides good insight to this topic (for anyone else reading this and having similar trouble using pointers in C#): http://www.c-sharpcorner.com/UploadFile/gregory_popek/WritingUnsafeCode11102005040251AM/WritingUnsafeCode.aspx

    I've tried wrapping my entire function with the unsafe declaration, but that results in the same error. Seems that I won't be allowed to use GM_PointStyle_t in both a managed and unmanaged context.

    Any additional insight on solving this that you can provide me with would be greatly appreciated!


                        foreach (uint fid in foundFeatures)
                        {
                            pPoint = GlobalMapperDLL.GM_GetPointFeature(pLayer, fid);
                            point = (GM_PointFeature_t)Marshal.PtrToStructure(pPoint, point.GetType());
                            style = point.mPointStyle;
                            style.mSymbolName = "Seismic Survey - Planned Source [selected]";
                            unsafe 
                            {
                                fixed(GM_PointStyle_t* stylePtr = &style);
                            }
                            LastGMError = GlobalMapperDLL.GM_SetPointFeatureDrawStyle(pLayer, fid, stylePtr);
                        }
    
  • global_mapper
    global_mapper Administrator
    edited April 2010
    I don't think your unsafe wrapping is correct, your current stylePtr declaration would go out of scope prior to your call to GM_SetPointFeatureDrawStyle. Try the following instead (also make sure that you have enabled the use of unsafe code in your project settings):

    unsafe
    {
    fixed(GM_PointStyle_t* stylePtr = &style)
    {
    LastGMError = GlobalMapperDLL.GM_SetPointFeatureDrawStyle(pLayer, fid, stylePtr);
    }
    }

    If that doesn't work, you can instead use the Marshal.AllocHGlobal to allocate memory the same of a GM_PointStyle_t structure, then use Marshal.StructureToPtr to copy the contents of your GM_PointStyle_t value to that memory, then pass in the pointer to that, then use Marshal.FreeHGlobal to free the allocated memory. You can avoid the use of unsafe code if you do this.

    Let me know if I can be of further assistance.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • Rod K
    Rod K Global Mapper User
    edited April 2010
    Hi Mike,

    I've tried several wrappings into an unsafe context and have not had any different results with that. The following produces the same error:
                        unsafe 
                        {
                            fixed (GM_PointStyle_t* stylePtr = &style)
                            {
                                LastGMError = GlobalMapperDLL.GM_SetPointFeatureDrawStyle(pLayer, fid, stylePtr);
                            }
                        }
    

    I also tried declaring the method unsafe:
            public unsafe void SelectFeatures(string queryFilter, string layerName)
            {
    

    as well as declaring the class unsafe:
        public unsafe partial class GlobalMapper2D : UserControl
        {
    

    none of these work. I think it may have to do with the fact that GM_PointStyle_t is defined in managed code or has a reference type within its structure.

    I would like to try using your suggested alternative. Would it be possible for you to provide a sample that uses that? It looks very greek to me, and you could probably have sample code formed up in a matter of minutes that uses that alternate method, where as I would still be wrestling with it tomorrow or the next day if left on my own with it.
  • global_mapper
    global_mapper Administrator
    edited April 2010
    Before going down the dynamic memory allocation route, can you try just changing your GM_SetPointFeatureDrawStyle declaration to the following:

    [DllImport(DLLFileName, EntryPoint = "GM_SetPointFeatureDrawStyle")]
    public static extern GM_Error_t32 GM_SetPointFeatureDrawStyle
    (
    GM_LayerHandle_t32 aLayer, // Layer the point is in
    UInt32 aPointIndex, // Index of point in layer
    ref GM_PointStyle_t aPointStyle // (const GM_PointStyle_t*) New style to use for point, pass IntPtr.Zero to restore default type-based stuff
    );

    Then call that directly with your 'style' value. The only thing you lose with this declaration is the ability to pass in IntPtr.Zero for the style to reset it to the default, but I don't think you care about this for your application. This approach is much simpler than wrestling with the other stuff.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • Rod K
    Rod K Global Mapper User
    edited April 2010
    Thank you Mike,

    That solved it! Here is the code I ended up with:
                    // get pointer to layer from dictionary given layerName
                    // note: this was saved into dictionary when layer was created
                    IntPtr pLayer = layers[layerName];
    
                    GM_PointFeature_t point = new GM_PointFeature_t();
                    IntPtr pPoint;
    
                    //create selected style
                    GM_PointStyle_t style = new GM_PointStyle_t();
    
                    foreach (uint fid in foundFeatures)
                    {
                        pPoint = GlobalMapperDLL.GM_GetPointFeature(pLayer, fid);
                        point = (GM_PointFeature_t)Marshal.PtrToStructure(pPoint, point.GetType());
                        style = point.mPointStyle;
                        style.mSymbolName = "Seismic Survey - Planned Source [selected]";
    
                        LastGMError = GlobalMapperDLL.GM_SetPointFeatureDrawStyle(pLayer, fid, ref style);
    
                    }
    
    
                    DrawLayersToBitmap();