1

I'm trying to write code to generate fixtures for a Django/GeoDjango project. I need to generate geometry for arcs (line string) given three lat/long pairs; start of arc, end of arc and centre of arc. I read through the GeoDjango documentation but this functionality doesn't seem to be available. Does anyone know if there is a Python library that provides this functionality? Or does anyone have an algorithm I can port to Python?

4
  • what kind of arc: a LineString, a curve ?
    – gene
    Commented Jul 11, 2014 at 17:07
  • Oh sorry, a line string. Commented Jul 11, 2014 at 18:48
  • If you're underlying database is postgis, it supports curves, IE ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406) from postgis.net/docs/ST_CurveToLine.html
    – DPierce
    Commented Jul 24, 2014 at 3:14
  • Thanks. I was originally using a plpgsql function that generates an arc from the three coordinate pairs. Unfortunately, we are re-designing our installer, which means the data is now written to json files instead of being loaded straight into PostGIS/PostgreSQL. So I can't use the function anymore and I have to generate the arg geometry using Python. Commented Jul 24, 2014 at 10:50

2 Answers 2

0

Shapely PyQGIS, and GeoDjango use the same API based on the GEOS library:

With Shapely:

with a list of points:

from shapely.geometry import Point, LineString, mapping
pt1 = Point(0,0)
pt2 = Point(20,20)
pt3 = Point (50,50)
line = LineString([pt1,pt2,pt3])
#GeoJSON format
print mapping(line)
{'type': 'LineString', 'coordinates': ((0.0, 0.0), (20.0, 20.0), (50.0, 50.0))}

or with a list of coordinates:

line = LineString([(0, 0), (20,20),(50,50)])
#GeoJSON format
print mapping(line)
{'type': 'LineString', 'coordinates': ((0.0, 0.0), (20.0, 20.0), (50.0, 50.0))}

with PyQGIS:

with a list of points:

line = QgsGeometry.fromPolyline([QgsPoint(0,0),QgsPoint(20,20),QgsPoint(50,50)])
#GeoJSON format
print line.exportToGeoJSON()
{ "type": "LineString", "coordinates": [ [0, 0], [20, 20], [50, 50] ] }

with GeoDjango (look at Django: GEOS API)

with a list of coordinates:

from django.contrib.gis.geos import LineString
line = LineString((0, 0), (20, 20), (50, 50))
# GeoJSON format
print line.json
{ "type": "LineString", "coordinates": [ [ 0.0, 0.0 ], [ 20.0, 20.0 ], [ 50.0, 50.0 ] ] }

The resulting line is made up of two segments: (0,0) to (20,20) and (20,20) to (50,50)

enter image description here

5
  • Thanks but this doesn't give me an arc, it only gives me a line between three points. Commented Jul 12, 2014 at 0:52
  • 1
    ""Oh sorry, a line string" -> what is an arc ? a segment of a LineString ?
    – gene
    Commented Jul 12, 2014 at 7:47
  • I found this image after a quick search that hopefully shows what I'm after. I may be using the wrong terminology so I apologise if I'm confusing people. Refer to item "2" in this image: docs.autodesk.com/CIV3D/2013/ENU/images/…. The arc is comprised of multiple line segments. Commented Jul 21, 2014 at 11:34
  • In item 2, its is a polyline with three segments (look above)
    – gene
    Commented Jul 21, 2014 at 14:04
  • two segments, sorry
    – gene
    Commented Jul 24, 2014 at 16:01
0

Building on @gene 's answer above if you're looking to approximate a curve as a sequence of points using spline interpolation. In Python you can do this through the scipy.interpolate library. Particularly 1d interpolation.

For example

import numpy as np
import scipy.interpolate

coords = np.array([[0, 0], [25, 10], [50, 50]])

#The curve fits as a quadratic equation on three points
f = scipy.interpolate.interp1d(coords[:, 0], coords[:, 1], kind='quadratic')

#New points will be evenly distributed along x
new_x = np.linspace(np.min(coords[:, 0]), np.max(coords[:, 0]), 10)
new_y = f(new_x)

new_coords = np.vstack([new_x, new_y]).T

enter image description here

With a bit more work (play with shapely.interpolate) you can get a curve in segments of equal like so:

from shapely.geometry import Point, LineString, mapping

fine_x = np.linspace(np.min(coords[:, 0]), np.max(coords[:, 0]), 1000)
fine_y = f(fine_x)

fine_coords = zip(fine_x, fine_y)
fine_line = LineString(fine_coords)

even_line = LineString([
    np.array(fine_line.interpolate(i))
    for i in np.arange(0, fine_line.length, 5) #points 5 units apart
])

enter image description here

8
  • you can simplify: fine_coords = zip(fine_x, fine_y)
    – gene
    Commented Jul 24, 2014 at 8:22
  • Thanks but I'm looking to generate segments using three coordinates; start of arc, end of arc and centre of arc. Commented Jul 24, 2014 at 11:03
  • @Stodge In which case take a look at this answer on Stack Overflow - it should have exactly what you're after
    – om_henners
    Commented Jul 24, 2014 at 15:43
  • The result is not a LineString with three points. Otherwise you can also use all the interpolation algorithms.
    – gene
    Commented Jul 24, 2014 at 15:57
  • @gene Yeah. I'm now thinking Stodge is after a circular arc as generalised to a line string. After looking at it a couple of times, in the picture supplied in the comment to your solution I think the centre point of the arc is the green circle to the left of the "2"
    – om_henners
    Commented Jul 24, 2014 at 16:05

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.