11

I want to create linestrings with a definite angle (e.g. 160°) and length (e.g. 2m) that are fixed to a number of points of another linestring. So, I want to use the ST_DumpPoints function to find the points and bind the created linestrings to them. Is there a way to declare an angle (α) during the linestring creation? Here is an example picture:

enter image description here

I want to create the blue linestrings.

EDIT

The angle (α2) in the picture isn't really exemplary. But rather an azimuth of 160° (like α1).

UPDATE

The answer from Evil Genius helped me calculating the maximum width of a polygon with a given aspect.

1 Answer 1

14
+50

You could accomplish this a few different ways depending on what sort of output you are wanting, but the concept is the same. It's generally easier to do a simple rotation followed by a translation rather than trying to calculate the coordinates in a single step.

In this case, the basic steps are:

  • Create a line of the desired length at the origin (0,0). This line should run along the axis that you wish to measure your angle from and have it's center at the origin.
  • Rotate the line around the origin.
  • Translate the line by the coordinates of the point that you want it to be centered on.

The following PostGIS view creates the lines from your example scenario. A few things are assumed:

  • The geometry column is called shape
  • The angle is measured from the x axis. Your example drawing was a bit confusing since you first mentioned 40 degrees, drew a dotted vertical line, but then said it should be around 160 degrees. I've interpreted that to mean you actually want to measure from the x axis.
  • The data is projected in the same units that you want to measure with (ie. meters).

    CREATE OR REPLACE VIEW <viewname> AS
    WITH vertices AS
    (SELECT 
          objectid, 
          (ST_DumpPoints(shape)).path[1] AS v_id, 
          (ST_DumpPoints(shape)).geom AS vertex
    FROM <source_data>
    )
    SELECT
        objectid,
        v_id,
        ST_SetSRID(ST_Translate(ST_Rotate(ST_MakeLine(ST_MakePoint( 1.0,0.0), 
                                                      ST_MakePoint(-1.0,0.0)),
                                          radians(40)), ST_X(vertex), ST_Y(Vertex)),
                                          ST_SRID(vertex)) AS newline
    FROM vertices
    

To break down what's actually going on with that last line, starting from the inner most: ST_SetSRID(ST_Translate(ST_Rotate(ST_MakeLine(ST_MakePoint( 0,1.0), ST_MakePoint(0,-1.0)), radians(40)), ST_X(vertex), ST_Y(Vertex)), ST_SRID(vertex)) AS newline

  • ST_MakePoint(1.0,0.0) and ST_MakePoint(-1.0,0.0): Create the endpoints for a horizontal line that is our desired length and centered on the origin.
  • ST_MakeLine(...): Use our newly created end points to create a line.
  • ST_Rotate(..., radians(40)): Rotate that new line around the origin.
  • ST_Translate(..., ST_X(vertex), ST_Y(vertex)): Center the rotated line onto our reference (input) point.
  • ST_SetSRID(..., ST_SRID(vertex)): Give the new line the same SRID as the input geometry.

If you are using PostGIS 2.0 you can simplify this since you can specify a different origin for ST_Rotate. If you want to rotate to an angle based on the slope of the line, you'll have to calculate that first and add it to the rotation angle.

If the data isn't projected in the same units that you want to measure in you can still do something similar, but you'll need an extra step:

  • Create a line (projected in something that uses what you want to measure in)
  • Rotate
  • Reproject to your target projection
  • Translate to the target point

Edit

I now understand what you mean by the angle. Essentially, you want a rotation clockwise from the Y axis (0 is up, 90 is right, 180 is down, etc.).

You do still need to use the radians function since ST_Rotate expect the angle in radians. You should be able to get the correct angle with two small changes:

  • Start with a vertical line (use ST_MakePoint(0.0,1.0) and ST_MakePoint(0.0,-1.0))
  • Multiply your angle by -1. This will make it negative, causing ST_rotate to rotate it in a clockwise direction. radians(<angle> * -1)
3
  • You're an evil genius! Thank You. It works perfect, but setting up the right angle. I work with angles (stored in a column), which are like an exposition or aspect (0 to 360 degrees). An aspect of 200° for example (like geo direction SSW): when I plot the linestrings they have not the right angle. Using degrees() the geo direction is like SSE and using radians() like SW.
    – Stefan
    Commented Oct 31, 2013 at 13:54
  • @StefanB. I'm glad it was helpful! I've edited my answer (very bottom) to show how you should be able to accomplish the angle you want. Commented Oct 31, 2013 at 14:08
  • It works. Brilliant idea!
    – Stefan
    Commented Oct 31, 2013 at 14:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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