Aller au contenu
Accueil » Hopes.studio – Empower your business by fulfilling client’s hopes » H-L : Hopes Language

H-L : Hopes Language

Le langage spécialisé pour la modélisation des interfaces commerciales pour toute gamme de produits imprimés, pliés et assemblés, sur mesure et personnalisés…

Introduction

Le H-L est le JSON-based domain-specific-language (DSL) de Hopes.studio, un langage métier spécifique basé sur le JSON. Le H-L, répond au besoin du domaine d’application de Hopes.studio, à savoir la commercialisation de produits physiques fabriqués par assemblage de composants éventuellement imprimés, découpés et éventuellement pliés.

Une approche low-code

En règle générale, le développement de logiciels nécessite beaucoup de « code standard » : des sections de code répétées à plusieurs endroits avec peu ou pas de variations, utilisées pour exécuter des fonctions de base. Dans les langages de programmation verbeux, cela nécessite beaucoup de travail et de temps.   

Pour réduire le temps consacré à ce que de nombreux programmeurs considèrent simplement comme un travail subalterne, ils peuvent adopter une approche low-code basée sur un langage de programmation personnalisé qui effectue tout le travail standard pour eux.   

Hopes.studio utilise un langage spécifique à un domaine (DSL) personnalisé créé en interne par notre équipe R&D. 

Ce langage est conçu selon une conception pilotée par domaine. Cela signifie qu’il est conçu pour correspondre au « domaine d’activité », le secteur d’activité ciblé par le logiciel en fonction des flux de travail et des entrées requis par le domaine de Hopes.studio 

Objectifs

La raison d’être de H-L est de simplifier l’écriture des fichiers bibliothèques décrivant paramétriquement des objets physiques nono-partie ou multi-parties issuent de la découpe et éventuellement du pliage de feuille/plaque, et assemblée(s) (si multi-parties).

Cette description paramétrique est réalisée de manière à répondre à 4 contextes d’utilisation, le recueil du besoin, la visualisation d’une maquette en 3 dimensions, l’évaluation tarifaire de la réponse au besoin et enfin les besoins du processus de fabrication.

Contexte de recueil du besoin

Pour recueillir le besoin d’un client, il faut l’interroger, donc construire un formulaire. Le H-L va permettre de spécifier cette interface utilisateur de recueil du besoin en décrivant les champs nécessaires, leur organisation ainsi que leurs interactions.

Contexte de visualisation d’une maquette 3D

Feed back essentiel de validation des besoin pour le client, la maquette du produit lui permet de visualiser l’impact de ses choix, de corriger le besoin ou de se projeter. La maquette 3D numérique est aussi un formidable moyen de partager son projet avec une communauté de parties prenantes. Il est même possible d’envisager du co-design. Le H-L va permettre de spécifier paramétriquement les géométries des sous-ensembles et l’agencement de ces sous-ensemble.

Contexte d’évaluation tarifaire

Feed back essentiel de validation du budget pour le client, l’évaluation tarifaire par l’établissement d’un devis est une étape indispensable à toute transaction commerciale. Le H-L permet de formaliser la requête d’interrogation d’un CPQ (Configure Price Quote) comme Clariprint.

Contexte de conception et fabrication

Quand la géométrie des produits est paramétrique, il est essentielle pour les processus de conception et fabrication de calculer les fichiers numérique de découpe, perçage, rainage. Tout comme pour la maquette 3D, le H-L permet de spécifier vectoriellement les géométries des sous-ensembles, autorisant ainsi la production automatique des fichiers de découpe. Ces fichiers de découpe serviront d’une part à la réalisation du design par les graphistes et d’autre part à l’automatisation des processus de fabrication.

Versatilité du H-L

Tourné vers les métiers et accessible à un non informaticien, le H-L offre des commodités qui lui apportent une grande flexibilité, comme :

  1. la possibilité de déclarer des variables dont les valeurs peuvent être des résultantes d’expression ;
  2. le recourt possible à des fonctions mathématiques dans les expressions ;
  3. des structures d’itération ;
  4. les expressions booléennes dans la structure « IF », « THEN », « ELSE » ;
  5. une version du switch case basée sur l’utilisation des tables ;
  6. un mécanisme d’héritage multiple, total ou partiel, pour favoriser la mutualisation des ressources ;

Ces commodités autorisent une grande liberté de création qui permet de répondre à une multitude de typologie de produits et de créer des offres innovantes.

Dans le framework Hopes.studio, les fichiers H-L sont interprétés par Hopes.studio Server pour adresser différents services via ses APIs.

Dans le framework Hopes.studio, les APIs de Hopes Headless Serveur sont invoqués par Hopes CSR qui est un client-side js framework.

Exemple d’usages via les APIs de Hopes Headless Server

L’API « GetJsonParameters » va interpréter la modélisation de l’interface utilisateur et retourner une structure de spécification qui sera interprétée par H-CSR (Client-Side Rendering) pour construire cette interface utilisateur.

L’API « GetSVGs » va interpréter l’arborescence du modèle et les expressions vectorielles des chemins de découpe et de pliage, pour retourner une liste de fichiers SVG de découpe et rainage. Ces fichiers serviront, d’une part aux graphistes pour concevoir les visuels. D’autre part aux fabricants pour concevoir les outils et/ou paramétrer les machines de découpe.

L’API « GetWebGl » va interpréter l’arborescence du modèle et les expressions vectorielles des chemins de découpe et de pliage, les setup géométriques ainsi que les actions graphiques, pour retourner un contexte graphique sous forme d’une structure d’objets qui sera interprétée par H-sampler, le sampler 3D WebGl de Hopes.studio.

Le concept de Require dans H-L

Le H-L est basé sur le concept de Require. Une Require est une ressource globale à un package H-L. Les fichiers bibliothèques H-L sont regroupés dans un dossier accessible par H-server. H-server construit automatiquement un index de ces fichiers, ainsi qu’un index des Require. De cette manière, il est possible d’invoquer au sein d’un fichier H-L, une Require déclarée dans un autre fichier sans se soucier de sa localisation.

Le concept de Require est un concept abstrait générique qui n’apparaît pas directement dans le vocabulaire du langage H-L. Dans H-L, nous utiliserons concrètement 6 sous-types de Require qui ont des rôles bien définis : Alias, Template, Group, Layout, Scene et CPQ.

Require / Alias

Chaque Alias peut être vu comme une ressource globale de type table, list, number, boolean ou string.

Require / Template

Chaque template représente une forme géométrique définie en deux dimensions, d’une part, par des faces dont le contour est décrit par un chemin vectoriel paramétrique, d’autre part, par des plis reliant chacun deux faces. Un template simple peut ne comporter qu’une seule face et ne pas avoir de pli. En outre, il est possible de décrire, pour chaque face, des chemins de découpes internes.

Require / Group

Un groupe est une composition de sous-groupe ou template, le regroupement permet une encapsulation facilitant notamment le positionnement 3D initial, puis le déplacement du groupe comme un seul bloc.

Require / Layout

La notion de Layout dérive de la notion de Group, c’est donc une composition d’éléments fils qui va permettre en plus de spécifier des interfaces. Interface utilisateur d’une part, et interface avec le serveur CPQ (Configure Price Quote) d’autre part.

Require / Scene

Une Scene fait référence à un Layout, elle permet de définir des séquences d’animation. Il est possible de se passer de Scene dans un premier temps car la notion de Layout autorise un mode « autoplay » qui joue automatiquement ses actions graphiques au chargement. Précisément, le mode « autoplay » d’un Layout crée automatiquement une Scene avec une série de séquences d’une seconde, chaque séquence jouant une action du Layout.

Require / CPQ

Les Requires de type CPQ vont permettre de spécifier des serveurs qui répondront à une requête de devis (RFQ : Request For Quote) et d’y faire référence dans un Layout pour préciser dans quel contexte business il évolue.

La syntaxe du JSON

Le JSON à l’avantage de proposer une syntaxe très simple et lisible qui est présentée exhaustivement sur json.org.

Pour résumer, le JSON reconnait pour les valeurs les types string, number, boolean, list/array et structure/table/objet (le vocabulaire peut varier en fonction des sensibilités). D’après la documentation officielle sur json.org, on nomme « array » les listes et « object » les structures/tables.

number

Regroupe les nombres entiers et les nombres réels dont la décimale et le caractère ‘.’.

string

Une string est une chaine de caractère entourré par des guillements ‘ »‘. Pour les caractères autorisés et spéciaux je vous prie de consulter la documentation officielle.

boolean

Un boolean est soit true (pour vrai) soit false (pour faux).

list / array

Les list/array sont des listes de valeurs séparé par le caractère ‘,’ (virgule) et entouré par les caractère ‘[‘ (crochet ouvrant) et ‘]’ (crochet fermant).

[ value1, value2, ..., valueN ]

Note : value1, value2, valueN sont des valeurs de type number, string, boolean, array ou object.

Dans la suite de ce document nous utiliserons préférentiellement le terme list.

table / structure / object

Les table sont des structures clef/valeur avec la syntaxe suivante :

{
  "key1" : value1,
  "key2" : value2,
...
  "keyN" : valueN
}

Note : value1, value2, valueN sont des valeurs de type number, string, boolean, array ou object.

Il est donc possible de représenter une arborescence en imbriquant les table/structure/objet.

Dans la suite du document nous utiliserons préférentiellement le terme table.

La syntaxe du H-L

Le H-L est une extension du JSON, cette extension est réalisée grâce à une arborescence codifiée et un vocabulaire de rubrique dédié.

Dans la suite du document nous allons vous présenter cette codification à travers les 11 sujets suivants :

  1. la structure de base du H-L
  2. le vocabulaire et le mécanisme de l’héritage des Require
  3. les expressions et les caractères d’invocation
  4. les différents type d’expression
  5. le vocabulaire et la structure spécifique d’un Template
  6. le vocabulaire et la structure spécifique des Group et Layout
  7. les rubriques spécifiques « parameters_value » et « variables« 
  8. les contextes d’évaluation des expressions
  9. le vocabulaire et la structure spécifique à l’invocation d’un CPQ
  10. le vocabulaire et la structure spécifique à la définition des actions graphiques
  11. un exemple de fichier bibliothèque écrit en H-L

La structure de base d’un fichier H-L

Un fichier H-L est une table avec au moins une des 6 rubriques majeures suivantes :

  • « alias » : de type table d’Alias, exemple { « nom de l’alias » : « valeur de l’alias », … }
  • « templates » : de type list de table, exemple [ {« name » : « tpl1 »},{« name » : « tpl2 »}, … ]
  • « groups » : de type list de table, exemple [ { « name » : « grp1 »},{« name » : « grp2 »}, …]
  • « layouts » : de type list de table, exemple [ { « name » : « lay1 »}, { « name » : « lay2 » }, …]
  • « scenes » : de type list de table, exempe [ « name » : « sce1 »}, { « name » : « sce2 » }, …]
  • « CPQs » : de type list de table, exemple [ {« name » : « CPQ1 »}, { « name » : « CPQ2 » }, … ]

En dehors des alias toutes les Require sont définies par des tables comportant à minima les rubriques suivantes :

  • « name » : obligatoire, de type string, caractères autorisés ‘a’-‘z’, ‘A’-‘Z’, ‘0’-‘9’, ‘_’, pas d’espace, représente le nom de la Require qui sera utilisé pour son invocation
  • « description » : optionnel, de type string, un texte descriptif

Exemple de fichier H-L

Apparaît en gras le vocabulaire spécifique à H-L.

{
 "alias" : {   "al1" : "hello world",
   "al2" : 24,
   "al3" : ["hello","the","world"],
   "al4" : { "H" : 24, "W" : 12, "L" : 54 }
},
 "templates" : [
   {
    "name" : "TPL1",
    "description" : "this is a template"
   }
 ],
 "groups" : [
   {
     "name" : "GRP1",
     "description" : "this is a group"
   }
 ],
 "layouts" : [
   {
     "name" : "LAY1",
     "description" : "this is a layout"
   }
],
 "scenes" : [
   {
     "name" : "SCENE1",
     "description" : "this is a scene"
   }
 ],
 "CPQs" : [
        {
            "name" : "myClariprintDev",
            "appName" : "Clariprint",
            "server_url" : "http://dev.clariprint.local/optimproject/json.wcl",
            "login" : "QYP",
            "password" : "QYP"
        }
 ]
}

Le mécanisme d’héritage

Le concept d’héritage de classe en informatique formalise le fait que 2 catégories (ou classes) d’objets qui partagent plusieurs propriétés peuvent être décrites comme extension d’une troisième catégorie (classe) mère qui recense les propriétés communes et interfaces communes.

H-L est basé sur JSON et chaque Require est organisée en table avec des rubriques de premier ordre comme « reification_params« , « required_fileds« , « composition« , « actions« , etc (la liste complète est à découvrir dans les sections suivantes). Le mécanisme d’héritage dans H-L va permettre la réutilisation pour une Require X de tout ou partie des rubriques de premier ordre des Require A,B,C etc …

Pour utiliser ce mécanisme dans H-L, toute Require peut comporter la rubrique « extends » de type string ou list de string. Cette rubrique « extends » permet de lister les Requires mères dont va hériter la Require courante. Ce mécanisme d’héritage autorise la redéfinition des parties du modèle et l’ordre dans la liste a une importance. En effet, La Require mère d’index n+1 dans la liste « extends » peut redéfinir des parties de la Require mère d’index n. En outre, dans H-L, le mécanisme d’héritage autorise l’héritage partiel via l’opérateur d’exploration « §« .

Exemple d’héritage :

      {
            "name" : "L_TOP_LEVEL_LAYOUT",
           "extends" : [
                "L_Base_Cards",
                "L_Ncards_in_four_folds_box_with_lid§reification_params",
                "L_N_rounded_cards§reification_params",
                "L_Book-square§reification_params",
                "L_Support_one_insert§reification_params",
                "L_Ncards_in_four_folds_box_with_lid§optional_params",
                "UIO_FULL_EXTENDS_BASE"
            ],
            ...
      }

Les caractères d’invocation ‘#’, ‘$’, ‘§’ dans les expressions

Le H-L supporte des expressions dans les valeurs de type string. Ces expressions sont destinées à être évaluées dans un contexte précis et pour un objectif précis. Pour faire appel à des éléments du contexte nous pouvons utiliser les 3 caractères spéciaux ‘#‘, ‘$‘ et ‘§‘ présenté ci-après.

#

Chaque Require peut être invoquée dans une expression en utilisant le préfixe « # » suivi du nom de la Require.

L’invocation peut être simple (exemple : « var1 » : « #RequireName ») ou paramétrisée grâce à deux méthodes alternatives :

  • soit via une table :
"param4" : { "#RequireName": {"param1" : {"A" : "value1", "B" : "value3"}, "param2" : "value2", ... }
  • soit dans une string :
"param4" : "#RequireName?param1=value1&param2=value2&..."

La première méthode permet l’affectation aux paramètres de valeurs de type list ou table, la deuxième se limite aux types simples mais est plus concise et plus lisible.

$

Les paramètres ainsi passés pourront être appelés comme les variables dans une expression grâce au préfixe « $« , exemple :

"var1" : "$param1_$param2" // résultera une concaténation des valeurs de type string séparées par '_'
"var2" : "=$param1 + $param2" // résultera l'addition des valeurs de type number

§

Admettons, pour « param1 » la valeur de type table suivante :

"param1" : {
   "a1" : {
     "b1" : {"c1" : 2}, 
     "b2" : 3
   }, 
   "a2" : "coucou
}

Il est possible d’accéder aux sous-valeurs grâce à l’opérateur d’exploration des tables/objets « §« . Ainsi :

"$param1§a1§b1"      === {"c1" : 2 }
"$param1§a1§b1§c1"   === 2
"$param1§a2"         === "coucou"

Les parameters_values

Dans chaque Require, il est possible de définir des valeurs par défaut via la rubrique « parameters_value » de type table, exemple :

"parameters_value" : {
  "param1" : "default1",
  "param2" : "default2",
  ...
}

Les paramètres de « parameters_value » peuvent être de type string, number, boolean, list ou table.

Les paramètres de « parameters_value » seront mixés avec les paramètres d’invocation de la Require, la priorité revenant aux paramètres d’invocation.

Les variables

Dans la plupart des Require, il est possible de définir des variables via la rubrique « variables » de type table, exemple :

"variables" : {
  "var1" : "exp1",
  "var2" : "exp2",
  ...
}

Une expression de variable peut aboutir à une valeur de type :

  • list, table, pour une invocation directe d’une Require ou d’une autre variable ou paramètre
  • number, si l’expression commence par « = » et que des opérateurs mathématiques sont utilisés entre les invocations de variables et/ou des nombre, exemple :
"var1" : "=cos($param1§a1§b1§c1 * #CONSTANTS§PI / 180)"
  • Certaines fonctions mathématiques sont disponibles tel que cos, sin, tan, abs, min, max, sign, +, *, /, –
  • boolean, si l’expression commence par « = » et que des opérateurs booléen sont utilisés tel que « & » et « | » :
"IF" : "'$T§target' = 'Empty' | '$T' = 'Empty' | '$T' = '#Empty'"
"IF" : "$i < 10"
  • string, si l’expression comporte du texte et des variables, exemple :
"var2" : "$param1§a2 les amis !"

Les différents types d’expression

Le langage H-L propose 6 types d’expressions.

Expression qui commence par ‘#’

Invocation paramétrique d’une Require, exemple :

"#L_BASE_LAYOUT§variables§total_thickness?N=10,card_thickness=0.4"

La valeur résultante sera la valeur de la sous-rubrique « total_thickness » de la sous-rubrique « variables » de la Require « L_BASE_LAYOUT » évaluée avec les paramètres « N » vaut 10 et « card_thickness » vaut 0.4. Le type de la valeur résultante dépendra de cette évaluation.

Expression qui commence par ‘=’

Les expressions commençant par ‘=’ ont pour objectif un calcul mathématique et donc doivent retourner un number. Si au moins une des variables de l’expression n’est pas connu la valeur reste l’expression inchangée et un warning est enregistré.

Exemple d’expression :

"=max($LG+2*$GAME_MARGINS_IN_WIDTH*$insert_number,$MIN_BOOK_WIDTH*$book_notice_number)"

L’exemple ci-dessous montre l’utilisation des opérateurs d’addition ‘+’ et multiplication ‘*’, ainsi que l’utilisation de la fonction « max » qui retourne la valeur maximale de 2 entrées séparées par le caractère ‘,’ (virgule).

Les opérateurs mathématiques reconnus dans H-L sont : ‘+’ (addition) , ‘-‘ (soustraction), ‘*’ (multiplication), ‘/’ (division).

Les fonctions mathématiques reconnues sont :

  • « max » : retourne la valeur maximal parmi 2 paramètres
  • « min » : retourne la valeur minimal parmi 2 paramètres
  • « cos » : retourne le cosinus du paramètre
  • « sin » : retourne le sinus du paramètre
  • « abs » : retourne la valeur absolue du paramètre
  • « sign » : retourne le signe 1 si le paramètre est positif sinon retourne -1

Expression qui commence par « CALLFUNC »

« CALLFUNC » permet d’invoquer une fonction spéciale de résolution pour traiter les tables et listes.

Exemple d’utilisation :

                "book_notice_number_table" : {
                    "without" : 0,
                    "folded" : 0,
                    "stitching" : 1,
                    "perfect binding" : 1
                },
                "book_notice_number" : "CALLFUNC(nth,$book_notice_number_table,$notice_option§value)",

Ici nous invoquons la fonction « nth » avec les paramètres « $book_notice_number_table » et « $notice_option§value ».

La fonction « nth » est actuellement la seule disponible, le premier paramètre est de type table et le second de type string.

Le résultat de l’invocation de « nth » est la valeur dans la table du premier paramètre de la rubrique dont le nom est égal à la valeur du second paramètre. Dans l’exemple ci-dessus :

  • si « $notice_option§value » vaut « stitching » ou « perfect_binding » la valeur de retour sera 1.
  • si « $notice_option§value » vaut « folded » ou « without » la valeur de retour sera 0.

Grâce à ce type d’expression, il est possible de simuler une structure de contrôle de type switch/case.

Expression qui ne commence ni par ‘#’ ni par ‘=’ ni par « CALLFUNC »

Dans le cas général ou l’expression ne commence ni par ‘#’ ni par ‘=’ ni par « CALLFUNC », l’expression sera évaluée comme une chaîne de caractère si l’ensemble des variables invoquées peut être évalué comme une chaîne de caractère. Exemple :

"notice_insert_option" : "$notice_option§value_$insert_option§value"

Ici les 2 invocations « $notice_option§value » et « $insert_option§value » seront évaluées et leur résultante string seront concaténée via le caractère ‘_’. Exemple de résultat : « stitching_yes »

Cas particulier des expressions booléenne de la rubrique « IF »

la rubrique « IF » apparaît dans une table de structure de contrôle de type IF, THEN, ELSE. L’expression de la rubrique « IF » est une expression de type booléenne.

Exemple 1 :

         "N" : {"IF" : "'$V' = 'bridge'", "THEN" : 54, "ELSE" : 78}

Un exemple simple avec l’opérateur d’égalité ‘=’ appliqué à 2 chaines de caractère

Exemple 2 :

         "Z": {"IF" : "$i < 10", "THEN" : "0$i", "ELSE" : "$i"}

Ici l’opérateur de comparaison ‘<‘ entre 2 number

Exemple 3 :

  "TB" : {"IF" : "'$B1§target' = 'Empty' | '$B1' = 'Empty' | '$B1' = '#Empty'", "THEN" : "0","ELSE" : "90"}

Ici l’utilisation de l’opérateur logique OU grâce au caractère ‘| ».

Note : L’opérateur logique ET en H-L est ‘&’.

Cas particulier de la rubrique « d » des faces et plis de Template

La rubrique « d » (et « cuts« ) est une des principales raison d’être du H-L. Elle contient l’expression du chemin vectoriel !

La syntaxe de ce type d’expressions est directement inspirée de la syntaxe de l’attribut « d » de l’élément « <path> » du SVG. Cette syntaxe permet d’exprimer une série de commande de type :

  • déplacement sans tracé : « m dx dy » ou « M X Y »
  • déplacement linéaire oblique avec tracé : « l dx dy » ou « L X Y »
  • déplacement linéaire horizontal avec tracé : « h dx » ou « H X »
  • déplacement linéaire vertical avec tracé : « v dy » ou « V Y »
  • déplacement curviligne suivant une courbe de Bézier cubique : « c dx1 dy1 dx2 dy2 dx dy » ou « C X1 Y1 X2 Y2 X Y »
  • déplacement curviligne suivant une courbe de Bézier quadratique : « Q dx1 dy1 dx dy » ou « Q X1 Y1 X Y »

L’ajout majeur du H-L à cette syntaxe est la possibilité d’exprimer les coordonnées par des formules mathématiques invoquant des variables.

C’est cette capacité qui rend le système géométrique paramétrique.

Nous retrouverons l’usage de ce type d’expression dans la suite du document dans la définition des Template au niveau des rubriques « faces« , « folds » via les sous rubriques « d » et « cuts« .

Exemple d’expression de chemin vectoriel :

        "d" : "m0,0 v-$W h$L-2*$E v$W m2*$E-$L,0"

La structure d’un Template

Les Requires de type Template disposent de deux rubriques spécifiques, « folds » et « faces« , toutes deux de type list. « folds » contient la liste des plis du Template et « faces » la liste des faces du Template.

Les faces

Chaque face est décrite par une table comprenant les rubriques suivantes :

  • « name » : obligatoire, de type string, caractères autorisés ‘a’-‘z’, ‘A’-‘Z’, ‘0’-‘9’, ‘_’, pas d’espace, nom de la face
  • « d » : de type string, chemin (path) du contour de la face. Ce chemin vectoriel est défini par une expression qui respecte la syntaxe des path SVG mais permet d’invoquer des variables et même d’inclure des expressions mathématiques, exemple :
"d" : "m0,0 l0,-$H+2*$E m$L,0 l0,$H-2*$E M0,0" 

Note : Si la face courante est une face fille alors « d » est défini relativement au vecteur du pli.

  • « folds » : de type list, la liste des nom de plis reliant la face courante à ses faces filles, exemple
"folds" : ["Fa2FaV1", "Fa2FaV2", "Fa2Fb" ]
  • « cuts » : de type list, la liste des chemins vectoriels de découpe interne à la face. Ces chemins sont exprimés suivant la même syntaxe que la rubrique « d« , exemple :
                    "cuts" : [
                                "m$mg,-$H+$mk q0,-$hr $hr,-$hr h$sg q$hr,0 $hr,$hr q0,$hr -$hr,$hr h-$sg q-$hr,0 -$hr,-$hr",
                                "m$L-$mg-2*$hr-$sg,-$H+$mk q0,-$hr $hr,-$hr h$sg q$hr,0 $hr,$hr q0,$hr -$hr,$hr h-$sg q-$hr,0 -$hr,-$hr",
                                "m$mg,-$H+$mk+3*$hr q-$hr,0 -$hr,$hr v$sk q0,$hr $hr,$hr q$hr,0 $hr,-$hr v-$sk q0,-$hr -$hr,-$hr"
                            ]

Les plis

Chaque pli est décrit par une table comprenant les rubriques suivantes :

  • « name » : de type string, caractères autorisés ‘a’-‘z’, ‘A’-‘Z’, ‘0’-‘9’, ‘_’, pas d’espace, nom du pli
  • « d » : de type string, le positionnement et tracé (path) du pli. L’expression est du même type que pour la rubrique « d » d’une face
  • « relativeToMaster » : de type booleen, true si « d » est défini par rapport au repère de la face mère, false si « d » est défini par rapport au repère du Template.
  • « theta_closed » : de type number, valeur en degré de l’angle au pli des deux faces quand le pli est fermé
  • « fold_radius » : optionnel, de type number, permet de personnaliser le rayon de courbure au pli
  • « morphGroup » : de type number, permet d’affecter un indice de transformation utilisé pour invoqué des transformations dans les actions d’animations
  • « child_face » : de type string, contient le nom d’une face fille déclarée dans le Template ou la référence à un autre Template ,

Exemple d’affectation de « chid_face »

Cas d’invocation d’une face déclarée dans le Template
"child_face" : "FS_FS1" 
Cas d’invocation du Template « Sflap » avec affectation des paramètres « L » et « W » de la cible
"child_face" : {"#Sflap":{"L":"$W","W":"$H"}}
Cas d’invocation dynamique de valeur de la variable $Fflap
"child_face" : "#$Fflap"

Exemple de valeurs pur « $Fflap », ou « T_Flap » correspond au « name » du Template ciblé et « A » et « M » aux paramètres affectés des valeurs 180 et 2 :

"Fflap" : {"#T_Fflap" : { "A" : 180, "Mg" : 2 }} 

"Fflap" : "#T_Flap?A=180&Mg=2" 

La possibilité de référencer un Template externe offre une grande liberté dans la définition des Templates, elle autorise entre autre la construction des Templates par récursivité d’un motifs comme le montre l’exemple de la bibliothèque des dépliants à la fin du document.

La structure des Layouts et Groups

La spécification de l’interface utilisateur

Les Requires de type Layouts sont les objets finaux qui contiennent toutes les définitions d’interfaces, d’une part d’interface graphique à travers les rubriques suivantes :

  • « reification_params » : liste des paramètres de réification. ces paramètres sont utilisés pour invoquer un Layout en spécialisant le contexte, par exemple le domaine ou la valeur par défaut des champs de formulaire
  • « required_fields » : liste des champs principaux du formulaire
  • « optional_fields » : liste des champs optionnels du formulaire
  • « graphic_fields » : liste des champs de personnalisation graphique du modèle
  • « delivery_fields » : liste des champs contenant les rubriques conditionnement et livraison
  • « user_interface_organizer » : table qui décrit, d’une part, comment les différents champs seront regroupés et classés. D’autre part les interactions dynamiques entre les champs de formulaire

reification_params

Définition

Chaque paramètre de réification est une table comportant les rubriques suivantes :

  • « name » : de type string, caractères autorisés ‘a’-‘z’, ‘A’-‘Z’, ‘0’-‘9’, ‘_’, pas d’espace, nom du paramètre
  • « label » : de type string, description libre
  • « type » : valeur au choix parmi « text », « list » ou « object »
  • « options » : de type list, uniquement pour un paramètre de type « list », contient les valeurs possibles attendues
  • « default » : de type number ou string si « type » = « text », de type table si « type » = « object » et de type list si « type » = « list »
Usages
  • La liste des « reification_params » est retournée par l’API « GetJsonReification » en passant dans le paramètre « ID » le « name » de la Require.
  • La structure de ces paramètres permet aisément l’implémentation d’un formulaire dans le backoffice d’un CMS.
  • Un paramètre de configuration de la widget Hopes.studio permet de spécifier l’id d’une Require et un autre paramètre la table d’affection des paramètres de reification.

required_fields, optional_fields, graphic_fields et delivery_fields

Définition

Chaque rubrique est une table comportant les sous-rubriques suivantes :

  • « name » : de type string, caractères autorisés ‘a’-‘z’, ‘A’-‘Z’, ‘0’-‘9’, ‘_’, pas d’espace, nom du paramètre
  • « label » : de type string, description libre
  • « default » : de type number, string ou table via un formalisme décrit plus bas
  • « unit » : optionnel, de type string, permet de spécifier une unité
  • « min » : optionnel, de type number, permet de spécifier un minimum
  • « max » : optionnel de type number, permet de spécifier un maximum
  • « step » : optionnel de type number, permet de spécifier un quantum d’itération

Les valeurs de « default » de type table permettent de définir des champs plus ou moins complexes qui ne peuvent pas se limiter à un champ de type « INPUT ». Cela va du simple « SELECT » géré nativement par H-CSR à des parties de formulaire comportant plusieurs champs et gérer par une extension de H-CSR (comme le module H-CSR dédié à Clariprint).

Les valeurs de « default » de type table respecte le formalisme suivant :

  • « kind » : de type string, décrit le type de champs évolué (plus qu’un simple input), parmi les « kind » standard de Hopes.studio : « select », « imgFile », « imgFileArchive ». D’autres « kind » peuvent être définis, et leur interprétation implémentée dans des modules additionnels à H-CSR
  • « options » : pour « kind » = « select », la liste des valeurs possibles
  • « options_img » : pour « kind » = « select », la liste des URL des images correspondant aux options
  • « role » : pour les « kind » de type « imgFile » ou « imgFileArchive », de type string, tag unique qui permet de repérer dans l’atlas de texture les images à mettre à jour avec la sélection du client
  • « value » : optionnel, représente soit une valeur par défaut de type string ou number pour un « select », soit un setup sous forme de table

Usages
  • la structure de l’interface utilisateur est retournée par l’API GetJsonParameters en passant dans le paramètre « ID » le « name » de la Require, et dans la table « parameters_value » les éventuels paramètres de réification.
  • SG CSR exploite cette structure pour construire l’interface utilisateur

user_interface_organizer

La rubrique « user_interface_organizer » est une table qui décrit, d’une part, comment les différents champs seront regroupés et classés. D’autre part les interactions dynamiques entre les champs de formulaire. Elle contient les sous-rubriques suivantes :

  • « required_fields« , « optional_fields« , « graphic_fields« , « delivery_fields » : ces 4 sous rubriques reprennent les rubriques de spécification des paramètres des 4 zones de l’interface graphique dans H-CSR. Ici nous allons pouvoir préciser comment sont agencés les paramètres grâce au formalisme suivant :
"required_fields" : [["group1","param1", "param2"],["group2","param4","param5"],["group3","param3"]]

Il s’agit d’une liste de groupe-liste ou chaque groupe-list commence par le label du groupe suivi de la série ordonnées des « name » des paramètres du groupe.

  • « on_change_effects » : permet de spécifier la dynamique des interactions des paramètres via une table respectant le formalisme suivant :
"on_change_effects" : { 
 "param1" : { 
   "yes" : {
     "hide" : ["param2"], 
     "set" : ["param3:no","param4:34"] 
   } , 
   "no" : {
     "show" : ["param2], 
     "set" : ["param3:yes", "param4:12"] 
   } 
  } 
}

La composition

Les Requires de type Layout et Group disposent d’une rubrique « composition » de type list décrivant les sous-parties.

Exemple :

"composition" : [
    { 
      "name" : "cmp1", 
      "target" : "RequireName1",
      ...
    },
    { 
      "name" : "cmp2", 
      "target" : "RequireName2",
      ...
    }, 
    ... 
]

La structure de chaque élément de composition comporte les rubriques suivantes :

  • « iteration » : optionnel, de type list, permet de définir une variable d’itération et de multiplier les composants avec une seule description, exemple « iteration » : [« i », 1, « $n »] ou i sera le nom de la variable d’itération, que l’on pourra invoquer dans des expressions avec « $i », 1 étant le début de l’intervalle d’itération et « $n » une variable de type number indiquant la fin de l’intervalle d’itération.
  • « sameShape » : optionnel, de type boolean, si true indique que la forme est identique qu’elle que soit l’itération. Permet d’accélérer les temps de traitement.
  • « variables » : optionnel, de type table {« nomVar1 » : « expressionValueVar1 », …} , permet de définir des variables locales au composant, utile notamment pour exploiter la variable d’itération
  • « name » : obligatoire, de type string, le nom du composant, il peut être défini par une expression comportant entre autre la variable d’itération, exemple « CARD_$i »
  • « target » : obligatoire, de type string, le nom de la Require cible du composant
  • « parameters_value » : optionnel, de type table {« paramCible1 » : « expressionValueParam1 », … }, permet de définir les paramètres de la Require cible
  • « required » : optionnel, de type list [« paramCible3″, »paramCible8 », … ], permet de lister les paramètres de la cible que l’on souhaite voir remonter dans le formulaire
  • « setup » : optionnel, de type list [{« type » : « translate », « params » : [0,0,0]},{« type » : « rotX », « params » : [-90]}, … ], permet de définir une série de transformation graphique pour le positionnement 3D initial
  • « extrusion » : uniquement pour les cibles de type Template, valeur de type number ou string, permet de définir la valeur d’extrusion du Template (2D) pour obtenir un objet 3D.
  • « textureRecto » : uniquement pour les cibles de type Template, de type string ou table, permet de définir pour la face Recto du Template :
    • si de type string, l’url du fichier image contenant la texture fixe
    • si de type table { « default » : « URLdefaultTexture », « custom » : {« kind » : « imgFile », « role » : « ListenerUID » } }, ou « default » représante l’URL du fichier image par défaut et « custom » le fichier image du client défini à travers un champ de type « imgFile », dont la rubrique « role » contient un UID de type string permettant d’affecter la ressource au bon endroit
  • « textureVerso » : idem « textureRecto » mais pour la face Verso du Template
  • « textureSide » : idem « textureRecto » mais pour la tranche générée par l’extrusion du Template

Exemple d’une composition formée par N Templates de carte :

            "variables" : {   
                "defaultTextureTable" : {
                    "bridge" : "$img_root/textures/jeux-cartes/bridge/carte-$suffix.png",
                    "Tarot" : "$img_root/textures/jeux-cartes/Tarot/carte-$suffix.png",
                    "default" : "$img_root/textures/jeux-cartes/default/carte.png"
                },
                "defaultTexture" : "CALLFUNC(nth,$defaultTextureTable,$gameKind)" 
            },
            "composition" : [
                {
                    "iteration" : ["i",1,"$N"],
                    "variables" : {
                        "backCardTexture" : { "default" : "$img_root/textures/jeux-cartes/$gameKind/$backTheme.png", "custom" : "$b" },    
                        "suffix": {"IF" : "$i < 10", "THEN" : "0$i", "ELSE" : "$i"},
                        "frontCardTexture" : { 
                            "default" : "$defaultTexture", 
                            "custom" : {"role" : "$roleBase-$i"} 
                        }
                    },
                    "name" : "T_$i",
                    "target" : "T_Rounded-Card",
                    "sameShape" : true,
                    "extrusion" : "$E",
                    "textureRecto" : "$frontCardTexture",
                    "textureVerso" : "$backCardTexture",
                    "textureSide" : "$img_root/textures/materials/white-paper.jpg",
                    "parameters_value" : {"H" : "$H", "L" : "$L", "E" : "$E", "F" : "", "R" : "$R"},
                    "setup" : [{ "type" : "translate", "params" : ["($i-1)*($L+10)",0,"-$E"] }]
                },
            ],

Expressions et contextes d’évaluation

Localisation des expressions

Dans le H-L les expressions invoquant des paramètres ou des variables via l’opérateur « $ » peuvent être utilisées un peu partout, entre autre dans les rubriques suivantes :

  • « required_fields« , « optional_fields« , « graphic_fields« , « delivery_fields« 
  • « variables« 
  • « business« 
  • « business_rules« 
  • « actions« 
  • « composition« 

En fait, la seule rubrique dans lesquelles les expressions ne seront pas évaluée est la rubrique « parameters_value » à la racine de la Require.

Définition d’un contexte d’évaluation

Chaque expression est évaluée dans un seul contexte de type table de hachage à plat. A plat car les tables/objects sont explorées pour créer des clefs grâce à l’opérateur d’exploration « §« .

Reprenons l’exemple précédant du paramètre « param1 » de type table :

"param1" : {
   "a1" : {
     "b1" : {"c1" : 2}, 
     "b2" : 3
   }, 
   "a2" : "coucou
}

Dans la table de contexte à plat cela donnera :

{
  "param1" : {
   "a1" : {
     "b1" : {"c1" : 2}, 
     "b2" : 3
   }, 
   "a2" : "coucou
  },
  "param1§a1" : { "b1" : {"c1 : 2}, "b2" : 3 },
  "param1§a1§b1 : {"c1 : 2},
  "param1§a1§b1§c1 : 3,
  "param1§a1§b2 : 3,
  "param1§a2" : "coucou"
}

Hiérarchie des contextes

Le 1er contexte d’une Require est formé par le mixage (merge) du contexte d’invocation et de la rubrique « parameters_value« . Le contexte d’invocation étant prioritaire, la valeur retenue pour un paramètre apparaissant dans les deux contextes sera celui du contexte ascendant, le contexte d’invocation. On appelle ce 1er contexte C1.

C1 va servir de contexte d’évaluation des expressions de la rubrique « reification_params« .

Puis les valeurs par défaut des paramètres de la rubrique « reification_params » vont être mixer à C1 pour former C2.

C2 sera le contexte d’évaluation des rubriques « required_fields« , « optional_fields« , « graphic_fields« , « delivery_fields« .

Puis les valeurs par défaut (sous-rubrique « default« ) des paramètres de ces rubriques seront mixées à C2 pour former C3.

C3 sera le contexte initial d’évaluation de la rubrique « variables« . Contexte initial, car les expressions des variables peuvent référencer d’autres variables définie sous la même rubrique. Donc chaque définition va nourrir C3 pour créer C3.1, C3.2, C3.3, C3.n… Avant de commencer l’évaluation, les variables seront ordonnées en fonction de leur interdépendance. Au final un nouveau contexte C4 apparaît.

C4 servira de contexte d’évaluation pour toute les autres rubriques.

Dans certaines rubriques comme « composition » ou « actions » viendrons s’ajouter à C4 des variables d’itération.

Et enfin pour le cas particulier des éléments fils de la rubrique « composition« , une sous-rubrique « variables » permettra de créer un nouveau contexte local C4.X qui servira dévaluation aux autres rubriques de l’élément fils de composition, comme « name« , « target« , « parameters_value« …

L’interface CPQ (configure Price Quote)

Pour formuler une requête au CPQ, nous devons, premièrement définir le contexte du CPQ, deuxièmement construire la requête en structurant les données de manière à respecter un formalisme imposé.

Définition du CPQ

Une Require de type CPQ apparaît dans la rubrique principale de type list « CPQs« . Une instance de CPQ est définie comme un table comportant les rubriques :

  • « name » : obligatoire, de type string, caractères autorisés ‘a’-‘z’, ‘A’-‘Z’, ‘0’-‘9’ et ‘_’, le nom du CPQ
  • « appName » : obligatoire, de type string, le nom de l’application CPQ
  • « server_url » : obligatoire, de type string, l’URL du serveur CPQ
  • « login » : obligatoire, de type string, l’identifiant de connexion
  • « password » : obligatoire, de type string, le mot de passe

Exemple de définition d’un CPQ :

    "CPQs" : [
        {
            "name" : "myClariprintDev",
            "appName" : "Clariprint",
            "server_url" : "http://dev.clariprint.local/optimproject/json.wcl",
            "login" : "QYP",
            "password" : "QYP"
        }
   ]

Utilisation du CPQ

Affin d’invoquer un CPQ pour un Layout, nous devons préciser le contexte CPQ dans lequel le Layout évolue grâce à la rubrique « usage » et la sous-rubrique « CPQ » dans laquelle nous référençons le nom de la Require de type CPQ.

Ensuite, pour construire la requête en structurant les données de manière à respecter un formalisme imposé, nous disposons de deux rubriques « business » et « business_rules« .

La rubrique « business »

La rubrique « business » décrire de une Require de type Layout, Group ou Template dans le référentiel du CPQ. Cette rubrique est de type table et comprend les rubriques suivantes :

  • « kind » : de type string, expression résultant une string représentant un type de composant métier dans le référentiel du CPQ
  • « quantity » : de type number ou string, entier ou expression résultant un entier, représentant une quantité souhaité
  • « forms » : de type list de table, ou chaque table représente un groupe de propriétés métiers qui comporte une rubrique « kind » représentant un type de macro-propriété dans le référentiel du CPQ, et une rubrique « value » de type table comportant une série de sous-rubriques respectant la nomenclature des rubriques du CPQ.

La rubrique « business_rules »

La rubrique « business_rules« , permet de décrire les Requires de l’arborescence des composants fils dans le référentiel du CPQ. Elle permet, s’il on le souhaite de centraliser l’ensemble des définitions liées à l’usage du CPQ.

Cette rubrique de type list, définie, pour des composants cibles, les règles de représentation métier dans le référentiel du CPQ.

Chaque règle est une table comportant les rubriques suivantes :

  • « target » : de type string, tout ou partie du « name » du composant ciblé par la règle
  • « kind » : de type string, représente un type de composant dans le référentiel du CPQ
  • « quantity » : de type number, le nombre d’instance du composant cible
  • « repeat » : de type number. Si le composant ciblé est le premier composant d’une série identique issue d’une itération, il est possible de le préciser en indiquant dans cette rubrique le nombre d’itération
  • « forms » : de type list de table, idem que la sous rubrique « forms » de la rubrique « business »

Il est possible de se passer de la rubrique « business_rules » si l’on défini les rubriques « business » de chaque composant de l’arborescence. En cas de conflit, c’est la « business_rules » de plus haut niveau qui s’applique, autorisant la redéfinition des sous-rubriques de type simple comme « kind« , « quantity« , « repeat« .

Exemple de codage des rubriques concernant le CPQ :

"usage" : {"CPQ" : "myClariprint", "3D" : "on", "SVG" : "on", "autoplay" : "on"},
"business" : {  
  "kind" : "$BUSINESS_KIND", 
  "quantity" : "$q", 
  "forms" : ["$kit_dimensions","$wrapping","$delivery"]  
},
"business_rules" : [
                                {   "target" : "T_1", 
                                    "kind" : "ClariprintLeaflet", 
                                    "quantity" : 1, 
                                    "repeat" : "$N", 
                                    "forms" : ["$card_paper","$card_print","$card_finish",
                                                { "kind" : "ClariprintFormDimension", 
                                                    "value" : {
                                                        "flat_width" : "=$x_rect_width / 10", 
                                                        "flat_height" : "=$x_rect_height / 10", 
                                                        "width" : "=$L / 10", 
                                                        "height" : "=$H / 10", 
                                                        "surface" : "=$x_area"} },
                                                { "kind" : "ClariprintFormCutAndHole", 
                                                    "value" : {
                                                        "cut_length" : "=$x_cut_length", 
                                                        "valley_length" : "=$x_valley_length", 
                                                        "form_cut_num" : 25, 
                                                        "cuttingdie" : 25,
                                                        "cuttingdie_exists" : "1",
                                                        "cut_tool_exists" : 0, 
                                                        "number_of_holes" : 0} }
                                            ]}
 ]

Dans l’exemple ci-dessus, on peut noter l’usage des expressions paramétriques dans les sous-rubriques de « business » et « business_rules« . il est important de distinguer les sous rubriques du H-L telles que « kind » et « value« , des sous rubriques des rubriques de « value« , comme « flat_width », « cut_length » ou « cutting_die » qui sont des rubriques de l’interface de l’application CPQ, ici Clariprint.

Dans l’exemple ci-dessus on voit apparaître des variables géométriques déclarées et calculées automatiquement par H-server, ces variables sont les suivantes :

  • « x_rect_width » : métrique géométrique calculée d’un template indiquant la largeur à plat de la forme en mm
  • « x_rect_heigth » : métrique géométrique calculée d’un template indiquant la hauteur à plat de la forme en mm
  • « x_area » : métrique géométrique calculée d’un template indiquant la surface de la forme en mm2
  • « x_cut_length » : métrique géométrique calculée d’un template indiquant la longueur totale de découpe (contour plus découpes internes) en mm
  • « x_valley_length » : métrique géométrique calculée d’un template indiquant la longueur totale de rainage pour pliage en mm

Les actions d’animation

La rubrique « actions » de type list, permet de définir des actions pour un Group ou un Layout. Ces actions ainsi définies pourront être invoquées par d’autres actions d’un groupe parent, dans des séquences de scenes, ou bien jouée automatiquement via le mode « autoplay » d’un Layout.

Chaque action est représentée par une table comportant les rubriques suivantes :

  • « name » : de type string, caractères autorisés identiques aux autres rubrique « name », désigne le nom qui servira à l’invocation de règle
  • « description » : de type string, description textuelle libre
  • « motions » : de type list, contient la liste des motions (mouvement ou transformation) appliqués
  • « action_calls » : de type list contient la liste des invocations d’action de composant descendant (fils, petit-fils etc)

Les motions

Chaque motion est une table qui comporte les rubriques suivantes :

  • « iteration » : de type list de 3 membres, le premier de type string désignant le nom de la variable d’itération, les 2 suivants de type number ou expression résultant un number, désignant le mini et maximum de l’intervalle d’itération. Exemple [« i »,1,12]
  • « targets » : de type list de string, désigne une liste de noms de composants cibles, les noms peuvent être des expressions utilisant la variable d’itération, exemple [« T_$i »]
  • « rotate » : optionnel, de type list de 3 numbers, représente le tableau des angles de rotation [tetaX,tetaY,tetaZ] à appliquer
  • « moveTo » : optionnel, de type list de 3 numbers, représente le tableau des translation sur les 3 axes [dX,dY,dZ] à appliquer
  • « bezier_pt1 » : optionnel, de type list de 3 numbers, représente le tableau des coordonnées du 1er point de bézier sur les 3 axes [b1X,b1Y,b1Z]
  • « bezier_pt2 » : optionnel, de type list de 3 numbers, représente le tableau des coordonnées du 2eme point de bézier sur les 3 axes [b2X,b2Y,b2Z]
  • « groupToClose » : de type list, désigne la liste des « morph_group » à fermer
  • « groupToOpen » : de type list, désigne la liste des « morph_group » à ouvrir

Exemple pour la mise en tas d’une file de cartes :

"motions" : [{"iteration" : ["i",2,"$N"], "targets" : ["T_$i"], "moveTo" : ["(1-$i)*($L+10)",0,"$E*($i-1)"]}]

Les action_calls

Chaque action_call est une table qui comporte les rubriques suivantes :

  • « targets » : de type list de string, désigne une liste de noms de composants cibles
  • « iteration » : de type list de 3 membres. Le premier de type string désigne le nom de la variable d’itération, les 2 suivants de type number ou expression résultant un number, désignant le mini et maximum de l’intervalle d’itération. Exemple [« i »,1,12]
  • « action » : de type string, désigne le « name » de l’action à invoquer. Peut être une expression utilisant la variable d’itération. exemple « A$i »

Exemple de fichier H-L

Exemple de « code » pour notre bibliothèque de dépliant de 4 à 16 pages.

{
"alias" : {
    "comment" : "list of JDF fold IDs"
    "JDF_LIST" : [
        "F4_1",
        "F6_1","F6_4",
        "F8_1","F8_3","F8_4","F8_5",
        "F10_1",
        "F12_3",
        "F14_1",
        "F16_4","F16_5"
    ],
    "JDF_LIST_IMG" : [
        "F4_1.png",
        "F6_1.png","F6_4.png",
        "F8_1.png","F8_3.png","F8_4.png","F8_5.png",
        "F10_1.png",
        "F12_3.png",
        "F14_1.png",
        "F16_4.png","F16_5.png"
    ],
    "THICK_FACTOR_FOR_JDF" : {
        "F4_1" : 2,
        "F6_1" : 3,"F6_4" : 3,
        "F8_1" : 4,"F8_3" : 4,"F8_4" : 4,"F8_5" : 4,
        "F10_1" : 5,
        "F12_3" : 6,"F12_4" : 6,"F12_6" : 6,
        "F14_1" : 7,
        "F16_4" : 8,"F16_5" : 8
    },
    "JDF_CODE_FROM_JDF_ID" : {
        "F4_1" : "F4-1",
        "F6_1" : "F6-1","F6_4" : "F6-4",
        "F8_1" : "F8-1","F8_3" : "F8-3","F8_4" : "F8-4","F8_5" : "F8-5",
        "F10_1" : "F10-1",
        "F12_3" : "F12-3","F12_4" : "F12-4","F12_6" : "F12-6",
        "F14_1" : "F14-1",
        "F16_4" : "F16-4","F16_5" : "F16-5"
    },
   
    "comment" : "alias definition by JDF IDs, # is a refence to an other require, here 'Fflap' is a template that is defined below, 'Empty' is an other template defined in an other file ",
         
    "F4_1" : {"#Fflap" : {"next" : {"#Fflap" : {"next" : "#Empty"}}, "A" : "180"}},
    "F6_1" : {"#Fflap" : {
            "comment" : "deux plis accordéon",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {"next" : "#Empty"}
                    }, "A" : "-180", "G" : 1
                }
            }, "A" : "180", "FR" : 0, "G" : 2 
        }
    },
    "F6_4" : {"#Fflap" : {
            "comment" : "deux plis roulés",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {"next" : "#Empty"}
                    },"FR" : 0, "G" : 1
                }
            }, "A" : "180", "FR" : 2, "G" : 2
        }
    },
    "F8_1" : {"#Fflap" : {
            "comment" : "deux plis parallèles économiques",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {"#Fflap" : {"next" : "#Empty"}},
                            "A" : "180", "FR" : 2
                        }
                    }, "A" : "180"
                }
            }, "A" : "-180"
        }
    },
    "F8_3" : {"#Fflap" : {
            "comment" : "trois plis accordéons",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {"#Fflap" : {"next" : "#Empty"}},
                            "A" : "-180"
                        }
                    }, "A" : "180"
                }
            }, "A" : "-180"
        }
    },
    "F8_4" : {"#Fflap" : {
            "comment" : "pli portefeuille à trois plis",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {"#Fflap" : {"next" : "#Empty"}},
                            "A" : "180"
                        }
                    }, "A" : "180","FR" : 2, "G" : 2
                }
            }, "A" : "180"
        }
    },
    "F8_5" : {"#Fflap" : {
            "comment" : "trois plis roulés",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {"#Fflap" : {"next" : "#Empty"}},
                            "A" : "180","FR" : 2,"G" : 3
                        }
                    }, "A" : "180","FR" : 1,"G" : 2
                }
            }, "A" : "180"
        }
    },
    "F10_1" : {"#Fflap" : {
            "comment" : "quatre plis accordéons",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {
                                "#Fflap" : {
                                    "next" : {"#Fflap" : {"next" : "#Empty"}},
                                    "A" : "-180"
                                },
                            }, "A" : "180"
                        }
                    }, "A" : "-180"
                }
            }, "A" : "180"
        }
    },
    "F12_3" : {"#Fflap" : {
            "comment" : "un pli simple et deux plis accordéons",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {
                                "#Fflap" : {
                                    "next" : {"#Fflap" : {"next" : {"#Fflap" : {"next" : "#Empty"}},"A" : "180", "FR" : 2, "G" : 2}
                                    }, "A" : "-180", "G" : 2
                                },
                            }, "A" : "180", "G" : 1
                        }
                    }, "A" : "180","FR" : 2, "G" : 2
                }
            }, "A" : "-180","G" : 2
        }
    },
    "F14_1" : {"#Fflap" : {
            "comment" : "cinq plis accordéons",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {
                                "#Fflap" : {
                                    "next" : {
                                        "#Fflap" : {
                                            "next" : {"#Fflap" : {"next" : {"#Fflap" : {"next" : "#Empty"}}, "A" : "-180", "FR" : 0, "G" : 1}
                                            }, "A" : "180", "FR" : 0, "G" : 1}
                                    },"A" : "-180", "G" : 2
                                },
                            }, "A" : "180", "G" : 1
                        }
                    }, "A" : "-180","FR" : 0, "G" : 1
                }
            }, "A" : "180","G" : 1
        }
    },
    "F16_4" : {"#Fflap" : {
            "comment" : "un pli simple et deux plis parallèles économiques",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {
                                "#Fflap" : {
                                    "next" : {
                                        "#Fflap" : {
                                            "next" : {
                                                "#Fflap" : {
                                                    "next" : {
                                                        "#Fflap" : {"next" : {"#Fflap" : {"next" : "#Empty"}
                                                            },  "A" : "180", "FR" : 6, "G" : 3}
                                                    }, "A" : "180", "FR" : 2, "G" : 2}
                                            }, "A" : "-180", "FR" : 0, "G" : 3}
                                    },"A" : "180","FR" : 0, "G" : 1
                                },
                            }, "A" : "180","FR" : 2, "G" : 3
                        }
                    }, "A" : "-180","FR" : 0, "G" : 2
                }
            }, "A" : "-180","FR" : 4,"G" : 3
        }
      },
    "F16_5" : {"#Fflap" : {
            "comment" : "sept plis accordéons",
            "next" : {
                "#Fflap" : {
                    "next" : {
                        "#Fflap" : {
                            "next" : {
                                "#Fflap" : {
                                    "next" : {
                                        "#Fflap" : {
                                            "next" : {
                                                "#Fflap" : {
                                                    "next" : {
                                                        "#Fflap" : {"next" : {"#Fflap" : {"next" : "#Empty"}
                                                            },"A" : "180", "FR" : 0, "G" : 1}
                                                    }, "A" : "-180", "FR" : 0, "G" : 1}
                                            }, "A" : "180", "FR" : 0, "G" : 1}
                                    },"A" : "-180", "G" : 2
                                },
                            }, "A" : "180", "G" : 1
                        }
                    }, "A" : "-180","FR" : 0, "G" : 1
                }
            }, "A" : "180","G" : 1
        }
    }
},

"layouts" : [
    {
        "name" : "L_Folder",
        "extends" : "LAYOUT_BASE?BUSINESS_KIND=ClariprintKit",
        "reification_params" : [
            { "name" : "DEF_W", "label" : "Default Width", "type" : "text", "default" : "50"},
            { "name" : "DEF_H", "label" : "Default Height", "type" : "text", "default" : "100"}
            { "name" : "JDF_CODE", "label" : "Jdf code" , "type" : "select", "default" : "F4_1", 
                "options" : "#JDF_LIST"},
            { "name" : "LAY_TITLE", "label" : "Layout title", "type" : "text", "default" : "Folder $JDF_CODE"},

            { "name" : "FOLDER_PAPER_CONF", "label" : "Paper configuration", "type" : "object", 
                "default" : "#CLARIPRINT_PAPER_CONF_FOLDED"  },
            { "name" : "FOLDER_PRINT_CONF", "label" : "Folder print configuration", "type" : "object", 
                "default" : "#CLARIPRINT_PRINT_CONF" },                
            { "name" : "FOLDER_FINISH_CONF", "label" : "Folder finish configuration", "type" : "object", 
                "default" : "#CLARIPRINT_FINISH_CONF_LIGHT" }

        ],
           "required_fields" : [
            { "name" : "H", "label" : "Height", "unit" : "mm", "default" : "$DEF_H", "min" : "50", "max" : "300", "step" : "1"},
            { "name" : "W", "label" : "Width", "unit" : "mm", "default" : "$DEF_W", "min" : "30", "max" : "250", "step" : "1"}

            { "name" : "folder_paper", "label" : "Folder material", 
                "default" : "#CLARIPRINT_PAPER_FORM?CONF=$FOLDER_PAPER_CONF"},

            { "name" : "JDF", "label" : "SWITCH TO JDF CODE", 
                "default" : {
                    "kind" : "select", 
                    "value" : "$JDF_CODE", 
                    "options" : "#JDF_LIST",
                    "options_img" : "#JDF_LIST_IMG"
                }}

        ],
        "optional_fields" : [
            { "name" : "folder_print", "label" : "Folder print", "default" : "#CLARIPRINT_PRINT_FORM?CONF=$FOLDER_PRINT_CONF" },
            { "name" : "folder_finish", "label" : "Folder finish", "default" : "#CLARIPRINT_FINISH_FORM?CONF=$FOLDER_FINISH_CONF" }
        ],
        "graphic_fields" : [
            { "name" : "f", "label" : "Folded front face", "default" : {"kind" : "imgFile", "role" : "folderFrontBG"}},
            { "name" : "b", "label" : "Folded back face", "default" : {"kind" : "imgFile", "role" : "folderBackBG"}}
           ],
           "user_interface_organizer" : {
               "required_fields" : [
                   "q","H","W","JDF","folder_paper"
               ]
           },
           "variables" : {
            "T" : "$folder_paper§value§papers§custom§thickness",
            "folder_thickness_factor" : "CALLFUNC(nth,#THICK_FACTOR_FOR_JDF,$JDF§value)",
            "folder_thickness" : "=$T * $folder_thickness_factor",
            "folderFrontTexture" : { "default" : "$img_root/textures/materials/white-paper.jpg", "custom" : "$f" },
            "folderBackTexture" : { "default" : "$img_root/textures/materials/white-paper.jpg", "custom" : "$b" },
            "jdf_fold_code" : "CALLFUNC(nth,#JDF_CODE_FROM_JDF_ID,$JDF§value)"
           },

           "business_rules_comment" : "CAREFULL : all variables used in business rules / forms will be filled width the target parameters value NOT width the local ones. Variables begining with $x_ are calculated with geometricals metrix.",
        "business_rules" : [
            {
                "target" : "T_Folder", 
                "kind" : "ClariprintFolded", "quantity" : 1, "repeat" : 1, "number_of_stack" : 1, 
                "forms" : ["$folder_paper","$folder_print","$folder_finish",
                            { "kind" : "ClariprintFormDimension", 
                                "value" : {
                                    "openwidth" : "=$x_rect_width / 10", 
                                    "openheight" : "=$x_rect_height / 10", 
                                    "width" : "=$W / 10", 
                                    "height" : "=$H / 10"}
                            },
                            {
                                "kind" : "ClariprintFormFold",
                                "value" : {
                                    "fold" : "$jdf_fold_code"
                                }
                            }
                        ]
            },
        ],

       "composition" : [
            {
                "name" : "T_Folder",
                "target" : "$JDF§value",
                "extrusion" : "$T",
                "textureRecto" : "$folderFrontTexture",
                "textureVerso" : "$folderBackTexture",
                "textureSide" : "$img_root/textures/materials/white-paper.jpg",
                "parameters_value" : { "T" : "$T" },

                "setup" : [{"type" : "rotX", "params" : [-90]},{"type" : "rotZ", "params" : [-90]}]                    
            }
        ],
       "actions" : [  
            {
                "name" : "FOLD",
                "description" : "folding",
                "motions" : [{"iteration" : ["i",1,3], "targets" : ["T_Folder:$JDF§value:Fflap"], "groupsToClose" : ["$i"]}]
            }               
        ]
    }
],

"templates" : [                 
     {   "name" : "Fflap",
        "description" : "Folder flap with/without next flap ",
        "parameters_value" : {
      	   "W" : 70, 		"W_comment" : "Width",
    	   "H" : 120, 		"H_comment" : "Height",
    	   "T" : 0.4,		"T_comment" : "Thickness",
    	   "A" : 180,		"A_comment" : "Angle for next flap",
    	   "G" : 1,		"G_comment" : "Morph group",
    	   "next" : "#Empty", 	"next_comment" : "next flap"
        },  
        "variables" : {
            "AC" : {
                "IF" : "'$next§target' = 'Empty' | '$next' = 'Empty' | '$next' = '#Empty'", 
                "THEN" : "0",
                "ELSE" : "$A"
            },
            "fradius" : "=$FR*$T"
        },
        "folds" : [
            {   "name" : "FS",
                "relativeToMaster" : "true",
                "theta_closed" : "$AC",
                "fold_radius" : "$fradius",
                "morphGroup" : "$G",
                "d" : "m0,-$W h$H",
                "child_face" : "#$next"
            }
        ],
        "faces" : [
            {
                "name" : "fs",
                "d" : "m0,0 0,-$W $H,0 0,$W -$H,0",
                "folds": [ "FS" ]
            }
        ]
    }  
]
}