Global Mapper v25.0

Example of how to use GM_GroundControlPoint_t with GM_LoadRectifiedLayer

codemouse
codemouse Global Mapper UserTrusted User
edited August 2013 in SDK
Hi,

I'm trying to programatically load up MrSID layers using the Global Mapper SDK. I realized that I can load them in using GM_LoadLayerList or GM_LoadLayerListEx, however unless they have an embedded projection, I will receive the popup GUI screen asking to select a projection per layer that I load. This is fine, but I wanted to have this all happen without any user interaction in the background.

So, I realized I can use GM_LoadRectifiedLayer and pass in a projection, however I also need to pass in the ground control point(s) in order to get this to work (vs. using GM_LoadLayerList* which seems to read the .sdw file automatically and grab the ground control point(s) for me).

Assuming I have an .sdw file that only has 1 control point, the way I understand it is I can look for and parse through that text file under the assumption that the 6 lines I need to grab have the following "standard"? world file layout:

Line 1: pixel size in the x-direction in units per pixel
Line 2: rotation about y-axis
Line 3: rotation about x-axis
Line 4: pixel size in the y-direction units per pixel
Line 5: x-coordinate of the center of the upper left pixel
Line 6: y-coordinate of the center of the upper left pixel

And assuming GM_GroundControlPoint_t def looks like this:
typedef struct
{
double mPixelX; // x pixel coordinate of GCP
double mPixelY; // y pixel coordinate of GCP (top is 0, increases down)
double mGroundX; // x ground coordinate of GCP (in provided projection)
double mGroundY; // y ground coordinate of GCP (in provided projection)
} GM_GroundControlPoint_t;

It seems to me that when I create a
GM_GroundControlPoint_t to pass to GM_LoadRectifiedLayer, I would pass Line 5 to mPixelX, and Line 6 to mPixelY - but what would I use for mGroundX and mGroundY? Assume a projection of UTM just for discussions-sake. Would that just be 0,0? Or what that be the UTM offset (northing/easting) for that Top-Left corner?

Any help is appreciated just so I know that I'm accomplishing this the right way. Thank you!

Brian

Comments

  • global_mapper
    global_mapper Administrator
    edited August 2013
    Brian,

    To simulate a world file with no projection you would need to pass in 2 control points, but in any case that's not what you need to do. You should use the base GM_LoadLayerList function, but first call GM_SetQueryProjectionCallback to provide a callback function into your own application to be used when a projection is needed. Then when your callback function is called during load just set whatever projection you want for the file.

    Let me know if I can be of further assistance.

    Thanks,

    Mike
    Global Mapper Guru
    geohelp@bluemarblegeo.com
    Blue Marble Geographics for Coordinate Conversion, Image Reprojection and Vector Translation
  • codemouse
    codemouse Global Mapper User Trusted User
    edited August 2013
    Mike,

    Thanks yes - I see some further info about that here - http://www.globalmapperforum.com/forums/sdk/4803-avoid-projection-dialog.html

    Will try, thank you!

    Brian
  • codemouse
    codemouse Global Mapper User Trusted User
    edited August 2013
    And for the lazy or those looking at how to do this in C# - here's what I did:

    In my GlobalMapper class wrapper I have defs for the following:
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
            public delegate void GM_SetQueryProjectionCallback(GM_QueryProjectionCallbackDef aCallBackFunc);
    
    
            [UnmanagedFunctionPointer(CallingConvention.StdCall)]
            public delegate byte GM_QueryProjectionCallbackDef(ref GM_Projection_t aProj, ref GM_Point_t aInitialPos, ref GM_ElevUnits_t8 aElevUnits);
    
    
    

    I call them in my main program and set them like this:
    var callbackDelegate = (GlobalMapper.GM_QueryProjectionCallbackDef)SetProjection;
    
    
                    var setQueryProjectionCallback = (GlobalMapper.GM_SetQueryProjectionCallback)Marshal.GetDelegateForFunctionPointer(NativeMethods.GetProcAddress(GlobalMapperInterfaceDllAddress, typeof(GlobalMapper.GM_SetQueryProjectionCallback).Name), typeof(GlobalMapper.GM_SetQueryProjectionCallback));
    
    
                    setQueryProjectionCallback(callbackDelegate);
    

    And then define SetProjection method with whatever projection as follows:
    private static byte SetProjection(ref GM_Projection_t aProj, ref GM_Point_t aInitialPos, ref GM_ElevUnits_t8 aElevUnits)
            {
                aProj = new GM_Projection_t() 
                { 
                    mProjSys = GM_ProjType_t16.GM_PRJ_GEO,
                    mUnit = GM_ProjUnit_t16.GM_PRJ_UNIT_ARC_DEGREES,
                    mDatum = GM_DatumType_t16.GM_DATUM_NAD83,
                    mNumAttrs = 0
                };
    
    
                aElevUnits = GM_ElevUnits_t8.GM_ElevUnit_Meters;
    
    
                return (byte)1;
            }
    

    and btw, my GlobalMapperInterfaceDllAddress is set as follows:
    const uint flag = (uint)NativeMethods.LoadLibraryExFlags.LOAD_WITH_ALTERED_SEARCH_PATH;
    
    
                    IntPtr GlobalMapperInterfaceDllAddress = NativeMethods.LoadLibraryEx(pathToGlobalMapperDll, IntPtr.Zero, flag);
    
    where LoadLibraryEx is:

    [DllImport("kernel32.dll", SetLastError = true)]
            public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
    
  • codemouse
    codemouse Global Mapper User Trusted User
    edited August 2013
    One other thing - you may need to store your delegate somewhere because GC will make it go out of scope when you leave the method.
    private GlobalMapper.GM_QueryProjectionCallbackDef _ProjectionCallbackDelegate;
    

    Then in the call:

    _ProjectionCallbackDelegate = (GlobalMapper.GM_QueryProjectionCallbackDef)SelectAndSetProjection;
    

    Brian