Changes between Version 77 and Version 78 of PostGIS_Raster_SoC_Idea_2012/Distance_Analysis_Tools


Ignore:
Timestamp:
Jul 28, 2012, 12:24:06 AM (12 years ago)
Author:
qliu
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • PostGIS_Raster_SoC_Idea_2012/Distance_Analysis_Tools

    v77 v78  
    5656<LI><A href=http://trac.osgeo.org/postgis/wiki/PostGIS_Raster_SoC_Idea_2012/Distance_Analysis_Tools#Week7Report>Week 7 Report (July 2nd - July 6th)</A></LI>
    5757<LI><A href=http://trac.osgeo.org/postgis/wiki/PostGIS_Raster_SoC_Idea_2012/Distance_Analysis_Tools#Week8Report>Week 8 Report (July 9th - July 13th)</A></LI>
     58<LI><A href=http://trac.osgeo.org/postgis/wiki/PostGIS_Raster_SoC_Idea_2012/Distance_Analysis_Tools#Week10Report>Week 10 Report (July 23th - July 27th)</A></LI>
    5859</UL>
    5960<br>
     
    833834
    834835 * I will be taking a vacation next week. And I will have to speed it up and continue to work on implementing a plpgsql prototype for Approach 3 in the document after I come back.
     836
     837
     838----
     839{{{
     840#!html
     841<div style='float: right; width:100px;'>
     842<a href="#PostGISRasterSoCIdea2012-DistanceAnalysisToolsforPostGISRaster">&nbsp;&nbsp;&nbsp;<img src="https://lh3.googleusercontent.com/-YR7gUJULQrM/T8nEPQ-AtzI/AAAAAAAAA1M/T_6vRjE8E4Q/s40/scroll_to_top_icon_40x40.png"><br>back to top</a>
     843</div>
     844}}}
     845
     846== Week 10 Report ==
     847
     848'''What did you get done this week?'''
     849 * Wrote plpgsql prototype for implementing Euclidean distance with KNN indexing approach.
     850{{{
     851#!sql
     852----------------------------------------------------------------------
     853-- $Id: st_euclideandistance.sql 2012-07-28 $
     854----------------------------------------------------------------------
     855
     856--------------------------------------------------------------------
     857-- ST_EuclideanDistance - (for one raster) Return a raster generated from a one band reference raster
     858--                        which values are the Euclidean distance
     859--                        from pixel to the points (for now only concerning point geometries)
     860--                        from the input source table of geometries
     861--                        (points for now, lines or polygons in the future).
     862-- Arguments
     863-- refrast raster -  Reference raster align with which Euclidean distance raster will be created.
     864-- pixeltype text - Pixeltype assigned to the resulting raster. By default
     865--                  to be the pixeltype of the reference raster if specified.
     866-- sourceschema text - Database schema of the source geometry table.
     867-- sourcetable text - Source geometry table name.
     868-- sourcegeomcolumn text - Source geometry table geometry column name.
     869-- maxdist double precision - Maximum distance from pixel to the source
     870--                                when the source is too far from the pixel.
     871--                                Pixel that exceeds it will be assigned nodatavalue.
     872--------------------------------------------------------------------
     873DROP FUNCTION IF EXISTS ST_EuclideanDistance(refrast raster, pixeltype text, sourceschema text, sourcetable text, sourcegeomcolumn text, maxdist double precision);
     874CREATE OR REPLACE FUNCTION ST_EuclideanDistance(refrast raster, pixeltype text, sourceschema text, sourcetable text, sourcegeomcolumn text, maxdist double precision)
     875    RETURNS raster AS
     876    $$
     877    DECLARE
     878        width integer;
     879        height integer;
     880        x integer;
     881        y integer;
     882                sourcex float8;
     883                sourcey float8;
     884                sourcexr integer;
     885                sourceyr integer;
     886                newx float8;
     887                newy float8;
     888                newsrid integer;
     889                exesql text;
     890                sourcegeom geometry;
     891        newnodatavalue float8;
     892                newinitialvalue float8;
     893        newrast raster;
     894        newval float8;
     895        newpixeltype text;
     896        newhasnodatavalue boolean := FALSE;
     897                -- Assuming reference raster has only one band
     898                band integer := 1;
     899    BEGIN
     900        -- Check if reference raster is NULL
     901        IF refrast IS NULL THEN
     902            RAISE NOTICE 'ST_EuclideanDistance: Reference raster is NULL. Returning NULL';
     903            RETURN NULL;
     904        END IF;
     905
     906        width := ST_Width(refrast);
     907        height := ST_Height(refrast);
     908                newsrid := ST_SRID(refrast);
     909
     910        -- Create a new empty raster having the same georeference as the provided raster
     911        newrast := ST_MakeEmptyRaster(width, height, ST_UpperLeftX(refrast), ST_UpperLeftY(refrast), ST_ScaleX(refrast), ST_ScaleY(refrast), ST_SkewX(refrast), ST_SkewY(refrast), newsrid);
     912
     913        -- Check if the new raster is empty (width = 0 OR height = 0)
     914        IF ST_IsEmpty(newrast) THEN
     915            RAISE NOTICE 'ST_EuclideanDistance: Raster is empty. Returning an empty raster';
     916            RETURN newrast;
     917        END IF;
     918       
     919        -- Set the new pixeltype
     920        newpixeltype := pixeltype;
     921                -- If pixeltype not specified then use the pixeltype of the reference raster
     922        IF newpixeltype IS NULL THEN
     923            newpixeltype := ST_BandPixelType(refrast, band);
     924        ELSIF newpixeltype != '1BB' AND newpixeltype != '2BUI' AND newpixeltype != '4BUI' AND newpixeltype != '8BSI' AND newpixeltype != '8BUI' AND
     925               newpixeltype != '16BSI' AND newpixeltype != '16BUI' AND newpixeltype != '32BSI' AND newpixeltype != '32BUI' AND newpixeltype != '32BF' AND newpixeltype != '64BF' THEN
     926            RAISE EXCEPTION 'ST_EuclideanDistance: Invalid pixeltype "%". Aborting.', newpixeltype;
     927        END IF;
     928
     929        -- Check for notada value
     930        newnodatavalue := ST_BandNodataValue(refrast, band);
     931        IF newnodatavalue IS NULL OR newnodatavalue < ST_MinPossibleValue(newpixeltype) OR newnodatavalue > (-ST_MinPossibleValue(newpixeltype) - 1) THEN
     932            RAISE NOTICE 'ST_EuclideanDistance: Reference raster do not have a nodata value or is out of range for the new raster pixeltype, nodata value for new raster set to the min value possible';
     933            newnodatavalue := ST_MinPossibleValue(newpixeltype);
     934        END IF;
     935        -- We set the initial value of the resulting raster to nodata value.
     936        -- If nodatavalue is null then the raster will be initialise to ST_MinPossibleValue
     937        newinitialvalue := newnodatavalue;
     938       
     939        -- Create the raster receiving all the computed distance values. Initialize it to the new initial value.
     940        newrast := ST_AddBand(newrast, newpixeltype, newinitialvalue, newnodatavalue);
     941
     942                -- Scan pixels in the raster set pixel value to zero if pixel is source point
     943                -- There is place for optimization here for a more efficient scanning method
     944                FOR x IN 1..width LOOP
     945                        FOR y IN 1..height LOOP
     946                                exesql := "SELECT " || sourcegeomcolumn || " FROM " || sourcetable || ";";
     947                                FOR geom IN EXECUTE(exesql) LOOP
     948                                        sourcex := ST_X(geom);
     949                                        sourcey := ST_Y(geom);
     950                                        sourcexr := ST_World2RasterCoordX(newrast, sourcex, sourcey);
     951                                        sourceyr := ST_World2RasterCoordY(newrast, sourcex, sourcey);
     952                                        IF x = sourcexr AND y = sourceyr THEN
     953                                                newrast := ST_SetValue(newrast, band, x, y, 0);
     954                                        END IF;
     955                                END LOOP;
     956                        END LOOP;
     957                END LOOP;
     958               
     959                -- There is place for optimization here for a more efficient scanning method
     960        FOR x IN 1..width LOOP
     961            FOR y IN 1..height LOOP
     962                                newx := ST_Raster2WorldCoordX(newrast, x, y);
     963                                newy := ST_Raster2WorldCoordY(newrast, x, y);
     964                                -- If pixel is not the source point then compute Eculidean distance
     965                                IF ST_Value(newrast, band, x, y) <> 0 THEN
     966                                        exesql := "SELECT ST_Distance(ST_GeomFromText('POINT(" || newx || " " || newy || ")'," || newsrid || "),ST_Transform(" || sourcegeomcolumn || "," || newsrid || ")) FROM " || sourcetable || " ORDER BY $1 <-> $2 LIMIT 1;";
     967                                        newval := EXECUTE(exesql);
     968                                END IF;
     969                                newrast := ST_SetValue(newrast, band, x, y, newval);
     970            END LOOP;
     971        END LOOP;
     972               
     973                -- There is place for optimization here for a more efficient scanning method
     974        FOR x IN 1..width LOOP
     975            FOR y IN 1..height LOOP
     976                                newx := ST_Raster2WorldCoordX(newrast, x, y);
     977                                newy := ST_Raster2WorldCoordY(newrast, x, y);
     978                                -- If pixel is the source point then Eculidean distance is zero
     979                                IF THEN
     980                                        newval := 0;
     981                                ELSE
     982                                        exesql := "SELECT ST_Distance(ST_GeomFromText('POINT(" || newx || " " || newy || ")'," || newsrid || "),ST_Transform(" || sourcegeomcolumn || "," || newsrid || ")) FROM " || sourcetable || " ORDER BY $1 <-> $2 LIMIT 1;";
     983                                        newval := EXECUTE(exesql);
     984                                END IF;
     985                                newrast := ST_SetValue(newrast, band, x, y, newval);
     986            END LOOP;
     987        END LOOP;
     988        RETURN newrast;
     989    END;
     990    $$
     991    LANGUAGE 'plpgsql';
     992}}}
     993
     994[[BR]][[BR]]
     995''' What do you plan on doing next week?'''
     996
     997 * Test the prototype.
     998 * Start writing document for cost-weighted distance.
     999 * Start writing C implementation for Euclidean distance.