polytri.cpp
来自「算断裂的」· C++ 代码 · 共 865 行 · 第 1/2 页
CPP
865 行
// ------------------------------------------------------------------// polytri.cpp//// This file contains a function for triangulating a planar polygon// or PSLG using CDT.// ------------------------------------------------------------------// Author: Stephen A. Vavasis// Copyright (c) 1999 by Cornell University. All rights reserved.// // See the accompanying file 'Copyright' for authorship information,// the terms of the license governing this software, and disclaimers// concerning this software.// ------------------------------------------------------------------// This file is part of the QMG software. // Version 2.0 of QMG, release date September 3, 1999.// ------------------------------------------------------------------#ifdef _MSC_VER#if _MSC_VER == 1200#include "qmatvec.h"#endif#endif#include "qpolytri.h"#include "qmatvec.h"#include <fstream>namespace QMG { namespace PolyTri { Triangulation pslg_constrained_delaunay_triangulate(VertexList& vtxlist, const vector<Edge>& elist); Triangulation poly_cdt(const Matrix& vtxlist, const vector<Edge>& elist, double tol); }}namespace { using namespace QMG; using namespace QMG::PolyTri; // The triangulation algorithm maintains a front, which is a // heap of labeled distances. The label is an int. struct Labeled_dist { Real dist; int label; Labeled_dist(Real d, int l) : dist(d), label(l) { } Labeled_dist(const Labeled_dist& o) : dist(o.dist), label(o.label) { } Labeled_dist() : dist(0), label(-1) { } bool operator==(const Labeled_dist& other) const; bool operator<(const Labeled_dist& other) const; }; bool Labeled_dist::operator==(const Labeled_dist& other) const { if (dist == other.dist && label == other.label) return true; return false; } bool Labeled_dist::operator<(const Labeled_dist& other) const { if (dist < other.dist || (dist == other.dist && label < other.label)) return true; return false; } Labeled_dist null_labeled_dist; // This routine projects three-dimensional vertices into 2D. // orthogonally to the plane containing the vertices. // The plane is computed via QR factorization with pivoting. void make_2d_vertices(const Matrix& vtxlist, VertexList& vtxlist2, double tol) { int m = vtxlist.numrows(); int n = vtxlist.numcols(); if (n < 2 || m < 3) { throw_error("Range error in make_2d_vertices"); } if (n == 2) { for (int k = 0; k < m; ++k) { vtxlist2.add_vertex(vtxlist(k,0), vtxlist(k,1)); } return; } Matrix A(n,m - 1); vector<Real> hhtrans(n); Real Afrob = 0.0; { for (int i = 1; i < m; ++i) { for (int j = 0; j < n; ++j) { A(j, i - 1) = vtxlist(i,j) - vtxlist(0,j); Afrob += A(j,i-1) * A(j,i-1); } } } Afrob = sqrt(Afrob); { for (int l = 0; l < 2; ++l) { Real maxnorm = 0.0; int pivcol = 0; for (int p = 0; p < m - 1; ++p) { Real thiscolnorm = 0.0; for (int i = l; i < n; ++i) { thiscolnorm += A(i,p) * A(i,p); } if (thiscolnorm > maxnorm) { maxnorm = thiscolnorm; pivcol = p; } } Real beta = Matrix::compute_hh_transform(&hhtrans[l], &A(l,pivcol), m - 1, n - l); { for (int j = 0; j < m - 1; ++j) { Real ip = 0.0; { for (int i = l; i < n; ++i) { ip += hhtrans[i] * A(i,j); } } Real beta1 = beta * ip; { for (int i = l; i < n; ++i) { A(i,j) -= beta1 * hhtrans[i]; } } } } } } { Real resdfro = 0.0; for (int j = 0; j < m - 1; ++j) { for (int i = 2; i < n; ++i) { resdfro += A(i,j) * A(i,j); } } resdfro = sqrt(resdfro); if (resdfro >= tol * Afrob) throw_error("Polygon vertices exceed non-coplanarity tolerance"); } vtxlist2.add_vertex(0.0, 0.0); { for (int j = 0; j < m - 1; ++j) { vtxlist2.add_vertex(A(0,j), A(1,j)); } } } // These two structs are used by search tri for walking from // triangle to triangle. enum Triangle_Label {NOT_YET_SEARCHED, KEEP, DELETE}; struct Two_Int { int first; int second; Two_Int() : first(-1), second(-1) { } Two_Int(const Two_Int& other) : first(other.first), second(other.second) { } Two_Int& operator=(const Two_Int& o) { first = o.first; second = o.second; return *this; } ~Two_Int() { } }; // This routine takes as input a triangulation and labels // the triangles according to whether they are inside // or outside the polygon. This is determined by // starting from the outer boundary (whose triangles // are not in the polygon) and then walking from // triangle to neighboring triangle. Each time // a boundary is crossed, the disposition changes. void search_tri(const vector<Edge>& elist, const Triangulation& init_tri, vector<Triangle_Label>& disposition) { map<Edge,int> countmap; int nume = elist.size(); { for (int k = 0; k < nume; ++k) { ++countmap[elist[k].sort()]; } } int nt = init_tri.numtri(); // Map edges to the two triangles that contain them. map<Edge,Two_Int> tri_occur; { for (int l = 0; l < nt; ++l) { for (int j = 0; j < 3; ++j) { Edge e(init_tri.tri_vertex(l,j), init_tri.tri_vertex(l, (j+1) % 3)); e = e.sort(); Two_Int twoint = tri_occur[e]; if (twoint.first == -1) twoint.first = l; else if (twoint.second == -1) twoint.second = l; else throw_error("edge adjacent to >2 triangles"); tri_occur[e] = twoint; } } } // Pick a starting triangle that was labeled by the caller. int starttri; for (starttri = 0; starttri < nt; ++starttri) { if (disposition[starttri] != NOT_YET_SEARCHED) break; } if (starttri == nt) throw_error("No starting triangle found"); vector<int> search_stack; search_stack.push_back(starttri); // Now search all triangles with a stack. while (search_stack.size() > 0) { int curtri = search_stack.back(); search_stack.pop_back(); Triangle_Label thislab = disposition[curtri]; if (thislab == NOT_YET_SEARCHED) throw_error("Stack inconsistency"); for (int j = 0; j < 3; ++j) { Edge e(init_tri.tri_vertex(curtri, j), init_tri.tri_vertex(curtri, (j+1) % 3)); e = e.sort(); Two_Int twoint = tri_occur[e]; int nbrtri = -1; if (twoint.first == curtri) nbrtri = twoint.second; else if (twoint.second == curtri) nbrtri = twoint.first; if (nbrtri < 0) throw_error("Inconsistent map state"); int occ_cnt = countmap[e]; Triangle_Label newlab; if ((occ_cnt % 2) ^ (thislab == KEEP)) { newlab = KEEP; } else { newlab = DELETE; } if (disposition[nbrtri] == NOT_YET_SEARCHED) { disposition[nbrtri] = newlab; search_stack.push_back(nbrtri); } else { if (disposition[nbrtri] != newlab) throw_error("Illegal polygon -- boundary does not close"); } } } { for (int l = 0; l < nt; ++l) { if (disposition[l] == NOT_YET_SEARCHED) throw_error("Disconnected triangulation?"); } } }}namespace QMG { namespace PolyTri { ostream& operator<<(ostream& os, const Edge& e) { os << "Ed:v" << e.endpoint(0) << "/v" << e.endpoint(1) << '/'; return os; } }}// #define POLYTRILOG// ------------------------------------------------------------------// This routine computes the constrained Delaunay triangulation (CDT)// of a planar straight line graph (PSLG).QMG::PolyTri::Triangulation QMG::PolyTri::pslg_constrained_delaunay_triangulate(VertexList& vtxlist, const vector<Edge>& elist) { // Make a list of all constraint edges. // Use a map to prevent duplicates. vector<Edge> constraint; vector<bool> top_done; vector<bool> bottom_done; map<Edge,int> checkedge; using std::advance;#ifdef POLYTRILOG using std::endl; std::ofstream dbstream("pslglog"); ostream* debug_str = &dbstream; for (int nv1 = 0; nv1 < vtxlist.size(); ++nv1) { *debug_str << "vertex v" << nv1 << "/ at " << vtxlist.coord(nv1,0) << ',' << vtxlist.coord(nv1,1) << endl; }#endif { int numv = vtxlist.size(); for (int j = 0; j < elist.size(); ++j) { Edge e = elist[j]; for (int k = 0; k < 2; ++k) { if (e.endpoint(k) < 0 || e.endpoint(k) >= numv) throw_error("Entry in edge list out of range"); } if (e.endpoint(0) == e.endpoint(1)) continue; if (checkedge.find(e.sort()) == checkedge.end()) { int edgeind = constraint.size(); constraint.push_back(e); top_done.push_back(false); bottom_done.push_back(false); checkedge[e.sort()] = edgeind;#ifdef POLYTRILOG *debug_str << " adding edge " << e << " at pos " << edgeind << endl;#endif } else {#ifdef POLYTRILOG *debug_str << " skipping edge " << e << endl;#endif } } } // Add the bounding box to the stack, and four new vertices. { Real minx = BIG_REAL; Real maxx = -BIG_REAL; Real miny = BIG_REAL; Real maxy = -BIG_REAL; for (int j = 0; j < vtxlist.size(); ++j) { Real x = vtxlist.coord(j,0); if (x < minx) minx = x; if (x > maxx) maxx = x; Real y = vtxlist.coord(j,1); if (y < miny) miny = y; if (y > maxy) maxy = y; } if (vtxlist.size() == 0) { minx = 0; maxx = 1; miny = 0; maxy = 1; } Real deltax = maxx - minx; if (deltax == 0.0) deltax = fabs(minx) + 1; Real deltay = maxy - miny; if (deltay == 0.0) deltay = fabs(miny) + 1; Real lbx = minx - deltax; Real ubx = maxx + deltax; Real lby = miny - deltay; Real uby = maxy + deltay; VertexIndex newv1 = vtxlist.add_vertex(lbx,lby); VertexIndex newv2 = vtxlist.add_vertex(ubx,lby); VertexIndex newv3 = vtxlist.add_vertex(ubx,uby); VertexIndex newv4 = vtxlist.add_vertex(lbx,uby);#ifdef POLYTRILOG *debug_str << " lbx, ubx, lby, uby = " << lbx << ',' << ubx << ',' << lby << ',' << uby << endl; *debug_str << " new verts = v" << newv1 << "/ v" << newv2 << "/ v" << newv3 << "/ v" << newv4 << "/" << endl;#endif int sz = constraint.size(); constraint.push_back(Edge(newv1,newv2)); top_done.push_back(false); bottom_done.push_back(true); checkedge[Edge(newv1,newv2).sort()] = sz++; constraint.push_back(Edge(newv2,newv3)); top_done.push_back(false); bottom_done.push_back(true); checkedge[Edge(newv2,newv3).sort()] = sz++; constraint.push_back(Edge(newv3,newv4)); top_done.push_back(false); bottom_done.push_back(true); checkedge[Edge(newv3,newv4).sort()] = sz++; constraint.push_back(Edge(newv4,newv1)); top_done.push_back(false); bottom_done.push_back(true); checkedge[Edge(newv4,newv1).sort()] = sz++; } Matrix transf(2,2); Matrix smalleq(2,2); Real smallrhs[2]; Real smallsoln[2]; vector<Labeled_dist> vtxqueue; vector<Labeled_dist> edgequeue; VertexList tvtxlist; vector<Real> tan_point_x; vector<Real> tan_point_y; vector<Real> slope_c;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?