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 }