/* compVis: * Compute visibility graph of vertices of polygons. * Only do polygons from index startp to end. * If two nodes cannot see each other, the matrix entry is 0. * If two nodes can see each other, the matrix entry is the distance * between them. */ static void compVis (vconfig_t *conf, int start) { int V = conf->N; Ppoint_t* pts = conf->P; int* nextPt = conf->next; int* prevPt = conf->prev; array2 wadj = conf->vis; int j, i, previ; COORD d; for (i = start; i < V; i++) { /* add edge between i and previ. * Note that this works for the cases of polygons of 1 and 2 * vertices, though needless work is done. */ previ = prevPt[i]; d = dist (pts [i], pts [previ]); wadj[i][previ] = d; wadj[previ][i] = d; /* Check remaining, earlier vertices */ if (previ == i-1) j = i-2; else j = i-1; for (; j >= 0; j--) { if (inCone(i,j,pts,nextPt,prevPt) && inCone(j,i,pts,nextPt,prevPt) && clear(pts[i],pts[j],V,V,V,pts,nextPt,prevPt)) { /* if i and j see each other, add edge */ d = dist (pts [i], pts [j]); wadj[i][j] = d; wadj[j][i] = d; } } } }
// Returns T iff (v_i, v_j) is a proper internal // diagonal of P. static bool diagonal(int i, int j, int n, const int* verts, int* indices) { return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices); }
static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region) { // Sort holes from left to right. for (int i = 0; i < region.nholes; i++) findLeftMostVertex(region.holes[i].contour, ®ion.holes[i].minx, ®ion.holes[i].minz, ®ion.holes[i].leftmost); qsort(region.holes, region.nholes, sizeof(rcContourHole), compareHoles); int maxVerts = region.outline->nverts; for (int i = 0; i < region.nholes; i++) maxVerts += region.holes[i].contour->nverts; rcScopedDelete<rcPotentialDiagonal> diags = (rcPotentialDiagonal*)rcAlloc(sizeof(rcPotentialDiagonal)*maxVerts, RC_ALLOC_TEMP); if (!diags) { ctx->log(RC_LOG_WARNING, "mergeRegionHoles: Failed to allocated diags %d.", maxVerts); return; } rcContour* outline = region.outline; // Merge holes into the outline one by one. for (int i = 0; i < region.nholes; i++) { rcContour* hole = region.holes[i].contour; int index = -1; int bestVertex = region.holes[i].leftmost; for (int iter = 0; iter < hole->nverts; iter++) { // Find potential diagonals. // The 'best' vertex must be in the cone described by 3 cosequtive vertices of the outline. // ..o j-1 // | // | * best // | // j o-----o j+1 // : int ndiags = 0; const int* corner = &hole->verts[bestVertex*4]; for (int j = 0; j < outline->nverts; j++) { if (inCone(j, outline->nverts, outline->verts, corner)) { int dx = outline->verts[j*4+0] - corner[0]; int dz = outline->verts[j*4+2] - corner[2]; diags[ndiags].vert = j; diags[ndiags].dist = dx*dx + dz*dz; ndiags++; } } // Sort potential diagonals by distance, we want to make the connection as short as possible. qsort(diags, ndiags, sizeof(rcPotentialDiagonal), compareDiagDist); // Find a diagonal that is not intersecting the outline not the remaining holes. index = -1; for (int j = 0; j < ndiags; j++) { const int* pt = &outline->verts[diags[j].vert*4]; bool intersect = intersectSegCountour(pt, corner, diags[i].vert, outline->nverts, outline->verts); for (int k = i; k < region.nholes && !intersect; k++) intersect |= intersectSegCountour(pt, corner, -1, region.holes[k].contour->nverts, region.holes[k].contour->verts); if (!intersect) { index = diags[j].vert; break; } } // If found non-intersecting diagonal, stop looking. if (index != -1) break; // All the potential diagonals for the current vertex were intersecting, try next vertex. bestVertex = (bestVertex + 1) % hole->nverts; } if (index == -1) { ctx->log(RC_LOG_WARNING, "mergeHoles: Failed to find merge points for %p and %p.", region.outline, hole); continue; } if (!mergeContours(*region.outline, *hole, index, bestVertex)) { ctx->log(RC_LOG_WARNING, "mergeHoles: Failed to merge contours %p and %p.", region.outline, hole); continue; } } }
/* addEndpoint: * Add node to graph representing spline end point p inside obstruction obs_id. * For each side of obstruction, add edge from p to corresponding triangle. * The node id of the new node in the graph is v_id. * If p lies on the side of its node (sides != 0), we limit the triangles * to those within 45 degrees of each side of the natural direction of p. */ static void addEndpoint(router_t * rtr, pointf p, node_t* v, int v_id, int sides) { int obs_id = ND_lim(v); int starti = rtr->obs[obs_id]; int endi = rtr->obs[obs_id + 1]; pointf* pts = rtr->ps; int i, t; double d; pointf vr, v0, v1; switch (sides) { case TOP : vr = add_pointf (p, north); v0 = add_pointf (p, northwest); v1 = add_pointf (p, northeast); break; case TOP|RIGHT : vr = add_pointf (p, northeast); v0 = add_pointf (p, north); v1 = add_pointf (p, east); break; case RIGHT : vr = add_pointf (p, east); v0 = add_pointf (p, northeast); v1 = add_pointf (p, southeast); break; case BOTTOM|RIGHT : vr = add_pointf (p, southeast); v0 = add_pointf (p, east); v1 = add_pointf (p, south); break; case BOTTOM : vr = add_pointf (p, south); v0 = add_pointf (p, southeast); v1 = add_pointf (p, southwest); break; case BOTTOM|LEFT : vr = add_pointf (p, southwest); v0 = add_pointf (p, south); v1 = add_pointf (p, west); break; case LEFT : vr = add_pointf (p, west); v0 = add_pointf (p, southwest); v1 = add_pointf (p, northwest); break; case TOP|LEFT : vr = add_pointf (p, northwest); v0 = add_pointf (p, west); v1 = add_pointf (p, north); break; case 0 : break; default : assert (0); break; } rtr->tg->nodes[v_id].ne = 0; rtr->tg->nodes[v_id].ctr = p; for (i = starti; i < endi; i++) { ipair seg; seg.i = i; if (i < endi - 1) seg.j = i + 1; else seg.j = starti; t = findMap(rtr->trimap, seg.i, seg.j); if (sides && !inCone (v0, p, v1, pts[seg.i]) && !inCone (v0, p, v1, pts[seg.j]) && !raySeg(p,vr,pts[seg.i],pts[seg.j])) continue; d = DIST(p, (rtr->tg->nodes + t)->ctr); addTriEdge(rtr->tg, v_id, t, d, seg); } }