
// Covers.java
// Murat Öksüzer, April 2021
// https://www.smartycoder.com/2021/04/geometry-model-jts-tutorial-1.html
// Modified by Andrew Davison, ad@coe.psu.ac.th, March 2023

/* Generate a random set of NUM_PTS points and apply three
   different point covering. In turn:
     * Delaunay Triangulation
        -- the triangulation and the component triangles are displayed
           in GeomsViewer
     * Voronoi diagramming
        -- the partitioning of the points and the resulting polygons 
           are displayed
     * Convex Hull

   Usage:
    > compile Covers.java
    > run Covers

  When prompted, press <enter> on the command line to move 
  to the next example.

  For:
   * Constrained Delaunay  -- see Triangulate.java
   * Polygon Triangulation

   * Conforming Delaunay   -- see Conforming.java

   * Concave Hull -- see Concanvity.java 
*/


import java.util.*;

import org.locationtech.jts.geom.*;
import org.locationtech.jts.triangulate.*;


public class Covers
{
  private static final int NUM_PTS = 20;

  private static GeomsViewer gv;
  private static GeometryFactory gf;


  public static void main(String[] args)
  {
    gv = Utils.view("Point Covers");
    gf = new GeometryFactory();
    Random rand = new Random();

    // generate random points
    gv.setTitle("Points");
    List<Coordinate> coords = new ArrayList<>();
    for(int i = 1; i <= NUM_PTS; i++) {
      int x = rand.nextInt(405) + 25;
      int y = rand.nextInt(405) + 20;
      coords.add(new Coordinate(x,y));
      gv.add(Utils.makePoint(x,y));
    }
    Utils.waitEnter();
    gv.clear();

    applyDelaunay(coords);

    // redisplay coordinates
    gv.setTitle("Points");
    for(Coordinate coord : coords)
      gv.add( gf.createPoint(coord));
    Utils.waitEnter();

    applyVoronoi(coords);

    // redisplay coordinates
    gv.setTitle("Points");
    for(Coordinate coord : coords)
      gv.add( gf.createPoint(coord));
    Utils.waitEnter();

    // create convex hull
    gv.setTitle("Convex Hull");
    Coordinate[] coordsArr = coords.toArray(new Coordinate[0]); 
    MultiPoint pts = gf.createMultiPointFromCoords(coordsArr);
    Geometry hull = pts.convexHull();
    gv.add(hull);
    System.out.println("Hull: " + hull);
    Utils.waitEnter();

    gv.close();
  } /* main */


  private static void applyDelaunay(List<Coordinate> coords)
  {
    DelaunayTriangulationBuilder dtBuilder =
                        new DelaunayTriangulationBuilder();
    dtBuilder.setSites(coords);
    GeometryCollection polys = 
         (GeometryCollection) dtBuilder.getTriangles(gf);

    gv.setTitle("Delaunay Triangulation");
    gv.add(polys);
    Utils.waitEnter();
    gv.clear();

    // extract each triangle and display separately
    gv.setTitle("Delaunay Triangles");
    System.out.println("Delaunay Triangles:");
    int count = polys.getNumGeometries();
    for(int i = 0; i < count; i++) {
      Geometry tri = polys.getGeometryN(i);
      gv.add("tri" + (i+1), tri);
      System.out.println((i+1) + ". " + tri);
    }
    Utils.waitEnter();
    gv.clear();
  }  // end of applyDelaunay()


  private static void applyVoronoi(List<Coordinate> coords)
  {
    VoronoiDiagramBuilder vdBuilder =
                        new VoronoiDiagramBuilder();
    vdBuilder.setSites(coords);
    GeometryCollection polys = 
         (GeometryCollection) vdBuilder.getDiagram(gf);

    gv.setTitle("Voronoi Partitions");
    gv.add(polys);
    Utils.waitEnter();
    gv.remove(polys);

    // extract each poly and display separately
    gv.setTitle("Voronoi Polygons");
    System.out.println("Voronoi Polygons:");
    int count = polys.getNumGeometries();
    for(int i = 0; i < count; i++) {
      Geometry poly = polys.getGeometryN(i);
      gv.add("poly" + (i+1), poly);
      System.out.println((i+1) + ". " + Utils.simplify(poly));
    }
    Utils.waitEnter();
    gv.clear();
  }  // end of applyVoronoi()


}  // end of Covers class
