> ## 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.

# Simplifier un FlexiLayout à l’aide d’un élément auxiliaire et d’une hypothèse nulle

> Simplifiez le code FlexiLayout complexe à l’aide d’un élément factice auxiliaire dont l’hypothèse nulle indique quand des contraintes de recherche partagées sont satisfaites pour plusieurs éléments.

Utilisez cette méthode lorsque vous devez vérifier les mêmes contraintes de recherche complexes pour plusieurs éléments. L’idée est de ne vérifier les contraintes et d’effectuer les calculs qu’une seule fois, dans un élément auxiliaire.

En fonction du résultat de cette vérification, l’élément concerné est soit recherché, soit ignoré ; l’hypothèse trouvée ou non trouvée sert donc de marqueur indiquant si les contraintes sont remplies.

<div id="how-the-dummy-element-signals-that-the-constraints-are-met">
  ## Comment l’élément fictif signale que les contraintes sont remplies
</div>

Cet élément auxiliaire est créé pour pouvoir toujours détecter quelque chose sur les images, à condition que la fonction `DontFind()` (c’est-à-dire « arrêter la recherche ») ne soit pas activée. Le nombre d’hypothèses ne doit pas être trop élevé, afin d’éviter de développer excessivement l’arbre des hypothèses et d’augmenter le temps de mise en correspondance.

Pour y parvenir, vous pouvez utiliser, par exemple, des éléments de type **Object Collection** ou **Paragraph**. Ces éléments génèrent toujours une seule hypothèse qui inclut tous les objets du type spécifié dans la zone de recherche.

La section **relations avancées de pré-recherche** de l’élément fictif contient le jeu de conditions permettant de vérifier certains éléments situés sous l’élément fictif dans l’arborescence du projet. Si toutes les conditions sont remplies, la fonction `DontFind()` est appelée pour l’élément fictif.

Dans ce cas, une hypothèse nulle est générée pour l’élément fictif et sert de marqueur indiquant que toutes les conditions ont été remplies lorsque FlexiLayout Studio commence à rechercher d’autres éléments. Cela indique à FlexiLayout Studio de n’exécuter que la vérification `IsNull` de l’élément fictif au lieu de vérifier plusieurs fois les mêmes contraintes lourdes pour plusieurs éléments.

<Note>
  Cette méthode permet de rendre le code plus explicite. De plus, si vous devez modifier les contraintes, vous pouvez le faire uniquement dans la description de l’élément fictif. Cela réduit le risque d’erreurs logiques et syntaxiques lors de la duplication du code.
</Note>

<Note>
  Les futures versions du produit devraient prendre en charge la création de variables dans la zone des sous-éléments des groupes. Les résultats de la vérification des contraintes seront alors stockés dans les valeurs de différentes variables.

  La méthode actuelle est une solution temporaire (solution de contournement) qui aide à simplifier le code dans les sections Advanced de la version actuelle de FlexiLayout Studio.
</Note>

<div id="the-two-invoice-layouts-in-the-sample-project">
  ## Les deux mises en page de facture dans le projet d’exemple
</div>

Le projet `1.fsp` (dossier `%public%\ABBYY\FlexiCapture\12.0\Samples\FLS\Tips and Tricks\Auxiliary element`) montre le fonctionnement de cette méthode.

Sur ces images, l’objectif est de trouver les champs suivants : « Numéro de facture », « Date de la facture », « Nom de l’entreprise » et « Adresse de l’entreprise ».

Supposons que des factures de deux types différents doivent être traitées :

* Les champs « Nom de l’entreprise » et « Adresse de l’entreprise » se trouvent au-dessus du champ « Numéro de facture ».
* Les champs « Nom de l’entreprise » et « Adresse de l’entreprise » se trouvent en dessous du champ « Numéro de facture ».

Comme vous pouvez le voir sur les images, les champs « Nom de l’entreprise » et « Adresse de l’entreprise » n’ont pas de nom, ce qui empêche d’utiliser la procédure standard consistant à rechercher un champ de données à partir de son nom.

Cependant, il existe un certain motif : lorsque le champ de date se trouve à droite du numéro de facture, le nom et l’adresse de l’entreprise se trouvent sous le champ « Numéro de facture » (pages 1 et 3). Si le champ de date se trouve sous le champ « Numéro de facture », les coordonnées de l’entreprise se trouvent au-dessus du champ « Numéro de facture » (pages 2 et 4).

En tenant compte de ce motif, il est préférable de rechercher d’abord l’emplacement des champs « Numéro de facture » et « Date de la facture », puis de détecter les autres champs en s’appuyant sur ces deux champs, en spécifiant leurs positions relatives.

<div id="search-for-the-date-field-with-two-sets-of-constraints">
  ## Rechercher le champ de date avec deux jeux de contraintes
</div>

Le projet contient un élément **Group** **InvoiceGroup** avec les éléments **InvoiceHeader**, **InvoiceNum** et **DateHeader**, ainsi qu’un élément **Group** **DateGroup**. Ces sous-éléments sont nécessaires pour détecter les noms de champ ainsi que les champs "Numéro de facture" et "Date de la facture".

<Note>
  Pour plus d’informations sur les méthodes de recherche de date, voir [Recherche de date après une reconnaissance de qualité élevée ou faible](/fr/flexi-capture/fls/tips-tricks/date2). Cette section décrit uniquement les contraintes de recherche de date dans ce projet.
</Note>

Comme vous pouvez le constater, les champs de date dans les images n’ont pas toujours de nom.

Ainsi, lors de la recherche d’un champ de date, vous devez spécifier deux jeux de contraintes : l’un pour les cas où le nom a été détecté, et l’autre pour les cas où il ne l’a pas été (un cas particulier est celui où le nom est présent sur la page, mais n’a pas été détecté, par exemple à cause du bruit).

```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 le nom du champ de date est détecté (la contrainte `if not DateHeader.IsNull` est vérifiée), la recherche sera alors effectuée par rapport au nom du champ de date : à droite du nom, sur la même ligne horizontale, avec une certaine marge d'erreur pour le décalage vertical :

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

Sinon, la zone de recherche est divisée en deux rectangles : l’un à droite du numéro de facture, au même niveau que celui-ci, et l’autre sous le champ de facture.

<Note>
  Par souci de simplicité, supposez que les images sont de bonne qualité et que le champ "Numéro de facture" ainsi que son nom sont toujours détectés.

  Dans une situation réelle, avant d’accéder aux propriétés de ces éléments, vous devez effectuer le test `IsNull`, car si les éléments ne sont pas détectés, la recherche suivante sera effectuée par rapport aux zones de recherche des éléments correspondants.
</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="Capture d’écran dans ABBYY FlexiLayout Studio montrant la zone de recherche du champ de date, définie comme un tableau de rectangles à droite du champ Numéro de facture et en dessous de celui-ci lorsque le nom du champ de date n’est pas détecté." width="716" height="406" data-path="images/flexi-capture/fls/auxillary_element.png" />
</Frame>

<div id="penalize-date-hypotheses-far-from-the-invoice-fields">
  ### Pénaliser les hypothèses de date éloignées des champs de la facture
</div>

La section **Advanced post-search relations** de l’élément **Date** contient le code suivant :

```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;
}
}
```

Ce code influe sur la qualité de l’hypothèse de date en fonction de sa distance par rapport au nom du champ de facture et, si le nom du champ de date n’est pas détecté, par rapport au champ "Numéro de facture" lui-même.

Plus la distance par rapport aux champs spécifiés est grande, plus la pénalité appliquée aux hypothèses correspondantes sera élevée ; autrement dit, le champ de date le plus proche du champ "Numéro de facture" est recherché.

<Note>
  Pour plus d’informations sur l’utilisation de ces fonctions, consultez [Rechercher des éléments avec Nearest et FuzzyQuality](/fr/flexi-capture/fls/tips-tricks/date9).
</Note>

<div id="search-constraints-for-the-dateasstring-element">
  ### Contraintes de recherche pour l’élément DateAsString
</div>

Des contraintes de recherche identiques sont spécifiées pour l’élément **DateAsString**, mais sa section **Advanced post-search relations** ajoute une ligne de plus au code présenté précédemment :

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

Cette ligne est nécessaire lors de la recherche de la date, afin qu’une hypothèse comportant une chaîne plus longue de caractères de l’alphabet soit préférée à une plus courte.

De plus, l’onglet **contraintes de recherche** de l’élément **DateAsString** précise que, lors de la recherche de la date sous forme de chaîne de caractères, la Region de l’élément **InvoiceNum** doit être exclue.

Cela s’explique par le fait que, par souci de simplicité, les contraintes de recherche spécifiées dans la section **relations avancées de pré-recherche** de l’élément **Date** ne sont pas reprises pour l’élément **DateAsString**. À la place, la zone de recherche est définie comme `RestrictSearchArea (Date.Rect);`.

Cela indique à FlexiLayout Studio de rechercher l’objet de l’élément **DateAsString** dans la zone du rectangle flou de l’élément **Date**. La zone de recherche de l’élément **Date** peut être représentée comme un array de rectangles.

Lorsqu’une hypothèse nulle est générée pour l’élément **Date**, le rectangle englobant la zone de recherche est pris comme rectangle (`Rect`) de l’élément actuel. Comme vous pouvez le voir sur l’image suivante, il englobe également le champ "Numéro de facture" décrit par l’élément **InvoiceNum**.

Dans certaines conditions (par exemple, lorsque le champ de date est très bruité), il peut arriver qu’au lieu du champ de date, l’élément **DateAsString** détecte le champ du numéro de facture, car les caractères (y compris les chiffres) spécifiés pour cet élément ne sont soumis à aucune restriction de format.

<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="Capture d’écran dans ABBYY FlexiLayout Studio montrant la zone de recherche de l’élément DateAsString, définie par RestrictSearchArea sur l’élément Date non détecté, englobant également le champ Numéro de facture décrit par l’élément 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">
  ## Vérifier la disposition des champs à l’aide de l’élément auxiliaire ShamElement
</div>

Une fois les éléments nécessaires à la recherche des champs "Numéro de facture" et "Date de la facture" décrits, l’étape suivante consiste à rechercher les champs "Nom de l’entreprise" et "Adresse de l’entreprise".

Le projet utilise un élément **Paragraph** nommé **ShamElement**. Cet élément sert d’élément auxiliaire et est utilisé exclusivement pour vérifier la position relative des champs "Numéro de facture" et "Date de la facture".

La section **relations avancées de pré-recherche** de l’élément auxiliaire contient le code suivant :

```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; }
```

Malgré la simplicité des contraintes vérifiées par ce code, celui-ci est plutôt lourd.

L'idée est que si le champ de date détecté au moyen de l'un des éléments **Date** ou **DateAsString** se trouve à droite du champ Numéro de facture, mais au même niveau (avec une tolérance verticale de 30 dt), FlexiLayout Studio reçoit l'instruction de générer une hypothèse nulle pour l'élément auxiliaire.

Dans les autres cas, l'élément **ShamElement** sera recherché sous le bord supérieur de la page. Comme l'élément auxiliaire est un élément **Paragraph** sans contrainte de recherche supplémentaire, il englobera tous les objets texte de la page, et une seule hypothèse sera générée.

La quasi-totalité des contraintes à vérifier est intuitive ; seule la plus compliquée d'entre elles est donc décrite ici.

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

Cette partie du code vérifie que le champ de date (dans ce cas, s’il est détecté par l’élément **Date**) se trouve sur la même ligne horizontale que l’élément correspondant à l’intitulé du champ "Numéro de facture". La date peut être légèrement plus haut ou plus bas que l’intitulé (en raison d’éventuelles erreurs lors de la numérisation ou du remplissage du document).

La différence maximale est définie à 30 dt. La position verticale relative des champs "Date de la facture" et "Numéro de facture" est vérifiée à l’aide de la même méthode.

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

Cette ligne vérifie que le champ de date se trouve à droite du libellé du champ "Numéro de facture" (la coordonnée de la limite gauche de la date est supérieure à celle de la limite droite du libellé).

Une tolérance de 100dt est spécifiée, car le numéro de facture lui-même doit se trouver entre le libellé et la date. Le champ de date se trouve donc à droite du champ "Numéro de facture".

Toutes les conditions de cette vérification sont ensuite dupliquées pour l’élément **DateAsString**.

Pour vérifier que le code est correct, exécutez la procédure de mise en correspondance sur toutes les pages. Sur les pages 1 et 3, où le champ de date se trouve à droite du numéro de facture, une hypothèse nulle a été générée pour l’élément **ShamElement**. Sur les deux autres pages, des fragments de texte ont été détectés.

<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="Capture d’écran des résultats de la mise en correspondance dans ABBYY FlexiLayout Studio montrant une hypothèse nulle générée pour l’élément auxiliaire ShamElement sur les pages 1 et 3, où le champ de date se trouve à droite du numéro de facture." 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">
  ## Rechercher le nom de l’entreprise par rapport aux champs de la facture
</div>

Pour détecter les coordonnées de l’entreprise, le projet utilise un élément **Group** **CompanyGroup**. Il regroupe l’élément **CompanyName** de type **Character String** (sur les images de test, le nom de l’entreprise est écrit sur une seule ligne) et l’élément **Address** de type **Paragraph**. Ce dernier élément est utilisé pour rechercher le bloc contenant l’adresse de l’entreprise.

L’utilisation de l’élément auxiliaire permet de simplifier le code qui décrit les contraintes de recherche de l’élément dans la section des **relations avancées de pré-recherche**.

Si l’élément auxiliaire n’est pas détecté (c’est-à-dire qu’une hypothèse nulle est générée pour lui), cela signifie que le champ de date se trouve à droite du champ de la facture. Dans ce cas, le champ "Nom de l’entreprise" sera recherché sous le champ "Numéro de facture".

Si l’élément auxiliaire est détecté, le champ "Nom de l’entreprise" sera recherché au-dessus du champ "Numéro de facture".

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

<Note>
  Dans ce cas, la fonction `Nearest` peut être utilisée, car elle permet de détecter avec précision et sans ambiguïté le champ contenant le nom de l’entreprise (aucun objet ne correspond aux mêmes contraintes de recherche).
</Note>

La section **Advanced post-search relations** de l’élément **CompanyName** contient le code suivant.

```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;
}
```

Ce code fonctionne lorsque le champ sur une seule ligne "Nom de l’entreprise" est recherché au-dessus du champ Numéro de facture. Les champs recherchés n’ont pas de nom. En même temps, la position relative des champs "Nom de l’entreprise" et "Adresse de l’entreprise" diffère sur les pages 2 et 4.

Les contraintes `Above: InvoiceGroup.InvoiceHeader;` et `Above: InvoiceGroup.InvoiceNum;` sont satisfaites non seulement par la chaîne contenant le nom de l’entreprise, mais aussi par les chaînes du champ d’adresse.

<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="Capture d’écran dans ABBYY FlexiLayout Studio montrant que la contrainte Above relative aux éléments InvoiceHeader et InvoiceNum est satisfaite à la fois par la chaîne du Nom de l’entreprise et par les lignes du champ d’adresse." width="611" height="474" data-path="images/flexi-capture/fls/auxillary_element4.png" />
</Frame>

Pour sélectionner la seule hypothèse correcte parmi toutes celles qui ont été générées, on utilise le code suivant dans la section Advanced post-search relations.

Les lignes

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

et

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

indiquent à FlexiLayout Studio d’appliquer des pénalités plus fortes aux hypothèses comportant des objets proches des limites inférieure et droite de l’image.

Cependant, sur la page 2, le champ "Nom de l’entreprise" se trouve à gauche du champ d’adresse, mais plus bas que sa ligne supérieure. Les contraintes décrites ne suffisent donc pas à détecter le champ recherché "Nom de l’entreprise" et une contrainte supplémentaire est nécessaire.

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

Cette ligne indique à FlexiLayout Studio de vérifier la hauteur de toutes les lignes pour les hypothèses générées. Plus les caractères d’une ligne sont grands, plus la qualité de l’hypothèse correspondante est élevée.

Après la mise en correspondance avec le FlexiLayout, vous pouvez voir que le champ "Nom de l’entreprise" a bien été détecté sur toutes les pages.

<div id="search-for-the-address-field-with-the-auxiliary-element">
  ## Rechercher le champ d’adresse à l’aide de l’élément auxiliaire
</div>

Pour détecter le champ d’adresse, saisissez le code suivant dans la section des **relations avancées de pré-recherche** de l’élément **Address** :

```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;
}
```

Ici encore, l’élément auxiliaire **ShamElement** est utilisé pour simplifier le code.

La création du FlexiLayout est désormais terminée. Une fois la procédure de mise en correspondance exécutée, vous constaterez que tous les champs ont bien été détectés.
