Salome HOME
CCAR: change in check_calcium.m4 macro for --with-cal-int=<intorlong>
[modules/kernel.git] / src / DSC / DSC_User / Datastream / DataIdFilter.hxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : DataIdFilter.hxx
23 //  Author : Eric Fayolle (EDF)
24 //  Module : KERNEL
25 //
26 /*   Module Filtre
27  *   -------------
28  *
29  *   Implemente les fonctions de filtrage et conversion d'un port de DATASTREAM
30  *
31  *   Rappel des fonctions du Filtrage:
32  *   --------------------------------
33  *
34  *   Dans une communication de type DATASTREAM, le destinataire indique à l'avance la liste
35  *   des instances qu'il veut recevoir, c'est à dire celles qui lui sont nécessaires.
36  *   Il indique pour cela la liste des 'times' et la liste des 'tags' qui
37  *   caractérisent les instances désirées.
38  *   Ces deux listes sont indépendantes. Toute instance dont les paramètres 'time' et
39  *   'tag' figurent dans la liste des 'times' et respectivement dans la liste des
40  *   'tags' est désirée par le destinataire.
41  *   Par la suite, une telle instance sera acceptée par le port-DATASTREAM. Les autres
42  *   seront rejetées.
43  *
44  *   Le filtrage consiste à limiter les valeurs possibles du paramètre TIME ou TAG (un
45  *   entier). La liste des valeurs possibles est décrite sous la forme d'une liste de
46  *   valeurs ou de séquences arithmétiques de valeurs.
47  *   Exemple: 
48  *     La liste 1; 3; 30:34; 40:50:2 autorise les valeurs 1 et 3 et toutes les valeurs
49  *     comprises entre 30 et 34 inclus et toutes les valeurs de la séquence 40 à 50
50  *     inclus par pas de 2, c'est à dire 40, 42, ... 50.
51  *   On appelle règle élémentaire de filtrage celle spécifiant un élément de la liste
52  *   des valeurs autorisées: soit une seule valeur, soit une séquence de valeurs. Une
53  *   séquence de valeurs est spécifiée par sa valeur de départ, sa valeur de fin et
54  *   son pas. Le filtrage est donc défini par une suite de règles de filtrage.
55  *   La fonction élémentaire de configuration du filtrage sert à spécifier une règle
56  *   de filtrage.
57  *
58  *   Rappels des fonctions de conversion:
59  *   -----------------------------------
60  *
61  *   La conversion est intimement liée au filtrage car seules les valeurs passant le
62  *   filtre sont converties. La conversion n'est pas obligatoire. Une valeur de TIME ou TAG
63  *   entrante peut ne pas être convertie. Elle garde alors sa valeur et est gardée
64  *   telle quelle pour l'objet destinataire.
65  *   DATASTREAM peut associer une règle de conversion à chaque règle élémentaire de
66  *   filtrage.
67  *   La conversion consiste à changer:
68  *     - un valeur de TIME ou TAG en une valeur différente
69  *     - une séquence de valeurs en une autre séquence de valeurs de même taille
70  *       (ex: 30:40 en 300:400:10)
71  *   Mais la conversion permet aussi de transformer:
72  *     - une valeur de TIME ou TAG unique en une séquence de valeurs (les données entrantes sont
73  *       alors duppliquées et à chaque fois que l'objet destinataire réclame une donnée
74  *       de la séquence, il reçoit en fait une copie de la donnée reçue une seule fois)
75  *
76  *     - une séquence de valeurs en une valeur unique (alors, chaque donnée entrante
77  *       associée à un TIME ou TAG de la séquence correspond à une donnée unique pour le
78  *       destinataire: seule la dernière reçue est la donnée valide)
79  *
80  */
81
82 #include <vector>
83 #include <iostream>
84
85 // Pour l'utilisation de "vector" de la STL
86 // Classe filtre_elementaire
87 //
88 // Implémente une structure de donnée décrivant un filtre élémentaire
89 // sur le paramètre TIME ou TAG; c'est
90 //    - soit une valeur entière unique
91 //    - soit une séquence arithmétique de valeurs
92 //
93 class filtre_elementaire
94 {
95 public:
96     int len;    // Longueur de séquence ou 1 pour une valeur unique
97     int debut;  // Début de la séquence ou valeur pour une valeur unique
98     int fin;    // Fin de la séquence
99     int pas;    // Pas de la séquence
100
101     // Constructeur par défaut
102     filtre_elementaire() {}
103     
104     // Création d'un filtre élémentaire pour une valeur unique
105     filtre_elementaire(int valeur)
106     {
107         this->len = 1;
108         this->debut = valeur;
109     }
110
111     // Création d'un filtre élémentaire pour une séquence de valeurs entières
112     // Le pas par défaut est 1
113     filtre_elementaire (int _debut, int _fin, int _pas=1)
114     {
115         this->debut = _debut;
116         this->len = (_fin - _debut) / _pas;
117         if (this->len > 0)
118         {
119             this->fin = _debut + _pas * this->len;  // Calcule la vrai borne de fin
120             this->pas = _pas;
121             this->len += 1;   // Compte les bornes et non les intervalles
122         }
123         else  // erreur de spécification: on ne prend que la première valeur
124             this->len = 1;
125     }
126
127     // Constructeur par copie
128     filtre_elementaire (filtre_elementaire &_f)
129     {
130       this->len = _f.len;
131       this->debut = _f.debut;
132       this->fin = _f.fin;
133       this->pas = _f.pas;
134     }
135 };
136
137 // Classe filtre_conversion
138 //
139 // Implémente le filtrage et la conversion du paramètre TIME ou TAG
140 // des données reçues par un port DATASTREAM.
141 //
142 // Mode d'emploi:
143 //      1) Création d'un objet
144 //      2) Configuration de cet objet par passage de paramètres
145 //         de filtage et de conversion
146 //      3) A la création d'un port DATASTREAM, on passe au constructeur
147 //         deux objets 'filtre_conversion', l'un pour le TIME, l'autre pour le TAG.
148 //      4) A l'utilisation du port DATASTREAM, celui-ci appelle la méthode
149 //         "applique_filtre_conversion" pour opérer
150 //
151 class filtre_conversion
152 {
153 private:
154     // Structure de données décrivant une conversion élémentaire:
155     // un filtre élementaire
156     // et un pointeur éventuel vers les paramètres de conversion associés
157     class conversion_elementaire
158     {
159     public :
160         // Data
161         filtre_elementaire filtre;
162         filtre_elementaire * p_convers;
163
164         // Constructeur
165         conversion_elementaire() {}
166
167         // Constructeur par copie d'un objet non modifie (const)
168         conversion_elementaire (const conversion_elementaire& _ce)
169         {
170             *this = _ce;
171         }
172         // Remarque: le Constructeur par copie d'un objet existe par defaut mais sans le modificateur 'const'
173         //           et l'emploi d'un objet comme element dans un vecteur oblige d'avoir un tel const-copy-constructor.
174     };
175
176     // Données de configuration de filtrage et conversion:
177     //    une table de filtres élémentaires
178     //    avec leurs données de conversion associées éventuelles
179     std::vector<conversion_elementaire> config;
180
181 public:
182     // Constructeur: juste une allocation mémoire initiale
183     filtre_conversion() {}
184
185     // Destructeur:
186     // réclamer la mémoire utilisée par tous les éléments du vecteur config
187     ~filtre_conversion()
188     {
189         std::vector<conversion_elementaire>::iterator i;
190         for (i = this->config.begin(); i != this->config.end(); i ++)
191         {
192             delete (*i).p_convers;
193         }
194     }
195
196     // Configuration partielle par ajout d'un filtre élémentaire
197     bool config_elementaire (filtre_elementaire& _f)
198     {
199 //    cout << "ajout config_elementaire 1  " << this << endl;
200         conversion_elementaire conv_elem;
201         
202         conv_elem.filtre = _f;
203         conv_elem.p_convers = NULL;
204
205         // Ajoute cette conversion/filtrage elementaire a la liste
206         this->config.push_back (conv_elem);
207     
208 //    vector<conversion_elementaire>::iterator i;
209 //    cout << "liste apres ajout:" << endl;
210 //    for (i = this->config.begin(); i != this->config.end(); i ++)
211 //    {
212 //        cout << "config elem   " << endl;
213 //        cout << "filtre: len, debut, fin, pas " << (*i).filtre.len << " " << (*i).filtre.debut << " " << (*i).filtre.fin << " " << (*i).filtre.pas << endl;
214 //    }
215         
216         return true;
217     }
218     
219     // Configuration partielle par ajout d'un filtre élémentaire
220     // et sa conversion associée
221     //
222     // Retourne false si les param de conversion sont incompatibles avec le filtre élémentaire.
223     // La configuration partielle est alors refusée.
224     //
225     bool config_elementaire (filtre_elementaire& _f, filtre_elementaire& _conv)
226     {
227 //    cout << "ajout config_elementaire 2  " << this << endl;
228     
229         if (_f.len == 1 || _conv.len == 1 || _f.len == _conv.len)
230         {
231             conversion_elementaire conv_elem;
232             conv_elem.filtre = _f;
233             conv_elem.p_convers = new filtre_elementaire(_conv);
234
235             // Ajoute cette conversion/filtrage elementaire a la liste
236             this->config.push_back (conv_elem);
237     
238 //    vector<conversion_elementaire>::iterator i;
239 //    cout << "liste apres ajout:" << endl;
240 //    for (i = this->config.begin(); i != this->config.end(); i ++)
241 //    {
242 //        cout << "config elem   " << endl;
243 //        cout << "filtre: len, debut, fin, pas " << (*i).filtre.len << " " << (*i).filtre.debut << " " << (*i).filtre.fin << " " << (*i).filtre.pas << endl;
244 //    }
245         
246             return true;
247         }
248         else
249         {
250             // Filtre et conversion incompatibles
251             return false;
252         }
253     }
254
255     // applique_filtre_conversion: Opération du filtre et de la conversion
256     template <typename T > T applique_filtre_conversion (T valeur_initiale, std::vector<T>& liste_conversions) const;
257 };
258
259
260
261 // filtre_conversion::applique_filtre_conversion: Opération du filtre et de la conversion
262 //
263 // Etant donné une valeur entière (de TIME ou de TAG), cette méthode détermine :
264 //   - si cette valeur passe le filtre
265 //   - dans le cas où une conversion existe, la liste des valeurs de conversion
266 //     qui correspondent à la valeur initiale
267 //
268 // Dans tous les cas, cette méthode retourne une liste de valeurs.
269 // Dans le cas où il n'y a pas de conversion, cette liste a une longueur 1
270 // et ne contient que la valeur initiale.
271 //
272 // Paramètre d'entrée :         la valeur initiale (integer)
273 //
274 // Paramètre de sortie :        la liste des valeurs après conversion (vector<int>)
275 //
276 // Valeur de retour :           la longueur de la liste
277 //     si cette longueur est 0, c'est que la valeur initiale ne passe pas le filtre
278 //
279 template <typename T>
280 T filtre_conversion::applique_filtre_conversion (T valeur_initiale, std::vector<T>& liste_conversions) const
281 {
282     // Part d'une liste vierge
283     liste_conversions.clear();
284
285 //    cout << "config applique_filtre_conversion " << this << endl;
286     
287     // Balaye tous les éléments de configuration
288     // et cherche pour chacun d'eux si la valeur initiale est présente parmi les valeurs filtrées
289
290     // Pour tous les éléments de configuration du filtrage/conversion
291     std::vector<conversion_elementaire>::const_iterator i;
292     for (i = config.begin(); i != config.end(); i ++)
293     {
294
295 //    cout << "config elem   " << endl;
296 //    cout << "filtre: len, debut, fin, pas " << (*i).filtre.len << " " << (*i).filtre.debut << " " << (*i).filtre.fin << " " << (*i).filtre.pas << endl;
297     
298         bool si_passe_filtre = false;
299
300         // Si la longueur du filtre est 1
301         if ((*i).filtre.len == 1) {
302           // Si la valeur initiale correspond à la valeur du filtre
303           if ((*i).filtre.debut == valeur_initiale)
304             si_passe_filtre = true;
305         } else  {
306           // Si la valeur initiale est dans la séquence des valeurs du filtre
307           //   la valeur est comprise dans les bornes [debut,fin]
308           //   et sa distance du début de la séquence est modulo le pas
309           if (  ((*i).filtre.fin - valeur_initiale >= 0) == (valeur_initiale - (*i).filtre.debut >= 0)
310                 &&  (valeur_initiale - (*i).filtre.debut) % (*i).filtre.pas == 0  ) {
311             si_passe_filtre = true;
312           }
313         }
314
315         // Si la valeur initiale passe le filtre
316         if (si_passe_filtre) {
317           //    cout << "config: filtre passe    " << endl;
318             
319           // Si il y a une conversion à effectuer
320           if ((*i).p_convers != NULL) {
321
322             // Si la longueur du filtre est 1
323             if ((*i).filtre.len == 1) {
324
325               // Si la longueur des paramètres de conversion est aussi 1
326               if ((*i).p_convers->len == 1) {
327                 // Ajoute la valeur de conversion à la liste des valeurs après conversion
328                 liste_conversions.push_back ((*i).p_convers->debut);
329               } else {
330                 // Ajoute la séquence de conversion à la liste des valeurs après conversion
331                 for (int s = (*i).p_convers->debut; s != (*i).p_convers->fin; s += (*i).p_convers->pas) {
332                   liste_conversions.push_back (s);
333                 }
334                 liste_conversions.push_back ((*i).p_convers->fin);
335               }
336
337             } else {
338               // Le filtre est une séquence qui est convertie en une autre séquence de même longueur
339               // Choisit la valeur au rang désiré dans la séquence de conversion
340               int rang = (valeur_initiale - (*i).filtre.debut) / (*i).filtre.pas;
341
342               int valeur_convertie = (*i).p_convers->debut + rang * (*i).p_convers->pas;
343
344               // Ajoute cette valeur à la liste des valeurs après conversion
345               liste_conversions.push_back (valeur_convertie);
346             }
347           } else {
348             // Ajoute la valeur initiale telle-quelle à la liste des valeurs après conversion
349             liste_conversions.push_back (valeur_initiale);
350           }
351         }
352     }
353
354     return liste_conversions.size();
355 }