#include #include #include #include #include"tree.h" #include"person.h" #include"help.h" using std::cout; Tree Tree::operator+ (const Tree& other)// { Tree result(treeName + other.treeName); //The tree resulting from the addition unsigned *newId = new unsigned[other.numPeople]; //The indexes members of the II tree will have in result unsigned idCounter = numPeople; for (unsigned 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.resize(result.numPeople); result.people = people; //Adds the members of the I tree to the resulting tree for (unsigned i=0; i < other.numPeople; ++i) //Adds the members of the II tree to the resulting tree { if (newId[i] >= numPeople) result.people.push(other.people[i]); } result.relations.resize(result.numPeople); result.relations = relations; for (unsigned 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(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]].resize(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 } } delete[]newId; return result; } Tree& Tree::operator+=(const Tree& other) { unsigned *newId = new unsigned[other.numPeople]; //The indexes people from II tree will have in I tree unsigned idCounter = numPeople; for (unsigned 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.resize(idCounter); for (unsigned i = 0; i < other.numPeople; ++i) //Adds the member personal data of II tree to I tree { if (newId[i] >= numPeople) people.push(other.people[i]); } relations.resize(idCounter); for (unsigned i = 0; i < other.numPeople; ++i) //Merges the relative data { if (newId[i] >= numPeople) { relations.push(other.relations[i]); for (unsigned 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 (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) ++people[newId[i]].numRel_; } relations[newId[i]].resize(people[newId[i]].numRel_); for (unsigned 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; } } } delete[]newId; numPeople = idCounter; //Number of members in I tree return *this; } Tree& Tree::operator-= (const Tree& other) { for (unsigned i = 0; i < numPeople; ++i) { for (unsigned j = 0; j < other.numPeople; ++j) { if (people[i] == other.people[j]) { removePerson(i); --i; break; } } } return *this; } void Tree::rename(const char* newName) { treeName = newName; } unsigned 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 (unsigned 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; } unsigned 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; } unsigned Tree::findCommonAncestor(const unsigned firstId, const unsigned secondId)const { Array visited(numPeople); //if a member is visited twice he's a common ancestor for (unsigned i = 0; i < numPeople; ++i) visited[i] = 0; commonAncestorRec(firstId, visited); commonAncestorRec(secondId, visited); unsigned oldestId = Nobody; U16 oldestBday = SHRT_MAX; for (unsigned i = 0; i < numPeople; ++i) { if (visited[i] == 2 && people[i].birth_.year < oldestBday) { oldestBday = people[i].birth_.year; oldestId = i; } } return oldestId; } void Tree::saveTree() const { std::ofstream peopleFile(treeName+ ".people", std::ios::binary); peopleFile.write(reinterpret_cast(&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); people.sNum(numPeople); 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])); relations[i].sNum(people[i].numRel_); } relations.sNum(numPeople); 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(newPerson); Array newRels; relations.push(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 == Invalid) 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({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; } } return 1; } void Tree::removeRelation(const char* firstName, const char* secondName) { removeRelation(findId(firstName), findId(secondName)); } void Tree::removePerson(const unsigned id) { unsigned relId; //Íoìåð íà òåêóùèÿ ðîäíèíàòà for (unsigned i = 0; i < people[id].numRel_; ++i) //Ïðåìàõâàò ñå âðúçêèòå íà ÷ëåíà çà ïðåìàõâàíå { relId = relations[id][i].id; for (unsigned j = 0; j < people[relId].numRel_; ++j) { if (relations[relId][j].id == id) { relations[relId].remove(j); break; } } --people[relId].numRel_; } for (unsigned i = 0; i < people[numPeople - 2].numRel_; ++i) //Ïîñëåäíèÿò ÷ëåí âçåìà íîìåðà íà ïðåìàõíàòèÿ { 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; } } } relations.remove(id); people.remove(id); --numPeople; } void Tree::removePerson(const char* personName, const short year, const unsigned char month, const unsigned char day) { removePerson(findId(personName, year, month, day)); } void Tree::removeRelation(const unsigned firstId, const unsigned secondId) { for (unsigned i = 0; i < people[firstId].numRel_; ++i) { if (relations[firstId][i].id == secondId) { relations[firstId].remove(i); --people[firstId].numRel_; break; } } for (unsigned i = 0; i < people[secondId].numRel_; ++i) { if (relations[secondId][i].id == firstId) { relations[secondId].remove(i); --people[secondId].numRel_; break; } } } void Tree::draw(person_id focused) const { erase(); //Clear the screen wnoutrefresh(stdscr); /* WINDOW* father = people[0].createPad(); */ /* WINDOW* mother = people[1].createPad(); */ /* U16 fw = getmaxx(father); /\* return size, not coords *\/ */ /* U16 fh = getmaxy(father); */ /* U16 mw = getmaxx(mother); */ /* U16 mh = getmaxy(mother); */ /* U16 drawX = (COLS - fw - mw) / 2; */ /* pnoutrefresh(father, 0, 0, */ /* 1, drawX, */ /* 1 +fh-1, drawX + fw-1); */ /* const U32 numPpl = people.gNum(); */ /* std::vector drawn(numPpl, false); */ U16 drawY = 0/* (LINES) / 2 */; U16 drawX = 0/* (COLS) / 2 */; drawLineWithWives(focused, drawY, drawX); /* people[0].draw(drawY, drawY); */ /* for(U32 i=0; i &visited)const { for (unsigned i = 0; i < people[id].numRel_; ++i) { if (relations[id][i].type == Child) { ++visited[relations[id][i].id]; commonAncestorRec(relations[id][i].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(person_id i = 0; i < rels.gNum(); ++i) { if(rels[i].type == RelType::Parent) children.push_back(rels[i].id); else if(rels[i].type == RelType::Spouse && spouse == Nobody) spouse = rels[i].id; } const size_t numKids = children.size(); person.draw(drawY, drawX, spouse!=Nobody, false, numKids!=0); U16 spouse_width = 0; if(spouse != Nobody) { people[spouse].draw(drawY, drawX + person.boxWidth() + spouse_dist, 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); }