Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
calculate_functors [2026/07/01 06:37] hermann [Overview] |
calculate_functors [2026/07/23 03:55] (current) hermann |
||
|---|---|---|---|
| Line 12: | Line 12: | ||
| | [[Calculate Value]] | ''$'' | Single scalar value | Once, with no spatial or row context | | | [[Calculate Value]] | ''$'' | Single scalar value | Once, with no spatial or row context | | ||
| | [[Calculate Lookup Table Values]] | ''%'' | Lookup table (values computed) | Once per row of a base lookup table | | | [[Calculate Lookup Table Values]] | ''%'' | Lookup table (values computed) | Once per row of a base lookup table | | ||
| - | | [[Calculate Lookup Table Keys And Values]] | ''<nowiki>%%</nowiki>'' | Lookup table (keys and values computed) | Once per row — two separate expressions | | + | | [[Calculate Lookup Table Keys And Values]] | <nowiki>%%</nowiki> | Lookup table (keys and values computed) | Once per row — two separate expressions | |
| - | The expression language, including all arithmetic, logical, conditional, spatial, and stochastic operators, is described in full in [[#the_expression_language|The Expression Language]] section. Per-functor restrictions and the availability of each operator category are noted both in each functor's own section and in the relevant expression-language subsections. | + | The shorthand symbols are also referred to as **abbreviated syntax** — both terms mean the same thing and are used interchangeably in this documentation and in the Dinamica EGO GUI options. |
| + | |||
| + | The expression language, including all arithmetic, logical, conditional, spatial, and stochastic operators, is described in full in [[#the_expression_language|The Expression Language]] section. Per-functor restrictions and the availability of each operator category are noted both in each functor's own section and in the relevant expression-language subsections. For a complete description of the EGO Script syntax used to call these functors — including the shorthand symbols, hook blocks, and conversion between forms — see [[ego_script#calculator_functor_shorthand|Calculator functor shorthand]] in the EGO Script documentation. | ||
| ---- | ---- | ||
| Line 33: | Line 35: | ||
| | Null Value | Null Value Type | No | Based on Cell Type | Sentinel value representing "no data" in the output. | | | Null Value | Null Value Type | No | Based on Cell Type | Sentinel value representing "no data" in the output. | | ||
| | Result Is Sparse | Boolean Value Type | No | False | If ''True'', only non-null cells are stored — saves memory but slows random access. | | | Result Is Sparse | Boolean Value Type | No | False | If ''True'', only non-null cells are stored — saves memory but slows random access. | | ||
| - | | Result Format | Map Type | No | None | Optional reference map whose spatial format (extent, resolution, projection) is applied to the output. Category information in the reference map is ignored. | | + | | Result Format | Map Type | No | None | Optional reference map whose spatial format (extent, resolution, projection) is applied to the output. Category information in the reference map is ignored. Prefer this port over a ''NumberMap'' hook when the map is needed only for format purposes — a hook defines an identifier in the expression namespace and blocks abbreviated syntax if that identifier is unused in the expression. | |
| ==== Output ==== | ==== Output ==== | ||
| Line 42: | Line 44: | ||
| ==== Available expression features ==== | ==== Available expression features ==== | ||
| - | All expression language features are available: image operators (''iX'', ''iX[line,col]''), the ''line'' and ''column'' spatial keywords, lookup table operators, multi-column table operators, neighbourhood functions (''nbMin'', ''nbMax'', ''nbAverage'', etc.), neighbourhood indexing (''nbMinRef'', ''nbMaxRef''), and the convolution operator (''nbConvol''). | + | All expression language features are available: image operators (''iX'', ''iX[line,col]''), the ''line'' and ''column'' spatial keywords, lookup table operators ([[#5_lookup_table_operators|section 5]]), multi-column table operators ([[#6_multi-column_table_operators|section 6]]), neighbourhood functions (''nbMin'', ''nbMax'', ''nbAverage'', etc. — [[#7_image_neighborhood_functions|section 7]]), neighbourhood indexing (''nbMinRef'', ''nbMaxRef'' — [[#8_image_neighborhood_indexing_functions|section 8]]), and the convolution operator (''nbConvol'' — [[#9_convolution_operator|section 9]]). |
| ---- | ---- | ||
| Line 48: | Line 50: | ||
| ===== CalculateCategoricalMap (''##'') ===== | ===== CalculateCategoricalMap (''##'') ===== | ||
| - | Computes a new **categorical raster map** using an expression. Functionally identical to ''CalculateMap'' — the same inputs, parameters, and expression language apply — but the output is typed as a **categorical map**, which preserves category semantics for downstream functors that distinguish categorical maps from continuous maps (e.g., [[Calc Areas]], [[For Each Category]]). | + | Computes a new **categorical raster map** using an expression. Functionally identical to [[Calculate Map]] — the same inputs, parameters, and expression language apply — but the output is typed as a **categorical map**, which preserves category semantics for downstream functors that distinguish categorical maps from continuous maps (e.g., [[Calc Areas]], [[For Each Category]]). |
| Use [[Calculate Categorical Map]] when the expression produces integer class codes rather than measured or continuous values. A common pattern is reclassifying a continuous map into discrete categories based on thresholds. | Use [[Calculate Categorical Map]] when the expression produces integer class codes rather than measured or continuous values. A common pattern is reclassifying a continuous map into discrete categories based on thresholds. | ||
| Line 59: | Line 61: | ||
| | Null Value | Null Value Type | No | Based on Cell Type | Sentinel value representing "no data" in the output. | | | Null Value | Null Value Type | No | Based on Cell Type | Sentinel value representing "no data" in the output. | | ||
| | Result Is Sparse | Boolean Value Type | No | False | If ''True'', only non-null cells are stored. | | | Result Is Sparse | Boolean Value Type | No | False | If ''True'', only non-null cells are stored. | | ||
| - | | Result Format | Map Type | No | None | Optional reference map whose spatial format is applied to the output. | | + | | Result Format | Map Type | No | None | Optional reference map whose spatial format is applied to the output. Prefer this port over a ''NumberMap'' hook when the map is needed only for format purposes — a hook defines an identifier in the expression namespace and blocks abbreviated syntax if that identifier is unused in the expression. | |
| ==== Output ==== | ==== Output ==== | ||
| Line 68: | Line 70: | ||
| ==== Available expression features ==== | ==== Available expression features ==== | ||
| - | Identical to ''CalculateMap'': all operators, spatial keywords, neighbourhood functions, indexing functions, and convolution are available. | + | Identical to [[Calculate Map]]: all operators, spatial keywords, neighbourhood functions, indexing functions, and convolution are available. |
| ---- | ---- | ||
| Line 90: | Line 92: | ||
| ==== Available expression features ==== | ==== Available expression features ==== | ||
| - | **Available:** all arithmetic and logical operators (sections [[#1_general_operators|1]] and [[#2_general_functions|2]]), scalar value references (''vX''), and lookup table queries (''tX[...]'') in all single-key and multi-column forms. | + | **Available:** all arithmetic and logical operators (sections [[#1_general_operators|1]] and [[#2_general_functions|2]]), scalar value references (''vX''), and lookup table queries (''tX[...]'') in all single-key and multi-column forms ([[#5_lookup_table_operators|section 5]], [[#6_multi-column_table_operators|section 6]]). |
| - | **Not available:** image operators (''iX'', ''iX[line,col]''), the ''line'' and ''column'' spatial keywords, neighbourhood functions, neighbourhood indexing functions, and the convolution operator. These all require a cell or row context that does not exist in ''CalculateValue''. | + | **Not available:** image operators (''iX'', ''iX[line,col]''), the ''line'' and ''column'' spatial keywords, neighbourhood functions, neighbourhood indexing functions, and the convolution operator. These all require a cell or row context that does not exist in [[Calculate Value]]. |
| ---- | ---- | ||
| Line 108: | Line 110: | ||
| | Key Column Name | String | **Yes** | — | Name of the key column in the output lookup table. | | | Key Column Name | String | **Yes** | — | Name of the key column in the output lookup table. | | ||
| | Value Column Name | String | **Yes** | — | Name of the value column in the output lookup table. | | | Value Column Name | String | **Yes** | — | Name of the value column in the output lookup table. | | ||
| - | | Base Lookup Table | Lookup Table Type | No | ''.none'' | A lookup table whose key set drives iteration. When ''.none'', the lowest-indexed connected ''NumberTable'' (verbose form) or the first lookup table named in the expression (shorthand form) is used instead — not a union of all connected tables. | | + | | Base Lookup Table | Lookup Table Type | No | ''.none'' | A lookup table whose key set drives iteration. When ''.none'', the ''NumberTable'' hook with the lowest list index that is connected to a **lookup table** (not a regular table) is used as the row source (verbose form), or the first lookup table named in the expression (shorthand form) — not a union of all connected tables. Prefer this port over a ''NumberTable'' hook when the table is needed only to define the row set and is not referenced in the expression, to keep abbreviated syntax available. | |
| ==== Output ==== | ==== Output ==== | ||
| Line 121: | Line 123: | ||
| ==== Available expression features ==== | ==== Available expression features ==== | ||
| - | **Available:** arithmetic and logical operators, scalar references (''vX''), lookup table queries (''tX[...]'') in all single-key and multi-column forms, ''line'' (as the current row key), and ''column'' (as the current row's value in the base lookup table). | + | **Available:** arithmetic and logical operators (sections [[#1_general_operators|1]] and [[#2_general_functions|2]]), scalar references (''vX''), lookup table queries (''tX[...]'') in all single-key and multi-column forms ([[#5_lookup_table_operators|section 5]], [[#6_multi-column_table_operators|section 6]]), ''line'' (as the current row key), and ''column'' (as the current row's value in the base lookup table). |
| **Not available:** ''iX'', ''iX[line,col]'', neighbourhood functions, neighbourhood indexing, and convolution. There is no spatial grid. | **Not available:** ''iX'', ''iX[line,col]'', neighbourhood functions, neighbourhood indexing, and convolution. There is no spatial grid. | ||
| Line 138: | Line 140: | ||
| | Key Column Name | String | **Yes** | — | Name of the key column in the output lookup table. | | | Key Column Name | String | **Yes** | — | Name of the key column in the output lookup table. | | ||
| | Value Column Name | String | **Yes** | — | Name of the value column in the output lookup table. | | | Value Column Name | String | **Yes** | — | Name of the value column in the output lookup table. | | ||
| - | | Base Lookup Table | Lookup Table Type | No | ''.none'' | A lookup table whose row set drives iteration. | | + | | Base Lookup Table | Lookup Table Type | No | ''.none'' | A lookup table whose row set drives iteration. Prefer this port over a ''NumberTable'' hook when the table is needed only to define the row set and is not referenced in the expression, to keep abbreviated syntax available. | |
| ==== Output ==== | ==== Output ==== | ||
| Line 147: | Line 149: | ||
| ==== Available expression features ==== | ==== Available expression features ==== | ||
| - | Same as ''CalculateLookupTableValues'': ''line'' represents the key of the current row in the base table, and ''column'' represents the value already associated with that key; ''vX'' and ''tX[...]'' are available; spatial and image operators are not. Both the key expression and the value expression share the same set of connected operands. | + | Same as [[Calculate Lookup Table Values]]: ''line'' represents the key of the current row in the base table, and ''column'' represents the value already associated with that key; ''vX'' and ''tX[...]'' are available (sections [[#5_lookup_table_operators|5]] and [[#6_multi-column_table_operators|6]]); spatial and image operators are not. Both the key expression and the value expression share the same set of connected operands. |
| ---- | ---- | ||
| Line 153: | Line 155: | ||
| ====== Connecting Data Inputs ====== | ====== Connecting Data Inputs ====== | ||
| - | All data referenced in any expression must be connected to the functor's ports before writing the expression. The same port types apply across all five functors: | + | All data referenced in any expression must be connected to the functor's ports before writing the expression. This is done through **hook** functors — [[Number Map]], [[Number Table]], and [[Number Value]] — which bind a connected data source to a numbered identifier used inside the expression. The same port types apply across all five functors: |
| - | * **Maps** are connected via a [[Number Map]] port → referenced as ''i1'', ''i2'', …, ''i100'' | + | * **Maps** are connected via a [[Number Map]] hook → referenced as ''i1'', ''i2'', …, ''i100'' |
| - | * **Tables and lookup tables** are connected via a [[Number Table]] port → referenced as ''t1'', ''t2'', …, ''t100'' | + | * **Tables and lookup tables** are connected via a [[Number Table]] hook → referenced as ''t1'', ''t2'', …, ''t100'' |
| - | * **Scalar values** are connected via a [[Number Value]] port → referenced as ''v1'', ''v2'', …, ''v100'' | + | * **Scalar values** are connected via a [[Number Value]] hook → referenced as ''v1'', ''v2'', …, ''v100'' |
| - | > **Tip:** Give every connected functor a descriptive alias. The expression editor lists all available identifiers with their aliases at the top, making complex models much easier to read and maintain. The alias is also what generates the functor's variable name, and that variable name is exactly what the shorthand notation references: a map aliased ''regions'', for example, is bound to the variable ''regions'' and is then referenced in a shorthand expression as ''#regions'', a table or lookup table as ''%regions'', and a value as ''$regions''. | + | > **Tip:** Give every connected functor a descriptive alias. The expression editor lists all available identifiers with their aliases at the top, making complex models much easier to read and maintain. The alias is also what generates the functor's variable name, and that variable name is exactly what the shorthand notation references: a map aliased ''regions'', for example, is bound to the variable ''regions'' and is then referenced in a shorthand expression as ''#regions'', a table or lookup table as ''%regions'', and a value as ''$regions''. See [[ego_script#calculator_functor_shorthand|Calculator functor shorthand]] for details on the shorthand notation. |
| - | > **Note:** Map connections (''NumberMap'' / ''iX'') are only meaningful in ''CalculateMap'' and ''CalculateCategoricalMap''. In ''CalculateValue'', ''CalculateLookupTableValues'', and ''CalculateLookupTableKeysAndValues'' there is no cell context, and ''iX'' references cannot be used in the expression. | + | > **Note:** Map hook connections (''NumberMap'' / ''iX'') are only meaningful in [[Calculate Map]] and [[Calculate Categorical Map]]. In [[Calculate Value]], [[Calculate Lookup Table Values]], and [[Calculate Lookup Table Keys And Values]] there is no cell context, and ''iX'' references cannot be used in the expression. |
| ---- | ---- | ||
| Line 174: | Line 176: | ||
| ^ Symbol ^ Refers to ^ Available in ^ | ^ Symbol ^ Refers to ^ Available in ^ | ||
| - | | ''iX'' | Value of map X at the current cell | ''CalculateMap'', ''CalculateCategoricalMap'' only | | + | | ''iX'' | Value of map X at the current cell | [[Calculate Map]], [[Calculate Categorical Map]] only | |
| | ''tX'' | Connected table or lookup table X (used with a bracket operator) | All five functors | | | ''tX'' | Connected table or lookup table X (used with a bracket operator) | All five functors | | ||
| | ''vX'' | Connected scalar value X | All five functors | | | ''vX'' | Connected scalar value X | All five functors | | ||
| - | | ''line'' | Spatial row index of the current cell, **starting at 1** //(map calculators)// **or** key of the current row //(table calculators)// | All except ''CalculateValue'' | | + | | ''line'' | Spatial row index of the current cell, **starting at 1** //(map calculators)// **or** key of the current row //(table calculators)// | All except [[Calculate Value]] | |
| - | | ''column'' | Spatial column index of the current cell, **starting at 1** //(map calculators)// **or** value associated with the current row's key //(table calculators)// | All except ''CalculateValue'' | | + | | ''column'' | Spatial column index of the current cell, **starting at 1** //(map calculators)// **or** value associated with the current row's key //(table calculators)// | All except [[Calculate Value]] | |
| X ranges from 1 to 100. In logical expressions, **zero is false** and any non-zero value is true. | X ranges from 1 to 100. In logical expressions, **zero is false** and any non-zero value is true. | ||
| Line 203: | Line 205: | ||
| | 6 | **Divide** | ''EXPR / EXPR'' | | ''i1 / i2'' | | | 6 | **Divide** | ''EXPR / EXPR'' | | ''i1 / i2'' | | ||
| | 6 | **Modulo** | ''EXPR % EXPR'' | Remainder after integer division | ''i1 % 100'' | | | 6 | **Modulo** | ''EXPR % EXPR'' | Remainder after integer division | ''i1 % 100'' | | ||
| - | | 7 | **Power** | ''EXPR ^ EXPR'' | Exponentiation | ''i1 ^ 3'' | | + | | 7 | **Power** | ''EXPR <nowiki>^</nowiki> EXPR'' | Exponentiation | ''i1 <nowiki>^</nowiki> 3'' | |
| - | | 8 | **Catch Error (''?'')** | ''EXPR ? EXPR'' | If the left expression produces an algebraic error (division by zero, key not found, etc.), return the right expression instead. | ''(i1 / i2) ? (i1 - i2)'' | | + | | 8 | **Catch Error (''?'')** | ''EXPR ? EXPR'' | If the left expression produces an algebraic error (division by zero, key not found, etc.), evaluate and return the **fallback expression** instead. The fallback can be any expression, including another calculation, a conditional, or a nested ''?''. | ''(i1 / i2) ? (i1 - i2)'' | |
| | 9 | **Boolean Not** | ''not EXPR'' / ''! EXPR'' | Inverts a boolean value. | ''not isNull(i1)'' | | | 9 | **Boolean Not** | ''not EXPR'' / ''! EXPR'' | Inverts a boolean value. | ''not isNull(i1)'' | | ||
| | 9 | **Negate** | ''-EXPR'' | Arithmetic negation. | ''-ceil(i1 + i2)'' | | | 9 | **Negate** | ''-EXPR'' | Arithmetic negation. | ''-ceil(i1 + i2)'' | | ||
| - | |||
| - | > **Note on null and equality:** Writing ''i1 == null'' does **not** test for null — because null participates in no arithmetic comparison, it always produces null itself, poisoning the expression. Always use ''isNull(i1)'' instead. See the [[#null_value_handling|Null Value Handling]] section for full details. | ||
| ---- | ---- | ||
| Line 226: | Line 226: | ||
| | Asin | ''asin(EXPR)'' | Arcsine; output in radians | ''asin(i1 + i2)'' | | | Asin | ''asin(EXPR)'' | Arcsine; output in radians | ''asin(i1 + i2)'' | | ||
| | Atan | ''atan(EXPR)'' | Arctangent; output in radians | ''atan(i1 + i2)'' | | | Atan | ''atan(EXPR)'' | Arctangent; output in radians | ''atan(i1 + i2)'' | | ||
| - | | Exp | ''exp(EXPR)'' | Natural exponential (e^x) | ''exp(i1 + i2)'' | | + | | Exp | ''exp(EXPR)'' | Natural exponential (e<nowiki>^</nowiki>x) | ''exp(i1 + i2)'' | |
| | Natural Logarithm | ''ln(EXPR)'' | log base e | ''ln(i1 / i4)'' | | | Natural Logarithm | ''ln(EXPR)'' | log base e | ''ln(i1 / i4)'' | | ||
| | Log base 10 | ''log(EXPR)'' | | ''log(i1 / i4)'' | | | Log base 10 | ''log(EXPR)'' | | ''log(i1 / i4)'' | | ||
| Line 239: | Line 239: | ||
| ===== Clamping Functions ===== | ===== Clamping Functions ===== | ||
| + | |||
| + | All clamping functions are available in all five calculator functors. | ||
| ^ Function ^ Syntax ^ Description ^ Example ^ | ^ Function ^ Syntax ^ Description ^ Example ^ | ||
| Line 246: | Line 248: | ||
| ===== Random / Stochastic Functions ===== | ===== Random / Stochastic Functions ===== | ||
| - | These functions generate a new random sample **for each evaluation unit** each time the expression is evaluated. In ''CalculateMap'' and ''CalculateCategoricalMap'', this means one sample per cell, making them suitable for spatially stochastic models. In ''CalculateLookupTableValues'' and ''CalculateLookupTableKeysAndValues'', one sample is drawn per table row. In ''CalculateValue'', a single sample is drawn for the whole expression. | + | All stochastic functions are available in all five calculator functors. They generate a new random sample **for each evaluation unit** each time the expression is evaluated. In [[Calculate Map]] and [[Calculate Categorical Map]], this means one sample per cell, making them suitable for spatially stochastic models. In [[Calculate Lookup Table Values]] and [[Calculate Lookup Table Keys And Values]], one sample is drawn per table row. In [[Calculate Value]], a single sample is drawn for the whole expression. |
| ^ Function ^ Syntax ^ Description ^ Example ^ | ^ Function ^ Syntax ^ Description ^ Example ^ | ||
| Line 257: | Line 259: | ||
| ^ Function ^ Syntax ^ Description ^ Example ^ | ^ Function ^ Syntax ^ Description ^ Example ^ | ||
| - | | Literal value | ''2'', ''-3.5e-2'', etc. | Any numeric literal, including scientific notation. | ''2 + i1 / -3.5e-2'' | | + | | Literal value | ''2'', ''-3.5e-2'', etc. | Any numeric literal, including scientific notation. Available in all five calculator functors. | ''2 + i1 / -3.5e-2'' | |
| - | | Abort | ''abort'' | Immediately halts model execution. Useful as a guard inside a conditional to catch unexpected states. | ''if i1 > 0 then i1 * i2 + 4 else abort'' | | + | | Abort | ''abort'' | Immediately halts model execution. Useful as a guard inside a conditional to catch unexpected states. Available in all five calculator functors. | ''if i1 > 0 then i1 * i2 + 4 else abort'' | |
| + | | Is Null | ''isNull(EXPR)'' | Returns 1 if the expression is null, 0 otherwise. Immune to the null poisoning rule — always resolves to 0 or 1. Available in all five calculator functors. | ''if not isNull(i1) then i1 else i2'' | | ||
| + | | Null | ''null'' | Makes the current evaluation unit null — the cell, row, or scalar result is marked as missing and any further arithmetic using it propagates null. This is an **abstract** null, not a numeric value; it cannot be used in arithmetic and has no numeric representation. Available in all five calculator functors. | ''if i1 > 2 then i1 else null'' | | ||
| + | |||
| + | > **Note on null and equality:** Writing ''i1 == null'' does **not** test for null — because null participates in no arithmetic comparison, it always produces null itself, poisoning the expression. Always use ''isNull(i1)'' instead. See the [[#null_value_handling|Null Value Handling]] section for full details. | ||
| ---- | ---- | ||
| Line 273: | Line 279: | ||
| ====== 4. Image Operators and Functions ====== | ====== 4. Image Operators and Functions ====== | ||
| - | > **Availability:** ''CalculateMap'' and ''CalculateCategoricalMap'' only. These operators require a cell context that does not exist in ''CalculateValue'', ''CalculateLookupTableValues'', or ''CalculateLookupTableKeysAndValues''. | + | > **Availability:** [[Calculate Map]] and [[Calculate Categorical Map]] only. These operators require a cell context that does not exist in [[Calculate Value]], [[Calculate Lookup Table Values]], or [[Calculate Lookup Table Keys And Values]]. |
| > | > | ||
| > **Exception:** ''line'' and ''column'' are also available in the two lookup table calculators, where they take on row-oriented meanings instead of spatial ones: ''line'' is the key of the current row, and ''column'' is the value associated with that key in the base lookup table being iterated. | > **Exception:** ''line'' and ''column'' are also available in the two lookup table calculators, where they take on row-oriented meanings instead of spatial ones: ''line'' is the key of the current row, and ''column'' is the value associated with that key in the base lookup table being iterated. | ||
| Line 279: | Line 285: | ||
| ^ Operator ^ Syntax ^ Description ^ Example ^ | ^ Operator ^ Syntax ^ Description ^ Example ^ | ||
| | Get Image Value | ''iX'' | Returns the value of image X at the **current cell**. | ''i2'' | | | Get Image Value | ''iX'' | Returns the value of image X at the **current cell**. | ''i2'' | | ||
| - | | Get Image Value At Location | ''iX[LINE_EXPR, COL_EXPR]'' | Returns the value of image X at the **specified (line, column) coordinate**. If the target cell is null, **returns 0** (not null). | ''i1[line - 1, column - 2]'' | | + | | Get Image Value At Location | ''iX[LINE_EXPR, COL_EXPR]'' | Returns the value of image X at the **specified (line, column) coordinate**. Coordinates outside the image boundary are **mirrored** back into range. For a row coordinate ''cellLine'' in an image of N rows, ''cellLine'' is normally expected to be in the range [1, N]. When ''cellLine'' is outside this range, it is mirrored back: if ''cellLine'' ≤ 0, the effective row is ''1 − cellLine'' (for instance, ''cellLine'' = 0 → row 1, ''cellLine'' = −1 → row 2, ''cellLine'' = −2 → row 3); if ''cellLine'' > N, the effective row is ''2N + 1 − cellLine'' (for instance, ''cellLine'' = N+1 → row N, ''cellLine'' = N+2 → row N−1, ''cellLine'' = N+3 → row N−2). The same formula applies independently to the column coordinate ''cellCol''. If the target cell is null, **returns 0** (not null). | ''i1[line - 1, column - 2]'' | |
| - | | Get Image Null Value | ''null'' | Returns the null sentinel value for the current output image, making the current cell null. Using ''null'' in arithmetic always poisons the result. | ''if i1 > 2 then i1 else null'' | | + | | Get Image Null Sentinel Value | ''null(iX)'' | Returns the **numeric sentinel value** stored in image X to represent missing data (e.g. −1, 32767, or any other number defined when the image was created). Unlike the abstract ''null'' keyword, this is a real number that participates normally in arithmetic — but be aware that using it as if it were a regular data value may produce misleading results. | ''if null(i2) > 2 then 1 else null'' | |
| - | | Get Image Null Value (specific) | ''null(iX)'' | Returns the null sentinel value defined for image X specifically. | ''if null(i2) > 2 then 1 else null'' | | + | |
| - | | Is Null | ''isNull(EXPR)'' | Returns 1 if the expression result is null, 0 otherwise. The **correct** way to test for null. | ''if not isNull(i1) then i1 else i2'' | | + | |
| | Get Line Number | ''line'' | In map calculators: returns the **row index** of the current cell, **counting from 1**. In lookup table calculators: returns the **key of the current row**. | ''line + 1'' | | | Get Line Number | ''line'' | In map calculators: returns the **row index** of the current cell, **counting from 1**. In lookup table calculators: returns the **key of the current row**. | ''line + 1'' | | ||
| | Get Column Number | ''column'' | In map calculators: returns the **column index** of the current cell being processed, **counting from 1**. In lookup table calculators: returns the **value associated with the key of the current row** in the base lookup table. | ''if column / 2 > 50 then 1 else null'' | | | Get Column Number | ''column'' | In map calculators: returns the **column index** of the current cell being processed, **counting from 1**. In lookup table calculators: returns the **value associated with the key of the current row** in the base lookup table. | ''if column / 2 > 50 then 1 else null'' | | ||
| Line 288: | Line 292: | ||
| > **Co-located evaluation.** When an expression references more than one map (''i1'', ''i2'', …), the **current cell is shared**: every ''iX'' is evaluated at the same ''line'' and ''column'' for each step of the calculation, so ''i1'' and ''i2'' always refer to the same spatial location, not just "image 1" and "image 2" in some generic sense. The connected maps do **not** need to have matching extent, resolution, or pixel dimensions beforehand — Dinamica EGO reconciles this automatically through **image virtualization**: each input map is transparently wrapped in a virtual version sharing a common extent and the highest resolution among the inputs, so that "the current cell" lines up to the same point on the ground across all of them. The one requirement that virtualization does //not// relax is **projection** — all maps given to the calculator at the same time must share the same projection. ''iX[LINE_EXPR, COL_EXPR]'' breaks the shared-cell default, letting an expression sample a given image at an explicit coordinate instead of the current cell. | > **Co-located evaluation.** When an expression references more than one map (''i1'', ''i2'', …), the **current cell is shared**: every ''iX'' is evaluated at the same ''line'' and ''column'' for each step of the calculation, so ''i1'' and ''i2'' always refer to the same spatial location, not just "image 1" and "image 2" in some generic sense. The connected maps do **not** need to have matching extent, resolution, or pixel dimensions beforehand — Dinamica EGO reconciles this automatically through **image virtualization**: each input map is transparently wrapped in a virtual version sharing a common extent and the highest resolution among the inputs, so that "the current cell" lines up to the same point on the ground across all of them. The one requirement that virtualization does //not// relax is **projection** — all maps given to the calculator at the same time must share the same projection. ''iX[LINE_EXPR, COL_EXPR]'' breaks the shared-cell default, letting an expression sample a given image at an explicit coordinate instead of the current cell. | ||
| - | > **''line'' and ''column''** in map calculators are invaluable for creating geometric masks, distance ramps, or for passing precise coordinates into ''iX[LINE, COL]'' lookups. Both are **1-indexed** — the top-left cell of the map is at ''line = 1, column = 1'', not 0. In ''CalculateLookupTableValues'' and ''CalculateLookupTableKeysAndValues'', both keywords serve a different, row-oriented role: ''line'' is the key of the current table row, and ''column'' is the value already associated with that key in the base lookup table — so ''column'' lets the expression read the row's existing value without a separate table lookup, while ''t1[line]'' (or ''%someTable[line]'' in shorthand) reads the corresponding value from any other connected table. | + | > **''line'' and ''column''** in map calculators are invaluable for creating geometric masks, distance ramps, or for passing precise coordinates into ''iX[LINE, COL]'' lookups. Both are **1-indexed** — the top-left cell of the map is at ''line = 1, column = 1'', not 0. In [[Calculate Lookup Table Values]] and [[Calculate Lookup Table Keys And Values]], both keywords serve a different, row-oriented role: ''line'' is the key of the current table row, and ''column'' is the value already associated with that key in the base lookup table — so ''column'' lets the expression read the row's existing value without a separate table lookup, while ''t1[line]'' (or ''%someTable[line]'' in shorthand) reads the corresponding value from any other connected table. |
| ---- | ---- | ||
| Line 309: | Line 313: | ||
| | Linear interpolation | ''tX[/ EXPR]'' | Returns a **linearly interpolated value** between the two surrounding keys. | ''t2[/ i2]'' | | | Linear interpolation | ''tX[/ EXPR]'' | Returns a **linearly interpolated value** between the two surrounding keys. | ''t2[/ i2]'' | | ||
| | Key existence test | ''tX[? EXPR]'' / ''tX[=? EXPR]'' / ''tX[==? EXPR]'' | Returns **1** if EXPR matches a key in the table, **0** otherwise. Does not retrieve a value. | ''t2[? i2]'' | | | Key existence test | ''tX[? EXPR]'' / ''tX[=? EXPR]'' / ''tX[==? EXPR]'' | Returns **1** if EXPR matches a key in the table, **0** otherwise. Does not retrieve a value. | ''t2[? i2]'' | | ||
| - | | Named attribute | ''tX["NAME"]'' | Returns the value bound to a **predefined attribute name** (e.g. ''"cellArea"''). Only valid for tables produced by ''Extract Map Attributes'' or ''Extract Lookup Table Attributes''. | ''t2["cellArea"]'' | | + | | Named attribute | ''tX["NAME"]'' | Returns the value bound to a **predefined attribute name** (e.g. ''"cellArea"''). Only valid for tables produced by [[Extract Map Attributes]] or [[Extract Lookup Table Attributes]]. | ''t2["cellArea"]'' | |
| + | |||
| + | > **Note:** The syntax ''tX{EXPR}'' (curly braces) was a deprecated alias for ''tX[<= EXPR]'' and is no longer supported. | ||
| The bound operators (''<='', ''<'', ''>='', ''>'', ''><'', ''/'') are especially useful for **range-based reclassification** and **interpolation**, where your table defines breakpoints rather than exact class codes. | The bound operators (''<='', ''<'', ''>='', ''>'', ''><'', ''/'') are especially useful for **range-based reclassification** and **interpolation**, where your table defines breakpoints rather than exact class codes. | ||
| Line 326: | Line 332: | ||
| | Default column | ''tX[ [EXPR, EXPR, ...] ]'' | Returns the value in the **first data column** matching the given set of keys. | ''t2[ [i1 + 2, i2/2, t1[v2]] ]'' | | | Default column | ''tX[ [EXPR, EXPR, ...] ]'' | Returns the value in the **first data column** matching the given set of keys. | ''t2[ [i1 + 2, i2/2, t1[v2]] ]'' | | ||
| | Named column | ''tX[ [EXPR, EXPR, ...] ["COL_NAME"] ]'' | Returns the value in the **named data column** matching the given set of keys. | ''t2[ [i1 + 2, i2/2, t1[v2]] ["Area_In_Hectares"] ]'' | | | Named column | ''tX[ [EXPR, EXPR, ...] ["COL_NAME"] ]'' | Returns the value in the **named data column** matching the given set of keys. | ''t2[ [i1 + 2, i2/2, t1[v2]] ["Area_In_Hectares"] ]'' | | ||
| - | | Indexed column | ''tX[ [EXPR, EXPR, ...] [EXPR] ]'' | Returns the value in the **column indexed by the second expression** matching the given set of keys. | ''t2[ [i1 + 2, i2/2, t1[v2]] [v1+2] ]'' | | + | | Indexed column | ''tX[ [EXPR, EXPR, ...] [EXPR] ]'' | Returns the value in the **column indexed by the second expression** matching the given set of keys. Column indices are **1-based**. | ''t2[ [i1 + 2, i2/2, t1[v2]] [v1+2] ]'' | |
| These operators allow joining spatial data to rich tabular datasets at the cell level — for example, retrieving a transition probability from a multi-dimensional probability table keyed by land-use class and elevation zone. | These operators allow joining spatial data to rich tabular datasets at the cell level — for example, retrieving a transition probability from a multi-dimensional probability table keyed by land-use class and elevation zone. | ||
| Line 334: | Line 340: | ||
| ====== 7. Image Neighborhood Functions ====== | ====== 7. Image Neighborhood Functions ====== | ||
| - | > **Availability:** ''CalculateMap'' and ''CalculateCategoricalMap'' only. A spatial grid is required. | + | > **Availability:** [[Calculate Map]] and [[Calculate Categorical Map]] only. A spatial grid is required. |
| Neighborhood operators aggregate values from a rectangular window centred on the current cell. | Neighborhood operators aggregate values from a rectangular window centred on the current cell. | ||
| Line 349: | Line 355: | ||
| | ''x'' | Column coordinate to anchor the window centre (optional) | | | ''x'' | Column coordinate to anchor the window centre (optional) | | ||
| - | The window centre defaults to the current cell when ''y'' and ''x'' are omitted. For even-sized windows, the centre is displaced toward the top-left corner. **Null cells within the window are excluded from all calculations.** | + | The window centre defaults to the current cell when ''y'' and ''x'' are omitted. For even-sized windows, the centre is displaced toward the top-left corner. When any cell in the window falls outside the image boundary, its coordinate is resolved using the same mirror formula as ''iX[LINE, COL]'', applied **independently to each out-of-bounds cell**: for a row coordinate ''cellLine'' in an image of N rows, if ''cellLine'' ≤ 0 the effective row is ''1 − cellLine'', and if ''cellLine'' > N the effective row is ''2N + 1 − cellLine''; the same applies to column coordinates. This applies to every cell in the window — not just the anchor position — so a window near the edge of the image will sample mirrored cells for all positions that extend beyond the boundary. **Null cells within the window are excluded from all calculations.** |
| ^ Operator ^ Syntax ^ Description ^ Example ^ | ^ Operator ^ Syntax ^ Description ^ Example ^ | ||
| Line 360: | Line 366: | ||
| | Median | ''nbMedian(...)'' | Median of non-null cells. For an even count, the **greater** of the two central values is returned. | ''nbMedian(i1, 5, 5)'' | | | Median | ''nbMedian(...)'' | Median of non-null cells. For an even count, the **greater** of the two central values is returned. | ''nbMedian(i1, 5, 5)'' | | ||
| | Mode | ''nbMode(...)'' | Most frequent value among non-null cells. Returns null if no mode exists; returns the **lesser** value if multiple modes tie. | ''nbMode(i1, 5, 5)'' | | | Mode | ''nbMode(...)'' | Most frequent value among non-null cells. Returns null if no mode exists; returns the **lesser** value if multiple modes tie. | ''nbMode(i1, 5, 5)'' | | ||
| - | | Variance | ''nbVar(...)'' | Population variance of non-null cells: sum of (xi - mean)^2 / n | ''nbVar(i4, 7, 7) / 25'' | | + | | Variance | ''nbVar(...)'' | Population variance of non-null cells: sum of (xi - mean)<nowiki>^</nowiki>2 / n | ''nbVar(i4, 7, 7) / 25'' | |
| | Standard Deviation | ''nbStdDev(...)'' | Population standard deviation of non-null cells: sqrt of variance | ''nbStdDev(i2, 3, 3, line+1, column)'' | | | Standard Deviation | ''nbStdDev(...)'' | Population standard deviation of non-null cells: sqrt of variance | ''nbStdDev(i2, 3, 3, line+1, column)'' | | ||
| Line 367: | Line 373: | ||
| ====== 8. Image Neighborhood Indexing Functions ====== | ====== 8. Image Neighborhood Indexing Functions ====== | ||
| - | > **Availability:** ''CalculateMap'' and ''CalculateCategoricalMap'' only. | + | > **Availability:** [[Calculate Map]] and [[Calculate Categorical Map]] only. |
| - | These operators compute a neighbourhood statistic and then use the result as an **index** to retrieve a value from either a lookup table or a second image. | + | These operators compute a neighbourhood statistic and then use the result as an **index** to retrieve a value from either a connected Lookup Table or a second image. ''TABLE'' below always refers to a **Lookup Table** specifically — see section 5 for the operators that query one directly. |
| + | |||
| + | > If ''TABLE'' is bound to a multi-column Table (not a Lookup Table), an error is reported. See section 6 for multi-column tables. | ||
| **Full syntax:** \\ | **Full syntax:** \\ | ||
| Line 379: | Line 387: | ||
| ''nbN(IMAGE, h, w, IMAGE2)'' | ''nbN(IMAGE, h, w, IMAGE2)'' | ||
| - | When a **TABLE** is provided: the statistic is used as a key to query the lookup table. \\ | + | When a **TABLE** (Lookup Table) is provided: the statistic is used as a key to query it, equivalent to ''TABLE[statistic]'' from section 5. \\ |
| When an **IMAGE2** is provided: the statistic is used as a pixel coordinate to sample ''IMAGE2''. | When an **IMAGE2** is provided: the statistic is used as a pixel coordinate to sample ''IMAGE2''. | ||
| ^ Operator ^ Syntax ^ Description ^ Example ^ | ^ Operator ^ Syntax ^ Description ^ Example ^ | ||
| - | | MinRef | ''nbMinRef(...)'' | Finds the minimum in the window, then uses it as an index. | ''nbMinRef(i4, 2, 3, t1, line, column)'' | | + | | MinRef | ''nbMinRef(...)'' | Finds the minimum in the window, then uses it as an index into the Lookup Table (or a coordinate into IMAGE2). | ''nbMinRef(i4, 2, 3, t1, line, column)'' | |
| - | | MaxRef | ''nbMaxRef(...)'' | Finds the maximum in the window, then uses it as an index. | ''nbMaxRef(i4, 2, 3, i1, line, column)'' | | + | | MaxRef | ''nbMaxRef(...)'' | Finds the maximum in the window, then uses it as an index into the Lookup Table (or a coordinate into IMAGE2). | ''nbMaxRef(i4, 2, 3, i1, line, column)'' | |
| ---- | ---- | ||
| Line 390: | Line 398: | ||
| ====== 9. Convolution Operator ====== | ====== 9. Convolution Operator ====== | ||
| - | > **Availability:** ''CalculateMap'' and ''CalculateCategoricalMap'' only. | + | > **Availability:** [[Calculate Map]] and [[Calculate Categorical Map]] only. |
| ''nbConvol'' applies a kernel-weighted convolution to an image — for spatial filtering such as Gaussian blur or edge detection. | ''nbConvol'' applies a kernel-weighted convolution to an image — for spatial filtering such as Gaussian blur or edge detection. | ||
| **Syntax:** ''nbConvol(IMAGE, TABLE, h, w)'' / ''nbConvol(IMAGE, TABLE, h, w, y, x)'' | **Syntax:** ''nbConvol(IMAGE, TABLE, h, w)'' / ''nbConvol(IMAGE, TABLE, h, w, y, x)'' | ||
| + | |||
| + | > If ''TABLE'' is bound to a multi-column Table (not a Lookup Table), an error is reported. See section 6 for multi-column tables. | ||
| ^ Parameter ^ Meaning ^ | ^ Parameter ^ Meaning ^ | ||
| | ''IMAGE'' | The image to convolve (''iX'') | | | ''IMAGE'' | The image to convolve (''iX'') | | ||
| - | | ''TABLE'' | A Table whose entries are the kernel coefficients, indexed 1 to h*w, mapped **left-to-right, top-to-bottom** | | + | | ''TABLE'' | A **Lookup Table** whose entries are the kernel coefficients, indexed 1 to h*w, mapped **left-to-right, top-to-bottom**. | |
| | ''h'' | Number of kernel rows | | | ''h'' | Number of kernel rows | | ||
| | ''w'' | Number of kernel columns | | | ''w'' | Number of kernel columns | | ||
| | ''y'', ''x'' | Anchor position (optional; defaults to window centre) | | | ''y'', ''x'' | Anchor position (optional; defaults to window centre) | | ||
| - | **Kernel index mapping for a 3x3 kernel (h=3, w=3):** | + | Each cell in the window is assigned a unique integer key, starting at 1 and advancing left-to-right, then top-to-bottom. The ''TABLE'' argument must be a Lookup Table containing one row per window cell, where the key is that cell's index and the value is its convolution coefficient. The result of ''nbConvol'' is the weighted sum of all pixel values in the window, each multiplied by the coefficient stored at the corresponding key in the table. |
| - | ^ Table key ^ Window position ^ | + | The grids below illustrate the index mapping for some common window sizes: |
| - | | 1 | top-left | | + | |
| - | | 2 | top-centre | | + | **3×3 window (h=3, w=3):** |
| - | | 3 | top-right | | + | |
| - | | 4 | mid-left | | + | ^ ^ col 1 ^ col 2 ^ col 3 ^ |
| - | | 5 | centre | | + | ^ row 1 | 1 | 2 | 3 | |
| - | | 6 | mid-right | | + | ^ row 2 | 4 | 5 | 6 | |
| - | | 7 | bottom-left | | + | ^ row 3 | 7 | 8 | 9 | |
| - | | 8 | bottom-centre | | + | |
| - | | 9 | bottom-right | | + | **5×5 window (h=5, w=5):** |
| + | |||
| + | ^ ^ col 1 ^ col 2 ^ col 3 ^ col 4 ^ col 5 ^ | ||
| + | ^ row 1 | 1 | 2 | 3 | 4 | 5 | | ||
| + | ^ row 2 | 6 | 7 | 8 | 9 | 10 | | ||
| + | ^ row 3 | 11 | 12 | 13 | 14 | 15 | | ||
| + | ^ row 4 | 16 | 17 | 18 | 19 | 20 | | ||
| + | ^ row 5 | 21 | 22 | 23 | 24 | 25 | | ||
| + | |||
| + | **3×5 window (h=3, w=5) — non-square example:** | ||
| + | |||
| + | ^ ^ col 1 ^ col 2 ^ col 3 ^ col 4 ^ col 5 ^ | ||
| + | ^ row 1 | 1 | 2 | 3 | 4 | 5 | | ||
| + | ^ row 2 | 6 | 7 | 8 | 9 | 10 | | ||
| + | ^ row 3 | 11 | 12 | 13 | 14 | 15 | | ||
| + | |||
| + | In all cases the total number of keys required in the table is h × w. | ||
| **Example:** Apply a Gaussian-blur kernel stored in ''t1'' over a 3x3 window on ''i1'': | **Example:** Apply a Gaussian-blur kernel stored in ''t1'' over a 3x3 window on ''i1'': | ||
| Line 425: | Line 451: | ||
| ====== Null Value Handling ====== | ====== Null Value Handling ====== | ||
| - | Null values **propagate by default**. Any null input in any operand — whether a map cell (''iX''), a table or lookup-table lookup (''tX[...]''), or a scalar value (''vX'') — produces a null result, unless the null is explicitly caught. This behaviour is identical across all five calculator functors and across every operand type. | + | ===== General rule (all five functors) ===== |
| + | |||
| + | A null value in any operand **poisons the entire expression**: the result becomes null regardless of what the rest of the expression does. This is not a special case — it is the default behaviour for every operator and every operand type, across all five calculator functors. | ||
| + | |||
| + | > **Note:** The keyword ''null'' (available in all five functors) is an **abstract** sentinel — it carries no numeric value and cannot participate in arithmetic. It is distinct from ''null(iX)'' (available in map calculators only), which returns the **numeric** value that image X uses internally to mark missing cells. These two are not interchangeable: ''null'' poisons any expression that uses it; ''null(iX)'' is a regular number that happens to be the image's no-data sentinel. | ||
| ^ Expression ^ Null behaviour ^ | ^ Expression ^ Null behaviour ^ | ||
| Line 431: | Line 461: | ||
| | ''v1 / 0'' | Always null — division by zero is null regardless of operand type | | | ''v1 / 0'' | Always null — division by zero is null regardless of operand type | | ||
| | ''t1[v1]'' | Null if the key ''v1'' is not found in lookup table ''t1'' | | | ''t1[v1]'' | Null if the key ''v1'' is not found in lookup table ''t1'' | | ||
| - | | ''i1 + t1[line] / v1 ^ 3'' | Null if the map cell ''i1'', the table lookup ''t1[line]'', or the value ''v1'' is null | | + | | ''i1 + t1[line] / v1 <nowiki>^</nowiki> 3'' | Null if the map cell ''i1'', the table lookup ''t1[line]'', or the value ''v1'' is null | |
| | ''if isNull(t1[v1]) then 1 else 2'' | **Never null** — ''isNull'' itself always resolves to 0 or 1 | | | ''if isNull(t1[v1]) then 1 else 2'' | **Never null** — ''isNull'' itself always resolves to 0 or 1 | | ||
| | ''if isNull(v1) then i2 else t1[line]'' | May be null, depending on ''i2'' or the table lookup ''t1[line]'' | | | ''if isNull(v1) then i2 else t1[line]'' | May be null, depending on ''i2'' or the table lookup ''t1[line]'' | | ||
| Line 437: | Line 467: | ||
| | ''(t1[v1]) ? i1'' | If the key ''v1'' is not found in ''t1'', falls back to ''i1''; may still be null if ''i1'' is null | | | ''(t1[v1]) ? i1'' | If the key ''v1'' is not found in ''t1'', falls back to ''i1''; may still be null if ''i1'' is null | | ||
| - | **Two safe patterns for handling nulls — shown here against a table lookup and a scalar value, but equally applicable to map cells:** | + | The poison spreads through the entire chain: if ''i1'' is null, then ''i1 + 5'' is null, ''(i1 + 5) * v1'' is null, and so on. There is no way to "un-null" a result once a null has entered the calculation — except by explicitly testing for it first. |
| + | |||
| + | In a realistic expression, null can enter from several independent sources simultaneously. This expression computes a weighted transition probability from two input maps and a per-class calibration table: | ||
| + | |||
| + | <code> | ||
| + | (i1 * t1[i3] + i2 * (1 - t1[i3])) / v1 | ||
| + | </code> | ||
| + | |||
| + | Here ''i1'' is a distance map, ''i2'' a slope map, ''i3'' a land-use class map, ''t1'' a calibration table keyed by class code, and ''v1'' a normalisation scalar. The result is null if //any// of the following is true at the current cell: ''i1'', ''i2'', or ''i3'' is null; the class code in ''i3'' is not a key in ''t1''; or ''v1'' is zero. A single missing class in the calibration table silently nulls every cell of that class, which may be difficult to diagnose. The defensive form makes each failure mode explicit: | ||
| + | |||
| + | <code> | ||
| + | if isNull(i1) or isNull(i2) or isNull(i3) then null | ||
| + | else (i1 * (t1[i3] ? 0) + i2 * (1 - (t1[i3] ? 0))) / v1 | ||
| + | </code> | ||
| + | |||
| + | The ''?'' operator provides a fallback of 0 for any missing table key, so cells whose class is absent from the calibration table are treated as having zero weight rather than propagating null. | ||
| + | |||
| + | **Two safe patterns for handling nulls — applicable to map cells, table lookups, and scalar values alike:** | ||
| - ''isNull(EXPR)'' — test for null and branch: | - ''isNull(EXPR)'' — test for null and branch: | ||
| Line 449: | Line 496: | ||
| </code> | </code> | ||
| - | > ''iX[LINE, COL]'' is the one exception: **accessing a map at a specific coordinate returns 0 (not null)** when the target cell is null. This exception applies only to map coordinate lookups — a table or lookup-table key lookup (''tX[EXPR]'') that finds no matching key still returns null, as noted in section 5. | + | > **Note:** ''isNull()'' is immune to the poisoning rule — it always returns 0 or 1, never null, even when its argument is null. It is the only reliable way to branch on null. |
| + | |||
| + | If the computed real value exceeds the range of the chosen Cell Type, that cell is also written as null rather than wrapping or clipping. This range check applies to [[Calculate Map]] and [[Calculate Categorical Map]] only — the only two functors that accept a Cell Type parameter and write to a typed cell grid. | ||
| + | |||
| + | ===== Exceptions in map calculators ===== | ||
| + | |||
| + | > **Availability:** [[Calculate Map]] and [[Calculate Categorical Map]] only. The two exceptions below involve ''iX'' references and neighbourhood functions, which do not exist in the other three calculator functors. | ||
| - | If the computed real value exceeds the range of the chosen Cell Type, that cell is also written as null rather than wrapping or clipping. (This range check applies to the map calculators only, since the other calculator functors do not write to a typed cell grid.) | + | * **Coordinate lookup** ''iX[LINE_EXPR, COL_EXPR]'' — accessing a map at a specific coordinate returns **0**, not null, when the target cell **is null**. Coordinates that fall **outside the image boundary** are mirrored back into range rather than producing an error. For a row coordinate ''cellLine'' in an image of N rows, ''cellLine'' is normally expected to be in the range [1, N]. When ''cellLine'' is outside this range, it is mirrored back: if ''cellLine'' ≤ 0, the effective row is ''1 − cellLine'' (for instance, ''cellLine'' = 0 → row 1, ''cellLine'' = −1 → row 2, ''cellLine'' = −2 → row 3); if ''cellLine'' > N, the effective row is ''2N + 1 − cellLine'' (for instance, ''cellLine'' = N+1 → row N, ''cellLine'' = N+2 → row N−1, ''cellLine'' = N+3 → row N−2). The same formula applies independently to the column coordinate ''cellCol''. It can be a source of subtle bugs: an expression that tests ''i1[line-1, column] > 0'' will silently treat a null neighbour as zero rather than null. A table or lookup-table key lookup (''tX[EXPR]'') that finds no matching key still returns null as normal — this exception applies only to map coordinate lookups. |
| + | * **Neighbourhood functions** ''nbN(iX, h, w)'' — operators such as ''nbSum'', ''nbAverage'', ''nbMax'', and so on aggregate over a window of cells and **exclude null cells from the calculation**. If ''i1'' is null at the current cell, the neighbourhood function simply ignores it and aggregates the remaining non-null cells in the window. | ||
| ---- | ---- | ||
| Line 457: | Line 511: | ||
| ====== EGO Script Syntax ====== | ====== EGO Script Syntax ====== | ||
| - | When writing expressions inside a ''.ego'' script file, the expression must be enclosed in square brackets ''[ ]''. Below are examples of each functor in both shorthand and verbose form. | + | When writing expressions inside a ''.ego'' script file (see [[ego_script|EGO Script Language]]), the expression must be enclosed in square brackets ''[ ]''. Below are examples of each functor in both shorthand and verbose form. |
| - | > **A note on operand naming.** Throughout the expression-language tables above, operands are written generically as ''iX'', ''tX'', and ''vX'' — the **numbered** form, used when a port is connected via an explicit ''NumberMap'', ''NumberTable'', or ''NumberValue'' functor (the **verbose** form below). EGO Script's **shorthand** form instead refers to operands **by name** — the variable already bound elsewhere in the script — prefixed with a sigil that marks its type: ''#'' for a map, ''%'' for a table or lookup table, ''$'' for a value. So ''i1'' in a verbose expression corresponds to ''#someMapVariable'' in the shorthand version of the same expression, ''t1'' corresponds to ''%someTableVariable'', and ''v1'' corresponds to ''$someValueVariable''. The two forms are interchangeable but cannot be mixed within a single expression. | + | > **A note on operand naming.** Throughout the expression-language tables above, operands are written generically as ''iX'', ''tX'', and ''vX'' — the **numbered** form, used when a port is connected via an explicit **hook** functor (''NumberMap'', ''NumberTable'', or ''NumberValue'') in the **verbose** form below. EGO Script's **shorthand** form instead refers to operands **by name** — the variable already bound elsewhere in the script — prefixed with a sigil that marks its type: ''#'' for a map, ''%'' for a table or lookup table, ''$'' for a value. So ''i1'' in a verbose expression corresponds to ''#someMapVariable'' in the shorthand version of the same expression, ''t1'' corresponds to ''%someTableVariable'', and ''v1'' corresponds to ''$someValueVariable''. The two forms are interchangeable but cannot be mixed within a single expression. See [[ego_script#calculator_functor_shorthand|Calculator functor shorthand]] in the EGO Script documentation for a full description of both forms. |
| ===== CalculateMap (''#'') ===== | ===== CalculateMap (''#'') ===== | ||
| Line 475: | Line 529: | ||
| resultFormat = .none | resultFormat = .none | ||
| } {{ | } {{ | ||
| - | NumberMap inputMap 1; // i1 | + | // i1 |
| - | NumberValue minVal 1; // v1 | + | NumberMap inputMap 1; |
| - | NumberValue maxVal 2; // v2 | + | // v1 |
| + | NumberValue minVal 1; | ||
| + | // v2 | ||
| + | NumberValue maxVal 2; | ||
| }}; | }}; | ||
| </code> | </code> | ||
| Line 503: | Line 560: | ||
| resultFormat = .none | resultFormat = .none | ||
| } {{ | } {{ | ||
| - | NumberMap elevationMap 1; // i1 | + | // i1 |
| - | NumberValue lowThreshold 1; // v1 | + | NumberMap elevationMap 1; |
| - | NumberValue highThreshold 2; // v2 | + | // v1 |
| + | NumberValue lowThreshold 1; | ||
| + | // v2 | ||
| + | NumberValue highThreshold 2; | ||
| }}; | }}; | ||
| </code> | </code> | ||
| Line 519: | Line 579: | ||
| expression = [ v1 * v2 + (1 - v1) * v3 ] | expression = [ v1 * v2 + (1 - v1) * v3 ] | ||
| } {{ | } {{ | ||
| - | NumberValue weight 1; // v1 | + | // v1 |
| - | NumberValue rateA 2; // v2 | + | NumberValue weight 1; |
| - | NumberValue rateB 3; // v3 | + | // v2 |
| + | NumberValue rateA 2; | ||
| + | // v3 | ||
| + | NumberValue rateB 3; | ||
| }}; | }}; | ||
| Line 531: | Line 594: | ||
| expression = [ t1[v1] ] | expression = [ t1[v1] ] | ||
| } {{ | } {{ | ||
| - | NumberTable calibrationTable 1; // t1 | + | // t1 |
| - | NumberValue targetClass 1; // v1 | + | NumberTable calibrationTable 1; |
| + | // v1 | ||
| + | NumberValue targetClass 1; | ||
| }}; | }}; | ||
| </code> | </code> | ||
| Line 548: | Line 613: | ||
| if t1[line] >= v1 and t2[line] >= v2 then 1 else null | if t1[line] >= v1 and t2[line] >= v2 then 1 else null | ||
| ] "Top_Id" "Is_Hilltop" .none {{ | ] "Top_Id" "Is_Hilltop" .none {{ | ||
| - | NumberTable saddleHeights 1; // t1 | + | // t1 |
| - | NumberTable saddleAngles 2; // t2 | + | NumberTable saddleHeights 1; |
| - | NumberValue minimumHeight 1; // v1 | + | // t2 |
| - | NumberValue minimumSlopeAngle 2; // v2 | + | NumberTable saddleAngles 2; |
| + | // v1 | ||
| + | NumberValue minimumHeight 1; | ||
| + | // v2 | ||
| + | NumberValue minimumSlopeAngle 2; | ||
| }}; | }}; | ||
| Line 578: | Line 647: | ||
| t1[[line]["Nearest_Distance"]] | t1[[line]["Nearest_Distance"]] | ||
| ] "Point_Id" "Nearest_Distance" pointKeys {{ | ] "Point_Id" "Nearest_Distance" pointKeys {{ | ||
| - | NumberTable nearestPoints 1; // t1 | + | // t1 |
| + | NumberTable nearestPoints 1; | ||
| }}; | }}; | ||
| </code> | </code> | ||
| Line 592: | Line 662: | ||
| (i1 - v1) / (v2 - v1) | (i1 - v1) / (v2 - v1) | ||
| </code> | </code> | ||
| - | ''v1'' = global minimum, ''v2'' = global maximum. | + | ''i1'' = input map; ''v1'' = global minimum, ''v2'' = global maximum. |
| ==== Weighted combination of two probability maps ==== | ==== Weighted combination of two probability maps ==== | ||
| Line 598: | Line 668: | ||
| i1 * v1 + i2 * (1 - v1) | i1 * v1 + i2 * (1 - v1) | ||
| </code> | </code> | ||
| - | ''v1'' is the blending weight. | + | ''i1'', ''i2'' = the two maps to blend; ''v1'' = blending weight. |
| ==== Convert degrees to radians and apply a trig function ==== | ==== Convert degrees to radians and apply a trig function ==== | ||
| Line 604: | Line 674: | ||
| sin(i1 * pi / 180) | sin(i1 * pi / 180) | ||
| </code> | </code> | ||
| + | ''i1'' = map of values in degrees. | ||
| ==== Clamp output to a valid range ==== | ==== Clamp output to a valid range ==== | ||
| Line 609: | Line 680: | ||
| clamp(i1 * v1 + i2 * v2, 0, 1) | clamp(i1 * v1 + i2 * v2, 0, 1) | ||
| </code> | </code> | ||
| + | ''i1'', ''i2'' = input maps; ''v1'', ''v2'' = their respective blending weights. | ||
| ==== Fill null cells with the local mean ==== | ==== Fill null cells with the local mean ==== | ||
| Line 614: | Line 686: | ||
| if isNull(i1) then nbAverage(i1, 3, 3) else i1 | if isNull(i1) then nbAverage(i1, 3, 3) else i1 | ||
| </code> | </code> | ||
| + | ''i1'' = input map. | ||
| ==== Focal range (texture measure) ==== | ==== Focal range (texture measure) ==== | ||
| Line 619: | Line 692: | ||
| nbMax(i1, 5, 5) - nbMin(i1, 5, 5) | nbMax(i1, 5, 5) - nbMin(i1, 5, 5) | ||
| </code> | </code> | ||
| + | ''i1'' = input map. | ||
| ==== Stochastic perturbation with Gaussian noise ==== | ==== Stochastic perturbation with Gaussian noise ==== | ||
| Line 624: | Line 698: | ||
| i1 + rNormal(0, v1) | i1 + rNormal(0, v1) | ||
| </code> | </code> | ||
| - | Adds Gaussian noise with zero mean and standard deviation ''v1'' to every cell. | + | ''i1'' = input map; adds Gaussian noise with zero mean and standard deviation ''v1'' to every cell. |
| ==== Coordinate-based gradient ramp ==== | ==== Coordinate-based gradient ramp ==== | ||
| Line 642: | Line 716: | ||
| (i1 / i2) ? (i1 - i2) | (i1 / i2) ? (i1 - i2) | ||
| </code> | </code> | ||
| - | If ''i2'' is zero at a cell, falls back to ''i1 - i2'' instead of producing null. | + | ''i1'' = numerator map, ''i2'' = denominator map. If ''i2'' is zero at a cell, falls back to ''i1 - i2'' instead of producing null. |
| ---- | ---- | ||
| Line 652: | Line 726: | ||
| if i1 == 2 then 1 else 0 | if i1 == 2 then 1 else 0 | ||
| </code> | </code> | ||
| + | ''i1'' = input categorical map. | ||
| ==== Multi-condition reclassification into categories ==== | ==== Multi-condition reclassification into categories ==== | ||
| Line 660: | Line 735: | ||
| else null | else null | ||
| </code> | </code> | ||
| + | ''i1'' = input categorical map. | ||
| ==== Reclassify a continuous map into classes using lookup table breakpoints ==== | ==== Reclassify a continuous map into classes using lookup table breakpoints ==== | ||
| Line 665: | Line 741: | ||
| t1[<= i1] | t1[<= i1] | ||
| </code> | </code> | ||
| - | Assigns each cell the category value from ''t1'' whose key is the greatest key <= the cell value — implementing interval-based reclassification without if/else chains. | + | ''i1'' = continuous input map; ''t1'' = breakpoint lookup table mapping value thresholds to category codes. Assigns each cell the category value from ''t1'' whose key is the greatest key <= the cell value — implementing interval-based reclassification without if/else chains. |
| ==== Assign a category based on multiple input maps ==== | ==== Assign a category based on multiple input maps ==== | ||
| Line 717: | Line 793: | ||
| if t1[line] >= v1 and t2[line] >= v2 then 1 else null | if t1[line] >= v1 and t2[line] >= v2 then 1 else null | ||
| </code> | </code> | ||
| - | Iterates over all row keys; ''t1[line]'' and ''t2[line]'' retrieve the corresponding values from two operand tables. | + | ''t1'', ''t2'' = operand lookup tables; ''v1'', ''v2'' = threshold values. Iterates over all row keys; ''t1[line]'' and ''t2[line]'' retrieve the corresponding values from each table. |
| ==== Apply a multiplicative scaling factor to existing table values ==== | ==== Apply a multiplicative scaling factor to existing table values ==== | ||
| Line 759: | Line 835: | ||
| t1[line] / v1 | t1[line] / v1 | ||
| </code> | </code> | ||
| - | Multiplies each key by 10 and divides the corresponding value by scalar ''v1''. | + | ''t1'' = base lookup table being iterated; ''v1'' = scaling divisor. Multiplies each key by 10 and divides the corresponding value by ''v1''. |
| ---- | ---- | ||
| Line 768: | Line 844: | ||
| t1[ [i1, i2] ["TransitionProb"] ] | t1[ [i1, i2] ["TransitionProb"] ] | ||
| </code> | </code> | ||
| - | Looks up a transition probability from table ''t1'' using two map values as composite keys. Available in ''CalculateMap'' and ''CalculateCategoricalMap''; the same syntax works in the table calculators by substituting ''line'' or ''vX'' for ''iX''. | + | ''i1'', ''i2'' = map layers providing the composite key values; ''t1'' = multi-key probability table. Looks up a transition probability using two map values as composite keys. Available in [[Calculate Map]] and [[Calculate Categorical Map]]; the same syntax works in the table calculators by substituting ''line'' or ''vX'' for ''iX''. |
| ---- | ---- | ||
| Line 778: | Line 854: | ||
| ===== CalculateMap and CalculateCategoricalMap ===== | ===== CalculateMap and CalculateCategoricalMap ===== | ||
| - | - **Connect your inputs first.** Connect all required maps (Number Map), tables (Number Table), and scalars (Number Value) to the operator's ports before opening the editor. | + | - **Connect your inputs first.** Connect all required maps ([[Number Map]]), tables ([[Number Table]]), and scalars ([[Number Value]]) to the operator's ports before opening the editor. |
| - **Open the expression editor.** All connected identifiers appear with their aliases at the top. | - **Open the expression editor.** All connected identifiers appear with their aliases at the top. | ||
| - **Write the expression** using the listed identifiers. | - **Write the expression** using the listed identifiers. | ||
| Line 786: | Line 862: | ||
| ===== CalculateValue ===== | ===== CalculateValue ===== | ||
| - | - **Connect your inputs first.** Connect all required tables (Number Table) and scalars (Number Value) to the operator's ports before opening the editor. Maps cannot be connected, since ''CalculateValue'' has no cell context. | + | - **Connect your inputs first.** Connect all required tables ([[Number Table]]) and scalars ([[Number Value]]) to the operator's ports before opening the editor. Maps cannot be connected, since [[Calculate Value]] has no cell context. |
| - **Open the expression editor.** All connected identifiers appear with their aliases at the top. | - **Open the expression editor.** All connected identifiers appear with their aliases at the top. | ||
| - **Write the expression** using the listed identifiers. There is no Cell Type or Null Value to set — the result is a single scalar. | - **Write the expression** using the listed identifiers. There is no Cell Type or Null Value to set — the result is a single scalar. | ||
| Line 792: | Line 868: | ||
| ===== CalculateLookupTableValues and CalculateLookupTableKeysAndValues ===== | ===== CalculateLookupTableValues and CalculateLookupTableKeysAndValues ===== | ||
| - | - **Connect your inputs first.** Connect all required tables (Number Table) and scalars (Number Value) to the operator's ports before opening the editor. | + | - **Connect your inputs first.** Connect all required tables ([[Number Table]]) and scalars ([[Number Value]]) to the operator's ports before opening the editor. |
| - **Set the Key Column Name and Value Column Name** for the output lookup table. | - **Set the Key Column Name and Value Column Name** for the output lookup table. | ||
| - | - **Connect a Base Lookup Table**, or leave it as ''.none'', in which case the row set instead comes from a single connected table — the lowest-indexed ''NumberTable'' in verbose form, or the first lookup table referenced by name in the expression in shorthand form. | + | - **Connect a Base Lookup Table**, or leave it as ''.none'', in which case the row source is the ''NumberTable'' hook with the lowest list index that is connected to a lookup table (not a regular table) in verbose form, or the first lookup table referenced by name in the expression in shorthand form. |
| - | - **Open the expression editor.** All connected identifiers appear with their aliases at the top. ''CalculateLookupTableValues'' has a single expression; ''CalculateLookupTableKeysAndValues'' has separate key and value expressions. | + | - **Open the expression editor.** All connected identifiers appear with their aliases at the top. [[Calculate Lookup Table Values]] has a single expression; [[Calculate Lookup Table Keys And Values]] has separate key and value expressions. |
| - **Write the expression(s)**, using ''line'' for the current row's key and ''column'' for the current row's existing value where needed. | - **Write the expression(s)**, using ''line'' for the current row's key and ''column'' for the current row's existing value where needed. | ||
| Line 802: | Line 878: | ||
| ====== Notes and Caveats ====== | ====== Notes and Caveats ====== | ||
| - | * **Choose the right functor for the output type.** Use ''CalculateMap'' for continuous rasters, ''CalculateCategoricalMap'' for class-coded rasters (so that downstream functors treat them as categorical), ''CalculateValue'' for a single scalar, and the two lookup table calculators for row-by-row table construction. | + | * **Choose the right functor for the output type.** Use [[Calculate Map]] for continuous rasters, [[Calculate Categorical Map]] for class-coded rasters (so that downstream functors treat them as categorical), [[Calculate Value]] for a single scalar, and the two lookup table calculators ([[Calculate Lookup Table Values]], [[Calculate Lookup Table Keys And Values]]) for row-by-row table construction. |
| - | * **''line'' and ''column'' are context-dependent.** In ''CalculateMap'' and ''CalculateCategoricalMap'', ''line'' is the spatial row index and ''column'' is the spatial column index of the current pixel, both **starting at 1**. In ''CalculateLookupTableValues'' and ''CalculateLookupTableKeysAndValues'', both are still available but take on row-oriented meanings: ''line'' is the key of the current table row, and ''column'' is the value already associated with that key in the base lookup table. A different table's value for that same key can be retrieved with ''%someTable[line]''. | + | * **''line'' and ''column'' are context-dependent.** In [[Calculate Map]] and [[Calculate Categorical Map]], ''line'' is the spatial row index and ''column'' is the spatial column index of the current pixel, both **starting at 1**. In [[Calculate Lookup Table Values]] and [[Calculate Lookup Table Keys And Values]], both are still available but take on row-oriented meanings: ''line'' is the key of the current table row, and ''column'' is the value already associated with that key in the base lookup table. A different table's value for that same key can be retrieved with ''%someTable[line]''. See [[#4_image_operators_and_functions|section 4]] for full details. |
| * **Native compilation.** Expression calculations across all five calculator functors can be compiled to native code automatically (requires the optional native expression support package), delivering near-C performance — no user action is needed beyond installing the package. | * **Native compilation.** Expression calculations across all five calculator functors can be compiled to native code automatically (requires the optional native expression support package), delivering near-C performance — no user action is needed beyond installing the package. | ||
| - | * **Overflow produces null.** If the result exceeds the Cell Type's range, the cell becomes null rather than wrapping. Applies to the map calculators only (the other functors return values or table entries that are not constrained to a cell type in the same way). | + | * **Overflow produces null.** If the result exceeds the Cell Type's range, the cell becomes null rather than wrapping. Applies to [[Calculate Map]] and [[Calculate Categorical Map]] only — the only two functors with a Cell Type parameter. |
| - | * **Neighbourhood functions ignore nulls.** All ''nbN'' operators skip null cells in their window; only non-null cells contribute to the statistic. | + | * **Neighbourhood functions ignore nulls.** All ''nbN'' operators ([[#7_image_neighborhood_functions|section 7]]) skip null cells in their window; only non-null cells contribute to the statistic. |
| - | * **''iX[LINE, COL]'' returns 0, not null, for out-of-bounds or null cells.** This is the one exception to the general null-propagation rule. | + | * **''iX[LINE, COL]'' returns 0, not null, when the target cell is null.** Coordinates outside the image boundary are mirrored rather than treated as out-of-bounds. This is the one exception to the general null-propagation rule. See [[#4_image_operators_and_functions|section 4]] and [[#null_value_handling|Null Value Handling]]. |
| ---- | ---- | ||