GM_CreateCustomVectorLayer - V130 Beta

QldblueQldblue Global Mapper UserPosts: 17
edited December 2008 in SDK
Hi I'm currently developing an app using Delphi 7. It is moving along fairly well but I have come up against a problem that I cannot seem to resolve.

I am creating a new Layer using the following settings, transposed into 'C'

theUtmProj.mProjSys = GM_PRJ_UTM;
theUtmProj.mDatum = GM_DATUM_AUSTRALIAN_GEODETIC_1984;
theUtmProj.mUnit = GM_PRJ_UNIT_METERS;
theUtmProj.mAttrList[0].mAttr = ZONE;
theUtmProj.mAttrList[0].mValue = -55;
theUtmProj.mNumAttrs = 1;

This is virtually the same as the example in the SDk reference.

When I inspect the layers using GM_GetLayerInfo I find the mAttrList[0].mValue = 0; All other settings are OK and I believe this is the problem.

Previously I created layers using the same call in an earlier version and It worked fine and in fact I was posting vector objects to the layers.

Is there a reason for this issue? Has the call been changed?

Cheers

Mark

Comments

  • global_mapperglobal_mapper Administrator Posts: 17,238
    edited December 2008
    Mark,

    The call has not changed. Can I see your declaration of the GM_Projection_t structure in Delphi? That may be the issue.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • QldblueQldblue Global Mapper User Posts: 17
    edited December 2008
    Mike

    The declarations in Delphi are as follows:



    {/// This type is used to describe a single projection attribute value }
    type
    GM_ProjAttrValue_t = record
    mAttr: GM_PROJATTR;
    mValue: double;
    end {GM_ProjAttrValue_t};

    {/// This type is used to fully describe a projection. }
    type
    PGM_Projection_t = ^GM_Projection_t; //This is a pointer declaration in Delphi
    GM_Projection_t = record
    mProjSys: GM_PROJSYS;
    mDatum: GM_DATUM;
    mUnit: GM_UNIT;
    mNumAttrs: Longword;
    mAttrList: Array[0..15] of GM_PROJATTRVALUE_T;
    end {GM_Projection_t};

    I renamed some of the enumeration variable names to ensure no conflicts with other parts of the program. "Unit" is a reserved word in Delphi.

    The heading fragment representing the type enumeration is shown here:

    {/// Enumeration of projection attribute types. These values are shared with }
    {/// the Global Mapper DLL so it is important that their values to not change. }

    type
    GM_PROJATTR = (
    FIRST_STANDARD_PARALLEL = 0,
    SECOND_STANDARD_PARALLEL,


    {/// Enumeration of the datum types. This enumeration is shared by the plugins }
    {/// so it is important that the order not change and that new datums be added }
    {/// to the end (before the interplanetary datums is ok) }

    type
    GM_DATUM = (
    GM_DATUM_ADINDAN = 0,
    GM_DATUM_ARC1950,


    {/// Enumeration of the unit types. This enumerator is shared by plugins and }
    {/// the Global Mapper DLL interface, so it is important that the order does }
    {/// not change and that new units are added to the end. }

    type
    GM_Unit = (
    GM_PRJ_UNIT_RADIANS = 0,
    GM_PRJ_UNIT_US_FEET = 1,


    {/// Enumeration of the projection types. This enumeration is shared by the plugins }
    {/// so it is important that the order not change and that new projections be added }
    {/// such that the enumerated value of existing projections is not disturbed. }
    type
    GM_PROJSYS =
    (
    GM_PRJ_GEO, // Geographic (lat/lon)
    GM_PRJ_UTM, // UTM

    The steps in the program are:
    1 Load an existing file with GM_LoadLayerList. All the layersup to "User Created and Modified" were created by Global Mapper Version 9. The layers Noise Sources (Point) and Buildings was created with an earlier version of the SDK.

    2 Insert new layers

    if GetUniqueLayerIndex(Layer_Name) < 0 then // Check if layer name exists
    begin
    strpcopy(S,Layer_Name); // Copy layer name to a variable format to suit GM SDK
    aDescription:= S; // and ensure that it is a pointer
    LayerHandle:= GM_CreateCustomVectorLayer(aDescription, aProj); //Create the layer and return a pointer
    if LayerHandle<> nil then // If GM SDK returns a valid pointer then
    begin
    aGlobalLayerList.Add(GM_LAYERHANDLE_T32(LayerHandle)); // Add pointer to the list of layer pointers
    end;
    end;

    3 Now Check the layer properties Used to create a display of layer properties

    for i:= 0 to aGlobalLayerList.Count-1 do
    begin
    p:= AglobalLayerList.Items;
    ALayerData:= GM_GetLayerInfo(P);
    if ALayerData <> nil then
    begin
    Desc:= String(AlayerData.mDescription);
    LayerDisplayForm.StringGrid1.Cells[0,i+1]:=Desc;

    I believe the type is behaving properly see the attached screen dump showing all the layers and variable names in a current file. The variables from the earlier layers created by Global Mapper or the earlier version of the SDK are correctly reported. Only the just created layers have an issue, namely mNativeProj.mAttrList[0].mValue is reported as zero, rather than -55 as set in the creation step. (The attached file has been converted to B&W bitmap and zipped to comply with file size constraints of Forum).

    As you can see there are only a few steps involved and I have attached most of the pertinent parts of the program.

    I have also tried to post objects to the Ground_Contours layer, the first new layer posted. The objects are inserted in the layer but are not displayed and are not saved when I call GM_ExportPackage(pchar(FileName),p,longword(0),nil,0.0,GM_ExportPackage_DiscardAttributes)
    Furthermore some of the layer attributes do not automatically change ie mnativerect or m globalrect, however, mnumlines is incremented by the number of objects.

    If you can shed any light on this it would be appreciated.

    Regards

    Mark
  • global_mapperglobal_mapper Administrator Posts: 17,238
    edited December 2008
    Mark,

    I would agree that the type does appear to be working correctly based on your screen dump. Where is the code where you setup the GM_Projection_t structure and provide it to the GM_CreateCustomVectorLayer function? I would guess that is where the culprit is. Or can you look at the projection structure just before you pass it into the GM_CreateCustomVectorLayer function to make sure it is correct?

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • QldblueQldblue Global Mapper User Posts: 17
    edited December 2008
    Mike,

    Thanks for the prompt reply.

    I attach a screen dump showing the aProj: GM_Projection_t variable in the watch window just prior to the call.

    For the purposes of this test I have filled the entire GM_PROJATTRVALUE_T array with the same values but passing the mNumAttrs as the number 1. I have also tries this call without setting the remaining 15 data variable to any values. Perhaps it should be filled with empty values.

    This is my call in delphi.

    function GM_CreateCustomVectorLayer(const aDescription: PChar; const aProj: GM_PROJECTION_T): GM_LayerHandle_t32; stdcall;

    and this is the original call in C

    // Creates a new custom layer for adding vector features to
    GM_DLL_EXPORTED GM_LayerHandle_t32 __stdcall GM_CreateCustomVectorLayer
    (
    const char* aDescription, // IN: Description to use for layer (can be NULL to use default)
    const GM_Projection_t* aProj // IN: Native projection of new layer
    );

    I have also tried pointers:

    {/// Creates a new custom layer for adding vector features to }

    function GM_CreateCustomVectorLayer(const aDescription: PChar; const aProj: PGM_PROJECTION_T): GM_LayerHandle_t32; stdcall; with appropriate change to the call statement

    LayerHandle:= GM_CreateCustomVectorLayer(aDescription, @aProj); //Create the layer and return a pointer

    and this also gives the same outcome.

    The final test is that I have tried to post a layer with 2 attributes (both Zone, -55) and it only accepts the one attribute.

    I assume at the call to GM_CreateCustomVectorLayer the layer info is copied to the new layer created by the dll and I do not need to create a dynamic variable and preserve the variable in memory?

    Regards

    Mark
  • global_mapperglobal_mapper Administrator Posts: 17,238
    edited December 2008
    Mark,

    I'm not really sure how to define a pointer parameter in Delphi, but in things like VB you define it as a reference parameter. Make sure you are doing that. Otherwise I'm not seeing any issues with what you are doing. You don't need to fill the attribute list in any special way, any entries beyond the specified mNumAttrs value are ignored. You also don't need to keep your GM_Projection_t structure around, it is copied.

    If you call GM_GetLayerInfo immediately after the GM_CreateCustomVectorLayer call does the mNativeProj value in the layer info structure not match the projection structure that you just passed in to the create call?

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • QldblueQldblue Global Mapper User Posts: 17
    edited December 2008
    Mike,

    The pointer is declared in

    {/// This type is used to fully describe a projection. }
    type
    PGM_Projection_t = ^GM_Projection_t; //This is a pointer declaration in Delphi
    GM_Projection_t = record

    I have trialled the previous version of the SDK and I still have the same issue.

    I have trialled the mAttrList array set to a length of 1, error reported by CreateCustomVectorLayer and a nil pointer returned.


    "If you call GM_GetLayerInfo immediately after the GM_CreateCustomVectorLayer call does the mNativeProj value in the layer info structure not match the projection structure that you just passed in to the create call?" - Same result no the projection is wrong.

    When I post an object onto the layer Ground_Contours I find that the object is accepted and the mnativerect variable is updated. Furthermore the line object count is incremented. However the object is not displayed and when i save the file GM_ExportPackage the layer is not saved. (View using Global mapper V9).

    I have gone through the structures on several occasions and I guess the solution is going to be very obscure.

    Regards

    Mark
  • global_mapperglobal_mapper Administrator Posts: 17,238
    edited December 2008
    Mark,

    I will do some debugging and make sure this is working on the C++ side so that the problem can be narrowed down to a translation problem.

    One thing to check is the size of your type declarations like GM_UNIT, GM_PROJSYS, etc. All of those enumerations should be a 16-bit integer type. The other thing to check is the structure alignment. There will be 2 bytes of implied padding after the mUnit value and another 2 bytes of implied padding after each mAttr value in a each GM_ProjAttrValue_t structure as per the structure alignment used by the SDK. Can you verify that Delphi is doing the same thing with structure alignment or perhaps just explicitly add the pad bytes?

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • QldblueQldblue Global Mapper User Posts: 17
    edited December 2008
    Mike,

    Thanks for this detail. It was just what I was looking for. I'll work on this over the next few hours and post back to you.

    I note the default byte size of enumerated types is 1 byte, not 4 bytes as required by the SDK, so I am hopeful we are close to a solution

    Cheers and thanks

    Mark
  • QldblueQldblue Global Mapper User Posts: 17
    edited December 2008
    Mike,

    Success.

    It had concerned me for some time that the Delphi defaults for an Enumerated type is 1 byte, but I did not know the dll's settings. I simply set the compiler directive {$Z2} whereby enumerated types become 2 bytes long.

    This should also solve a host of other niggling issues I was having with creating pen types, area types etc.

    Cheers and thanks for your assistance and prompt replies.

    Mark
  • global_mapperglobal_mapper Administrator Posts: 17,238
    edited December 2008
    Mark,

    I'm glad this is solved, but I just wanted to point out that not all of the enumerated types in the SDK are 16-bits. You'll need to check each one in the SDK and see what size it is defined to, then use the appropriate size in Delphi. Some are 8-bit, some 16, and some 32.

    Let me know if I can be of further assistance.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
  • QldblueQldblue Global Mapper User Posts: 17
    edited December 2008
    Mike,

    Thanks for the warning. I can now see the size of the enumeration type in the C declaration.

    BTW in the declaration for GM_Projection_t in projectionTypes.h the variable mNumAttrs has a type "unsigned long". I cannot be entirely sure but the nomenclature used in the SDK would suggest this should be Uint32?

    Regards

    Mark
  • global_mapperglobal_mapper Administrator Posts: 17,238
    edited December 2008
    Mark,

    Yes, unsigned long is the same as uint32. Anything with 'int' or 'long' is 32-bit and 'short' is 16 bit.

    Let me know if I can be of further assistance.

    Thanks,

    Mike
    Global Mapper Support
    support@globalmapper.com
Sign In or Register to comment.