How to use a raster function?

1065
3
Jump to solution
01-31-2018 12:49 AM
BernardoArevalo
New Contributor II

I was wondering if anyone had any experience or examples rendering raster functions as a raster layer.

Every time I pass a raster function with the mask_function the whole raster isn't shown.

I use a function of the following

{  "raster_function":{"type":"Mask_function"},  "raster_function_arguments":  {    "nodata_values":{"double_array":["0.0","1.0","2.0","3.0","4.0","5.0","6.0","7.0","8.0","9.0","10.0","11.0","12.0","13.0","14.0","15.0","16.0","17.0","18.0","19.0","20.0","21.0","22.0","23.0","24.0","25.0","26.0","27.0","28.0","29.0","30.0","31.0","32.0","33.0","34.0","35.0","36.0","37.0","38.0","39.0","40.0","41.0","42.0","43.0","44.0","45.0","46.0","47.0","48.0","49.0","50.0"],"type":"Raster_function_variable"},    "nodata_interpretation":{"nodata_interpretation":"all","type":"Raster_function_variable"},    "raster":{"name":"raster","is_raster":true,"type":"Raster_function_variable"},    "type":"Raster_function_arguments"  },"type":"Raster_function_template"}

I have also tried using instead of string values just regular values in the form of [0.0, 1.0, 2.0, ...]

My code looks like the following

class func loadOnlineRasterImage(function: String, complete: @escaping (AGSRasterLayer) ->()) {

    let x = URL.init(string: "https://utility.arcgis.com/usrsvcs/servers/11e0cb598d77463cbe3b90d5e53f37d6/rest/services/WorldEleva...")

    let imageServiceRaster = AGSImageServiceRaster.init(url: x!)

    let serviceInfo = imageServiceRaster.serviceInfo

    let renderingRule = AGSRenderingRule(renderingRuleJSON: [

      "rasterFunction": function,

      "format":"jpg"

      ])

    

    imageServiceRaster.renderingRule = renderingRule

    imageServiceRaster.load { (error) in

      if let error = error {

        print(error)

        return

      }

      

      let rasterFunction = self.setRasterfunction(raster: imageServiceRaster)

      

      let finalRaster = AGSRaster.init(rasterFunction: rasterFunction)

      

      print("nardo")

      print(error)

      let rasterLayer = AGSRasterLayer(raster: finalRaster)

      complete(rasterLayer)

      

      

      

    }

  }

  

  class func setRasterfunction(raster: AGSImageServiceRaster) -> AGSRasterFunction{

    var x: [Double] = []

    for index in 0...50 {

      x.append(Double(index))

    }

    

    var xx = x.map({abc -> String in  "\(abc)"}).joined(separator: ",")

    

    

    var content = "{  \"raster_function\":{\"type\":\"Mask_function\"},  \"raster_function_arguments\":  {    \"nodata_values\":{\"double_array\":[{{replace}}],\"type\":\"Raster_function_variable\"},    \"nodata_interpretation\":{\"nodata_interpretation\":\"all\",\"type\":\"Raster_function_variable\"},    \"raster\":{\"name\":\"raster\",\"is_raster\":true,\"type\":\"Raster_function_variable\"},    \"type\":\"Raster_function_arguments\"  },\"type\":\"Raster_function_template\"}".replacingOccurrences(of: "{{replace}}", with: xx )

    

    print(content)

    

    FileUtil.writefile(name: "hi.json", content: content  )

    

    let docDir = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)

    let mapUrl = docDir.appendingPathComponent("hi.json")

    

    let rasterFunction = AGSRasterFunction(fileURL: mapUrl)

    // initialize the arguments of the raster function

    let rasterFunctionArguments = rasterFunction.arguments

    print(rasterFunctionArguments.debugDescription)

    

    

    

    let rasterNames = rasterFunctionArguments!.rasterNames

    // assuming rasterNames has 2 entries, set the 2 rasters

    rasterFunctionArguments!.setRaster(raster, withName: rasterNames[0])

    return rasterFunction

  }

The first function uses the second function to create a raster function and load it into a new agsraster which is then placed in a layer. I know that the file is properly being written as I've checked it. I'm not sure what I'm doing wrong : \

Does anyone have any working examples or advice?

0 Kudos
1 Solution

Accepted Solutions
PhilipGruenler
Esri Contributor

In the loadOnlineRasterImage function, imageServiceRaster is going out of scope.  The call to load is asynchronous; when the completion block is executed and tries to use imageServiceRaster, it has gone out of scope.  With that fixed, your code is working for me.  I made two other minor changes.  I wasn't sure why you were setting the renderingRule so I removed that code.  And instead of writing the JSON to disk and reading it back, I changed it to use the fromJSON method, like this:

let rasterFunction = AGSRasterFunction.fromJSON(content, error: nil) as? AGSRasterFunction

I hope that helps.

Phil

View solution in original post

0 Kudos
3 Replies
BernardoArevalo
New Contributor II

So I managed to get the raster function working with a saved raster file. However when I try to apply a raster function to a AGSImageServiceRaster the raster never gets rendered. When checking the web requests that go out, there are none that go out to the export service that are used to populate the raster : \

Has anyone ever used an AGSImageServiceRaster with a raster function?

0 Kudos
PhilipGruenler
Esri Contributor

In the loadOnlineRasterImage function, imageServiceRaster is going out of scope.  The call to load is asynchronous; when the completion block is executed and tries to use imageServiceRaster, it has gone out of scope.  With that fixed, your code is working for me.  I made two other minor changes.  I wasn't sure why you were setting the renderingRule so I removed that code.  And instead of writing the JSON to disk and reading it back, I changed it to use the fromJSON method, like this:

let rasterFunction = AGSRasterFunction.fromJSON(content, error: nil) as? AGSRasterFunction

I hope that helps.

Phil

0 Kudos
MichaelBranscomb
Esri Frequent Contributor

Hi,

Confirming this works in the following example (C# WPF):

async Task AddRasterAndSetBackgroundColorValue() 
{
    try
    {
        // Create a raster dataset from a local file raster.
        Raster raster = new Raster(@"..\FileRaster.tif");

        // Await the Load to catch any errors.
        await raster.LoadAsync();

        // Create a raster function from the JSON string using the static/Shared method called: RasterFunction.FromJson(json as String)
        RasterFunction rasterFunction = RasterFunction.FromJson(jsonFunction);

        // Get the raster function arguments
        RasterFunctionArguments rasterFunctionArguments = rasterFunction.Arguments;
                
        // Get the list of raster names from the raster function arguments.
        IReadOnlyList<string> rasterNames = rasterFunctionArguments.GetRasterNames();

        // Set the local file raster as a raster name argument.
        rasterFunctionArguments.SetRaster(rasterNames[0], raster);

        // Create a new raster based on the raster function.
        Raster rasterWithFunction = new Raster(rasterFunction);

        // Create a new raster layer from the raster with function applied.
        RasterLayer rasterLayer = new RasterLayer(rasterWithFunction);

        // Add RasterLayer with function to Map OperationalLayers collection.
        Map.OperationalLayers.Add(rasterLayer);
    }
    catch (Exception ex)
    {
        // TODO : Handle Errors
    }
}

string jsonFunction =
@"{
    ""raster_function"":{""type"":""Mask_function""},
    ""raster_function_arguments"":
    {
        ""nodata_values"":{""double_array"":[0],""type"":""Raster_function_variable""},
        ""nodata_interpretation"":{""nodata_interpretation"":""all"",""type"":""Raster_function_variable""},
        ""raster"":{""name"":""raster"",""is_raster"":true,""type"":""Raster_function_variable""},
        ""type"":""Raster_function_arguments""
   },
    ""type"":""Raster_function_template""
}";‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Mike

0 Kudos