diff --git a/Geo/Cell.cpp b/Geo/Cell.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..58553fc608f45bd42e1c352814ab6cb00bd4b36c
--- /dev/null
+++ b/Geo/Cell.cpp
@@ -0,0 +1,341 @@
+// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+//
+// Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
+
+#include "CellComplex.h"
+
+#if defined(HAVE_KBIPACK)
+
+bool Less_Cell::operator()(const Cell* c1, const Cell* c2) const {
+  
+  //cells with fever vertices first
+  
+  if(c1->getNumVertices() != c2->getNumVertices()){
+    return (c1->getNumVertices() < c2->getNumVertices());
+  }
+  
+  //"natural number" -like ordering (the number of a vertice corresponds a digit)
+  
+  for(int i=0; i < c1->getNumVertices();i++){
+    if(c1->getSortedVertex(i) < c2->getSortedVertex(i)) return true;
+    else if (c1->getSortedVertex(i) > c2->getSortedVertex(i)) return false;
+  }
+  
+  return false;
+}
+
+
+void Cell::restoreCell(){
+  _boundary = _obd;
+  _coboundary = _ocbd;
+  _bdSize = _boundary.size();
+  _cbdSize = _coboundary.size();
+  _combined = false;
+  _index = 0;
+  _immune = false;   
+}
+
+std::list< Cell* > Cell::getBoundary() {
+  std::list<Cell*> boundary;
+  for( biter it= _boundary.begin(); it != _boundary.end();it++){
+    Cell* cell = (*it).first;
+    boundary.push_back(cell);
+  }
+  return boundary;
+}
+
+std::list< Cell* > Cell::getCoboundary() {
+  std::list<Cell*> coboundary;
+  for( biter it= _coboundary.begin();it!= _coboundary.end();it++){
+    Cell* cell = (*it).first;
+    coboundary.push_back(cell);
+  }
+  return coboundary;
+}
+
+
+bool Cell::addBoundaryCell(int orientation, Cell* cell) {
+  _bdSize++;
+  biter it = _boundary.find(cell);
+  if(it != _boundary.end()){
+    (*it).second = (*it).second + orientation;
+    if((*it).second == 0) {
+      _boundary.erase(it); _bdSize--;
+      (*it).first->removeCoboundaryCell(this,false);
+      return false;
+    }
+    return true;
+  }
+  _boundary.insert( std::make_pair(cell, orientation ) );
+  return true;
+}
+
+bool Cell::addCoboundaryCell(int orientation, Cell* cell) {
+  _cbdSize++;
+  biter it = _coboundary.find(cell);
+  if(it != _coboundary.end()){
+    (*it).second = (*it).second + orientation;
+    if((*it).second == 0) {
+      _coboundary.erase(it); _cbdSize--;
+      (*it).first->removeBoundaryCell(this,false);
+      return false;
+    }
+    return true;
+  }
+  _coboundary.insert( std::make_pair(cell, orientation ) );
+  return true;
+}
+
+int Cell::removeBoundaryCell(Cell* cell, bool other) {
+  biter it = _boundary.find(cell);
+  if(it != _boundary.end()){
+    _boundary.erase(it);
+    if(other) (*it).first->removeCoboundaryCell(this, false);
+    _bdSize--;
+    return (*it).second;
+  }
+  
+  return 0;
+} 
+int Cell::removeCoboundaryCell(Cell* cell, bool other) {
+  biter it = _coboundary.find(cell);
+  if(it != _coboundary.end()){
+    _coboundary.erase(it);
+    if(other) (*it).first->removeBoundaryCell(this, false);
+    _cbdSize--;
+    return (*it).second;
+  }
+  return 0;
+}
+   
+bool Cell::hasBoundary(Cell* cell, bool org){
+  if(!org){
+    biter it = _boundary.find(cell);
+    if(it != _boundary.end()) return true;
+    return false;
+  }
+  else{
+    biter it = _obd.find(cell);
+    if(it != _obd.end()) return true;
+    return false;
+  }
+}
+
+bool Cell::hasCoboundary(Cell* cell, bool org){
+  if(!org){
+    biter it = _coboundary.find(cell);
+    if(it != _coboundary.end()) return true;
+    return false;
+  }
+  else{
+    biter it = _ocbd.find(cell);
+    if(it != _ocbd.end()) return true;
+    return false;
+  } 
+}
+
+void Cell::makeDualCell(){ 
+  std::map<Cell*, int, Less_Cell > temp = _boundary;
+  _boundary = _coboundary;
+  _coboundary = temp;
+  _dim = 3-_dim;     
+}
+
+void Cell::printBoundary() {  
+  for(biter it = _boundary.begin(); it != _boundary.end(); it++){
+    printf("Boundary cell orientation: %d ", (*it).second);
+    Cell* cell2 = (*it).first;
+    cell2->printCell();
+  }
+  if(_boundary.empty()) printf("Cell boundary is empty. \n");
+}
+void Cell::printCoboundary() {
+  for(biter it = _coboundary.begin(); it != _coboundary.end(); it++){
+    printf("Coboundary cell orientation: %d, ", (*it).second);
+    Cell* cell2 = (*it).first;
+    cell2->printCell();
+    if(_coboundary.empty()) printf("Cell coboundary is empty. \n");
+  }
+}
+   
+void Cell::printOrgBd() {
+  for(biter it = _obd.begin(); it != _obd.end(); it++){
+    printf("Boundary cell orientation: %d ", (*it).second);
+    Cell* cell2 = (*it).first;
+    cell2->printCell();
+  }
+  if(_obd.empty()) printf("Cell boundary is empty. \n");
+}
+void Cell::printOrgCbd() {
+  for(biter it = _ocbd.begin(); it != _ocbd.end(); it++){
+    printf("Coboundary cell orientation: %d, ", (*it).second);
+    Cell* cell2 = (*it).first;
+    cell2->printCell();
+    if(_ocbd.empty()) printf("Cell coboundary is empty. \n");
+  }
+}  
+
+
+CombinedCell::CombinedCell(Cell* c1, Cell* c2, bool orMatch, bool co) : Cell() {
+  
+  // use "smaller" cell as c2
+  if(c1->getNumVertices() < c2->getNumVertices()){
+    Cell* temp = c1;
+    c1 = c2;
+    c2 = temp;
+  }
+  
+  _index = c1->getIndex();
+  _tag = c1->getTag();
+  _dim = c1->getDim();
+  _num = c1->getNum();
+  _inSubdomain = c1->inSubdomain();
+  _onDomainBoundary = c1->onDomainBoundary();
+  _combined = true;
+  
+  _v.reserve(c1->getNumVertices() + c2->getNumVertices());
+  _vs.reserve(c1->getNumVertices() + c2->getNumVertices());
+  
+     
+  _v = c1->getVertexVector();
+  for(int i = 0; i < c2->getNumVertices(); i++){
+    if(!this->hasVertex(c2->getVertex(i)->getNum())) _v.push_back(c2->getVertex(i));
+  }
+  
+  // sorted vertices
+  for(unsigned int i = 0; i < _v.size(); i++) _vs.push_back(_v.at(i)->getNum());
+  std::sort(_vs.begin(), _vs.end());
+  
+  // cells
+  _cells = c1->getCells();
+  std::list< std::pair<int, Cell*> > c2Cells = c2->getCells();
+  for(std::list< std::pair<int, Cell*> >::iterator it = c2Cells.begin(); it != c2Cells.end(); it++){
+    if(!orMatch) (*it).first = -1*(*it).first;
+    _cells.push_back(*it);
+  }
+  
+  // boundary cells
+  std::map< Cell*, int, Less_Cell > c1Boundary = c1->getOrientedBoundary();
+  std::map< Cell*, int, Less_Cell > c2Boundary = c2->getOrientedBoundary();
+  
+  for(std::map<Cell*, int, Less_Cell>::iterator it = c1Boundary.begin(); it != c1Boundary.end(); it++){
+    Cell* cell = (*it).first;
+    int ori = (*it).second;
+    cell->removeCoboundaryCell(c1); 
+    if(this->addBoundaryCell(ori, cell)) cell->addCoboundaryCell(ori, this);
+  }
+  for(std::map<Cell*, int, Less_Cell >::iterator it = c2Boundary.begin(); it != c2Boundary.end(); it++){
+    Cell* cell = (*it).first;
+    if(!orMatch) (*it).second = -1*(*it).second;
+    int ori = (*it).second;
+    cell->removeCoboundaryCell(c2);    
+    if(co){
+      std::map<Cell*, int, Less_Cell >::iterator it2 = c1Boundary.find(cell);
+      bool old = false;
+      if(it2 != c1Boundary.end()) old = true;
+      if(!old){  if(this->addBoundaryCell(ori, cell)) cell->addCoboundaryCell(ori, this); }
+    }
+    else{
+      if(this->addBoundaryCell(ori, cell)) cell->addCoboundaryCell(ori, this);
+    }
+  }
+  
+  // coboundary cells
+  std::map<Cell*, int, Less_Cell > c1Coboundary = c1->getOrientedCoboundary();
+  std::map<Cell*, int, Less_Cell > c2Coboundary = c2->getOrientedCoboundary();
+  
+  for(std::map<Cell*, int, Less_Cell>::iterator it = c1Coboundary.begin(); it != c1Coboundary.end(); it++){
+    Cell* cell = (*it).first;
+    int ori = (*it).second;
+    cell->removeBoundaryCell(c1); 
+    if(this->addCoboundaryCell(ori, cell)) cell->addBoundaryCell(ori, this);
+  }
+  for(std::map<Cell*, int, Less_Cell>::iterator it = c2Coboundary.begin(); it != c2Coboundary.end(); it++){
+    Cell* cell = (*it).first;
+    if(!orMatch) (*it).second = -1*(*it).second;
+    int ori = (*it).second;
+    cell->removeBoundaryCell(c2);    
+    if(!co){
+      std::map<Cell*, int, Less_Cell >::iterator it2 = c1Coboundary.find(cell);
+      bool old = false;
+      if(it2 != c1Coboundary.end()) old = true;
+      if(!old) { if(this->addCoboundaryCell(ori, cell)) cell->addBoundaryCell(ori, this); }
+    }
+    else {
+      if(this->addCoboundaryCell(ori, cell)) cell->addBoundaryCell(ori, this);
+    }
+  }
+  
+}
+
+
+CombinedCell::~CombinedCell(){
+  std::list< std::pair<int, Cell*> > cells = getCells();
+  for(std::list< std::pair<int, Cell*> >::iterator it = cells.begin(); it != cells.end(); it++){
+    Cell* cell2 = (*it).second;
+    delete cell2;
+  }
+} 
+
+// true if this cell has given vertex
+bool CombinedCell::hasVertex(int vertex) const {
+  //std::vector<int>::iterator it = std::find(_vs.begin(), _vs.end(), vertex);
+  //if (it == _vs.end()) return false;
+  //else return true;
+  for(unsigned int i = 0; i < _v.size(); i++){
+    if(_v.at(i)->getNum() == vertex) return true;
+  }
+  return false;
+}
+
+void CombinedCell::printCell() const {
+  printf("Cell dimension: %d, ", getDim() ); 
+  printf("Vertices: ");
+  for(int i = 0; i < this->getNumVertices(); i++){
+    printf("%d ", this->getSortedVertex(i));
+  }
+  printf(", in subdomain: %d\n", _inSubdomain);
+}
+
+/*
+ int Cell::incidence(Cell* tau) const{
+ for(int i=0; i < tau->getNumVertices(); i++){
+ if( !(this->hasVertex(tau->getVertex(i)->getNum())) ) return 0;
+ }
+  
+ if(this->getDim() - tau->getDim() != 1) return 0;
+  
+ int value=1;
+ 
+  for(int i = 0; i < this->getNumFacets(); i++){
+    std::vector<MVertex*> vTau = tau->getVertexVector(); 
+    std::vector<MVertex*> v;
+    this->getFacetVertices(i, v);
+    value = -1;
+    
+    if(v.size() != vTau.size()) printf("Error: invalid facet!");
+    
+    do {
+      value = value*-1;
+      if(v == vTau) return value;
+    }
+    while (std::next_permutation(vTau.begin(), vTau.end()) );
+    
+    vTau = tau->getVertexVector();
+    value = -1;
+    do {
+      value = value*-1;
+      if(v == vTau) return value;
+    }
+    while (std::prev_permutation(vTau.begin(), vTau.end()) );
+    
+    
+  }
+  
+  return 0;
+}*/
+
+#endif