11

I want to extrude a polygon shape in postgis to create a pseudo 3D effect. To this end I have written a crude function to achieve it. This is very much test code and it creates a new Y vertice for each point on the polygon and then closes it by returning to the original point:-

CREATE OR REPLACE FUNCTION public.extrude_polygon(wkb_geometry_param geometry, height integer, simplify boolean DEFAULT false)
  RETURNS geometry AS
 $BODY$
DECLARE
f int;
ret_geom geometry;
wkb_geometry geometry;
BEGIN

--convert polygon to linestring
IF ST_GeometryType(wkb_geometry_param) != 'ST_Polygon' THEN 
    RETURN NULL;
END IF;

IF simplify THEN
    wkb_geometry =         ST_Simplify(ST_Transform(ST_Exteriorring(wkb_geometry_param), 27700), 0.5);
ELSE
wkb_geometry = ST_Transform(ST_Exteriorring(wkb_geometry_param), 27700);
END IF;

--initialise output geometry
ret_geom =ST_MakeLine(ST_PointN(wkb_geometry,1),ST_PointN(wkb_geometry,1));

--Move first point to up

SELECT ST_AddPoint(ret_geom,
      ST_MakePoint(ST_X(ST_PointN(wkb_geometry, 1)), 
                   ST_Y(ST_PointN(wkb_geometry, 1)) + height)
) into ret_geom;

FOR f IN 1..ST_NPoints(wkb_geometry) LOOP
    IF f < ST_NPoints(wkb_geometry) THEN
    --across to next high point
    SELECT ST_AddPoint(ret_geom,
               ST_MakePoint(ST_X(ST_PointN(wkb_geometry, f + 1)), 
               ST_Y(ST_PointN(wkb_geometry, f + 1)) + height)
    ) into ret_geom;
    --down to next point
    SELECT ST_AddPoint(ret_geom, ST_PointN(wkb_geometry,f + 1)) into ret_geom;
    --back to last point
    SELECT  ST_AddPoint(ret_geom, ST_PointN(wkb_geometry,f)) into ret_geom;
    --back then up again
    SELECT ST_AddPoint(ret_geom, ST_PointN(wkb_geometry,f + 1)) into ret_geom;
    SELECT ST_AddPoint(ret_geom,
               ST_MakePoint(ST_X(ST_PointN(wkb_geometry, f + 1)), 
               ST_Y(ST_PointN(wkb_geometry, f + 1)) + height)
    ) into ret_geom;
ELSE
    --across to first high point
    SELECT ST_AddPoint(ret_geom,
               ST_MakePoint(ST_X(ST_PointN(wkb_geometry, 1)), 
               ST_Y(ST_PointN(wkb_geometry, 1)) + height)
           ) into ret_geom;

    SELECT ST_AddPoint(ret_geom, ST_PointN(wkb_geometry,1)) into ret_geom;

END IF;
END LOOP;

RETURN ST_Buffer(ST_Buffer(ST_MakePolygon(ret_geom),10), -10);


END;

$BODY$
  LANGUAGE plpgsql

It works with simple polygons but has problems with interior rings, but the main issue is that it is really slow. I need to output the resultant shape as a polygon that can be shaded and rendered in mapserver. Hence the buffer operations at the end which is the only way I know of reducing the shape to it's outline.

The end result will be an extruded shape representing the original polygon. I can then offset the original polygon by the same extrusion distance and place it on top to make the roof. enter image description here

I considered using the ST_Extrude function in postgis-2.1.1 BUT this creates a ST_PolyhedralSurface type and I am not able to render it in mapserver. As far as I can tell there is no way to create an outline of this either as ST_Buffer does not work with ST_polyhedralsurfaces.

So, my question is, can my function be improved? Or is there a better approach. The output needs to look as per the diagram which I created by placing the offset polygon onto my extruded shape.

3

A fast solution for very simple polygons like circles. Results in 2 different tables which have to be rendered in the right direction.

-Table poly with input polygon(s)

-Table poly_prj with polygon from projected points

WITH points AS (
  SELECT (ST_DumpPoints(geom)).geom AS geom 
FROM poly
  SELECT 
    ST_MakePolygon(
      ST_MakeLine(
        ST_Project(geom, 5000, radians(0.0))::geometry)) AS geom 
  FROM points;

-Table cvx with a convex hull of the 2 features.

Table poly_prj has to be on top of the table cvx.

After that you can play with the new fill options in QGIS 2.10!

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.