#include #include #include #include"tree.h" #include"person.h" #include"help.h" using std::cout; using std::vector; Tree Tree::operator+ (const Tree& other)// { Tree result(treeName + other.treeName); //The tree resulting from the addition vector newId; //The indexes members of the II tree will have in result newId.reserve(other.numPeople); U32 idCounter = numPeople; for (U32 i = 0, j; i < other.numPeople; ++i) //Searches for people present in both trees and gives them the same index in result { for (j = 0; j < numPeople; ++j) { if (other.people[i] == people[j]) { newId[i] = j; break; } } if (j >= numPeople) newId[i] = ++idCounter; } result.numPeople = idCounter; //The number of members the resulting tree has result.people.reserve(result.numPeople); result.people = people; //Adds the members of the I tree to the resulting tree for (U32 i=0; i < other.numPeople; ++i) //Adds the members of the II tree to the resulting tree { if (newId[i] >= numPeople) result.people.push_back(other.people[i]); } result.relations.reserve(result.numPeople); result.relations = relations; for (U32 i=0; i < other.numPeople; ++i) //Adds the relatives from the II tree { if (newId[i] >= numPeople) //If the member is found in the II tree but not in the I { result.relations.push_back(other.relations[i]); } else //If he's found in both { for (unsigned j = 0; j < other.people[i].numRel_; ++j) //Adds the number of relatives from the II to the number in the I { if (newId[other.relations[i][j].id] > numPeople) ++result.people[newId[i]].numRel_; } result.relations[newId[i]].reserve(result.people[newId[i]].numRel_); result.relations[newId[i]] = relations[newId[i]]; result.relations[newId[i]] += other.relations[i]; //The relatives from the II tree } } return result; } Tree& Tree::operator+=(const Tree& other) { vector newId; //The indexes people from II tree will have in I tree newId.reserve(other.numPeople); U32 idCounter = numPeople; for (U32 i = 0, j; i < other.numPeople; ++i) //Searches for people present in both trees and gives them the same index in I { for (j = 0; j < numPeople; ++j) { if (other.people[i] == people[j]) { newId[i] = j; break; } } if (j >= numPeople) newId[i] = idCounter++; } people.reserve(idCounter); for (U32 i = 0; i < other.numPeople; ++i) //Adds the member personal data of II tree to I tree { if (newId[i] >= numPeople) people.push_back(other.people[i]); } relations.reserve(idCounter); for (U32 i = 0; i < other.numPeople; ++i) //Merges the relative data { if (newId[i] >= numPeople) { relations.push_back(other.relations[i]); for (U32 j = 0; j < other.people[i].numRel_; ++j) relations[newId[i]][j].id = newId[ relations[newId[i]][j].id ]; } else //If the member is present in both trees { for (U32 j = 0; j < other.people[i].numRel_; ++j) //Adds the number of relatives from the II to the number in the I { if (newId[other.relations[i][j].id] >= numPeople) ++people[newId[i]].numRel_; } relations[newId[i]].reserve(people[newId[i]].numRel_); for (U32 j = 0; j < other.people[i].numRel_; ++j) { relations[newId[i]][j + people[newId[i]].numRel_ - other.people[i].numRel_].id = newId[other.relations[i][j].id]; relations[newId[i]][j + people[newId[i]].numRel_ - other.people[i].numRel_].type = other.relations[i][j].type; } } } numPeople = idCounter; //Number of members in I tree return *this; } Tree& Tree::operator-= (const Tree& other) { for (U32 i = 0; i < numPeople; ++i) { for (const Person& othPers: other.people) { if (people[i] == othPers) { removePerson(i); --i; break; } } } return *this; } void Tree::rename(const char* newName) { treeName = newName; } person_id Tree::findId(const char* name, const short year, const unsigned char month, const unsigned char day) const { //TODO //Person sought(name, day, month, year,) for (person_id i = 0; i < numPeople; ++i) { if (name == people[i].name_) //&& (year == people[i].year || !year || !people[i].year) && (month == people[i].month || !month || !people[i].month) && (day == people[i].day || !day || people[i].day)) return i; } return Nobody; } person_id Tree::findOldestAncestor(unsigned id, bool isMale)const { for (unsigned i = 0; i < people[id].numRel_; ++i) { if (relations[id][i].type == Child && people[ relations[id][i].id ].isMale_ == isMale) return findOldestAncestor(relations[id][i].id, isMale); } return id; } person_id Tree::findCommonAncestor(const unsigned firstId, const unsigned secondId) const { vector visited(numPeople); //if a member is visited twice he's a common ancestor commonAncestorRec(firstId, visited); commonAncestorRec(secondId, visited); person_id oldest = Nobody; U16 oldestBday = SHRT_MAX; for (person_id i = 0; i < numPeople; ++i) { if (visited[i] == 2 && people[i].birth_.year < oldestBday) { oldestBday = people[i].birth_.year; oldest = i; } } return oldest; } person_id Tree::findParent(person_id child, bool isParentMale) const { person_id parent = Nobody; for(const Relation& rel: relations[child]) { if (rel.type == Child && people[rel.id].isMale()) parent = rel.id; } return parent; } person_id Tree::findSpouse(person_id person) const { person_id spouse = Nobody; for(const Relation& rel: relations[person]) { if (rel.type == Spouse) { spouse = rel.id; break; } } return spouse; } /* person_id Tree::findRelation(person_id first, person_id second) const */ /* { */ /* const auto& curRels = relations[first]; */ /* for(auto i =0; i(&numPeople), sizeof(numPeople)); for (unsigned i = 0; i < numPeople; ++i) people[i].save(peopleFile); peopleFile.close(); std::ofstream relationFile(treeName + ".relations", std::ios::binary); for (unsigned i = 0; i < numPeople; ++i) { //relationFile.write((char*)&people[i].numRel_, sizeof(people[i].numRel_)); for (unsigned j = 0; j < people[i].numRel_; ++j) relationFile.write(reinterpret_cast(&relations[i][j]), sizeof(relations[i][j])); } relationFile.close(); } bool Tree::loadTree() { std::ifstream peopleFile(treeName + ".people", std::ios::binary); if (peopleFile.peek() == std::char_traits::eof()) { peopleFile.close(); return 0; } peopleFile.read(reinterpret_cast(&numPeople), sizeof(numPeople)); people.resize(numPeople); for (unsigned i = 0; i < numPeople; ++i) people[i].load(peopleFile); peopleFile.close(); std::ifstream relationFile(treeName + ".relations", std::ios::binary); relations.resize(numPeople); for (unsigned i = 0; i < numPeople; ++i) { relations[i].resize(people[i].numRel_); for (unsigned j = 0; j < people[i].numRel_; ++j) relationFile.read(reinterpret_cast(&relations[i][j]), sizeof(relations[i][j])); } relationFile.close(); return 1; } void Tree::addPerson(const char* name, bool isMale, unsigned father, unsigned mother, EventTime birth, EventTime death) { Person newPerson(name, birth, isMale, death); people.push_back(newPerson); vector newRels; relations.push_back(newRels); ++numPeople; addRelation(father, Parent, numPeople - 1); addRelation(mother, Parent, numPeople - 1); } bool Tree::addRelation(const char* firstName, const RelType type, const char* secondName) { return addRelation(findId(firstName), type, findId(secondName)); } bool Tree::addRelation(const unsigned firstId, const RelType type, const unsigned secondId, bool opposite)// { if (firstId == Nobody || firstId >= numPeople || secondId == Nobody || secondId >= numPeople || type == None) return 0; unsigned i = 0; for (; i < people[firstId].numRel_; ++i) //If they are already relatives { if (relations[firstId][i].id == secondId) { relations[firstId][i].type = type; break; } } if (i >= people[firstId].numRel_) { relations[firstId].push_back({secondId, type}); ++people[firstId].numRel_; } if (!opposite) { switch (type) { case Parent: addRelation(secondId, Child, firstId, 1); break; case Child: addRelation(secondId, Parent, firstId, 1); break; case Sibling: case HalfSibling: case Spouse: case ExSpouse: addRelation(secondId, type, firstId, 1); break; default: assert(!"Unexpected case"); break; } } return 1; } void Tree::removeRelation(const char* firstName, const char* secondName) { removeRelation(findId(firstName), findId(secondName)); } void Tree::removePerson(const person_id id) { person_id relId; //Íoìåð íà òåêóùèÿ ðîäíèíàòà for (Relation rel: relations[id]) //Remove all of his relations { relId = rel.id; for (U32 j = 0; j < relations[relId].size(); ++j) { if (relations[relId][j].id == id) { remove(relations[relId], j); break; } } } for (unsigned i = 0; i < people[numPeople - 2].numRel_; ++i) //Move the last in his place and update IDs { relId = relations[numPeople - 1][i].id; for (unsigned j = 0; j < people[relId].numRel_; ++j) { if (relations[relId][j].id == numPeople - 1) { relations[relId][j].id = id; break; } } } remove(relations, id); remove(people, id); --numPeople; } void Tree::removePerson(const char* personName, short year, unsigned char month, unsigned char day) { removePerson(findId(personName, year, month, day)); } void Tree::removeRelation(const unsigned firstId, const unsigned secondId) { for (unsigned i = 0; i < relations[firstId].size(); ++i) { if (relations[firstId][i].id == secondId) { remove(relations[firstId], i); break; } } for (unsigned i = 0; i < relations[secondId].size(); ++i) { if (relations[secondId][i].id == firstId) { remove(relations[secondId], i); break; } } } void Tree::display() { draw(); I32 c; do { c = std::tolower(getch()); switch(c) { case '\n': focused_ = selected_; draw(); break; case KEY_DOWN: selectDown(); break; case KEY_UP: selectUp(); break; case 'h': selectLeft(); break; case 'j': selectDown(); break; case 'k': selectUp(); break; case 'l': selectRight(); break; case 'i': people[selected_].displayInfo(); draw(); break; default: break; } } while(c != 'w'); } void Tree::draw() const { erase(); //Clear the screen wnoutrefresh(stdscr); I16 drawY = 0/* (LINES) / 2 */; I16 drawX = 0/* (COLS) / 2 */; drawLineWithWives(focused_, drawY, drawX); doupdate(); } void Tree::print() const { for(const Person& member: people) member.displayInfo(); } void Tree::printRel(const unsigned id)const { /* cout << people[id].name_; */ /* if (people[id].numRel_ == 0) */ /* cout << " has no known relatives"; */ /* else */ /* { */ /* unsigned relId; */ /* cout << "'s relatives:\n"; */ /* for (unsigned i = 0; i < people[id].numRel_; ++i) */ /* { */ /* relId = relatives[id][i]; */ /* cout << people[relId].name_ << " - "; */ /* switch (relations[id][i]) */ /* { */ /* case Father: */ /* case Mother: */ /* cout << (people[relId].isMale_ ? "son" : "daughter"); */ /* break; */ /* case Son: */ /* case Daughter: */ /* cout << (people[relId].isMale_ ? "father" : "mother"); */ /* break; */ /* case Brother: */ /* case Sister: */ /* cout << (people[relId].isMale_ ? "brother" : "sister"); */ /* break; */ /* case HalfBrother: */ /* case HalfSister: */ /* cout << (people[relId].isMale_ ? "half brother" : "half sister"); */ /* break; */ /* case Husband: */ /* cout << "wife"; */ /* break; */ /* case Wife: */ /* cout << "husband"; */ /* break; */ /* case ExHusband: */ /* cout << "ex-wife\n"; */ /* break; */ /* case ExWife: */ /* cout << "ex-husband\n"; */ /* break; */ /* } */ /* cout << '\n'; */ /* } */ /* cout << '\n'; */ /* } */ } void Tree::printMember(const unsigned id)const { people[id].displayInfo(); } void Tree::printOldestAncestors(const unsigned id)const { people[findOldestAncestor(id)].displayInfo(); people[findOldestAncestor(id, 1)].displayInfo(); } void Tree::commonAncestorRec(person_id id, vector &visited) const { ++visited[id]; auto& curRels = relations[id]; for (const Relation& rel: curRels) { if (rel.type == Child) { ++visited[rel.id]; commonAncestorRec(rel.id, visited); } } } static U8 linkToFirstBorn(I16 startY, I16 startX, bool moreSiblings) { if (startY >= -2 && startX >= 0) { WINDOW* win = newwin(3, 1, startY, startX); /* TODO: pad */ waddch(win, ACS_VLINE); mvwaddch(win, 1, 0, moreSiblings ? ACS_LTEE : ACS_VLINE); mvwaddch(win, 2, 0, ACS_VLINE); wnoutrefresh(win); delwin(win); } return 3; } static U8 linkToChild(I16 startY, I16 startX, I16 endX, bool moreSiblings) { assert(endX >= startX); if (startY >= -1 && endX >= 0) { const I16 len = endX - startX; WINDOW* win = newwin(2, len, startY, startX); for(U16 i = 0; i < len-1; ++i) waddch(win, ACS_HLINE); /* whline(win, '_', len-1); */ waddch(win, moreSiblings ? ACS_TTEE : ACS_URCORNER); mvwaddch(win, 1, len-1, ACS_VLINE); wnoutrefresh(win); delwin(win); } return 3; } /* I16 Tree::drawLine(person_id id, I16 drawY, I16 drawX) const */ /* { */ /* people[id].draw(drawY, drawX, true, false, true); */ /* std::vector children; */ /* for(U32 i=0; i children; for(const auto& rel: rels) { if (rel.type == RelType::Parent) children.push_back(rel.id); else if (rel.type == RelType::Spouse && spouse == Nobody) spouse = rel.id; } const size_t numKids = children.size(); person.draw(drawY, drawX, id == selected_, spouse!=Nobody, false, numKids!=0); U16 spouse_width = 0; if (spouse != Nobody) { people[spouse].draw(drawY, drawX + person.boxWidth() + spouse_dist_, spouse == selected_, false, true); spouse_width = spouse_dist_ + people[spouse].boxWidth(); } auto childX = drawX; if (numKids!=0) { auto prevX = childX; drawY += BOX_HEIGHT; auto lnHt = linkToFirstBorn(drawY, childX, numKids > 1); /* Link height */ childX = drawLineWithWives(children[0], drawY + lnHt, childX); for(size_t j = 1; j < numKids; ++j) { lnHt = linkToChild(drawY+1, prevX+1, childX+1, j < numKids-1); prevX = childX; childX = drawLineWithWives(children[j], drawY + lnHt, childX); } } return max(drawX + person.boxWidth() + dist_between_ + spouse_width, childX); } void Tree::selectLeft() /* todo */ { if (findCommonAncestor(focused_, selected_) != Nobody) //if the selected is part of main tree { } else { person_id spouse = findSpouse(selected_); selected_ = spouse; draw(); } } void Tree::selectDown() { const auto& curRels = relations[selected_]; for(const Relation& rel: curRels) { if (rel.type == Parent) { selected_ = rel.id; draw(); return; } } } void Tree::selectUp() { person_id dad = Nobody, mom = Nobody; for(const Relation& rel: relations[selected_]) { if (rel.type == Child) { if (people[rel.id].isMale()) dad = rel.id; else mom = rel.id; } } if (mom == focused_ || (mom != Nobody && dad == Nobody)) selected_ = mom; else if (dad != Nobody) selected_ = dad; draw(); } void Tree::selectRight() /* todo */ { if (findCommonAncestor(focused_, selected_) != Nobody) //if the selected is part of main tree { person_id spouse = findSpouse(selected_); if (spouse != Nobody) selected_ = spouse; else ; draw(); } else { } }