polytri.cpp
来自「算断裂的」· C++ 代码 · 共 865 行 · 第 1/2 页
CPP
865 行
vector<Real> slope_d; int numv = vtxlist.size(); Triangulation tri; // Main loop: generate a triangle for each edge in the workstack. for (int eloop = 0; eloop < constraint.size() * 2; ++eloop) { int edgeind1 = eloop / 2; Edge e = constraint[edgeind1]; if (eloop & 1) { if (top_done[edgeind1]) continue; top_done[edgeind1] = true; } else { if (bottom_done[edgeind1]) continue; bottom_done[edgeind1] = true; e = e.reverse(); }#ifdef POLYTRILOG *debug_str << "\n\n+++Main loop processing edge "<< e << endl;#endif int nume = constraint.size(); // Find a tranformation so that the two endpoints of the edge are at (-1,0) and (1,0). VertexIndex startv = e.endpoint(0); VertexIndex endv = e.endpoint(1); Real stx = vtxlist.coord(startv, 0); Real sty = vtxlist.coord(startv, 1); Real enx = vtxlist.coord(endv, 0); Real eny = vtxlist.coord(endv, 1); Real xdisp = enx - stx; Real ydisp = eny - sty; Real elength2 = xdisp * xdisp + ydisp * ydisp; if (elength2 == 0) continue; Real mult = 2.0 / elength2; transf(0,0) = xdisp * mult; transf(0,1) = ydisp * mult; transf(1,0) = -ydisp * mult; transf(1,1) = xdisp * mult; Real offsetx = (stx + enx) * 0.5; Real offsety = (sty + eny) * 0.5; tvtxlist.resize(0); { for (int j = 0; j < numv; ++j) { Real tmpx = vtxlist.coord(j,0) - offsetx; Real tmpy = vtxlist.coord(j,1) - offsety; Real newx = transf(0,0) * tmpx + transf(0,1) * tmpy; Real newy = transf(1,0) * tmpx + transf(1,1) * tmpy; if (j == startv || j == endv) { newy = 0.0; if (j == startv) newx = -1.0; else newx = 1.0; }#ifdef POLYTRILOG *debug_str << " tvtx new vertex v" << j << "/ at " << newx << "," << newy << endl;#endif tvtxlist.add_vertex(newx, newy); } } // For each vertex, compute its p-value and insert it into the // queue. vtxqueue.resize(0, null_labeled_dist); { for (int j = 0; j < numv; ++j) { Real y = tvtxlist.coord(j,1); if (y <= 0) continue; Real x = tvtxlist.coord(j,0); Real p = (x * x + y * y - 1) / (2 * y);#ifdef POLYTRILOG *debug_str << " new vtxqueue entry v" << j << "/ with p = " << p << endl;#endif vtxqueue.push_back(Labeled_dist(p,j)); } } // For each constraint edge, compute its p-value and insert it into // the queue if its tangent point is in the segment's // relative interior. edgequeue.resize(0, null_labeled_dist); tan_point_x.resize(nume); tan_point_y.resize(nume); slope_c.resize(nume); slope_d.resize(nume); { for (int j = 0; j < nume; ++j) {#ifdef POLYTRILOG *debug_str << "Considering constraint " << constraint[j] << endl;#endif VertexIndex startv1 = constraint[j].endpoint(0); VertexIndex endv1 = constraint[j].endpoint(1); if (startv == startv1 && endv == endv1) continue; if (startv == endv1 && endv == startv1) continue; Real stx1 = tvtxlist.coord(startv1,0); Real sty1 = tvtxlist.coord(startv1,1); Real enx1 = tvtxlist.coord(endv1,0); Real eny1 = tvtxlist.coord(endv1,1); if (startv == startv1 && eny1 <= 0.0) continue; if (endv == startv1 && eny1 <= 0.0) continue; if (startv == endv1 && sty1 <= 0.0) continue; if (endv == endv1 && sty1 <= 0.0) continue; smalleq(0,0) = stx1; smalleq(0,1) = sty1; smalleq(1,0) = enx1; smalleq(1,1) = eny1; smallrhs[0] = 1; smallrhs[1] = 1; Real condest = smalleq.linear_solve(smallrhs, smallsoln); if (condest == BIG_REAL) continue; Real c = smallsoln[0]; Real d = smallsoln[1];#ifdef POLYTRILOG *debug_str << " for this constraint, c, d = " << c << ',' << d << endl;#endif Real cdlen = c * c + d * d; Real qa = c * c; Real qb = 2.0 * d; Real qc = cdlen - 1.0; Real discr; Real ynum; if (startv == startv1 || startv == endv1 || endv == startv1 || endv == endv1) { discr = 0.0; ynum = 0; } else { ynum = 1.0 - c * c; discr = 4.0 * cdlen * ynum; }#ifdef POLYTRILOG *debug_str << " for this constraint, ynum = " << ynum << endl;#endif if (ynum < 0.0) continue; Real p; // numerically stable quadratic formula if (c == 0.0 && d < 0.0) continue; if (d <= 0.0) p = (-qb + sqrt(discr)) / (2 * qa); else p = 2.0 * qc / (-qb - sqrt(discr));#ifdef POLYTRILOG *debug_str << " for this constraint p = " << p << endl;#endif // compute y coord Real y = sqrt(ynum / cdlen); // Numerically stable way to recover x Real x; if (startv == startv1 || startv == endv1) x = -1.0; else if (endv == startv1 || endv == endv1) x = 1.0; else if (fabs(d) > fabs(c)) x = (y - p) * c / d; else x = (1.0 - d * y) / c;#ifdef POLYTRILOG *debug_str << " for this constraint tan point = " << x << ',' << y << " versus endpoints " << stx1 << ',' << sty1 << " and " << enx1 << ',' << eny1 << endl;#endif //Check whether (x,y) is actually in the segment. if ((x - stx1) * (x - enx1) + (y - sty1) * (y - eny1) > 0) continue; // Put it in the queue. tan_point_x[j] = x; tan_point_y[j] = y; slope_c[j] = c; slope_d[j] = d; edgequeue.push_back(Labeled_dist(p,j));#ifdef POLYTRILOG *debug_str << "new edgequeue entry " << constraint[j] << " tangent at point " << tan_point_x[j] << "," << tan_point_y[j] << " slope = " << slope_c[j] << ',' << slope_d[j] << " p = " << p << endl;#endif } } // Sort the two queues. sort(edgequeue.begin(), edgequeue.end()); sort(vtxqueue.begin(), vtxqueue.end()); // Now start growing the circle until we hit something. int vqptr = 0; int eqptr = 0; typedef multimap<Real,int> Front_type; typedef Front_type::iterator FTI; Front_type front;#ifdef POLYTRILOG *debug_str << " \nbeginning front search " << endl;#endif for (;;) { if (vqptr >= vtxqueue.size()) throw_error("Unexpected end of vertex queue in polytri"); // Check if the next thing to add is a vertex. bool hit_on_vertex; Real x,y,p; VertexIndex thisvtxind; int thisedgeind; if (eqptr >= edgequeue.size() || edgequeue[eqptr].dist >= vtxqueue[vqptr].dist) { hit_on_vertex = true; thisvtxind = vtxqueue[vqptr].label; p = vtxqueue[vqptr].dist; x = tvtxlist.coord(thisvtxind,0); y = tvtxlist.coord(thisvtxind,1);#ifdef POLYTRILOG *debug_str << " processing front vertex v" << thisvtxind << "/ at x,y " << x << ',' << y << " p = " << p << endl;#endif } else { hit_on_vertex = false; thisedgeind = edgequeue[eqptr].label; p = edgequeue[eqptr].dist; x = tan_point_x[thisedgeind]; y = tan_point_y[thisedgeind];#ifdef POLYTRILOG *debug_str << " processing front edge" << constraint[thisedgeind] << " at x,y " << x << ',' << y << " p = " << p << endl;#endif } // Check if the point x,y is hidden by the front. // Find the angle that (x,y) makes w.r.t the center // of the circle at (0,p). Real ang = atan2(y - p,x);#ifdef POLYTRILOG *debug_str << " ang = " << ang << endl;#endif int checkcount; int checklist[2]; if (front.size() == 0) checkcount = 0; else { FTI next = front.lower_bound(ang); FTI prev; if (next == front.begin()) { prev = front.end(); advance(prev, -1); } else { prev = next; advance(prev, -1); } if (next == front.end()) { next = front.begin(); } if (prev == next) { checkcount = 1; checklist[0] = prev -> second; } else { checkcount = 2; checklist[0] = prev -> second; checklist[1] = next -> second; } } bool hidden = false; for (int checki = 0; checki < checkcount; ++checki) { // Determine if (x,y) is hidden. // If the test point is a vertex of the edge we // are checking, then it is not hidden. int cedgeind = checklist[checki]; if (hit_on_vertex && (constraint[cedgeind].endpoint(0) == thisvtxind || constraint[cedgeind].endpoint(1) == thisvtxind)) continue;#ifdef POLYTRILOG *debug_str << " checking against edge " << constraint[cedgeind] << endl;#endif // Intersect the segment from the new point to the origin // with the support line of the constraint. smalleq(0,0) = slope_c[cedgeind]; smalleq(0,1) = slope_d[cedgeind]; smallrhs[0] = 1.0; smalleq(1,0) = y; smalleq(1,1) = -x; smallrhs[1] = 0; Real condest = smalleq.linear_solve(smallrhs,smallsoln); if (condest > 1e16) continue;#ifdef POLYTRILOG *debug_str << " smallsoln = " << smallsoln[0] <<',' << smallsoln[1] << " y = " << y << endl;#endif if (fabs(y) > fabs(x)) { if (smallsoln[1] >= 0 && smallsoln[1] <= y && smallsoln[0]) { hidden = true; } } else { if (fabs(smallsoln[0]) <= fabs(x) && smallsoln[0] * x >= 0) { hidden = true; } } if (hidden) break; }#ifdef POLYTRILOG *debug_str << "hidden = " << hidden << endl;#endif if (hit_on_vertex) { if (!hidden) { // The hit is on a vertex, and the vertex is not hidden, // then we have found the sought-after triangle and we // can emit it. tri.add_triangle(startv, endv, thisvtxind);#ifdef POLYTRILOG *debug_str << " adding triangle v" << startv << "/ v" << endv << "/ v" << thisvtxind << "/" << endl;#endif // Add two new constraint edges, if not already present. for (int k = 0; k < 2; ++k) { VertexIndex ep1 = (k == 0)? endv : thisvtxind; VertexIndex ep2 = (k == 0)? thisvtxind : startv; Edge enew(ep1, ep2); if (checkedge.find(enew.sort()) == checkedge.end()) { int sz = constraint.size(); constraint.push_back(enew); top_done.push_back(true); bottom_done.push_back(false); checkedge[enew.sort()] = sz;#ifdef POLYTRILOG *debug_str << " adding constraint edge " << enew << " at position " << sz << endl;#endif } else { int j1 = checkedge[enew.sort()]; if (ep1 == constraint[j1].endpoint(0)) { if (top_done[j1]) throw_error("Top of edge done twice?"); top_done[j1] = true; } else { if (bottom_done[j1]) throw_error("Bottom of edge done twice?"); bottom_done[j1] = true; } } } break; //end of front; } else { // hidden ++vqptr; } } else { // hit is on edge if (!hidden) { // Add it to the front.#ifdef POLYTRILOG *debug_str << " adding edge " << constraint[thisedgeind] << " to front" << endl;#endif front.insert(pair<Real,int>(ang,thisedgeind)); } ++eqptr; } } // Done with finding triangle } // End of main work loop. return tri;}// ------------------------------------------------------------------// poly_cdt computes the CDT of a polygon. It first computes the// CDT of the corresponding PSLG, then it calls searchtri to // get rid of unused triangles.QMG::PolyTri::Triangulation QMG::PolyTri::poly_cdt(const Matrix& vtxlist, const vector<Edge>& elist, double tol) { VertexList vl; make_2d_vertices(vtxlist, vl, tol); Triangulation init_tri = pslg_constrained_delaunay_triangulate(vl, elist); int nt = init_tri.numtri(); vector<Triangle_Label> disposition(nt); { for (int k = 0; k < nt; ++k) { disposition[k] = NOT_YET_SEARCHED; for (int l = 0; l < 3; ++l) { if (init_tri.tri_vertex(k,l) >= vtxlist.numrows()) disposition[k] = DELETE; } } } search_tri(elist, init_tri, disposition); Triangulation result; { for (int k = 0; k < nt; ++k) { if (disposition[k] == KEEP) { result.add_triangle(init_tri.tri_vertex(k,0), init_tri.tri_vertex(k,1), init_tri.tri_vertex(k,2)); } } } return result;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?