TinkerCell Core 1.0
TinkerCell's Core library providing all basic functionalities
ItemFamily.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003 Copyright (c) 2008 Deepak Chandran
00004 Contact: Deepak Chandran (dchandran1@gmail.com)
00005 See COPYRIGHT.TXT
00006 
00007 This is one of the main classes in Tinkercell
00008 This file defines the ItemFamily, NodeFamily, and ConnectionFamily classes.
00009 Each item in Tinkercell has an associated family.
00010 
00011 ****************************************************************************/
00012 #include <iostream>
00013 #include <QtDebug>
00014 #include "Ontology.h"
00015 #include "ItemFamily.h"
00016 #include "ItemHandle.h"
00017 
00018 namespace Tinkercell
00019 {
00020         /*********************************
00021         Units
00022         **********************************/
00023         
00024         Unit::Unit(const QString& p, const QString& s): property(p), name(s)
00025         {
00026         }
00027         
00028         Unit::Unit(): property(QString()), name(QString())
00029         {
00030         }
00031 
00032         bool Unit::operator == (const Unit& a) const
00033         {
00034                 return (a.property == property && a.name == name);
00035         }
00036 
00037         /*********************************
00038         ITEM FAMILY
00039         **********************************/
00040         
00041         QStringList ItemFamily::ALLNAMES;
00042         QList<const ItemFamily*> ItemFamily::ALLFAMILIES;
00043         QHash<QString,int> ItemFamily::NAMETOID;
00044 
00045         ItemFamily::ItemFamily(const QString& s): type(0)
00046         {
00047                 setName(s);
00048         }
00049 
00050         ItemFamily::~ItemFamily()
00051         {
00052                 for (int i=0; i < graphicsItems.size(); ++i)
00053                         if (graphicsItems[i] && !graphicsItems[i]->scene())
00054                                 delete graphicsItems[i];
00055         }
00056         
00057         QString ItemFamily::name() const
00058         {
00059                 return _name;
00060         }
00061         
00062         ItemFamily * ItemFamily::parent() const {       return 0;  }
00063         
00064         QList<ItemFamily*> ItemFamily::parents() const { return QList<ItemFamily*>(); }
00065         
00066         QList<ItemFamily*> ItemFamily::children() const { return QList<ItemFamily*>(); }
00067 
00068         int ItemFamily::depth() const
00069         {
00070                 int i = 0;
00071                 ItemFamily * p = parent();
00072                 while (p)
00073                 {
00074                         p = p->parent();
00075                         ++i;
00076                 }
00077                 return i;
00078         }
00079         
00080         void ItemFamily::setName(const QString& s)
00081         {
00082                 if (s.isNull() || s.isEmpty()) return;
00083 
00084                 if (NAMETOID.contains(s.toLower()))
00085                 {
00086                         _name = s.toLower();
00087                         ID = NAMETOID[ _name ];
00088                         return;
00089                 }
00090 
00091                 _name = s.toLower();
00092                 ID = ALLNAMES.size();
00093                 ALLNAMES += _name;
00094                 ALLFAMILIES += this;
00095                 NAMETOID.insert( _name , ID );
00096         }
00097         
00098         bool ItemFamily::isA(int ID) const
00099         {
00100                 return false;
00101         }
00102 
00103         bool ItemFamily::isA(const QString& name) const
00104         {
00105                 QString s1 = name.toLower();
00106                 ConnectionFamily * f1 = Ontology::connectionFamily(s1);
00107                 if (f1)
00108                         s1 = f1->name(); //map possible synonyms to default names
00109                 NodeFamily * f2 = Ontology::nodeFamily(s1);
00110                 if (f2)
00111                         s1 = f2->name(); //map possible synonyms to default names
00112         
00113                 if (NAMETOID.contains(s1))
00114                         return isA(NAMETOID.value(s1));
00115                 
00116                 if (s1.endsWith('s'))
00117                         s1.chop(1);
00118 
00119                 if (NAMETOID.contains(s1))
00120                         return isA(NAMETOID.value(s1));
00121                 
00122                 return false;
00123         }
00124 
00125         bool ItemFamily::isA(const ItemFamily* family) const
00126         {
00127                 if (!family) return false;
00128                 return isA(family->ID);
00129         }
00130         
00131         bool ItemFamily::isParentOf(const QString& name) const
00132         {
00133                 if (!NAMETOID.contains(name)) return false;
00134                 int id = NAMETOID.value(name);
00135                 
00136                 if (ALLFAMILIES.size() <= id) return false;
00137                 
00138                 const ItemFamily * family = ALLFAMILIES[id];
00139                 
00140                 if (!family) return false;
00141                 return family->isA(ID);
00142         }
00143 
00144         bool ItemFamily::isParentOf(const ItemFamily* family) const
00145         {
00146                 if (!family) return false;
00147                 return family->isA(ID);
00148         }
00149 
00150         ItemFamily * ItemFamily::root() const
00151         {
00152                 ItemFamily * root = const_cast<ItemFamily*>(this);
00153                 while (root->parent())
00154                         root = root->parent();
00155                 return root;
00156         }
00157 
00158         bool ItemFamily::isRelatedTo(const ItemFamily * family) const
00159         {
00160                 if (!family) return false;
00161                 return isA(family->root()->ID);
00162         }
00163         
00164         QList<ItemFamily*> ItemFamily::allChildren() const
00165         {
00166                 QList<ItemFamily*> list  = children(), list2;
00167                 
00168                 for (int i=0; i < list.size(); ++i)
00169                         if (list[i])
00170                         {
00171                                 list2 = list[i]->children();
00172                                 for (int j=0; j < list2.size(); ++j)
00173                                         if (list2[j] && !list.contains(list2[j]))
00174                                                 list << list2[j];
00175                         }
00176                 
00177                 return list;
00178         }
00179 
00180         /**************************************
00181                                 NODE FAMILY
00182         **************************************/
00183         
00184         int NodeFamily::TYPE = 1;
00185         
00186         NodeFamily * NodeFamily::cast(ItemFamily* item)
00187         {
00188                 if (item && item->type == NodeFamily::TYPE)
00189                         return static_cast<NodeFamily*>(item);
00190                 return 0;
00191         }
00192 
00193         QList<NodeFamily*> NodeFamily::cast(const QList<ItemFamily*>& items)
00194         {
00195                 QList<NodeFamily*> nodes;
00196                 NodeFamily * item = 0;
00197                 for (int i=0; i < items.size(); ++i)
00198                         if ((item = cast(items[i])) && !nodes.contains(item))
00199                                 nodes += item;
00200                 return nodes;
00201         }
00202 
00203 
00204         NodeFamily::NodeFamily(const QString& s): 
00205                 ItemFamily(s)
00206         {
00207                 type = NodeFamily::TYPE;
00208         }
00209 
00210         NodeFamily::~NodeFamily() {}
00211 
00212         ItemFamily* NodeFamily::parent() const
00213         {
00214                 if (parentFamilies.isEmpty()) return 0;
00215                 ItemFamily * p = 0;
00216                 int maxd = 0, d = 0;
00217                 for (int i=0; i < parentFamilies.size(); ++i)
00218                         if (parentFamilies[i])
00219                         {
00220                                 d = parentFamilies[i]->depth();
00221                                 if (p==0 || d >= maxd)
00222                                 {
00223                                         p = parentFamilies[i];
00224                                         maxd = d;
00225                                 }
00226                         }
00227                 return p;
00228         }
00229 
00231         bool NodeFamily::isA(int id) const
00232         {
00233                 if (ID == id) return true;
00234 
00235                 QList<NodeFamily*> families = parentFamilies;
00236                 for (int i=0; i < families.size(); ++i)
00237                 {
00238                         if (families[i]->ID == id) return true;
00239                         families += families[i]->parentFamilies;
00240                 }
00241                 
00242                 return false;
00243         }
00244         
00245         bool NodeFamily::isA(const QString& name) const
00246         {
00247                 QString s1 = name.toLower();
00248                 NodeFamily * f = Ontology::nodeFamily(s1);
00249                 if (f)
00250                         s1 = f->name(); //map possible synonyms to default names
00251         
00252                 if (NAMETOID.contains(s1))
00253                         return isA(NAMETOID.value(s1));
00254                 
00255                 if (s1.endsWith('s'))
00256                         s1.chop(1);
00257 
00258                 if (NAMETOID.contains(s1))
00259                         return isA(NAMETOID.value(s1));
00260                 
00261                 return false;
00262         }
00263 
00264         bool NodeFamily::isA(const ItemFamily* family) const
00265         {
00266                 if (!family) return false;
00267                 return isA(family->ID);
00268         }
00269 
00270         QList<ItemFamily*> NodeFamily::parents() const
00271         {
00272                 QList<ItemFamily*> list;
00273                 for (int i=0; i < parentFamilies.size(); ++i)
00274                         list += parentFamilies.at(i);
00275                 return list;
00276         }
00277 
00278         QList<ItemFamily*> NodeFamily::children() const
00279         {
00280                 QList<ItemFamily*> list;
00281                 for (int i=0; i < childFamilies.size(); ++i)
00282                         list += childFamilies.at(i);
00283                 return list;
00284         }
00285 
00286         void NodeFamily::setParent(NodeFamily* p)
00287         {
00288                 if (!p || this == p || isA(p->ID) || p->isA(ID)) return;
00289                 if (!parentFamilies.contains(p))
00290                         parentFamilies.append(p);
00291                 if (!p->childFamilies.contains(this))
00292                         p->childFamilies.append(this);
00293         }
00294 
00295         /*********************************
00296         CONNECTION FAMILY
00297         **********************************/
00298 
00299         int ConnectionFamily::TYPE = 2;
00300         QStringList ConnectionFamily::ALLROLENAMES;
00301         QHash<QString,int> ConnectionFamily::ROLEID;    
00302 
00303         ConnectionFamily * ConnectionFamily::cast(ItemFamily* item)
00304         {
00305                 if (item && item->type == ConnectionFamily::TYPE)
00306                         return static_cast<ConnectionFamily*>(item);
00307                 return 0;
00308         }
00309         
00310         QList<ConnectionFamily*> ConnectionFamily::cast(const QList<ItemFamily*>& items)
00311         {
00312                 QList<ConnectionFamily*> connections;
00313                 ConnectionFamily * item = 0;
00314                 for (int i=0; i < items.size(); ++i)
00315                         if ((item = cast(items[i])) && !connections.contains(item))
00316                                 connections += item;
00317                 return connections;
00318         }
00319 
00320         ConnectionFamily::ConnectionFamily(const QString& s): 
00321                 ItemFamily(s)
00322         {
00323                 type = ConnectionFamily::TYPE;
00324         }
00325 
00326         ConnectionFamily::~ConnectionFamily() {}
00327 
00329         bool ConnectionFamily::isA(int id) const
00330         {
00331                 if (ID == id) return true;
00332 
00333                 QList<ConnectionFamily*> families = parentFamilies;
00334                 for (int i=0; i < families.size(); ++i)
00335                 {
00336                         if (families[i]->ID == id) return true;
00337                         families += families[i]->parentFamilies;
00338                 }
00339                 
00340                 return false;
00341         }
00342         
00343         bool ConnectionFamily::isA(const QString& name) const
00344         {
00345                 QString s1 = name.toLower();
00346                 ConnectionFamily * f = Ontology::connectionFamily(s1);
00347                 if (f)
00348                         s1 = f->name(); //map possible synonyms to default names
00349         
00350                 if (NAMETOID.contains(s1))
00351                         return isA(NAMETOID.value(s1));
00352                 
00353                 if (s1.endsWith('s'))
00354                         s1.chop(1);
00355 
00356                 if (NAMETOID.contains(s1))
00357                         return isA(NAMETOID.value(s1));
00358                 
00359                 return false;   
00360         }
00361 
00362         bool ConnectionFamily::isA(const ItemFamily* family) const
00363         {
00364                 if (!family) return false;
00365                 return isA(family->ID);
00366         }
00367 
00368         ItemFamily* ConnectionFamily::parent() const
00369         {
00370                 if (parentFamilies.isEmpty()) return 0;
00371                 ItemFamily * p = 0;
00372                 int maxd = 0, d = 0;
00373                 for (int i=0; i < parentFamilies.size(); ++i)
00374                         if (parentFamilies[i])
00375                         {
00376                                 d = parentFamilies[i]->depth();
00377                                 if (p==0 || d >= maxd)
00378                                 {
00379                                         p = parentFamilies[i];
00380                                         maxd = d;
00381                                 }
00382                         }
00383                 return p;
00384 
00385         }
00386 
00387         QList<ItemFamily*> ConnectionFamily::parents() const
00388         {
00389                 QList<ItemFamily*> list;
00390                 for (int i=0; i < parentFamilies.size(); ++i)
00391                         list += parentFamilies.at(i);
00392                 return list;
00393         }
00394 
00395         QList<ItemFamily*> ConnectionFamily::children() const
00396         {
00397                 QList<ItemFamily*> list;
00398                 for (int i=0; i < childFamilies.size(); ++i)
00399                         list += childFamilies.at(i);
00400                 return list;
00401         }
00402 
00403         void ConnectionFamily::setParent(ConnectionFamily* p)
00404         {
00405                 if (!p || this == p || isA(p->ID) || p->isA(ID)) return;
00406                 if (!parentFamilies.contains(p))
00407                         parentFamilies.append(p);
00408                 if (!p->childFamilies.contains(this))
00409                         p->childFamilies.append(this);
00410         }
00411 
00412         bool ConnectionFamily::isValidSet(const QList<NodeHandle*>& nodes, bool full)
00413         {
00414                 if (nodes.isEmpty())
00415                         return !full;
00416                 
00417                 for (int i=0; i < restrictions.size(); ++i)
00418                         if (!checkRestrictions(restrictions[i],nodes,full))
00419                                 return false;
00420 
00421                 NodeHandle * h;
00422 
00423                 if ((full && nodes.size() != nodeRoles.size()) ||
00424                         (nodes.size() > nodeRoles.size()))
00425                 {
00426                         return false;
00427                 }
00428                 
00429                 bool b;
00430                 int boolean1 = 0, boolean2 = 1;
00431                                 
00432                 for (int i=0; i < nodes.size(); ++i)  //for each node in this connection
00433                 {
00434                         b = false;
00435                         boolean2 = boolean2 | (1 << i);
00436                         for (int j=0; j < nodeRoles.size(); ++j)   //check of the family allows it
00437                         {
00438                                 if (nodes[i] && 
00439                                         nodes[i]->family() && 
00440                                                 (nodes[i]->family()->isA(nodeRoles[j].second) || 
00441                                                         (nodeRoles[j].second < ALLFAMILIES.size() && ALLFAMILIES.at(nodeRoles[j].second)->isA(nodes[i]->family()))
00442                                                 )
00443                                         )
00444                                 {
00445                                         boolean1 = (boolean1  | (1 << j));
00446                                         b = true;
00447                                 }
00448                         }
00449                         
00450                         if (!b)
00451                                 return false;
00452                 }
00453                 
00454                 if (full && (boolean1 != boolean2))
00455                 {
00456                         return false;
00457                 }
00458                 
00459                 return true;
00460         }
00461 
00462         QList<ItemFamily*> ConnectionFamily::findValidChildFamilies(const QList<NodeHandle*>& nodes, bool full)
00463         {
00464                 QList<ItemFamily*> validFamilies, childFamilies, list;
00465 
00466                 //breadth first search starting from current family
00467 
00468                 ConnectionFamily * connection;
00469 
00470                 if (isValidSet(nodes,full))
00471                         validFamilies << this;
00472 
00473                 childFamilies << this;
00474 
00475                 for (int i=0; i < childFamilies.size(); ++i)
00476                         if (childFamilies[i])
00477                         {
00478                                 list = childFamilies[i]->children();
00479                                 for (int j=0; j < list.size(); ++j)
00480                                 {
00481                                         connection = ConnectionFamily::cast(list[j]);
00482                                         if (connection && !childFamilies.contains(connection))
00483                                         {
00484                                                 childFamilies << connection; 
00485                                                 if (connection->isValidSet(nodes,full))
00486                                                         validFamilies << connection;
00487                                         }
00488                                 }
00489                         }
00490 
00491                 return validFamilies;
00492         }
00493         
00494         bool ConnectionFamily::addParticipant(const QString& role, const QString& family)
00495         {
00496                 QString f = family.toLower().trimmed(), r = role.toLower().trimmed();
00497                 
00498                 if (!ItemFamily::NAMETOID.contains(f)) return false;
00499                 
00500                 int nodeid = NAMETOID.value(f);
00501                 int roleid = 0;
00502                 
00503                 if (ROLEID.contains(r) && ALLROLENAMES.size() > ROLEID.value(r))        
00504                 {
00505                         roleid = ROLEID.value(r);
00506                 }
00507                 else
00508                 {
00509                         roleid = ALLROLENAMES.size();
00510                         ALLROLENAMES += r;
00511                         ROLEID.insert( r, roleid );
00512                 }
00513 
00514                 if (!nodeRoles.contains(QPair<int,int>( roleid, nodeid ))) //don't allow duplicate roles
00515                         nodeRoles += QPair<int,int>( roleid, nodeid );
00516                 return true;
00517         }
00518         
00519         QString ConnectionFamily::participantFamily(const QString& role) const
00520         {
00521                 QString r = role.toLower();
00522                 if (!ROLEID.contains(r)) return QString();              
00523                 int k1 = ROLEID.value(r);
00524                 int k2 = -1;
00525                 
00526                 for (int i=0; i < nodeRoles.size(); ++i)
00527                         if (nodeRoles[i].first == k1)
00528                         {
00529                                 k2 = nodeRoles[i].second;
00530                                 break;
00531                         }
00532                 
00533                 if (k2 < 0) 
00534                         return QString();
00535 
00536                 if (ItemFamily::ALLNAMES.size() > k2)
00537                         return ItemFamily::ALLNAMES[k2];
00538                 
00539                 return QString();
00540         }
00541 
00542         QStringList ConnectionFamily::participantRoles() const
00543         {
00544                 QStringList roles;
00545                 for (int i=0; i < nodeRoles.size(); ++i)
00546                         if (ALLROLENAMES.size() > nodeRoles[i].first)
00547                                 roles += ALLROLENAMES[ nodeRoles[i].first ];
00548 
00549                 return roles;
00550         }
00551         
00552         QStringList ConnectionFamily::participantTypes() const
00553         {
00554                 QStringList families;
00555                 for (int i=0; i < nodeRoles.size(); ++i)
00556                         if (ItemFamily::ALLNAMES.size() > nodeRoles[i].second)
00557                                 families += ItemFamily::ALLNAMES[ nodeRoles[i].second ];
00558 
00559                 return families;
00560         }
00561         
00562         int ConnectionFamily::numberOfIdenticalNodesFamilies(ConnectionFamily * other) const
00563         {
00564                 if (!other) return 0;
00565                 
00566                 int total = 0;
00567                 for (int i=0; i < nodeRoles.size(); ++i)
00568                         for (int j=0; j < other->nodeRoles.size(); ++j)
00569                                 if (nodeRoles[i].second == other->nodeRoles[j].second)
00570                                 {
00571                                         ++total;
00572                                         break;
00573                                 }
00574         }
00575         
00576         QStringList ConnectionFamily::synonymsForRole(const QString& rolename) const
00577         {
00578                 int roleid = ALLROLENAMES.indexOf(rolename.toLower());
00579                 if (roleid < 0) return QStringList();
00580                 
00581                 int index = -1;
00582                 
00583                 for (int i=0; i < nodeRoles.size(); ++i)
00584                         if (nodeRoles.at(i).first == roleid)
00585                         {
00586                                 index = i;
00587                                 break;
00588                         }
00589 
00590                 if (index == -1)
00591                 {
00592                         for (int i=0; i < childFamilies.size(); ++i)
00593                         {
00594                                 const ConnectionFamily * child = childFamilies.at(i);
00595                                 for (int j=0; j < child->nodeRoles.size(); ++j)
00596                                         if (child->nodeRoles.at(j).first == roleid)
00597                                         {
00598                                                 index = j;
00599                                                 break;
00600                                         }
00601                                 if (index > -1) break;
00602                         }
00603                 }
00604                 
00605                 QStringList rolelist;
00606                 QList<int> roleids;
00607                 
00608                 if (index == -1) return rolelist;
00609                 
00610                 if (nodeRoles.size() > index)
00611                         if (ALLROLENAMES.size() > nodeRoles[index].first && !roleids.contains(nodeRoles[index].first))
00612                         {
00613                                 roleids += nodeRoles[index].first;
00614                                 rolelist += ALLROLENAMES[ nodeRoles[index].first ];
00615                         }
00616                 
00617                 for (int i=0; i < childFamilies.size(); ++i)
00618                 {
00619                         const ConnectionFamily * child = childFamilies.at(i);
00620                         if (child->nodeRoles.size() > index)
00621                                 if (ALLROLENAMES.size() > child->nodeRoles[index].first && !roleids.contains(child->nodeRoles[index].first))
00622                                 {
00623                                         roleids += child->nodeRoles[index].first;
00624                                         rolelist += ALLROLENAMES[ child->nodeRoles[index].first ];                      
00625                                 }
00626                 }
00627                 
00628                 return rolelist;
00629         }
00630         
00631         bool ConnectionFamily::checkRestrictions(const QString & restriction, const QList<NodeHandle*>& nodes, bool checkFull)
00632         {
00633                 if (checkFull && restriction.toLower() == QString("different compartments"))
00634                 {
00635                         if (nodes.size() < 2 || !nodes[0]) return false;
00636 
00637                         ItemHandle * parent = nodes[0]->parent;
00638                         for (int i=1; i < nodes.size(); ++i)
00639                         {
00640                                 if (nodes[i] && nodes[i]->parent != parent)
00641                                         return true;
00642                         }
00643                         return false;
00644                 }
00645                 return true;
00646         }
00647 }
00648 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines