
3 Point2D[] points = dataPoints();
4 // Create Voronoi Diagram
5 Voronoi diagram = new Voronoi (w, h, points);
6 // Partition vertices
7 int vSize = diagram.vertices.length;
8 int[][] v = partitionData(diagram, vSize, nP);
9 // Partition Edges
10 int eSize = diagram.edges.length;
11 int[][] e = partitionData(diagram, eSize, nP);
12 // Create subsets
13 Object[] partitions = createPartitions(v, e, nP);
14 Places places = new Places("Partitions", nP);
15 places.callAll(Parititions.Init, partitions);
16 places.callAll(Parititions.Intersections);
17 // Compute Largest Empty Circle
18 places.callAll(Partitions.LEC, points);
19 // Return all Largest Empty Circles
20 Object[] results
21 = places.callAll(Partitions.Collect);
22 // Get The largest empty circle from all the circles
23 max(results);
24 } }
4.3.2 Data-Streaming Approach
Sedona first constructs a convex hull, using the al-
gorithm described in Section 4.1.2. It then gener-
ates a Voronoi diagram from these points, using its
built-in VoronoiDiagramBuilder class. Thereafter,
Sedona clips the diagram along the convex hull edges
to obtain Voronoi polygons. These polygons, com-
bined with the convex hull, help identify candidate
points. The candidate points are then converted to
spatial RDD which gets partitioned, using Sedona’s
EQUALGRID. A nearest neighbor search is applied
to them within each partition to determine the center
and radius of the largest empty circle. Finally, Se-
dona combines all the centers and radiuses from all
partitions to find the one with the largest radius.
4.3.3 Message-Passing Approach
Rank 0 sequentially creates a Voronoi diagram from
input points, using the Fortune’s sweep-line algo-
rithm. It then creates the convex hull as described
in Section 4.1.3. Next, the Voronoi vertices, Voronoi
edges, and the convex hull points are split into parti-
tions and distributed to all MPI ranks. They compute
the intersection points between the subsets of Voronoi
Edges and the Convex Hull edges in their partition.
All the ranks iteratively examine their Voronoi ver-
tices and the intersection points to calculate the radius
to their closest original data point. Their local LECs
are collected at rank 0 that finds the largest one.
4.4 Range Search (RGS)
4.4.1 Agent-Based Approach
Listing 5 outlines agent propagation down over a KD
tree from its root in search for all tree nodes in a given
range. First, MASS creates a KD tree from Graph-
Places (lines 3-4), which is the slowest part of the
code as the tree is recursively constructed from main()
(line 5). Thereafter, the initial agent starts a KD tree
search from its root (line 6) and repeats propagating
its copies along the left/right tree branches (line 7-
10). Upon every propagation down to the next tree
level, agents report back to main() if they encounter
tree nodes within a queried range (lines 8-9). Lines 6-
10 can be repetitively used for responding to different
queries. The MASS implementation’s strength is a
global KD tree construction over distributed memory.
Listing 5: Agent-based range search.
1 public class RGS {
2 public static void main(String args[]) {
3 ArrayList<Point2D> points = getPoints(inputFile);
4 GraphPlaces kdTree = new GraphPlaces("KDTree")
;
5 constructTree(kdTree, points);
6 Agents rovers = new Agents("Rover", kdTree, 1);
7 while( rovers.nAgents() > 0 ) { // tree traverse
8 Object results[] = rovers.callAll(Rover.search);
9 Collections.addAll(results); // range identified
10 rovers.manageAll();
11 } } }
4.4.2 Data-Streaming Approach
Sedona uses SpatialRangeQuery, a built-in function.
It requires only a few parameters to operate: a spatial-
RDD with data points, an Envelope defining the query
boundaries, a spatial predicate, and a boolean to spec-
ify index usage. This configuration enables Sedona to
identify all points within the Envelope in spatialRDD.
Before processing a query, the spatialRDD is parti-
tioned using GridType.EQUALGRID, and results are
subsequently collected.
4.4.3 Message-Passing Approach
First, data points are read from a CSV input file,
equally partitioned, and distributed to all MPI ranks.
Each rank constructs its local KD tree by recursively
selecting dimension X or Y in turn, sorting the local
points in terms of the selected dimension, splitting the
smaller and the larger half in the left and right sub-
trees. Upon a tree completion, a query about finding
points in a given range is passed to all the ranks, each
traversing its own local KD tree. Once all the ranks
have completed querying their trees, MPI Gather() is
called to collect into rank 0 all the points that are
found in a specified range.
4.5 Programmability
Having coded the four benchmark programs with the
three libraries, we summarized their programmabil-
Agent-Based Computational Geometry
519