### ----------------------------------------------------
### -- GEOS
### -- Licenses: MIT
### -- Authors: Brian Duggan
### -- File: t/07-more.rakutest
### ----------------------------------------------------
use Test;
use GEOS::Geometry;

plan 58;

# Test point coordinates
my $point = GEOS::Geometry.from-geojson('{"type":"Point","coordinates":[1,4]}');
is $point.x, 1, 'x coordinate';
is $point.y, 4, 'y coordinate';
is $point.z, NaN, 'z coordinate';
is $point.geometry-type, 'Point', 'geometry type';
is $point.dimension, 0, 'point dimension';
ok !$point.is-empty, 'point is not empty';
ok $point.is-valid, 'point is valid';
ok $point.is-simple, 'point is simple';

# Test polygon properties
my $polygon = GEOS::Geometry.from-geojson('{"type":"Polygon","coordinates":[[[0,0],[0,4],[4,4],[4,0],[0,0]]]}');
is $polygon.geometry-type, 'Polygon', 'polygon type';
is $polygon.dimension, 2, 'polygon dimension';
is-approx $polygon.area, 16.0, 'polygon area';
is-approx $polygon.length, 16.0, 'polygon perimeter';

# Test geometric operations
my $buffered = $point.buffer(1);
ok $buffered.area > 3.1, 'buffer creates larger area';
ok $buffered.area < 3.15, 'buffer area is reasonable';

my $centroid = $polygon.centroid;
is-approx $centroid.x, 2.0, 'centroid x';
is-approx $centroid.y, 2.0, 'centroid y';

my $env = $polygon.envelope;
is $env.geometry-type, 'Polygon', 'envelope type';
is-approx $env.area, 16.0, 'envelope area';

# Test serialization
my $wkt = $point.wkt;
like $wkt, /^'POINT'/, 'WKT format';

my $geojson = $point.geojson;
like $geojson, /'Point'/, 'GeoJSON format';

# Test geometric set operations
my $rect1 = GEOS::Geometry.from-geojson('{"type":"Polygon","coordinates":[[[0,0],[0,2],[2,2],[2,0],[0,0]]]}');
my $rect2 = GEOS::Geometry.from-geojson('{"type":"Polygon","coordinates":[[[1,1],[1,3],[3,3],[3,1],[1,1]]]}');

my $intersection = $rect1.intersection($rect2);
is-approx $intersection.area, 1.0, 'intersection area';

my $union = $rect1.union($rect2);
is-approx $union.area, 7.0, 'union area';

my $difference = $rect1.difference($rect2);
is-approx $difference.area, 3.0, 'difference area';

my $sym_diff = $rect1.sym-difference($rect2);
is-approx $sym_diff.area, 6.0, 'symmetric difference area';

# Test spatial predicates
my $point1 = GEOS::Geometry.from-geojson('{"type":"Point","coordinates":[1,1]}');
my $point2 = GEOS::Geometry.from-geojson('{"type":"Point","coordinates":[5,5]}');
my $circle = $point1.buffer(2);

ok $circle.contains($point1), 'circle contains center point';
nok $circle.contains($point2), 'circle does not contain distant point';
ok $point1.within($circle), 'point is within circle';
ok $rect1.intersects($rect2), 'rectangles intersect';
nok $point1.equals($point2), 'different points are not equal';

# Test distance operations
is-approx $point1.distance-to($point2), 5.656854249492381, 'point-to-point distance';
my $point3 = GEOS::Geometry.from-geojson('{"type":"Point","coordinates":[2,2]}');
is-approx $point1.distance-to($point3), 1.4142135623730951, 'diagonal distance';

# Test minimum bounding shape
my $diagonal_line = GEOS::Geometry.from-geojson('{"type":"LineString","coordinates":[[0,0],[1,1],[2,2]]}');
my $buffer = $diagonal_line.buffer(0.1);  # Create a small buffer to ensure area
ok $buffer.area > 0, 'buffered line has area';
ok $buffer.contains($diagonal_line), 'buffer contains original line';

# Test with a polygon instead
my $triangle = GEOS::Geometry.from-geojson('{"type":"Polygon","coordinates":[[[0,0],[1,1],[2,0],[0,0]]]}');
my $triangle_env = $triangle.oriented-envelope;
ok $triangle_env.area > 0, 'triangle envelope has area';
ok $triangle_env.contains($triangle), 'envelope contains original triangle';

# Test boundary operations
my $boundary = $rect1.boundary;
is-approx $boundary.length, 8.0, 'rectangle boundary length';

# Test convex hull
my $points = GEOS::Geometry.from-geojson('{"type":"MultiPoint","coordinates":[[0,0],[1,1],[2,0]]}');
my $hull = $points.convex-hull;
is-approx $hull.area, 1.0, 'triangle hull area';

# Test simplification
my $complex_line = GEOS::Geometry.from-geojson('{"type":"LineString","coordinates":[[0,0],[0.1,0.1],[0.2,0],[0.3,0.1],[1,1]]}');
my $simple_line = $complex_line.simplify(0.2);
ok $simple_line.length < $complex_line.length, 'simplification reduces length';

# Test topology operations
my $multi_point = GEOS::Geometry.from-geojson('{"type":"MultiPoint","coordinates":[[0,0],[1,1],[2,2]]}');
is $multi_point.get-num-geometries, 3, 'correct number of geometries in MultiPoint';
my $first_point = $multi_point.get-geometry-n(0);
is $first_point.x, 0, 'first point x coordinate';
is $first_point.y, 0, 'first point y coordinate';

# Test polygon rings
my $polygon_with_hole = GEOS::Geometry.from-geojson('{"type":"Polygon","coordinates":[[[0,0],[10,0],[10,10],[0,10],[0,0]],[[2,2],[2,8],[8,8],[8,2],[2,2]]]}');
is $polygon_with_hole.get-num-interior-rings, 1, 'one interior ring';
my $exterior = $polygon_with_hole.get-exterior-ring;
my $interior = $polygon_with_hole.get-interior-ring-n(0);
ok $exterior.length > $interior.length, 'exterior ring longer than interior';

# Test spatial predicates
my $point_on_boundary = GEOS::Geometry.from-geojson('{"type":"Point","coordinates":[5,0]}');
my $point_outside = GEOS::Geometry.from-geojson('{"type":"Point","coordinates":[20,20]}');
ok $polygon_with_hole.touches($point_on_boundary), 'point touches polygon boundary';
ok $polygon_with_hole.disjoint($point_outside), 'point is disjoint from polygon';

# Test line operations
my $line1 = GEOS::Geometry.from-geojson('{"type":"LineString","coordinates":[[0,0],[2,2]]}');
my $line2 = GEOS::Geometry.from-geojson('{"type":"LineString","coordinates":[[2,0],[0,2]]}');
ok $line1.crosses($line2), 'lines cross';
my $shared = $line1.shared-paths($line2);
like $shared.wkt, /EMPTY/, 'no shared paths';

# Test snapping
my $point_near = GEOS::Geometry.from-geojson('{"type":"Point","coordinates":[0.1,0.1]}');
my $snapped = $point_near.snap-to($line1, 0.2);
ok $snapped.distance-to($line1) < 0.0001, 'point snapped to line';

# Test Frechet distance
my $curve1 = GEOS::Geometry.from-geojson('{"type":"LineString","coordinates":[[0,0],[1,1],[2,2]]}');
my $curve2 = GEOS::Geometry.from-geojson('{"type":"LineString","coordinates":[[0,0],[1,0],[2,0]]}');
ok $curve1.frechet-distance($curve2) > 0, 'Frechet distance is positive';
ok $curve1.frechet-distance($curve2) >= $curve1.hausdorff-distance($curve2), 'Frechet distance >= Hausdorff distance';

# Test invalid geometry fixing
my $invalid_polygon = GEOS::Geometry.from-geojson('{"type":"Polygon","coordinates":[[[0,0],[1,1],[1,0],[0,1],[0,0]]]}');
my $valid_polygon = $invalid_polygon.make-valid;
ok $valid_polygon.is-valid, 'geometry was made valid';

# Test covers/covered-by
my $big_square = GEOS::Geometry.from-geojson('{"type":"Polygon","coordinates":[[[0,0],[10,0],[10,10],[0,10],[0,0]]]}');
my $small_square = GEOS::Geometry.from-geojson('{"type":"Polygon","coordinates":[[[1,1],[2,1],[2,2],[1,2],[1,1]]]}');
ok $big_square.covers($small_square), 'big square covers small square';
ok $small_square.covered-by($big_square), 'small square is covered by big square';

# Test unary union on multigeometry
my $multi_polygon = GEOS::Geometry.from-geojson('{"type":"MultiPolygon","coordinates":[[[[0,0],[1,0],[1,1],[0,1],[0,0]]],[[[0.5,0.5],[1.5,0.5],[1.5,1.5],[0.5,1.5],[0.5,0.5]]]]}');
my $unified = $multi_polygon.unary-union;
ok $unified.get-num-geometries == 1, 'overlapping polygons were unified';

# Test normalization
my $norm = GEOS::Geometry.from-geojson('{"type":"LineString","coordinates":[[2,2],[1,1],[0,0]]}');
ok $norm.normalize, 'normalized geometry';
is $norm.wkt, 'LINESTRING (0 0, 1 1, 2 2)', 'geometry was normalized';

my $line = GEOS::Geometry.from-geojson('{"type":"LineString","coordinates":[[0,0],[1,1],[2,2]]}');
my @coords = $line.get-coordinates;
#my $reversed = $line.reverse;
#my @coords = $reversed.get-coordinates;
#is-deeply @coords, [[2,2], [1,1], [0,0]], 'reversed coordinates are correct';

# Test precision setting
my $pt = GEOS::Geometry.from-geojson('{"type":"Point","coordinates":[1.23456789,2.34567890]}');
my $precise_point = $pt.set-precision(0.01);
is $precise_point.x, 1.23, 'x coordinate rounded correctly';
is $precise_point.y, 2.35, 'y coordinate rounded correctly';

done-testing;


