> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abbyy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Simplifique un FlexiLayout con un elemento auxiliar y una hipótesis nula

> Simplifique el código complejo de FlexiLayout con un elemento auxiliar ficticio cuya hipótesis nula indica cuándo se cumplen restricciones de búsqueda compartidas en varios elementos.

Utilice este método cuando necesite comprobar las mismas restricciones de búsqueda complejas para varios elementos. La idea es que las restricciones se comprueben y los cálculos se realicen una sola vez en un elemento auxiliar.

Dependiendo del resultado de la comprobación de las restricciones, el elemento en cuestión se busca o no, de modo que la hipótesis encontrada o no encontrada actúa como marcador de si se cumplen las restricciones.

<div id="how-the-dummy-element-signals-that-the-constraints-are-met">
  ## Cómo el elemento ficticio señala que se cumplen las restricciones
</div>

Este elemento auxiliar se crea para que siempre pueda detectar algo en las imágenes, siempre que no esté activada la función `DontFind()` (es decir, "detener la búsqueda"). El número de hipótesis no debe ser demasiado grande para evitar expandir en exceso el árbol de hipótesis y aumentar el tiempo de emparejamiento de FlexiLayout.

Para ello, puede usar, por ejemplo, elementos de los tipos **colección de objetos** o **párrafo**. Estos elementos siempre generan una única hipótesis que incluye todos los objetos del tipo especificado en el área de búsqueda.

La sección de **relación avanzada de prebúsqueda** del elemento ficticio contiene el conjunto de condiciones para comprobar algunos de los elementos situados debajo del elemento ficticio en el árbol del proyecto. Si se cumplen todas las condiciones, se llama a la función `DontFind()` para el elemento ficticio.

En este caso, se generará una hipótesis nula para el elemento ficticio, que servirá como marcador de que todas las condiciones se han cumplido cuando FlexiLayout Studio empiece a buscar otros elementos. Esto hace que FlexiLayout Studio ejecute solo la comprobación `IsNull` del elemento ficticio, en lugar de verificar las mismas restricciones complejas para varios elementos.

<Note>
  Este método ayuda a que el código sea más descriptivo. Además, si necesita editar las restricciones, puede hacerlo solo en la descripción del elemento ficticio. Esto reduce la probabilidad de errores lógicos y sintácticos al duplicar el código.
</Note>

<Note>
  Está previsto que futuras versiones del producto admitan la creación de variables en el área de subelementos de los grupos. Los resultados de la comprobación de las restricciones se almacenarán entonces en los valores de distintas variables.

  El método actual es una solución temporal (workaround) que ayuda a simplificar el código en las secciones Advanced de la versión actual de FlexiLayout Studio.
</Note>

<div id="the-two-invoice-layouts-in-the-sample-project">
  ## Los dos diseños de factura en el proyecto de ejemplo
</div>

El proyecto `1.fsp` (carpeta `%public%\ABBYY\FlexiCapture\12.0\Samples\FLS\Tips and Tricks\Auxiliary element`) muestra cómo funciona este método.

En estas imágenes, el objetivo es encontrar los siguientes campos: "Número de factura", "Fecha de la factura", "Nombre de la empresa" y "Dirección de la empresa".

Suponga que deben procesarse facturas de dos tipos distintos:

* Los campos "Nombre de la empresa" y "Dirección de la empresa" están encima del campo "Número de factura".
* Los campos "Nombre de la empresa" y "Dirección de la empresa" están debajo del campo "Número de factura".

Como puede ver en las imágenes, los campos "Nombre de la empresa" y "Dirección de la empresa" no tienen nombre, lo que impide usar el procedimiento estándar para buscar un campo de datos a partir de su nombre.

Sin embargo, hay un patrón determinado: cuando el campo de fecha está a la derecha del número de factura, el nombre y la dirección de la empresa están debajo del campo "Número de factura" (páginas 1 y 3). Si el campo de fecha está debajo del campo de número de factura, los datos de la empresa están encima del campo "Número de factura" (páginas 2 y 4).

Teniendo en cuenta este patrón, lo mejor es buscar primero la ubicación de los campos "Número de factura" y "Fecha de la factura", y luego detectar los demás campos basándose en ellos dos y especificando sus posiciones relativas.

<div id="search-for-the-date-field-with-two-sets-of-constraints">
  ## Buscar el campo de fecha con dos conjuntos de restricciones
</div>

El proyecto contiene un elemento de **grupo** **InvoiceGroup** con los elementos **InvoiceHeader**, **InvoiceNum** y **DateHeader**, así como un elemento de **grupo** **DateGroup**. Estos subelementos son necesarios para detectar los nombres de los campos y los campos "Número de factura" y "Fecha de la factura".

<Note>
  Para obtener más información sobre los métodos para buscar fechas, consulte [Búsqueda de fechas después de un reconocimiento de alta o baja calidad](/es/flexi-capture/fls/tips-tricks/date2). En esta sección solo se describen las restricciones para la búsqueda de fechas en el proyecto actual.
</Note>

Como puede ver, los campos de fecha en las imágenes no siempre tienen nombre.

Por ello, al buscar un campo de fecha, debe especificar dos conjuntos de restricciones: uno para los casos en que se detecta el nombre y otro para los casos en que no se detecta (un caso especial sería que el nombre esté presente en la página pero no se haya detectado, por ejemplo, debido al ruido).

```text theme={null}
if not DateHeader.IsNull then
{ RightOf: DateHeader.Rect.Right;
Below: DateHeader.Rect.Top - 30dt;
Above: DateHeader.Rect.Bottom + 30dt;
}
else
{ RectArray ar;
Let ar1 = Rect (InvoiceNum.Rect.Right, InvoiceNum.Rect.Top-30dt, PageRect.Right, InvoiceNum.Rect.Bottom + 30dt);
Let ar2 = Rect (InvoiceHeader.Rect.Left, InvoiceHeader.Rect.Bottom, InvoiceHeader.Rect.Right + 300dt, InvoiceHeader.Rect.Bottom + 150dt);
ar = RectArray (ar1);
ar.Add (ar2);
RestrictSearchArea (ar);
}
```

Si se detecta el nombre del campo de fecha (es decir, si se cumple la restricción `if not DateHeader.IsNull`), la búsqueda se realizará tomando como referencia el nombre del campo de fecha: a la derecha del nombre, en el mismo nivel horizontal, con cierto margen de error para el desplazamiento vertical:

```text theme={null}
{ RightOf: DateHeader.Rect.Right;
Below: DateHeader.Rect.Top - 30dt;
Above: DateHeader.Rect.Bottom + 30dt;
}
```

De lo contrario, el área de búsqueda se divide en dos rectángulos: uno a la derecha del número de factura, al mismo nivel que este, y otro debajo del campo de la factura.

<Note>
  Para simplificar, supongamos que las imágenes son de buena calidad y que el campo "Número de factura" y su nombre siempre se detectan.

  En una situación real, antes de acceder a las propiedades de estos elementos, debe comprobar `IsNull`, porque, si los elementos no se detectan, las búsquedas posteriores se realizarán tomando como referencia las áreas de búsqueda de los elementos correspondientes.
</Note>

<Frame>
  <img src="https://mintcdn.com/abbyy/lqYknuOmCa79141v/images/flexi-capture/fls/auxillary_element.png?fit=max&auto=format&n=lqYknuOmCa79141v&q=85&s=f9a44ef58fb998dfe5322e344ae33470" alt="Captura de pantalla de ABBYY FlexiLayout Studio que muestra el área de búsqueda del campo de fecha definida como un array de rectángulos a la derecha y debajo del campo Número de factura cuando no se detecta el nombre del campo de fecha." width="716" height="406" data-path="images/flexi-capture/fls/auxillary_element.png" />
</Frame>

<div id="penalize-date-hypotheses-far-from-the-invoice-fields">
  ### Penalizar las hipótesis de fecha alejadas de los campos de facturas
</div>

La sección **Relaciones avanzadas de posbúsqueda** del elemento **Fecha** contiene el siguiente código:

```text theme={null}
if (DateHeader.IsNull) and (not IsNull) then
{if (not InvoiceHeader.IsNull) then
{ FuzzyQuality: Rect.Left - InvoiceHeader.Rect.Right, {0, 0, 0, 50000}*dt;
FuzzyQuality: Rect.Top - InvoiceHeader.Rect.Bottom, {-50000, 0, 0, 50000}*dt;
}
if (not InvoiceNum.IsNull) then
{ FuzzyQuality: Rect.Left - InvoiceNum.Rect.Right, {0, 0, 0, 50000}*dt;
FuzzyQuality: Rect.Top - InvoiceNum.Rect.Bottom, {-50000, 0, 0, 50000}*dt;
}
}
```

Este código influye en la calidad de la hipótesis de fecha en función de su distancia con respecto al nombre del campo de fecha de la factura y, si no se detecta el nombre del campo de fecha, con respecto al propio campo "Número de factura".

Cuanto mayor sea la distancia hasta los campos especificados, mayor será la penalización aplicada a las hipótesis correspondientes; es decir, se busca el campo de fecha más cercano al campo "Número de factura".

<Note>
  Para obtener más información sobre el uso de estas funciones, consulte [Buscar elementos con Nearest y FuzzyQuality](/es/flexi-capture/fls/tips-tricks/date9).
</Note>

<div id="search-constraints-for-the-dateasstring-element">
  ### Restricciones de búsqueda para el elemento DateAsString
</div>

Se especifican restricciones de búsqueda idénticas para el elemento **DateAsString**, pero su sección de **Relaciones avanzadas de posbúsqueda** añade una línea más al código mostrado anteriormente:

```text theme={null}
FuzzyQuality: 600dt - Width, {0, 0, 0, 50000}*dt;
```

Esta línea es necesaria durante la búsqueda de la fecha, para que se prefiera una hipótesis con una cadena más larga de caracteres del alfabeto frente a una más corta.

Además, la pestaña **Restricciones de búsqueda** del elemento **DateAsString** especifica que, al buscar la fecha como una cadena de caracteres, debe excluirse la región del elemento **InvoiceNum**.

Esto se debe a que decidimos, por simplicidad, no duplicar para el elemento **DateAsString** las mismas restricciones de búsqueda que habíamos especificado en la sección de **relación avanzada de prebúsqueda** del elemento **fecha**. En su lugar, el área de búsqueda se especifica como `RestrictSearchArea (Date.Rect);`.

Esto indica a FlexiLayout Studio que busque el objeto del elemento **DateAsString** en el área del rectángulo difuso del elemento **fecha**. El área de búsqueda del elemento **fecha** puede representarse como un array de rectángulos.

Cuando se genera una hipótesis nula para el elemento **fecha**, el rectángulo que encierra el área de búsqueda se toma como un rectángulo (`Rect`) del elemento actual. Como puede ver en la imagen siguiente, también encierra el campo "Número de factura" descrito por el elemento **InvoiceNum**.

En algunas condiciones (por ejemplo, cuando el campo de fecha tiene mucho ruido), puede darse una situación en la que, en lugar del campo de fecha, el elemento **DateAsString** detecte el campo del número de factura, ya que los caracteres (incluidos los dígitos) especificados para este elemento no tienen ninguna restricción de formato.

<Frame>
  <img src="https://mintcdn.com/abbyy/lqYknuOmCa79141v/images/flexi-capture/fls/auxillary_element2.png?fit=max&auto=format&n=lqYknuOmCa79141v&q=85&s=a1caa464b42e23727332aadb1c046913" alt="Captura de pantalla de ABBYY FlexiLayout Studio que muestra el área de búsqueda del elemento DateAsString, definida por RestrictSearchArea en el elemento fecha no detectado, que también encierra el campo Número de factura descrito por el elemento InvoiceNum." width="684" height="467" data-path="images/flexi-capture/fls/auxillary_element2.png" />
</Frame>

<div id="check-the-field-arrangement-with-the-shamelement-auxiliary-element">
  ## Compruebe la disposición de los campos con el elemento auxiliar ShamElement
</div>

Después de describir los elementos necesarios para buscar los campos "Número de factura" y "Fecha de la factura", el siguiente paso es buscar los campos "Nombre de la empresa" y "Dirección de la empresa".

El proyecto usa un elemento **Párrafo** llamado **ShamElement**. Este elemento actúa como elemento auxiliar y se utiliza exclusivamente para comprobar la ubicación relativa de los campos "Número de factura" y "Fecha de la factura".

La sección **Relación avanzada de prebúsqueda** del elemento auxiliar contiene el siguiente código:

```text theme={null}
Let Date1 = InvoiceGroup.DateGroup.Date;
Let Date2 = InvoiceGroup.DateGroup.DateAsString;
Let DateGroup = InvoiceGroup.DateGroup;
Let InvoiceHeader = InvoiceGroup.InvoiceHeader;
Let InvoiceNumber = InvoiceGroup.InvoiceNum;

if ((not InvoiceHeader.IsNull) or (not InvoiceNumber.IsNull)) and
(
((Date1.IsNull == FALSE) and ((max (InvoiceHeader.Rect.YCenter - Date1.Rect.YCenter, Date1.Rect.YCenter - InvoiceHeader.Rect.YCenter ) < 30dt) or (max (InvoiceNumber.Rect.YCenter - Date1.Rect.YCenter, Date1.Rect.YCenter - InvoiceNumber.Rect.YCenter ) < 30dt)) and ((Date1.Rect.Left - InvoiceHeader.Rect.Right > 100dt) or (Date1.Rect.Left - InvoiceNumber.Rect.Right > 50dt)))
or
((Date2.IsNull == FALSE) and ((max (InvoiceHeader.Rect.YCenter - Date2.Rect.YCenter, Date2.Rect.YCenter - InvoiceHeader.Rect.YCenter ) < 30dt) or (max (InvoiceNumber.Rect.YCenter - Date2.Rect.YCenter, Date2.Rect.YCenter - InvoiceNumber.Rect.YCenter ) < 30dt)) and ((Date2.Rect.Left - InvoiceHeader.Rect.Right > 100dt) or (Date2.Rect.Left - InvoiceNumber.Rect.Right > 50dt)))
)
then
{ Dontfind(); }
else
{ Below: PageRect.Top; }
```

A pesar de lo sencillas que son las restricciones que comprueba este código, el código en sí es bastante extenso.

La idea es que, si el campo de fecha detectado mediante uno de los elementos **fecha** o **DateAsString** se encuentra a la derecha del campo Número de factura, pero al mismo nivel (con una tolerancia vertical de 30 dt), se indica a FlexiLayout Studio que debe generarse una hipótesis nula para el elemento auxiliar.

En los demás casos, el elemento **ShamElement** se buscará debajo del borde superior de la página. Como el elemento auxiliar es un elemento **párrafo** sin restricciones de búsqueda adicionales, abarcará todos los objetos de texto de la página y se generará una única hipótesis.

Casi todas las restricciones que deben comprobarse se entienden de forma intuitiva, por lo que aquí solo se describen las más complicadas.

```text theme={null}
max (InvoiceHeader.Rect.YCenter - Date1.Rect.YCenter, Date1.Rect.YCenter - InvoiceHeader.Rect.YCenter ) < 30dt
```

Esta parte del código comprueba que el campo de fecha (en este caso, si lo detecta el elemento **fecha**) esté situado en el mismo nivel horizontal que el elemento correspondiente al nombre del campo "Número de factura". La fecha puede estar ligeramente más arriba o más abajo que el nombre (debido a posibles errores durante el escaneo o el rellenado del documento).

La diferencia máxima se especifica como 30 dt. La posición vertical relativa de los campos "Fecha de la factura" y "Número de factura" se comprueba con el mismo método.

```text theme={null}
Date1.Rect.Left - InvoiceHeader.Rect.Right > 100dt
```

Esta línea comprueba que el campo de fecha está situado a la derecha del nombre del campo "Número de factura" (la coordenada del borde izquierdo de la fecha es mayor que la del borde derecho del nombre).

Se especifica una tolerancia de 100dt porque el propio número de factura debe quedar entre el nombre y la fecha. El campo de fecha está situado a la derecha del campo "Número de factura".

A continuación, se duplican todas las condiciones de la comprobación para el elemento **DateAsString**.

Para comprobar que el código es correcto, ejecute el procedimiento de emparejamiento de FlexiLayout en todas las páginas. En las páginas 1 y 3, donde el campo de fecha está situado a la derecha del número de factura, se generó una hipótesis nula para el elemento **ShamElement**. En las otras dos páginas, se detectaron fragmentos de texto.

<Frame>
  <img src="https://mintcdn.com/abbyy/lqYknuOmCa79141v/images/flexi-capture/fls/auxillary_element3.png?fit=max&auto=format&n=lqYknuOmCa79141v&q=85&s=c52bdce87a889d29654e1a4cc998ca34" alt="Captura de pantalla de los resultados del emparejamiento de FlexiLayout en ABBYY FlexiLayout Studio que muestra una hipótesis nula generada para el elemento auxiliar ShamElement en las páginas 1 y 3, donde el campo de fecha está situado a la derecha del número de factura." width="611" height="474" data-path="images/flexi-capture/fls/auxillary_element3.png" />
</Frame>

<div id="search-for-the-company-name-relative-to-the-invoice-fields">
  ## Buscar el nombre de la empresa en relación con los campos de facturas
</div>

Para detectar los datos de la empresa, el proyecto utiliza un elemento de grupo **CompanyGroup**. Agrupa el elemento **CompanyName** de tipo **cadena de caracteres** (el nombre de la empresa en las imágenes de prueba está escrito en una sola línea) y el elemento **dirección** de tipo **párrafo**. Este último elemento se utiliza para buscar el bloque que contiene la dirección de la empresa.

El uso del elemento auxiliar ayuda a simplificar el código que describe las restricciones de búsqueda del elemento en la sección de relación avanzada de prebúsqueda.

Si no se detecta el elemento auxiliar (es decir, se genera una hipótesis nula para él), esto significa que el campo de fecha está situado a la derecha del campo de factura. En este caso, el campo "Nombre de la empresa" se buscará debajo del campo "Número de factura".

Si se detecta el elemento auxiliar, el campo "Nombre de la empresa" se buscará encima del campo "Número de factura".

```text theme={null}
if ShamElement.IsNull then
{ Below: InvoiceGroup.InvoiceHeader;
Below: InvoiceGroup.InvoiceNum;
NearestY: PageRect.Top;
}
else
{ Above: InvoiceGroup.InvoiceHeader;
Above: InvoiceGroup.InvoiceNum;
}
```

<Note>
  En este caso, puede usarse la función `Nearest`, ya que permite identificar de forma inequívoca y precisa el campo que contiene el nombre de la empresa (no hay objetos que coincidan con las mismas restricciones de búsqueda).
</Note>

La sección Relaciones avanzadas de posbúsqueda del elemento **CompanyName** contiene el siguiente código.

```text theme={null}
if not IsNull then
{ FuzzyQuality: Rect.Left - PageRect.Left, {0, 0, 0, 50000}*dt;
FuzzyQuality: Rect.Top - PageRect.Top, {0, 0, 0, 50000}*dt;
FuzzyQuality: 100dt - Height, {0, 0, 0, 10000}*dt;
}
```

Este código funciona cuando se busca el campo de una sola línea "Nombre de la empresa" encima del campo del número de factura. Los campos buscados no tienen nombres. Al mismo tiempo, la posición relativa de los campos "Nombre de la empresa" y "Dirección de la empresa" es diferente en las páginas 2 y 4.

Las restricciones `Above: InvoiceGroup.InvoiceHeader;` y `Above: InvoiceGroup.InvoiceNum;` las cumplen no solo la cadena con el nombre de la empresa, sino también las cadenas del campo de dirección.

<Frame>
  <img src="https://mintcdn.com/abbyy/lqYknuOmCa79141v/images/flexi-capture/fls/auxillary_element4.png?fit=max&auto=format&n=lqYknuOmCa79141v&q=85&s=661fd13f411e171cfa77ad25abf2c445" alt="Captura de pantalla de ABBYY FlexiLayout Studio que muestra que la restricción Above relativa a los elementos InvoiceHeader e InvoiceNum la cumplen tanto la cadena del nombre de la empresa como las líneas del campo de dirección." width="611" height="474" data-path="images/flexi-capture/fls/auxillary_element4.png" />
</Frame>

Para seleccionar la única hipótesis correcta entre todas las hipótesis generadas, se usa el siguiente código en la sección Relaciones avanzadas de posbúsqueda.

Las líneas

```text theme={null}
FuzzyQuality: Rect.Left - PageRect.Left, {0, 0, 0, 50000}*dt;
```

y

```text theme={null}
FuzzyQuality: Rect.Top -PageRect.Top, {0, 0, 0, 50000}*dt;
```

indique a FlexiLayout Studio que aplique penalizaciones más severas a las hipótesis con objetos cercanos a los límites inferior y derecho de la imagen.

Sin embargo, en la página 2 el campo "Nombre de la empresa" está situado a la izquierda del campo de dirección, pero por debajo de su línea superior. Por lo tanto, las restricciones descritas no bastan para detectar el campo "Nombre de la empresa" buscado, y se necesita una restricción adicional.

```text theme={null}
FuzzyQuality: 100dt - Height, {0, 0, 0, 10000}*dt;
```

Esta línea le indica a FlexiLayout Studio que compruebe la altura de todas las líneas de las hipótesis generadas. Cuanto más altos sean los caracteres de la línea, mayor será la calidad de la hipótesis correspondiente.

Tras aplicar el FlexiLayout, puede ver que el campo "Nombre de la empresa" se ha detectado correctamente en todas las páginas.

<div id="search-for-the-address-field-with-the-auxiliary-element">
  ## Buscar el campo de dirección con el elemento auxiliar
</div>

Para detectar el campo de dirección, escriba el siguiente código en la sección **relación avanzada de prebúsqueda** del elemento **Dirección**:

```text theme={null}
if ShamElement.IsNull then
{ Below: CompanyName;
Above: TotalSumHeader.Rect.Top;
}
else
{
Above: InvoiceGroup.InvoiceHeader;
Above: InvoiceGroup.InvoiceNum;
RightOf: CompanyName.Rect.Left;
Exclude: CompanyName;
}
```

Aquí también se utiliza el elemento auxiliar **ShamElement**, lo que ayuda a simplificar el código.

La creación del FlexiLayout ya está completa. Una vez que haya ejecutado el procedimiento de emparejamiento de FlexiLayout, verá que todos los campos se han detectado correctamente.
