![]() |
TinkerCell Core 1.0
TinkerCell's Core library providing all basic functionalities
|
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