Cannot identify the layer_input specified in tp.input arguments

edited June 2014 in Ruby Scripting
Hi Matthias,

When performing the script in queues for tile_processor, I got the following error:
*** ERROR: Worker thread: Unknown variable or function 'l1' at position 1 (..l1 & l2).area(bx))

Can you please help to point out my wrong?

The snapshot of codes causing the error are:
-------------------------------------
...
lyname = "l1"
tp.input(lyname, ly, tcindex, RBA::LayerInfo::new(layer, datatype)) # the layer_name was passed thru string variable lyname
...
lyname = "l2"
tp.input(lyname, ly, tcindex, RBA::LayerInfo::new(layer, datatype))
...
all_ly = "(l1 & l2).area(bx)"
tp.var("a", all_ly) # is this the right way to define "a" for execution in queue scripts?

tp.queue(<<END)
var bx = _tile.bbox;
_output(image, to_f(a) / to_f(bx.area))
END
-------------------------------------
I have removed the complexity to emphasis the problem only. Because of that, the codes may look strange in those variables definition. Never mind.

It looks that the tile processor cannot identify the layer variables.

Thanks

Comments

  • edited November -1

    Hi,

    I see, that requires some explanation.

    Basically the tiling processor runs in two different domains. The "outside" domain feeds it with the parameters required, while int "inside" domain is executed for every tile. Both domains are strictly separated.

    The skeleton is that:

    tp = RBA::TilingProcessor::new
    
    ... configure tp
    
    tp.queue("script")
    
    tp.execute
    

    With Ruby's inline string notation the "queue" call is easier to write for a multi-line script:

    tp.queue(<<END)
    script
    END
    

    The script itself is an "expression", it's not Ruby. You can declare variables with "var name". Statements have to be separated by ";". There is no "if", but you can use "?:" and "&&" or "||" shortcut evaluation for conditional statements.

    Communication between the script and the outside domain happens through the configuration methods of the tiling processor, i.e. "input", "output" and "var". "var" just creates a variable and it will become available in the script. So if you want to pass a value, you'll have to do it like this:

    tp.var("f", 5.0)
    tp.queue(<<END)
      var area_times_f = l1.area * f;
      output(image, area_times_f)
    END
    

    "input" and "output" will make other variables available which can be used as input (layout) and as targets for outputting data.

    Certain functions exist which perform actions inside the script or deliver tile information. These functions are prefixed with an underscore to avoid name conflicts. Specifically "_output" is required which delivers data to the outside domain and "_tile" which delivers a layout object holding a rectangle representing the current tile.

    The computation of the boolean operations should happen inside the script too.

    So your code should look like this:

    tp.queue(<<END)
      var bx = _tile.bbox;
      var a = (l1 & l2).area(bx);
      _output(image, to_f(a) / to_f(bx.area))
    END
    

    I hope this clears up some of the confusion created. There is a more detailed description available along with the TilingProcessor class documentation.

    Regards,

    Matthias

  • edited June 2014
    Thanks Matthias.
    I didn't explicitly code "var a = (l1 & l2).area(bx)" in the script block (between tp.queue(<<END) and END) because that the layer_inputs are unknown. In my function, the layers are user input and the number of layers is flexible so that I cannot hardcode them.
    To define the tp.input, I used lyname variable as follows and lyname stores one of the user input layers and loop.
    tp.input(lyname, ly, tcindex, RBA::LayerInfo::new(layer, datatype))

    Is there a way to pass a expression (non-ruby) from "outside" domain into the "inside" domain??

    I looked into manual doc and the class decriptions on web, but cannot find a clue.

    Best Regards,
  • edited November -1

    Hi,

    I see your point.

    Basically you can also code the "inside" script dynamically. It's a plain string.

    For example if you want to combine the layers 1, 5, 6, 7, 10 and 11:

    layers = [ 1, 5, 6, 7, 10, 11 ]
    
    # combine theses layers
    layers.each do |layer|
      tp.input("input_#{layer}", ly, tcindex, RBA::LayerInfo(layer, datatype))
    end
    
    # create the script: it will be like
    #   var l = input_1;
    #   l = l + input_5;
    #   ...
    #   bx = _tile.bbox; a = l.area(bx); _output(image, to_f(a) / to_f(bx.area))
    script = ""
    layers.each do |layer|
      if script == ""
        script += "var l = input_#{layer};"
      else
        script += "l = l + input_#{layer};"
      end
    end
    script += "bx = _tile.bbox; a = l.area(bx); _output(image, to_f(a) / to_f(bx.area))"
    
    # use the script
    tp.queue(script);
    

    Of course the list can be dynamic.

    Matthias

Sign In or Register to comment.