Community Spring Cleaning week is here! Join your fellow Maveryx in digging through your old posts and marking comments on them as solved. Learn more here!

Dev Space

Customize and extend the power of Alteryx with SDKs, APIs, custom tools, and more.
SOLVED

Accessing Spatial Functionality from Plugin SDK

SigIsaac
7 - Meteor

Hello Alteryx Developers,

 

I'm testing Alteryx Designer 2018.1 x64 to see if our company can integrate functionality from our software systems with Alteryx Designer as plug-in tools.

I've looked at the C++ and C# Custom Tools samples and have a basic idea of how the interface works. What I can't figure out is how to read and write spatial fields in a record. For example, our tools would have to be able to create polygons based on some input values based on the tool configuration and record values and then store them in the record as a spatial field. Looking through the C++ .h files and the .NET object browser for the AlteryxRecordInfo.NET and AlteryxGuiToolkit assemblies, I don't see anything that would allow me to do this.

 

I am new to the Alteryx world, so maybe I am looking in the wrong places. I would greatly appreciate anyone steering me in the right direction on this.

 

Many thanks in advance,

Sig Isaac

11 REPLIES 11
TashaA
Alteryx Alumni (Retired)

Really great question @SigIsaac

 

I'm reaching out to some of our architects to see what spatial capabilities (if any) can be accessed through the SDKs.

SigIsaac
7 - Meteor

Great!  Look forward to any information you can provide.

RobertB
Alteryx Alumni (Retired)

@SigIsaac -

 

  In either the C++ or C# SDKs, you can read and write data to spatial fields using GetAsString() and SetFromString() and passing the object in GeoJSON format.   These will do the same conversion that you get by switching a string to a spatial object (or vice-versa) using a Select tool in the Designer, so that's a good way to get an example of the string it is looking for.

 

In c++ you can also get/set spatial fields as blobs, but you can't do much of anything with the blob besides store it or set it to another field.  So GeoJSON is the way to go if you want to create the spatial objects in the first place or crack open existing ones and manipulate them.

 

-Rob Bryan

SigIsaac
7 - Meteor

Thanks, Robert, I'll do some research on GeoJSON and give that a try.

SigIsaac
7 - Meteor

So I'm getting back to my work in developing a custom Alteryx tool and I'm taking Rob's advice of using GeoJSON strings to work with spatial fields.  However, I find that when I try to set the value of a spatial field with FieldBase.SetFromString() an exception is thrown.  

 

Here is a test code snippet from my II_PushRecord(AlteryxRecordInfoNet.RecordData pRecord) implementation:

 

AlteryxRecordInfoNet.FieldBase spatialField = m_recordInfoOut[inFieldCount]; // Previously created spatial field
spatialField.SetFromString(recordOut, "{ \"type\": \"Point\", \"coordinates\": [ -119.561378, 47.307156 ] }"); // THROWS EXCEPTION.

 

The exception error is pretty generic and does not provide much info: "External component has thrown an exception."

 

I got the GeoJSON string by looking at an existing point spatial record, so the format should be correct.

 

Is there perhaps a problem with the quotation marks in the GeoJSON string?  Any suggestions would be appreciated.

TashaA
Alteryx Alumni (Retired)

@RobertB, tagging you.

PaulN
Alteryx Alumni (Retired)

Hey @SigIsaac,

 

From my experience, it's not possible to translate a string into a blob (or spatial blob directly).

 

SrcLib.dll provides ConvertFromGeoJSON (void ConvertFromGeoJSON(const char* pszJson, unsigned char **pSpatialObj, unsigned int *pLen)) that can convert a GeoJSON string into a spatial object. Then SetFromSpatialBlob() should help you to achieve your goals.

 

Unfortunately I don't have an example ready in C#/C++...

 

Thanks,

 

Paul Noirel

Sr Customer Support Engineer, Alteryx

 

SigIsaac
7 - Meteor

Thanks, Paul Noirel, tapping into the SrcLib.dll was the key to solving this problem.  Many thanks for that suggestion.  (It is a bit of a hack, though, and having that functionality available in the SDK would be preferable for the future.)

 

For anyone else needing similar functionality, here is a simplified version of my code.

 

bool ConvertFromGeoJSON(const std::string& geoJSON, unsigned char** spatialObj, unsigned int* blobSize)
{

typedef int(__cdecl *FunctionConvertGeoJSON)(const char* pszJson, unsigned char **pSpatialObj, unsigned int *pLen);

std::wstring pathSrcDll = L"C:\\Program Files\\AlteryxServer\\bin\\SrcLib.dll"; // Hard-coded for now

 

*spatialObj = nullptr;
*blobSize = 0;
bool success = false;

 

HINSTANCE hinstLib = LoadLibrary(pathSrcDll.c_str());
if (hinstLib != NULL)
{
    ProcConvertGeoJSON = (FunctionConvertGeoJSON)GetProcAddress(hinstLib, "ConvertFromGeoJSON");
    if (NULL != ProcConvertGeoJSON)
    {
        (ProcConvertGeoJSON)(geoJSON.c_str(), spatialObj, blobSize);
        success = true;
    }
    FreeLibrary(hinstLib);
}

return success;

}

 

 

// Calling code in OutputDetailRecord()

...

 const FieldBase* pFieldSpatialBlob = m_recordInfoOut.GetFieldByName(DriveTimeSpatialField.c_str(), true);

...

unsigned char* spatialBlob = nullptr;
unsigned int blobSize = 0;
if (ConvertFromGeoJSON(geoJSON, &spatialBlob, &blobSize))
{
    SRC::BlobVal blobVal;
    blobVal.pValue = spatialBlob;
    blobVal.nLength = blobSize;

    pFieldSpatialBlob->SetFromSpatialBlob(currentRecordOut.Get(), blobVal);
}

else

{

    pFieldSpatialBlob->SetNull(currentRecordOut.Get());

}

PaulN
Alteryx Alumni (Retired)

Great job @SigIsaac!!! Many thanks for sharing your code! 

 

I will let @TashaA taking note of your point for the future of the SDK(s).

 

Have a nice day,

 

Paul Noirel

Sr Customer Support Engineer, Alteryx