----------------------------------------------------------------------
--- Some simple functions to generate linestring grids and clip
--- polygons by arbitrary linestrings
---
--- $Id: polygon_clipping_functions.sql 4293 2012-04-04 12:15:32Z dk1f0c9 $	
---
--- Copyright (C) 2012 David M. Kaplan
--- Licence: GPL (Gnu Public License)
---
----------------------------------------------------------------------
BEGIN TRANSACTION;

--- Simple function to do matlab style Xmin:DX:Xmax
CREATE OR REPLACE FUNCTION generate_float_series(Xmin float,Xmax float,DX float)
       RETURNS SETOF float AS
$BODY$
SELECT $1 + $3 * generate_series(0,floor(($2-$1)/$3)::int);
$BODY$ LANGUAGE 'sql' IMMUTABLE;

--- Function for making a rectangular point grid
CREATE OR REPLACE FUNCTION 
       ST_MakePointGrid( lnmin float,lnmax float,dx float,
       		       	 ltmin float,ltmax float,dy float ) 
RETURNS geometry AS
$BODY$
SELECT ST_Union(ST_MakePoint(x,y)) 
FROM generate_float_series($1,$2,$3) x, generate_float_series($3,$4,$5) y;
$BODY$ LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION 
       ST_MakePointGrid( dx float, dy float ) 
RETURNS geometry AS
$BODY$
SELECT ST_MakePointGrid(-180,180,$1,-90,90,$2);
$BODY$ LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION 
       ST_MakePointGrid( dx float ) 
RETURNS geometry AS
$BODY$
SELECT ST_MakePointGrid($1,$1);
$BODY$ LANGUAGE 'sql' IMMUTABLE;

--- Function for making a rectangular linestring grid
CREATE OR REPLACE FUNCTION 
       ST_MakeLinestringGrid( lnmin float,lnmax float,dx float,
       		    	      ltmin float,ltmax float,dy float ) 
RETURNS geometry AS
$BODY$
SELECT ST_Union(g) AS g 
FROM
(SELECT ST_MakeLine( 
       ST_MakePoint(i,$4),ST_MakePoint(i,$5) ) AS g 
FROM (SELECT generate_float_series($1,$2,$3) AS i) i
UNION
SELECT ST_MakeLine( 
       ST_MakePoint($1,i),ST_MakePoint($2,i) ) AS g 
FROM (SELECT generate_float_series($4,$5,$6) AS i) i) i;
$BODY$ LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION 
       ST_MakeLinestringGrid( dx float, dy float ) 
RETURNS geometry AS
$BODY$
SELECT ST_MakeLinestringGrid(-180,180,$1,-90,90,$2);
$BODY$ LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION 
       ST_MakeLinestringGrid( dx float ) 
RETURNS geometry AS
$BODY$
SELECT ST_MakeLinestringGrid($1,$1);
$BODY$ LANGUAGE 'sql' IMMUTABLE;

-- Function to make linestring grid based on another geometry
CREATE OR REPLACE FUNCTION 
       ST_MakeLinestringGrid( g geometry, dx float, dy float ) 
RETURNS geometry AS
$BODY$
SELECT ST_MakeLinestringGrid(ST_XMin($1),ST_XMax($1),$2,
		ST_YMin($1),ST_YMax($1),$3);
$BODY$ LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION 
       ST_MakeLinestringGrid( g geometry, dx float ) 
RETURNS geometry AS
$BODY$
SELECT ST_MakeLinestringGrid($1,$2,$2);
$BODY$ LANGUAGE 'sql' IMMUTABLE;


-- Function to cut poly along linestring
CREATE OR REPLACE FUNCTION ST_CutPolyByLinestring (poly geometry,line geometry) 
       RETURNS SETOF geometry AS
$BODY$
DECLARE
	mygeo geometry;
BEGIN
	IF ST_GeometryType(poly) != 'ST_Polygon' THEN
   	   RAISE EXCEPTION 'First argument must be POLYGON';
	ELSIF ST_GeometryType(line) NOT LIKE '%LineString%' THEN
      	   RAISE EXCEPTION 'Second argument must be LINESTRING OR MULTILINESTRING';
	ELSIF ST_SRID(poly) != ST_SRID(line) THEN
      	   RAISE EXCEPTION 'SRID values differ';
	END IF;

	IF ST_NRings(poly) = 1 THEN
	   RETURN QUERY SELECT (ST_Dump(ST_Polygonize(
	   	  ST_Intersection(ST_Union(ST_Boundary($1),$2),$1)))).geom;
	ELSE 
	   FOR mygeo IN SELECT (ST_Dump(ST_Polygonize(
	   	  ST_Intersection(ST_Union(ST_Boundary($1),$2),$1)))).geom LOOP
	       IF ST_Intersects(ST_PointOnSurface(mygeo),poly) THEN
	       	  RETURN NEXT mygeo;
	       END IF;
	   END LOOP;
	END IF;

	RETURN;
END;	   
$BODY$ LANGUAGE 'plpgsql' IMMUTABLE;

END TRANSACTION;
