• No results found

The Polyline-Traits Class

Arrangement-Traits Classes

5.3 The Polyline-Traits Class

// Get the name o f t he in pu t f i l e from t he command l i n e , or use t he d e f a u l t // Europe . dat f i l e i f no command−line parameters are given .

const char∗ filename = ( argc > 1) ? argv [ 1 ] : "Europe . dat" ; std : : l i s t <Segment> segments ;

read_objects<Segment>(filename , std : : back_inserter ( segments ) ) ; // Construct the arrangement by a g g r e g a t e l y i n s e r t i n g a l l segments . Arrangement a r r ;

std : : cout << "Performing ␣ aggregated ␣ i n s e r t i o n ␣ o f ␣"

<< segments . s i z e ( ) << "␣segments . " << std : : endl ; boost : : timer timer ;

insert_non_intersecting_curves( arr , segments . begin ( ) , segments . end ( ) ) ; double s e c s = timer . ela psed ( ) ;

print_arrangement_size ( a r r ) ;

std : : cout << " Construction ␣took␣" << s e c s << "␣ seconds . " << std : : endl ; return 0 ;

}

5.2.3 The Linear-Traits Class

The Arr_linear_traits_2<Kernel> class template used in the previous chapter for demonstrat-ing the construction of arrangements of unbounded curves is capable of handldemonstrat-ing bounded and un-bounded linear objects, namely, lines, rays, and line segments. It models the concepts Arrangement-Traits_2, ArrangementLandmarkArrangement-Traits_2, and ArrangementOpenBoundaryTraits_2. It is parame-terized by a geometric kernel and its nested type Point_2 is defined to be the kernel-point type.

The Curve_2 (and X_monotone_curve_2) nested types are constructible from a Kernel::Line_2, a Kernel::Ray_2, or a Kernel::Segment_2 object. Given a linear-curve object c, you can use the calls c.is_line(), c.is_ray(), and c.is_segment() to find out whether it has a source point or a target point. Based on the curve type, you can access its endpoints using the methods c.source()(for rays and for line segments) and c.target() (for segments only). It is also pos-sible to cast a curve into a Kernel::Line_2, a Kernel::Ray_2, or a Kernel::Segment_2 type, using the methods c.line(), c.ray(), and c.segment(), respectively.

Note that, like the default line-segment traits class, the linear-curve traits class uses caching techniques to speed up its predicate evaluations and object constructions.

5.3 The Polyline-Traits Class

Polylines are continuous piecewise linear curves. Polylines are of particular interest, as they can be used to approximate more complex curves in the plane. At the same time they are easier to handle in comparison to higher-degree algebraic curves, as rational arithmetic is sufficient to carry

out computations on polylines, and to construct arrangements of polylines in an exact and robust manner.

The Arr_polyline_traits_2<SegmentTraits> class template handles polylines. It models the conceptsArrangementTraits_2 and ArrangementLandmarkTraits_2 depending on the type that substitutes the SegmentTraits parameter when the Arr_polyline_traits_2> class template is instantiated. The substituted type must be a geometry-traits class that handles segments and models the concept ArrangementXMonotoneTraits_2. If it also models the ArrangementTraits_

2 concept, the instantiated Arr_polyline_traits_2<SegmentTraits> type models the concept ArrangementTraits_2 as well. The same holds for the ArrangementLandmarkTraits_2 concept.

The curves handled by each operation defined by the type that substitutes the SegmentTraits parameter are restricted to line segments. (This precondition cannot be enforced by the compiler.) An instance of the polyline class-template inherits its point type from the substituted line-segment traits class, and defines the new type Curve_2, which is used to represent polylines. A curve of this type is stored as a vector of SegmentTraits::X_monotone_curve_2 objects (namely line segments). Polyline objects are constructible from a range of points, where two succeeding points in the range represent the endpoints of a segment of the polyline. The nested X_monotone_curve_

2 type inherits from the type Curve_2. The points in anx-monotone polyline curve are always stored in lexicographically increasing order of their coordinates. The polyline traits class also supports the traversal over the range of defining points, whose first and past-the-end iterators can be obtained through the methods c.begin() and c.end() of a polylinec.

The polyline-traits class does not perform any geometric operations directly. Instead, it solely relies on the functionality of the substituted segment-traits class. For example, when we need to determine the position of a point with respect to anx-monotone polyline, we use binary search to locate the relevant segment that contains the point in itsx-range. Then, we compute the position of the point with respect to this segment. Thus, operations on x-monotone polylines of size m typically takeO(log m) time.

You are free to choose the underlying line-segment traits class. Your decision could be based, for example, on the number of expected intersection points (see discussion above in Section5.2.1).

Moreover, it is possible to substitute the SegmentTraits template parameter with a traits class that handles segments with some additional data attached to each individual segment; see Sec-tion5.5. This makes it possible to associate different data objects with the different segments that compose a polyline.

advanced

Consider, for example, the Equal_2 predicate that returns true iff the graphs of two given x-monotone polylines are the same; see Section 5.1.1. The implementation of this predicate for polylines follows the algorithm below presented in pseudo-code, where, first_segment(c) and last_segment(c) return the first and last segments of the polyline c, respectively; next_segment (c, s) returns the segment of the polyline c following the segment s; minpoint(s) and maxpoint(s) return the lexicographically minimum and maximum endpoints of a segments, respectively; and ison(p, s) determines whether the point p lies on a segment s. These functions are trivially imple-mented with the operations of the traits class other than the Equal_2 predicate and the access functions of the polyline class. The correctness of the algorithm is based on the assumption that the subcurve that goes through two points is unique, namely, that the subcurve is linear.

Are the graphs of the polylinesc1 andc2equal?

s1← first_segment(c1) s2← first_segment(c2)

if (minpoint(s1) = minpoint(s1)) return false

while(s1= last_segment(c1) ∧ s2= last_segment(c2)) if (maxpoint(s1) = maxpoint(s2))

s1← next_segment(c1, s1) s2← next_segment(c2, s2) else if (maxpoint(s1) < maxpoint(s2))

if ¬ison(maxpoint(s1), s2) return false s1← next_segment(c1, s1)

else

assert(maxpoint(s2) < maxpoint(s1)) if ¬ison(maxpoint(s2), s1) return false s2← next_segment(c2, s2)

if (s1= last_segment(c1) ∨ s2= last_segment(c2)) return false if (maxpoint(s1) = maxpoint(s2)) return false

return true

advanced

π1

π2

π3

Example: The program listed below constructs an ar-rangement of three polylines, π1, π2, and π3, as depicted in the figure to the right. In this example, each polyline is constructed from points stored in a different container, i.e., array, list, and vector. Points defining the polylines are not necessarily associated with arrangement vertices.

The arrangement vertices are either the extreme points of eachx-monotone polyline (drawn as dark discs) or the in-tersection points between two polylines (drawn as rings).

Observe that the polylineπ2 is split into threex-monotone polylines, and that the two curvesπ1andπ3have two over-lapping sections—an impossible scenario in arrangements of line segments.

// F i l e : ex _polylines . cpp

#include <l i s t >

#include <vector>

#include " a r r _po lylines . h"

#include " arr_print . h"

int main ( ) {

// Construct three p o l y l i n e s and compute t h e i r arrangement . Point pts1 [ ] =

{Point ( 0 , 0 ) , Point ( 2 , 4 ) , Point ( 3 , 0 ) , Point ( 4 , 4 ) , Point ( 6 , 0 ) } ; std : : l i s t <Point> pts2 ;

pts2 . push_back ( Point ( 1 , 3 ) ) ; pts2 . push_back ( Point ( 0 , 2 ) ) ; pts2 . push_back ( Point ( 1 , 0 ) ) ; pts2 . push_back ( Point ( 2 , 1 ) ) ; pts2 . push_back ( Point ( 3 , 0 ) ) ; pts2 . push_back ( Point ( 4 , 1 ) ) ; pts2 . push_back ( Point ( 5 , 0 ) ) ; pts2 . push_back ( Point ( 6 , 2 ) ) ; pts2 . push_back ( Point ( 5 , 3 ) ) ; pts2 . push_back ( Point ( 4 , 2 ) ) ;

std : : vector<Point> pts3 ( 4 ) ;

pts3 [ 0 ] = Point ( 0 , 2 ) ; pts3 [ 1 ] = Point ( 1 , 2 ) ; pts3 [ 2 ] = Point ( 3 , 6 ) ; pts3 [ 3 ] = Point ( 5 , 2 ) ; Arrangement a r r ;

i n s e r t ( arr , P o l y l i n e(&pts1 [ 0 ] , &pts1 [ 5 ] ) ) ; // pi1 i n s e r t ( arr , P o l y l i n e ( pts2 . begin ( ) , pts2 . end ( ) ) ) ; // pi2 i n s e r t ( arr , P o l y l i n e ( pts3 . begin ( ) , pts3 . end ( ) ) ) ; // pi3 print_arrangement( a r r ) ;

return 0 ; }

The common types used by the example programs involving arrangements of polylines are listed below, and defined in the header file arr_polylines.h. As we do in the case of segments and linear objects, we use the predefined Cgal kernel to instantiate our traits class. However, in this case we have yet another layer of template instantiation, namely the instantiation of the polyline-traits class-template with an instance of a line-segment traits class-template. Naturally, we use the Arr_segment_traits_2 class, instantiated with the predefined filtered kernel of Cgal.

#include <CGAL/Exact_predicates_exact_constructions_kernel . h>

#include <CGAL/Arr_segment_traits_2 . h>

#include <CGAL/Arr_polyline_traits_2 . h>

#include <CGAL/Arrangement_2 . h>

typedef CGAL: : Exact_predicates_exact_constructions_kernel Kernel ;

typedef Kernel : :FT Number_type ;

typedef CGAL: : Arr_segment_traits_2<Kernel> Segment_traits ; typedef CGAL: : Arr_polyline_traits_2<Segment_traits> Tr a its ;

typedef Tr a its : : Point_2 Point ;

typedef Tr a its : : Curve_2 P o l y l i n e ;

typedef CGAL: : Arrangement_2<Traits> Arrangement ;