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