SALOME documentation central

src/DSC/DSC_User/Datastream/DataIdFilter.hxx

00001 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 //  This library is free software; you can redistribute it and/or
00007 //  modify it under the terms of the GNU Lesser General Public
00008 //  License as published by the Free Software Foundation; either
00009 //  version 2.1 of the License.
00010 //
00011 //  This library is distributed in the hope that it will be useful,
00012 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 //  Lesser General Public License for more details.
00015 //
00016 //  You should have received a copy of the GNU Lesser General Public
00017 //  License along with this library; if not, write to the Free Software
00018 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 //  File   : DataIdFilter.hxx
00023 //  Author : Eric Fayolle (EDF)
00024 //  Module : KERNEL
00025 //
00026 /*   Module Filtre
00027  *   -------------
00028  *
00029  *   Implemente les fonctions de filtrage et conversion d'un port de DATASTREAM
00030  *
00031  *   Rappel des fonctions du Filtrage:
00032  *   --------------------------------
00033  *
00034  *   Dans une communication de type DATASTREAM, le destinataire indique à l'avance la liste
00035  *   des instances qu'il veut recevoir, c'est à dire celles qui lui sont nécessaires.
00036  *   Il indique pour cela la liste des 'times' et la liste des 'tags' qui
00037  *   caractérisent les instances désirées.
00038  *   Ces deux listes sont indépendantes. Toute instance dont les paramètres 'time' et
00039  *   'tag' figurent dans la liste des 'times' et respectivement dans la liste des
00040  *   'tags' est désirée par le destinataire.
00041  *   Par la suite, une telle instance sera acceptée par le port-DATASTREAM. Les autres
00042  *   seront rejetées.
00043  *
00044  *   Le filtrage consiste à limiter les valeurs possibles du paramètre TIME ou TAG (un
00045  *   entier). La liste des valeurs possibles est décrite sous la forme d'une liste de
00046  *   valeurs ou de séquences arithmétiques de valeurs.
00047  *   Exemple: 
00048  *     La liste 1; 3; 30:34; 40:50:2 autorise les valeurs 1 et 3 et toutes les valeurs
00049  *     comprises entre 30 et 34 inclus et toutes les valeurs de la séquence 40 à 50
00050  *     inclus par pas de 2, c'est à dire 40, 42, ... 50.
00051  *   On appelle règle élémentaire de filtrage celle spécifiant un élément de la liste
00052  *   des valeurs autorisées: soit une seule valeur, soit une séquence de valeurs. Une
00053  *   séquence de valeurs est spécifiée par sa valeur de départ, sa valeur de fin et
00054  *   son pas. Le filtrage est donc défini par une suite de règles de filtrage.
00055  *   La fonction élémentaire de configuration du filtrage sert à spécifier une règle
00056  *   de filtrage.
00057  *
00058  *   Rappels des fonctions de conversion:
00059  *   -----------------------------------
00060  *
00061  *   La conversion est intimement liée au filtrage car seules les valeurs passant le
00062  *   filtre sont converties. La conversion n'est pas obligatoire. Une valeur de TIME ou TAG
00063  *   entrante peut ne pas être convertie. Elle garde alors sa valeur et est gardée
00064  *   telle quelle pour l'objet destinataire.
00065  *   DATASTREAM peut associer une règle de conversion à chaque règle élémentaire de
00066  *   filtrage.
00067  *   La conversion consiste à changer:
00068  *     - un valeur de TIME ou TAG en une valeur différente
00069  *     - une séquence de valeurs en une autre séquence de valeurs de même taille
00070  *       (ex: 30:40 en 300:400:10)
00071  *   Mais la conversion permet aussi de transformer:
00072  *     - une valeur de TIME ou TAG unique en une séquence de valeurs (les données entrantes sont
00073  *       alors duppliquées et à chaque fois que l'objet destinataire réclame une donnée
00074  *       de la séquence, il reçoit en fait une copie de la donnée reçue une seule fois)
00075  *
00076  *     - une séquence de valeurs en une valeur unique (alors, chaque donnée entrante
00077  *       associée à un TIME ou TAG de la séquence correspond à une donnée unique pour le
00078  *       destinataire: seule la dernière reçue est la donnée valide)
00079  *
00080  */
00081 
00082 #include <vector>
00083 #include <iostream>
00084 
00085 // Pour l'utilisation de "vector" de la STL
00086 // Classe filtre_elementaire
00087 //
00088 // Implémente une structure de donnée décrivant un filtre élémentaire
00089 // sur le paramètre TIME ou TAG; c'est
00090 //    - soit une valeur entière unique
00091 //    - soit une séquence arithmétique de valeurs
00092 //
00093 class filtre_elementaire
00094 {
00095 public:
00096     int len;    // Longueur de séquence ou 1 pour une valeur unique
00097     int debut;  // Début de la séquence ou valeur pour une valeur unique
00098     int fin;    // Fin de la séquence
00099     int pas;    // Pas de la séquence
00100 
00101     // Constructeur par défaut
00102     filtre_elementaire() {}
00103     
00104     // Création d'un filtre élémentaire pour une valeur unique
00105     filtre_elementaire(int valeur)
00106     {
00107         this->len = 1;
00108         this->debut = valeur;
00109     }
00110 
00111     // Création d'un filtre élémentaire pour une séquence de valeurs entières
00112     // Le pas par défaut est 1
00113     filtre_elementaire (int _debut, int _fin, int _pas=1)
00114     {
00115         this->debut = _debut;
00116         this->len = (_fin - _debut) / _pas;
00117         if (this->len > 0)
00118         {
00119             this->fin = _debut + _pas * this->len;  // Calcule la vrai borne de fin
00120             this->pas = _pas;
00121             this->len += 1;   // Compte les bornes et non les intervalles
00122         }
00123         else  // erreur de spécification: on ne prend que la première valeur
00124             this->len = 1;
00125     }
00126 
00127     // Constructeur par copie
00128     filtre_elementaire (filtre_elementaire &_f)
00129     {
00130       this->len = _f.len;
00131       this->debut = _f.debut;
00132       this->fin = _f.fin;
00133       this->pas = _f.pas;
00134     }
00135 };
00136 
00137 // Classe filtre_conversion
00138 //
00139 // Implémente le filtrage et la conversion du paramètre TIME ou TAG
00140 // des données reçues par un port DATASTREAM.
00141 //
00142 // Mode d'emploi:
00143 //      1) Création d'un objet
00144 //      2) Configuration de cet objet par passage de paramètres
00145 //         de filtage et de conversion
00146 //      3) A la création d'un port DATASTREAM, on passe au constructeur
00147 //         deux objets 'filtre_conversion', l'un pour le TIME, l'autre pour le TAG.
00148 //      4) A l'utilisation du port DATASTREAM, celui-ci appelle la méthode
00149 //         "applique_filtre_conversion" pour opérer
00150 //
00151 class filtre_conversion
00152 {
00153 private:
00154     // Structure de données décrivant une conversion élémentaire:
00155     // un filtre élementaire
00156     // et un pointeur éventuel vers les paramètres de conversion associés
00157     class conversion_elementaire
00158     {
00159     public :
00160         // Data
00161         filtre_elementaire filtre;
00162         filtre_elementaire * p_convers;
00163 
00164         // Constructeur
00165         conversion_elementaire() {}
00166 
00167         // Constructeur par copie d'un objet non modifie (const)
00168         conversion_elementaire (const conversion_elementaire& _ce)
00169         {
00170             *this = _ce;
00171         }
00172         // Remarque: le Constructeur par copie d'un objet existe par defaut mais sans le modificateur 'const'
00173         //           et l'emploi d'un objet comme element dans un vecteur oblige d'avoir un tel const-copy-constructor.
00174     };
00175 
00176     // Données de configuration de filtrage et conversion:
00177     //    une table de filtres élémentaires
00178     //    avec leurs données de conversion associées éventuelles
00179     std::vector<conversion_elementaire> config;
00180 
00181 public:
00182     // Constructeur: juste une allocation mémoire initiale
00183     filtre_conversion() {}
00184 
00185     // Destructeur:
00186     // réclamer la mémoire utilisée par tous les éléments du vecteur config
00187     ~filtre_conversion()
00188     {
00189         std::vector<conversion_elementaire>::iterator i;
00190         for (i = this->config.begin(); i != this->config.end(); i ++)
00191         {
00192             delete (*i).p_convers;
00193         }
00194     }
00195 
00196     // Configuration partielle par ajout d'un filtre élémentaire
00197     bool config_elementaire (filtre_elementaire& _f)
00198     {
00199 //    cout << "ajout config_elementaire 1  " << this << endl;
00200         conversion_elementaire conv_elem;
00201         
00202         conv_elem.filtre = _f;
00203         conv_elem.p_convers = NULL;
00204 
00205         // Ajoute cette conversion/filtrage elementaire a la liste
00206         this->config.push_back (conv_elem);
00207     
00208 //    vector<conversion_elementaire>::iterator i;
00209 //    cout << "liste apres ajout:" << endl;
00210 //    for (i = this->config.begin(); i != this->config.end(); i ++)
00211 //    {
00212 //        cout << "config elem   " << endl;
00213 //        cout << "filtre: len, debut, fin, pas " << (*i).filtre.len << " " << (*i).filtre.debut << " " << (*i).filtre.fin << " " << (*i).filtre.pas << endl;
00214 //    }
00215         
00216         return true;
00217     }
00218     
00219     // Configuration partielle par ajout d'un filtre élémentaire
00220     // et sa conversion associée
00221     //
00222     // Retourne false si les param de conversion sont incompatibles avec le filtre élémentaire.
00223     // La configuration partielle est alors refusée.
00224     //
00225     bool config_elementaire (filtre_elementaire& _f, filtre_elementaire& _conv)
00226     {
00227 //    cout << "ajout config_elementaire 2  " << this << endl;
00228     
00229         if (_f.len == 1 || _conv.len == 1 || _f.len == _conv.len)
00230         {
00231             conversion_elementaire conv_elem;
00232             conv_elem.filtre = _f;
00233             conv_elem.p_convers = new filtre_elementaire(_conv);
00234 
00235             // Ajoute cette conversion/filtrage elementaire a la liste
00236             this->config.push_back (conv_elem);
00237     
00238 //    vector<conversion_elementaire>::iterator i;
00239 //    cout << "liste apres ajout:" << endl;
00240 //    for (i = this->config.begin(); i != this->config.end(); i ++)
00241 //    {
00242 //        cout << "config elem   " << endl;
00243 //        cout << "filtre: len, debut, fin, pas " << (*i).filtre.len << " " << (*i).filtre.debut << " " << (*i).filtre.fin << " " << (*i).filtre.pas << endl;
00244 //    }
00245         
00246             return true;
00247         }
00248         else
00249         {
00250             // Filtre et conversion incompatibles
00251             return false;
00252         }
00253     }
00254 
00255     // applique_filtre_conversion: Opération du filtre et de la conversion
00256     template <typename T > T applique_filtre_conversion (T valeur_initiale, std::vector<T>& liste_conversions) const;
00257 };
00258 
00259 
00260 
00261 // filtre_conversion::applique_filtre_conversion: Opération du filtre et de la conversion
00262 //
00263 // Etant donné une valeur entière (de TIME ou de TAG), cette méthode détermine :
00264 //   - si cette valeur passe le filtre
00265 //   - dans le cas où une conversion existe, la liste des valeurs de conversion
00266 //     qui correspondent à la valeur initiale
00267 //
00268 // Dans tous les cas, cette méthode retourne une liste de valeurs.
00269 // Dans le cas où il n'y a pas de conversion, cette liste a une longueur 1
00270 // et ne contient que la valeur initiale.
00271 //
00272 // Paramètre d'entrée :         la valeur initiale (integer)
00273 //
00274 // Paramètre de sortie :        la liste des valeurs après conversion (vector<int>)
00275 //
00276 // Valeur de retour :           la longueur de la liste
00277 //     si cette longueur est 0, c'est que la valeur initiale ne passe pas le filtre
00278 //
00279 template <typename T>
00280 T filtre_conversion::applique_filtre_conversion (T valeur_initiale, std::vector<T>& liste_conversions) const
00281 {
00282     // Part d'une liste vierge
00283     liste_conversions.clear();
00284 
00285 //    cout << "config applique_filtre_conversion " << this << endl;
00286     
00287     // Balaye tous les éléments de configuration
00288     // et cherche pour chacun d'eux si la valeur initiale est présente parmi les valeurs filtrées
00289 
00290     // Pour tous les éléments de configuration du filtrage/conversion
00291     std::vector<conversion_elementaire>::const_iterator i;
00292     for (i = config.begin(); i != config.end(); i ++)
00293     {
00294 
00295 //    cout << "config elem   " << endl;
00296 //    cout << "filtre: len, debut, fin, pas " << (*i).filtre.len << " " << (*i).filtre.debut << " " << (*i).filtre.fin << " " << (*i).filtre.pas << endl;
00297     
00298         bool si_passe_filtre = false;
00299 
00300         // Si la longueur du filtre est 1
00301         if ((*i).filtre.len == 1) {
00302        // Si la valeur initiale correspond à la valeur du filtre
00303        if ((*i).filtre.debut == valeur_initiale)
00304          si_passe_filtre = true;
00305         } else  {
00306        // Si la valeur initiale est dans la séquence des valeurs du filtre
00307        //   la valeur est comprise dans les bornes [debut,fin]
00308        //   et sa distance du début de la séquence est modulo le pas
00309        if (  ((*i).filtre.fin - valeur_initiale >= 0) == (valeur_initiale - (*i).filtre.debut >= 0)
00310                 &&  (valeur_initiale - (*i).filtre.debut) % (*i).filtre.pas == 0  ) {
00311          si_passe_filtre = true;
00312        }
00313         }
00314 
00315         // Si la valeur initiale passe le filtre
00316         if (si_passe_filtre) {
00317        //    cout << "config: filtre passe    " << endl;
00318             
00319        // Si il y a une conversion à effectuer
00320        if ((*i).p_convers != NULL) {
00321 
00322          // Si la longueur du filtre est 1
00323          if ((*i).filtre.len == 1) {
00324 
00325            // Si la longueur des paramètres de conversion est aussi 1
00326            if ((*i).p_convers->len == 1) {
00327           // Ajoute la valeur de conversion à la liste des valeurs après conversion
00328           liste_conversions.push_back ((*i).p_convers->debut);
00329            } else {
00330           // Ajoute la séquence de conversion à la liste des valeurs après conversion
00331           for (int s = (*i).p_convers->debut; s != (*i).p_convers->fin; s += (*i).p_convers->pas) {
00332             liste_conversions.push_back (s);
00333           }
00334           liste_conversions.push_back ((*i).p_convers->fin);
00335            }
00336 
00337          } else {
00338            // Le filtre est une séquence qui est convertie en une autre séquence de même longueur
00339            // Choisit la valeur au rang désiré dans la séquence de conversion
00340            int rang = (valeur_initiale - (*i).filtre.debut) / (*i).filtre.pas;
00341 
00342            int valeur_convertie = (*i).p_convers->debut + rang * (*i).p_convers->pas;
00343 
00344            // Ajoute cette valeur à la liste des valeurs après conversion
00345            liste_conversions.push_back (valeur_convertie);
00346          }
00347        } else {
00348          // Ajoute la valeur initiale telle-quelle à la liste des valeurs après conversion
00349          liste_conversions.push_back (valeur_initiale);
00350        }
00351         }
00352     }
00353 
00354     return liste_conversions.size();
00355 }