• Nenhum resultado encontrado

There are two types of vertices that may appear on the boundary. The first are vertices from the original polygons that appear on the union. There can be at mostnsuch vertices, and each is charged to itself. The more troublesome vertices are those that arise when two edges of two pseudodisks intersect each other.

Suppose that two edgese1ande2of pseudodisks P1 andP2intersect along the union. Follow edgee1

into the interior of the pseudodiske2. Two things might happen. First, we might hit the endpointvof this e1 before leaving the interiorP2. In this case, charge the intersection tov. Note thatv can get at most two such charges, one from either incident edge. Ife1passes all the way throughP2before coming to the endpoint, then try to do the same with edgee2. Again, if it hits its endpoint before coming out ofP1, then charge to this endpoint. See the figure below.

e

Cannot happen Charge u

Charge v

v u v u

2

e e

2 1 2 e1 e e1

v

Figure 85: Proof of Lemma 2.

But what do we do if bothe1shoots straight throughP2ande2shoots straight throughP1? Now we have no vertex to charge. This is okay, because the pseudodisk property implies that this cannot happen. If both edges shoot completely through, then the two polygons must cross over each other.

Recall that in our application of this lemma, we havenC-obstacles, each of which has at mostm+ 3vertices, for a total input complexity ofO(nm). Since they are all pseudodisks, it follows from Lemma 2 that the total complexity of the free space isO(nm).

We store a pointer to the face to the left of the edgee.left(we can access the face to the right from the twin edge). This is called the dent face. We also store the next and previous directed edges in counter-clockwise order about the incident face,e.nextande.prev, respectively.

Face: Each facef stores a pointer to a single edge for which this face is the incident face,f.inc edge. (See the text for the more general case of dealing with holes.)

DCEL Alternative view

e.next e.left

e.prev

e.org e.twin

e

Figure 86: Doubly-connected edge list.

The figure shows two ways of visualizing the DCEL. One is in terms of a collection of doubled-up directed edges. An alternative way of viewing the data structure that gives a better sense of the connectivity structure is based on covering each edge with a two element block, one foreand the other for its twin. The next and prev pointers provide links around each face of the polygon. The next pointers are directed counterclockwise around each face and the prev pointers are directed clockwise.

Of course, in addition the data structure may be enhanced with whatever application data is relevant. In some applications, it is not necessary to know either the face or vertex information (or both) at all, and if so these records may be deleted. See the book for a complete example.

For example, suppose that we wanted to enumerate the vertices that lie on some facef. Here is the code:

Vertex enumeration using DCEL enumerate_vertices(Face f) {

Edge start = f.inc_edge;

Edge e = start;

do {

output e.org;

e = e.next;

} while (e != start);

}

Merging subdivisions: Let us return to the applications problem that lead to the segment intersection problem. Sup-pose that we have two planar subdivisions,S1andS2, and we want to compute their overlay. In particular, this is a subdivision whose vertices are the union of the vertices of each subdivision and the points of intersection of the line segments in the subdivision. (Because we assume that each subdivision is a planar graph, the only new vertices that could arise will arise from the intersection of two edges, one fromS1and the other fromS2.) Sup-pose that each subdivision is represented using a DCEL. Can we adapt the plane-sweep algorithm to generate the DCEL of the overlaid subdivision?

The answer is yes. The algorithm will destroy the original subdivisions, so it may be desirable to copy them before beginning this process. The first part of the process is straightforward, but perhaps a little tedious. This part consists of building the edge and vertex records for the new subdivision. The second part involves building the face records. It is more complicated because it is generally not possible to know the face structure at the moment that the sweep is advancing, without looking “into the future” of the sweep to see whether regions will merge. (You might try to convince yourself of this.) The entire subdivision is built first, and then the face information is constructed and added later. We will skip the part of updating the face information (see the text).

For the first part, the most illustrative case arises when the sweep is processing an intersection event. In this case the two segments arise as two edgesa1andb1from the two subdivisions. We will assume that we select the half-edges that are directed from left to right across the sweep-line. The process is described below (and is illustrated in the figure below). It makes use of two auxiliary procedures. Split(a1, a2)splits an edgea1at its midpoint into two consecutive edgesa1followed bya2, and linksa2 into the structure. Splice(a1, a2, b1, b2) takes two such split edges and links them all together.

Merge two edges into a common subdivision Merge(a1, b1) :

(1) Create a new vertexvat the intersection point.

(2) Split each of the two intersecting edges, by adding a vertex at the common intersection point. Leta2andb2

be the new edge pieces. They are created by the callsa2= Split(a1)andb2= Split(b1)given below.

(3) Link the four edges together by invokingSplice(a1, a2, b1, b2), given below.

The splitting procedure creates the new edge, links it into place. After this the edges have been split, but they are not linked to each other. The edge constructor is given the origin and destination of the new edge and creates a new edge and its twin. The procedure below initializes all the other fields. Also note that the destination of a1, that is the origin ofa1’s twin must be updated, which we have omitted. The splice procedure interlinks four edges around a common vertex in the counterclockwise ordera1(entering),b1(entering),a2(leaving),b2

(leaving).

Split an edge into two edges Split(edge &a1, edge &a2) { // a2 is returned

a2 = new edge(v, a1.dest()); // create edge (v,a1.dest) a2.next = a1.next; a1.next.prev = a2;

a1.next = a2; a2.prev = a1;

a1t = a1.twin; a2t = a2.twin; // the twins a2t.prev = a1t.prev; a1t.prev.next = a2t;

a1t.prev = a2t; a2t.next = a1t;

}

Splice four edges together Splice(edge &a1, edge &a2, edge &b1, edge &b2) {

a1t = a1.twin; a2t = a2.twin; // get the twins b1t = b1.twin; b2t = b2.twin;

a1.next = b2; b2.prev = a1; // link the edges together b2t.next = a2; a2.prev = b2t;

a2t.next = b1t; b1t.prev = a2t;

b1.next = a1t; a1t.prev = b1;

}

a1 b1t

a1 a1t

b1

b1t a2t a2 b2t a1 b2

split a1t

splice b1

a1t

b2 b2t

a2 b1t a2t

b1

Figure 87: Updating the DCEL.