diff --git a/wrap/mt/mt.h b/wrap/mt/mt.h new file mode 100644 index 00000000..af7f521d --- /dev/null +++ b/wrap/mt/mt.h @@ -0,0 +1,296 @@ +/**************************************************************************** +* 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 $ + +****************************************************************************/ + +#ifndef VCG_MT_H +#define VCG_MT_H + +#include +#include +#include + +#include +#include +#include + +namespace vcg { + + /** \addtogroup mt */ +/*@{*/ + /** + The templated class for representing a mt structure. + The class is templated over the Cell class which MUST implement this functions: + float Error(); + float Distance(Cell &c, Point3f &p); + see mt_file.h for an example. + */ + +template class MT { +public: + typedef C Cell; + +private: + + class Frag:public std::vector {}; + + struct Node { + std::vector in; + std::vector out; + std::vector frags; + float error; + bool visited; + }; + + std::vector nodes; + +public: + + /** Update class for defining the history. + Notice how the Update class holds pointers. + You are responsible of holding the Cell structure and rebuild the structure + if the pointers change. + */ + class Update { + public: + std::vector erased; + std::vector created; + }; + + ///build mt strucure from a sequence of updates. + void Load(std::vector &updates) { + //The last update erases everything. + assert(updates[0].erased.size() == 0); + + //maps cell -> node containing it + std::map cell_node; + nodes.resize(updates.size()); + + //building fragments and nodes. + unsigned int current_node = 0; + std::vector::iterator u; + for(u = updates.begin(); u != updates.end(); u++) { + + Node &node = nodes[current_node]; + node.error = 0; + + //created cells belong to this node, we look also for max error. + for(unsigned int i = 0; i < (*u).created.size(); i++) { + Cell *cell = (*u).created[i]; + if(cell->Error() > node.error) + node.error = cell->Error(); + + cell_node[cell] = current_node; + } + + //Every erased cell already belonged to a node. + //we record for each node its cells. + std::map > node_erased; + + for(unsigned int i = 0; i < (*u).erased.size(); i++) { + Cell *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 frag and put the corresponding cells in it. + std::map >::iterator e; + for(e = node_erased.begin(); e != node_erased.end(); e++) { + //Build a new Frag. + Frag fr; + float max_err = -1; + + //Fill it with erased cells. + std::vector &cells = (*e).second; + std::vector::iterator k; + for(k = cells.begin(); k != cells.end(); k++) { + Cell *cell = (*k); + fr.push_back(cell); + if(cell->Error() > max_err) + max_err = cell->Error(); + } + + //Add the new Frag to the node. + unsigned int floor_node = (*e).first; + Node &oldnode = nodes[floor_node]; + oldnode.frags.push_back(fr); + if(node.error < max_err) + node.error = max_err; + + //Update in and out of the nodes. + node.in.push_back(&oldnode); + oldnode.out.push_back(&node); + } + current_node++; + } + } + void Clear() { + nodes.clear(); + } + + ///error based extraction + template void Extract(CONT &selected, float error) { + std::vector::iterator n; + for(n = nodes.begin(); n != nodes.end(); n++) + (*n).visited = false; + + std::queue qnodo; + qnodo.push(&nodes[0]); + nodes[0].visited = true; + + for( ; !qnodo.empty(); qnodo.pop()) { + Node &node = *qnodo.front(); + + std::vector::iterator fragment; + std::vector::iterator on; + for(on = node.out.begin(), fragment = node.frags.begin(); on != node.out.end(); ++on, ++fragment) { + if((*on)->visited) continue; + + if(error < (*on)->error) { //need to expand this node. + qnodo.push(*on); + (*on)->visited = 1; + } else { + vector::iterator cell; + for(cell=(*fragment).begin(); cell != (*fragment).end(); ++cell) + selected.push_back(*cell); + } + } + } + } + + //custom extraction + template void Extract(CONT &selected, POLICY &policy) { + std::vector::iterator n; + for(n = nodes.begin(); n != nodes.end(); n++) + (*n).visited = false; + + std::queue qnodo; + qnodo.push(&nodes[0]); + nodes[0].visited = true; + + for( ; !qnodo.empty(); qnodo.pop()) { + Node &node = *qnodo.front(); + + std::vector::iterator i; + std::vector::iterator on; + for(i = node.frags.begin(), on = node.out.begin(); i != node.frags.end(); i++, on++) { + if((*on)->visited) continue; + Frag &frag = (*i); + std::vector::iterator cell; + for(cell = frag.begin(); cell != frag.end(); cell++) { + if(policy.Expand(*cell)) + visit(*on, qnodo); + } + } + } + Extract(selected); + } + + //extract using a user class which must provides: + //bool refineCell(Cell *cell, Frustum &frustum); + //void addCell(Cell *cell); + //void removeCell(Cell *cell); + //template void extract(std::vector &selected, Frustum &frustum, T &error); + + ///extract using the visited flag in nodes to a STL container of Cell * + template void Extract(CONT &selected) { + selected.clear(); + std::vector::iterator i; + for(i = nodes.begin(); i != nodes.end(); i++) { + Node &node = *i; + if(!node.visited) + continue; + + std::vector::iterator n; + std::vector::iterator f; + for(n = node.out.begin(), f = node.frags.begin(); n != node.out.end(); n++, f++) { + if(!(*n)->visited || (*n)->error == 0) { + vector::iterator c; + Frag &frag = (*f); + for(c = frag.begin(); c != frag.end(); c++) + selected.insert(selected.end(), *c); + } + } + } + } + + ///add a node to the queue recursively mantaining coherence. + void Visit(Node *node, std::queue &qnode) { + std::vector::iterator n; + for(n = node->in.begin(); n != node->in.end(); n++) + if(!(*n)->visited) + visit(*n, qnode); + + node->visited = true; + qnode.push(node); + } + + +}; + +template class FrustumPolicy { +public: + typedef C Cell; + + Frustumf frustum; + ///target error in screen space (pixels) + float error; + + bool Expand(Cell *cell) { + if(cell->Error() == 0) return false; + float dist = Distance(*cell, frustum.ViewPoint()); + /*Point3f line = frustum.viewPoint() - cell->sphere.center; + float dist = line.Norm() - cell->sphere.radius; */ + if(dist < 0) return true; + dist = pow(dist, 1.2); + float res = cell->Error() / (frustum.Resolution()*dist); + return res; + } +}; + +///really simple example policy +template class DiracPolicy { +public: + typedef C Cell; + + Point3f focus; + ///max error in object space at distance 0 + float error; + + DiracPolicy(Point3f &f = Point3f(0, 0, 0), float e = 0): focus(f), error(e) {} + + bool Expand(Cell *cell) { + if(cell->Error() == 0) return false; + float dist = Distance(*cell, focus); + if(dist > 0) return true; + return false; + } +}; + +}//namespace vcg + +#endif \ No newline at end of file