/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ /**************************************************************************** History $Log: not supported by cvs2svn $ Revision 1.9 2005/02/20 00:43:23 ponchio Less memory x extraction. (removed frags) Revision 1.8 2005/02/19 17:14:02 ponchio History quick by default. Revision 1.7 2005/02/19 16:22:45 ponchio Minor changes (visited and Cell) Revision 1.6 2005/02/17 16:40:35 ponchio Optimized BuildLevels. Revision 1.5 2005/02/08 12:43:03 ponchio Added copyright ****************************************************************************/ #include #include #include #include "history.h" #include "nexus.h" using namespace std; using namespace nxs; History::~History() { if(buffer) delete []buffer; nodes = NULL; in_links= NULL; out_links = NULL; } void History::Clear() { if(buffer) delete []buffer; buffer = NULL; updates.clear(); } void History::ClearQuick() { if(buffer) delete []buffer; buffer = NULL; } void History::ClearUpdates() { updates.clear(); } bool History::Load(unsigned int _size, char *mem) { if(buffer) delete []buffer; unsigned int is_quick = *(unsigned int *)mem; bool success; if(is_quick == 53) { success = LoadQuick(_size, mem); } else if(is_quick == 32) { success = LoadUpdates(_size, mem); } else { cerr << "Invalid history: " << is_quick << "\n"; return false; } return success; } bool History::LoadQuick(unsigned int _size, char *mem) { buffer = mem; nodes = (Node *)(buffer + 4 * sizeof(int)); in_links = (Link *)(nodes + n_nodes()); out_links = in_links + n_in_links(); //check size is ok; assert(n_nodes() * sizeof(Node) + (n_in_links() + n_out_links()) * sizeof(Link) + 4 * sizeof(int) == _size); size = _size; return LoadPointers(); } bool History::LoadUpdates(unsigned int _size, char *mem) { unsigned int *tmp = (unsigned int *)mem; updates.resize(tmp[1]); unsigned int pos = 2; for(unsigned int i = 0; i < updates.size(); i++) { unsigned int erased = tmp[pos++]; unsigned int created = tmp[pos++]; updates[i].erased.resize(erased); updates[i].created.resize(created); for(unsigned int e = 0; e < erased; e++) updates[i].erased[e] = tmp[pos++]; for(unsigned int e = 0; e < created; e++) updates[i].created[e] = tmp[pos++]; } delete []mem; buffer = 0; return true; } bool History::LoadPointers() { //now convert integer to pointers for(unsigned int i = 0; i < n_nodes(); i++) { Node &node = nodes[i]; assert(((unsigned int)node.in_begin) <= n_in_links()); assert(((unsigned int)node.out_begin) <= n_out_links()); node.in_begin = in_links + (unsigned int)(node.in_begin); node.in_end = in_links + (unsigned int)(node.in_end); node.out_begin = out_links + (unsigned int)(node.out_begin); node.out_end = out_links + (unsigned int)(node.out_end); } for(unsigned int i = 0; i < n_in_links(); i++) { Link &link = in_links[i]; assert(((unsigned int)link.node) <= n_nodes()); link.node = nodes + (unsigned int)(link.node); } for(unsigned int i = 0; i < n_out_links(); i++) { Link &link = out_links[i]; assert(((unsigned int)link.node) <= n_nodes()); link.node = nodes + (unsigned int)(link.node); } return true; } char *History::Save(unsigned int &_size) { if(buffer) return SaveQuick(_size); else return SaveUpdates(_size); } char *History::SaveQuick(unsigned int &_size) { assert(buffer); for(unsigned int i = 0; i < n_nodes(); i++) { Node &node = nodes[i]; node.in_begin = (Link *)(node.in_begin - in_links); node.in_end = (Link *)(node.in_end - in_links); node.out_begin = (Link *)(node.out_begin - out_links); node.out_end = (Link *)(node.out_end - out_links); } for(unsigned int i = 0; i < n_in_links(); i++) { Link &link = in_links[i]; link.node = (Node *)(link.node - nodes); } for(unsigned int i = 0; i < n_out_links(); i++) { Link &link = out_links[i]; link.node = (Node *)(link.node - nodes); } assert(n_nodes() * sizeof(Node) + (n_in_links() + n_out_links()) * sizeof(Link) + 4 * sizeof(int) == size); _size = size; char *tmp = buffer; buffer = NULL; return tmp; } char *History::SaveUpdates(unsigned int &_size) { vector buf; buf.push_back(32); buf.push_back(updates.size()); for(unsigned int i = 0; i < updates.size(); i++) { Update &update = updates[i]; buf.push_back(update.erased.size()); buf.push_back(update.created.size()); for(unsigned int e = 0; e < update.erased.size(); e++) buf.push_back(update.erased[e]); for(unsigned int e = 0; e < update.created.size(); e++) buf.push_back(update.created[e]); } _size = buf.size() * sizeof(unsigned int); char *mem = new char[_size]; memcpy(mem, &*buf.begin(), _size); return mem; } bool History::UpdatesToQuick(Nexus &nexus) { //maps cell -> node containing it map cell_node; //maps node -> Links map > node_inlinks; map > node_outlinks; vector tmp_nodes; tmp_nodes.resize(updates.size()); vector tmp_in_links; vector tmp_out_links; vector tmp_frags; unsigned int current_node = 0; vector::iterator u; for(u = updates.begin(); u != updates.end(); u++) { Node &node = tmp_nodes[current_node]; //created cells belong to this node, for(unsigned int i = 0; i < (*u).created.size(); i++) { unsigned int cell = (*u).created[i]; cell_node[cell] = current_node; } //Every erased cell already belonged to a node //node -> its cells map > node_erased; for(unsigned int i = 0; i < (*u).erased.size(); i++) { unsigned int cell = (*u).erased[i]; assert(cell_node.count(cell)); node_erased[cell_node[cell]].push_back(cell); } //for every node with erased cells we build a fragment and //put the corresponding cells in it. map >::iterator e; for(e = node_erased.begin(); e != node_erased.end(); e++) { unsigned int floor_node = (*e).first; vector &cells = (*e).second; Node &parent = tmp_nodes[floor_node]; Link inlink; inlink.node = (Node *)floor_node; inlink.begin = tmp_frags.size(); inlink.end = inlink.begin + cells.size(); Link outlink; outlink.node = (Node *)current_node; outlink.begin = tmp_frags.size(); outlink.end = outlink.begin + cells.size(); //Fill it with erased cells. vector::iterator k; for(k = cells.begin(); k != cells.end(); k++) tmp_frags.push_back(*k); //Add the new Frag to the nodes (in and out) node_outlinks[floor_node].push_back(outlink); node_inlinks[current_node].push_back(inlink); } current_node++; } map >::iterator k; for(k = node_outlinks.begin(); k != node_outlinks.end(); k++) { unsigned int inode = (*k).first; vector &links = (*k).second; tmp_nodes[inode].out_begin = (Link *)(tmp_out_links.size()); tmp_nodes[inode].out_end = (Link *)(tmp_out_links.size() + links.size()); // tmp_nodes[inode].out_link_begin = (Link *)(tmp_out_links.size()); // tmp_nodes[inode].out_link_size = links.size(); for(unsigned int i = 0; i < links.size(); i++) tmp_out_links.push_back(links[i]); } for(k = node_inlinks.begin(); k != node_inlinks.end(); k++) { unsigned int inode = (*k).first; vector &links = (*k).second; // tmp_nodes[inode].in_link_begin = (Link *)(tmp_in_links.size()); // tmp_nodes[inode].in_link_size = links.size(); tmp_nodes[inode].in_begin = (Link *)(tmp_in_links.size()); tmp_nodes[inode].in_end = (Link *)(tmp_in_links.size() + links.size()); for(unsigned int i = 0; i < links.size(); i++) tmp_in_links.push_back(links[i]); } //Here we reorder entries in nexus... nexus.Flush(); vector entries; entries.resize(nexus.size()); for(unsigned int i = 0; i < nexus.size(); i++) { assert(!nexus[i].patch); entries[i] = nexus[i]; } assert(tmp_frags.size() == nexus.size()); for(unsigned int i = 0; i < tmp_frags.size(); i++) { nexus[i] = entries[tmp_frags[i]]; } //WARNING CRITICAL TODOHey we should do the same on the borders! vector backward; backward.resize(tmp_frags.size()); for(unsigned int i = 0; i < backward.size(); i++) backward[tmp_frags[i]] = i; for(unsigned int i = 0; i < nexus.borders.size(); i++) { Border &border = nexus.borders.GetBorder(i); for(unsigned int k = 0; k < border.Size(); k++) border[k].end_patch = backward[border[k].end_patch]; } nexus.borders.Flush(); vector borders; borders.resize(nexus.borders.size()); for(unsigned int i = 0; i < nexus.borders.size(); i++) { borders[i] = nexus.borders[i]; } assert(tmp_frags.size() == nexus.borders.size()); for(unsigned int i = 0; i < tmp_frags.size(); i++) { nexus.borders[i] = borders[tmp_frags[i]]; } size = tmp_nodes.size() * sizeof(Node) + tmp_in_links.size() * sizeof(Link) + tmp_out_links.size() * sizeof(Link) + 4 * sizeof(int); if(buffer) delete []buffer; buffer = new char[size]; quick() = 53; n_nodes() = tmp_nodes.size(); n_in_links() = tmp_in_links.size(); n_out_links() = tmp_out_links.size(); nodes = (Node *)(buffer + 4 * sizeof(int)); in_links = (Link *)(nodes + n_nodes()); out_links = in_links + n_in_links(); memcpy(nodes, &*tmp_nodes.begin(), tmp_nodes.size()*sizeof(Node)); memcpy(in_links, &*tmp_in_links.begin(), tmp_in_links.size()*sizeof(Link)); memcpy(out_links, &*tmp_out_links.begin(), tmp_out_links.size()*sizeof(Link)); return LoadPointers(); } void History::BuildLevels(vector &levels) { levels.clear(); if(buffer) { //Saved in quick mode: for(unsigned int n = 0; n < n_nodes(); n++) { Node *node = nodes+n; Node::iterator l; unsigned int current = 0; if(node != nodes) { //not root Link *inlink = node->in_begin; unsigned int p = inlink->begin; assert(p < levels.size()); assert(p >= 0); current = levels[p]+1; } for(l = node->out_begin; l != node->out_end; l++) { Link &link = *l; for(unsigned int p = link.begin; p != link.end; p++) { while(p >= levels.size()) levels.push_back(-1); levels[p] = current; } } } } else { //Saved in updates mode: for(unsigned int i = 0; i < updates.size(); i++) { Update &u = updates[i]; unsigned int current = 0; if(!u.erased.size()) current = 0; else current = levels[u.erased[0]] + 1; for(unsigned int i = 0; i < u.created.size(); i++) { unsigned int p = u.created[i]; while(p >= levels.size()) levels.push_back(-1); levels[p] = current; } } } }