@Test
  public void testRing() {
    List<Point> pts = new ArrayList<Point>();
    pts.add(new Point(0.0, 0.0));
    pts.add(new Point(0.0, 1.0));
    pts.add(new Point(1.0, 2.0));
    pts.add(new Point(2.0, 1.0));
    pts.add(new Point(1.0, 0.0));
    pts.add(new Point(0.0, 0.0));
    LinearRing geo = new LinearRing(pts, true);
    assertEquals(1, geo.getNumParts());
    assertEquals(pts.size(), geo.getNumPoints());
    assertFalse(geo.is3D());
    // center: (1.0' 0" E, 1.0' 0" N)
    Geodetic2DPoint center = geo.getCenter();
    assertEquals(1.0, center.getLatitudeAsDegrees(), EPSILON);
    assertEquals(1.0, center.getLongitudeAsDegrees(), EPSILON);

    geo = new LinearRing(geo.getBoundingBox());
    assertEquals(1, geo.getNumParts());
    assertEquals(5, geo.getNumPoints());
    // center: (1.0' 0" E, 1.0' 0" N)
    center = geo.getCenter();
    assertEquals(1.0, center.getLatitudeAsDegrees(), EPSILON);
    assertEquals(1.0, center.getLongitudeAsDegrees(), EPSILON);
  }
  /** This method performs format conversions with string constructors in degrees and dms */
  public void testRandomEquals() {
    for (int i = 0; i < 1000; i++) {
      Geodetic3DPoint a1 = randomGeoPoint(r);
      Geodetic3DPoint a2 =
          new Geodetic3DPoint(a1.getLongitude(), a1.getLatitude(), a1.getElevation());
      // note by making equals() work in round off errors (such as in this case) using
      // Angle.equals() vs phi1=phi2 && lamb1==lamb2
      // but break contract in hashCode such that a.equals(b) -> true but hashCode(a) may not equal
      // hashCode(b)
      assertEquals(a1, a2);
      assertEquals(a1.hashCode(), a2.hashCode());

      // for symmetric tests to work elevation must be non-zero
      final double elevation = a1.getElevation();
      if (elevation == 0.0 || Math.abs(elevation) < 1e-8) a1.setElevation(1234.5);

      // test symmetric equals tests a.equals(b) -> b.equals(a)
      Geodetic2DPoint pt2 = new Geodetic2DPoint(a1.getLongitude(), a1.getLatitude());
      assertFalse(pt2.equals(a1));
      assertFalse(a1.equals(pt2));
      a1.setElevation(0);
      assertEquals(pt2, a1); // pt2.equals(al) -> a1.equals(pt2)
      assertEquals(a1, pt2);
    }
  }
 /** Test 2d vs 3d points with 3d elavations at/close to 0 */
 public void testMismatchedEquals() {
   Geodetic2DPoint p1 = makePoint(-81.9916466079043, 29.9420387052815, 5000.1);
   Geodetic2DPoint p2 = makePoint(-81.9916466079043, 29.9420387052815, 0.0);
   if (p1.equals(p2)) fail("different elevation but equals() == true");
   if (p2.equals(p1)) fail("different elevation but equals() == true");
   Geodetic2DPoint p3 = makePoint(-81.9916466079043, 29.9420387052815);
   assertEquals("2d with elev=0 and 3d point same lat/lon", p2, p3);
   assertEquals("2d with elev=0 and 3d point same lat/lon", p3, p2);
   Geodetic2DPoint p4 = makePoint(-81.9916466079043, 29.9420387052815, 1e-6);
   // assertEquals(p3, new Geodetic2DPoint(p4.getLongitude(), p4.getLatitude()));
   assertEquals("3d with elev=1e-4 and 3d point same lat/lon", p2, p4);
   assertEquals("3d with elev=1e-4 and 3d point same lat/lon", p4, p2);
   assertEquals("3d with elev=1e-4 and 3d point same lat/lon", p3, p4);
 }
  @Test
  public void testMultiLine() {
    List<Line> lines = new ArrayList<Line>();
    List<Point> pts = new ArrayList<Point>();
    for (int i = 0; i < 10; i++) {
      pts.add(new Point(i * .01 + 0.1, i * .01 + 0.1, true)); // sets 0.0 elevation
    }
    Line line = new Line(pts);
    line.setTessellate(false);
    line.setAltitudeMode(AltitudeModeEnumType.clampToGround);
    lines.add(line);
    pts = new ArrayList<Point>();
    for (int i = 0; i < 10; i++) {
      pts.add(new Point(i * .02 + 0.2, i * .02 + 0.2, 100));
    }
    line = new Line(pts);
    line.setTessellate(true);
    lines.add(line);
    Geometry geo = new MultiLine(lines);
    assertEquals(2, geo.getNumParts());
    assertEquals(20, geo.getNumPoints());
    assertTrue(geo.is3D());
    Geodetic2DBounds bounds = geo.getBoundingBox();
    assertTrue(bounds instanceof Geodetic3DBounds);
    // bounding box of MultiLine must contain bounding box for each of its lines
    assertTrue(bounds.contains(line.getBoundingBox()));

    // (0� 14' 24" E, 0� 14' 24" N) @ 0m
    final Geodetic2DPoint cp = geo.getCenter();
    System.out.println("multiline center=" + cp);
    assertEquals(0.24, cp.getLatitudeAsDegrees(), EPSILON);
    assertEquals(0.24, cp.getLongitudeAsDegrees(), EPSILON);

    List<Point> points = geo.getPoints(); // all 20 points
    assertEquals(20, points.size());
    for (int i = 0; i < 10; i++) {
      assertEquals(pts.get(i), points.get(i + 10));
    }

    List<Geometry> geometries = new ArrayList<Geometry>();
    geometries.add(pts.get(0));
    geometries.add(line);
    geo = new GeometryBag(geometries);
    assertEquals(2, geo.getNumParts());
    assertTrue(geo.is3D());
  }
  @Test
  public void testGeometryBag() {
    List<Geometry> geometries = new ArrayList<Geometry>();
    geometries.add(new Point(2.0, 2.0));
    List<Point> points = new ArrayList<Point>();
    points.add(new Point(0.0, 0.0));
    points.add(new Point(0.0, 1.0));
    points.add(new Point(1.0, 0.0));
    final Line line = new Line(points);
    geometries.add(line);
    GeometryBag geo = new GeometryBag(geometries);
    assertEquals(2, geo.size()); // number of geometries
    assertEquals(2, geo.getNumParts()); // aggregate parts of all geometries
    assertNotNull(geo.getPart(0));
    assertNull(geo.getPart(2));
    assertEquals(1 + points.size(), geo.getNumPoints());
    assertFalse(geo.is3D());
    assertTrue(geo.contains(line));
    assertFalse(geo.isEmpty());

    // center = (1� 15' 0" E, 1� 15' 0" N)
    final Geodetic2DPoint cp = geo.getCenter();
    assertEquals(1.0, cp.getLatitudeAsDegrees(), EPSILON);
    assertEquals(1.0, cp.getLongitudeAsDegrees(), EPSILON);

    geo.clear();
    assertEquals(0, geo.size());
    assertEquals(0, geo.getNumParts());
    assertTrue(geo.isEmpty());
    assertFalse(geo.is3D());

    geometries.clear();
    final Point pt = new Point(30.0, 40.0, 400);
    geometries.add(pt);
    geo = new GeometryBag(geometries);
    assertEquals(1, geo.size());
    assertTrue(geo.is3D());
    Object[] objs = geo.toArray();
    assertTrue(objs.length == 1);
    assertTrue(geo.remove(pt));
    assertEquals(0, geo.size());
    assertNull(geo.getBoundingBox());
  }
  @Test
  public void testClippedAtDateLine() {
    // create outline of Fiji islands which wrap international date line
    List<Point> pts = new ArrayList<Point>();
    final Point firstPt = new Point(-16.68226928264316, 179.900033693558);
    pts.add(firstPt);
    pts.add(new Point(-16.68226928264316, -180));
    pts.add(new Point(-17.01144405215603, -180));
    pts.add(new Point(-17.01144405215603, 179.900033693558));
    pts.add(firstPt);
    Line line = new Line(pts);
    assertTrue(line.clippedAtDateLine());

    // (179� 57' 0" E, 16� 50' 49" S)
    Geodetic2DPoint cp = line.getCenter();
    // System.out.println("Fctr=" + cp.getLatitudeAsDegrees() + " " + cp.getLongitudeAsDegrees());
    assertEquals(-16.846856667399592, cp.getLatitudeAsDegrees(), EPSILON);
    assertEquals(179.950016846779, cp.getLongitudeAsDegrees(), EPSILON);

    LinearRing ring = new LinearRing(pts, true);
    assertTrue(ring.clippedAtDateLine());
    assertEquals(cp, ring.getCenter());
  }
  @Test
  public void testPolygon() {
    List<Point> pts = new ArrayList<Point>(6);
    // Outer LinearRing in Polygon must be in clockwise point order
    pts.add(new Point(0.0, 0.0));
    pts.add(new Point(1.0, 0.0));
    pts.add(new Point(2.0, 1.0));
    pts.add(new Point(1.0, 2.0));
    pts.add(new Point(0.0, 1.0));
    pts.add(new Point(0.0, 0.0));
    final LinearRing ring = new LinearRing(pts, true);
    Polygon geo = new Polygon(ring, true);
    assertEquals(1, geo.getNumParts());
    assertNotNull(geo.getPart(0));
    assertEquals(pts.size(), geo.getNumPoints());
    assertFalse(geo.is3D());
    Geodetic2DPoint cp = geo.getCenter();
    // center: (1.0' 0" E, 1.0' 0" N)
    assertEquals(1.0, cp.getLatitudeAsDegrees(), EPSILON);
    assertEquals(1.0, cp.getLongitudeAsDegrees(), EPSILON);

    // create new polygon with outer and inner ring
    pts = new ArrayList<Point>();
    pts.add(new Point(0.2, 0.2));
    pts.add(new Point(0.2, 0.8));
    pts.add(new Point(0.8, 0.8));
    pts.add(new Point(0.8, 0.2));
    pts.add(new Point(0.2, 0.2));
    LinearRing ir = new LinearRing(pts);
    geo = new Polygon(ring, Collections.singletonList(ir));
    assertEquals(2, geo.getNumParts());
    assertEquals(ring.getNumPoints() + ir.getNumPoints(), geo.getNumPoints());
    cp = geo.getCenter();
    // center: (1.0' 0" E, 1.0' 0" N)
    assertEquals(1.0, cp.getLatitudeAsDegrees(), EPSILON);
    assertEquals(1.0, cp.getLongitudeAsDegrees(), EPSILON);
  }
  @Test
  public void testLineBBox() {
    double lat = 40.0 + (5.0 * RandomUtils.nextDouble());
    double lon = 40.0 + (5.0 * RandomUtils.nextDouble());
    Geodetic2DPoint pt1 =
        new Geodetic2DPoint(new Longitude(lon, Angle.DEGREES), new Latitude(lat, Angle.DEGREES));
    Geodetic2DBounds bbox = new Geodetic2DBounds(pt1);
    try {
      // single point bbox - line requires at least 2 points
      new Line(bbox);
      fail("Expected to throw Exception");
    } catch (IllegalArgumentException iae) {
      // expected
    }
    try {
      new LinearRing(bbox); // ring requires at least 4 points
      fail("Expected to throw Exception");
    } catch (IllegalArgumentException iae) {
      // expected
    }

    Geodetic2DPoint pt2 =
        new Geodetic2DPoint(new Longitude(lon + 10, Angle.DEGREES), pt1.getLatitude());
    bbox = new Geodetic2DBounds(pt1, pt2);
    Line line = new Line(bbox);
    assertEquals(2, line.getNumPoints());
    try {
      // 2-point line bbox - ring requires at least 4 points
      new LinearRing(bbox);
      fail("Expected to throw Exception");
    } catch (IllegalArgumentException iae) {
      // expected
    }

    Geodetic2DPoint pt3 =
        new Geodetic2DPoint(pt1.getLongitude(), new Latitude(lat + 10, Angle.DEGREES));
    bbox = new Geodetic2DBounds(pt1, pt3);
    line = new Line(bbox);
    assertEquals(2, line.getNumPoints());
    try {
      // 2-point line bbox - ring requires at least 4 points
      new LinearRing(bbox);
      fail("Expected to throw Exception");
    } catch (IllegalArgumentException iae) {
      // expected
    }

    Geodetic2DPoint pt4 = new Geodetic2DPoint(pt2.getLongitude(), pt3.getLatitude());
    line = new Line(new Geodetic2DBounds(pt1, pt4));
    assertEquals(5, line.getNumPoints());
  }