void Tree::Trichotomise() { double lengthbefore = GetLength(); PolyNode* node = mRoot->down; if (node->next->next == node) { if (!node->IsLeaf()) { node = node->next; } else { if (node->next->IsLeaf()) { cerr << "error : cannot trichotomise a two species tree\n"; exit(1); } } PolyNode* temp = node->next; node->Detach(); // PolyNode* temp = mRoot->down; mRoot->down = 0; // delete mRoot; mRoot = temp; mRoot->up = 0; node->branchLength += mRoot->branchLength; mRoot->branchLength = 0; node->AttachTo(mRoot); } double lengthafter = GetLength(); if (fabs(lengthafter - lengthbefore) > 1e-8) { cerr << "error in trichotomise: length not conserved\n"; cerr << "length before : " << lengthbefore << '\n'; cerr << "length after : " << lengthafter << '\n'; cerr << lengthbefore - lengthafter << '\n'; exit(1); } }
void Tree::RootAt(PolyNode* inNode) { double lengthbefore = GetLength(); // inNode should not be root if (inNode->IsRoot()) { cerr << "error in PolyNode::RootAt : inNode is root\n"; exit(1); } if (inNode) { PolyNode* theUp = inNode->Up(); PolyNode* newRoot = 0; if (theUp->IsRoot()) { inNode->Detach(); if (theUp->down->next != theUp->down) { newRoot = new PolyNode(); newRoot->SetTree(this); theUp->AttachTo(newRoot); theUp->mProb = inNode->mProb; } else { newRoot = theUp; } } else { newRoot = theUp->FlipFlop(); if ( ! newRoot) { newRoot = new PolyNode(); newRoot->SetTree(this); } inNode->Detach(); theUp->AttachTo(newRoot); theUp->mProb = inNode->mProb; } inNode->AttachTo(newRoot); mRoot = newRoot; } double lengthafter = GetLength(); if (fabs(lengthafter - lengthbefore) > 1e-8) { cerr << "error in rerooting: length not conserved\n"; cerr << "length before : " << lengthbefore << '\n'; cerr << "length after : " << lengthafter << '\n'; cerr << lengthbefore - lengthafter << '\n'; // exit(1); } double totallength = mRoot->down->branchLength + mRoot->down->next->branchLength; mRoot->down->branchLength = totallength / 2; mRoot->down->next->branchLength = totallength / 2; }
void SHAPE_POLY_SET::importTree( PolyTree* tree) { m_polys.clear(); for( PolyNode* n = tree->GetFirst(); n; n = n->GetNext() ) { if( !n->IsHole() ) { POLYGON paths; paths.push_back( convertFromClipper( n->Contour ) ); for( unsigned int i = 0; i < n->Childs.size(); i++ ) paths.push_back( convertFromClipper( n->Childs[i]->Contour ) ); m_polys.push_back(paths); } } }
int Tree::ReadPhylip(istream& is, PolyNode* currentNode) { // int verbose = 1; PolyNode* node = 0; double d; int END = 0; char c = is.peek(); while ((c == ' ') || (c == '\n') || (c == '\t')) { is.get(); c = is.peek(); } while( (! is.eof()) && (! END) ) { string s; char c = is.peek(); // cerr << c ; switch (c) { case '\n' : case ' ' : case '\t' : is >> c; if (verbose) { cerr << c; } break; case '(' : is >> c; if (verbose) { cerr << c; } // make a new polynode node = new PolyNode(); node->AttachTo(currentNode); currentNode = node; break; case ',' : is >> c; if (verbose) { cerr << c; } node = new PolyNode(); if (currentNode->IsRoot()) { cerr << "error in reading tree file : found a coma not within brackets\n"; exit(1); } node->AttachTo(currentNode->Up()); currentNode = node; break; case ')' : is >> c; if (verbose) { cerr << c; } if (currentNode->IsRoot()) { cerr << "error in reading tree file: found more closing than opening brackets\n"; exit(1); } currentNode = currentNode->Up(); // check whether is followed by a digit, a ':', a ')' or a ',' (anything else will throw exception) c = is.peek(); switch(c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // probability is >> d; if (verbose) { cerr << d; } currentNode->SetProb(d); // then check whether is further followed by ':' or ',' or ')' (anything else exits) c = is.peek(); switch(c) { case ':' : is >> c; if (verbose) { cerr << c; } // read branchLength // and check that it is followed either by ',' or by ')' is >> d; if (verbose) { cerr << "BL" << d; } currentNode->SetBranchLength(d); c = is.peek(); if ((c != ',') && (c != ')') && (c != ';')) { cerr << "error\n"; cerr << c << '\n'; exit(1); } break; case ',' : case ')' : break; default : cerr << "error in reading tree file : after reading a branchlength of an internal node\n"; cerr << c << '\n'; double d; is >> d; cerr << d << '\n'; exit(1); break; } break; case ':' : is >> c; if (verbose) { cerr << c; } // read branchLength // and check that it is followed either by ',' or by ')' is >> d; if (verbose) { cerr << "BL" << d; } currentNode->SetBranchLength(d); c = is.peek(); if ((c != ',') && (c != ')') && (c != ';')) { cerr << "error\n"; cerr << c << '\n'; exit(1); } break; case ';' : case ',' : case ')' : break; default : cerr << "error in reading tree file\n"; cerr << "character : " << c << '\n'; exit(1); break; } break; case ';' : is >> c; if (verbose) { cerr << "END" << c; } // close the tree // current node should be root if (! currentNode->IsRoot()) { cerr << "error in reading tree file : lacking closing brackets overall\n"; exit(1); } END = 1; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // species label s == ""; do { s += c; is >> c; if (is.eof()) { cerr << "error in reading treefile : unexpected end of file in string\n"; exit(1); } c = is.peek(); } while ((c != ',') && (c != ':') && (c != ')')); if (IsInt(s)) { int i = Int(s); // is >> i; if (verbose) { cerr << i; } node->SetLabel(i); } else { node->SetName(s); } // check whether is followed by : or , or ) (anything else will throw exception) c = is.peek(); switch(c) { case ':' : is >> c; if (verbose) { cerr << c; } // branchlength double d; is >> d; if (verbose) { cerr << "BL" << d; } node->SetBranchLength(d); c = is.peek(); if ((c != ',') && (c != ')')) { cerr << "error\n"; cerr << c << '\n'; exit(1); } break; case ',' : case ')' : break; default : cerr << "error in reading tree file\n"; cerr << "character : " << c << '\n'; exit(1); break; } break; default : // assume this is a species name s == ""; do { s += c; is >> c; if (is.eof()) { return 0; } c = is.peek(); } while ((c != ',') && (c != ':') && (c != ')')); currentNode->SetName(s); if (verbose) { cerr << '\"' << s << '\"'; } // check whether is followed by : or , (anything else will throw exception) c = is.peek(); switch(c) { case ':' : is >> c; if (verbose) { cerr << c; } // branchlength double d; is >> d; if (verbose) { cerr << "BL" << d; } node->SetBranchLength(d); break; case ',' : case ')': break; default : cerr << "error in reading tree file : after reading species name\n"; exit(1); break; } break; } } if (verbose) { cerr << "tree read : ok " << '\n' << '\n'; cerr.flush(); } return 1; }
void triangulate(const Polygon& inputPoly, std::vector<Mesh>& outputMeshes) { // Use Clipper to ensure strictly simple polygons using namespace ClipperLib; Clipper clipper; clipper.StrictlySimple(true); try { clipper.AddPaths(polyToClipperPaths(inputPoly), ptSubject, true); } catch (...) { std::cerr << "Error in Clipper::AddPaths" << std::endl; return; } PolyTree polyTree; clipper.Execute(ctUnion, polyTree, pftNonZero, pftNonZero); // Traverse the PolyTree nodes and triangulate them with only their children holes PolyNode *currentNode = polyTree.GetFirst(); while(currentNode != NULL) { // The holes are only used as the children of the contours if (currentNode->IsHole()) { currentNode = currentNode->GetNext(); continue; } // Convert to poly2tri's format std::vector<p2t::Point> allPoints; std::vector<size_t> linesSizes; // Contour for (const auto& pt : currentNode->Contour) allPoints.emplace_back(static_cast<double>(pt.X), static_cast<double>(pt.Y)); linesSizes.push_back(allPoints.size()); // Holes for(const auto childNode : currentNode->Childs) { // Slightly modify the polygon to guarantee no duplicate points edgeShrink(childNode->Contour); for (const auto& pt : childNode->Contour) allPoints.emplace_back(static_cast<double>(pt.X), static_cast<double>(pt.Y)); linesSizes.push_back(allPoints.size()); } // Poly2Tri uses pointers to points std::vector<p2t::Point*> contourLine; std::vector<std::vector<p2t::Point*>> holes; auto nbLines = linesSizes.size(); size_t start = 0; for (size_t i = 0; i < nbLines; ++i) { size_t end = linesSizes[i]; std::vector<p2t::Point*> line; line.reserve(end - start); for (size_t j = start; j < end; ++j) line.push_back(&allPoints[j]); start = end; if (!i) contourLine = std::move(line); else holes.push_back(std::move(line)); } // Set the contour in poly2tri p2t::CDT cdt(contourLine); // Add the holes for(auto& hole : holes) cdt.AddHole(hole); // Do the actual triangulation cdt.Triangulate(); // Downscale the points and add them to the mesh Mesh mesh; for (const auto pt : allPoints) mesh.addPoint(convert(pt)); // Convert the triangles auto triangles = cdt.GetTriangles(); auto firstPt = allPoints.data(); for (const auto triangle : triangles) { int ptId1 = std::distance(firstPt, triangle->GetPoint(0)); int ptId2 = std::distance(firstPt, triangle->GetPoint(1)); int ptId3 = std::distance(firstPt, triangle->GetPoint(2)); mesh.addTriangle(ptId1, ptId2, ptId3); } outputMeshes.push_back(mesh); currentNode = currentNode->GetNext(); } }