Skip to content

Instantly share code, notes, and snippets.

@giohappy
Last active September 29, 2015 14:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save giohappy/f2abde1549aa2775b5aa to your computer and use it in GitHub Desktop.
Save giohappy/f2abde1549aa2775b5aa to your computer and use it in GitHub Desktop.
Lenght along linestring to point
# -*- coding: utf-8 -*-
#
# Copyright © 2012 Giovanni Allegri (Gis3W s.a.s.)
# Licensed under the terms of the LGPLv2 License
from qgis.core import *
import math
def pointInterpolate(geom,point):
geomType = geom.wkbType ()
if geomType <> QGis.WKBLineString:
return None
linegeom = geom.asPolyline()
segStop = nearestSegToPoint(linegeom,point)
segPoints = (linegeom[segStop],linegeom[segStop+1])
length = 0.0
seg = 0
while seg < segStop:
p1 = linegeom[seg]
p2 = linegeom[seg+1]
length += distToPoint(p1,p2)
seg += 1
pointProj = closesPointToSeg(segPoints[0],segPoints[1],point)
partSegLength = distToPoint(segPoints[0],pointProj)
length += partSegLength
return length
def nearestSegToPoint(linegeom,point):
nearestseg = 0
mindist = -1
nsegs = len(linegeom)-1
for seg in range(nsegs):
lpt1 = linegeom[seg]
lpt2 = linegeom[seg+1]
dist = distToSeg(lpt1,lpt2,point)
if seg == 0 or dist<mindist:
nearestseg = seg
mindist = dist
if mindist==float(0):
nearestseg = seg
break
seg = seg+1
return nearestseg
def closesPointToSeg(lpt1,lpt2,point):
lpt1x = lpt1.x()
lpt1y = lpt1.y()
lpt2x = lpt2.x()
lpt2y = lpt2.y()
pointx = point.x()
pointy = point.y()
if (lpt1x == lpt2x) and (lpt1y == lpt2y):
return lpt1
r = (((pointx-lpt1x) * (lpt2x-lpt1x)) + ((pointy-lpt1y) * (lpt2y-lpt1y))) / (((lpt2x-lpt1x) * (lpt2x-lpt1x)) + ((lpt2y-lpt1y) * (lpt2y-lpt1y)))
if r<0:
return lpt1
if r>1:
return lpt2
x = lpt1x + ((lpt2x-lpt1x)*r)
y = lpt1y + ((lpt2y-lpt1y)*r)
return QgsPoint(x,y)
def distToPoint(p1,p2):
h = p2.x()-p1.x()
v = p2.y()-p1.y()
return math.sqrt((h*h)+(v*v))
def distToSeg(lpt1,lpt2,point):
lpt1x = lpt1.x()
lpt1y = lpt1.y()
lpt2x = lpt2.x()
lpt2y = lpt2.y()
pointx = point.x()
pointy = point.y()
if (lpt1x == lpt2x) and (lpt1y == lpt2y):
return distToPoint(lpt1,point)
r = (((pointx-lpt1x) * (lpt2x-lpt1x)) + ((pointy-lpt1y) * (lpt2y-lpt1y))) / (((lpt2x-lpt1x) * (lpt2x-lpt1x)) + ((lpt2y-lpt1y) * (lpt2y-lpt1y)))
if r<0:
return distToPoint(lpt1,point)
if r>0:
return distToPoint(lpt2,point)
s = (((lpt1y-pointy) * (lpt2x-lpt1x)) - ((lpt1x-pointx) * (lpt2y-lpt1y))) / (((lpt2x-lpt1x) * (lpt2x-lpt1x)) + ((lpt2y-lpt1y) * (lpt2y-lpt1y)))
return math.fabs(s) * math.sqrt(math.fabs(((lpt2x-lpt1x) * (lpt2x-lpt1x)) - ((lpt2y-lpt1y) * (lpt2y-lpt1y))))
@pierluigiderosa
Copy link

Hi Giovanni,
I'm just using your script to make some test.
It seems that the length the code provide does not include last part of segment.
Please try this line:
XS_geom.asPolyline() [(290680,4.7684e+06), (290611,4.76834e+06), (290576,4.76831e+06), (290562,4.76834e+06), (290504,4.76836e+06), (290367,4.76844e+06), (290108,4.76845e+06)]
whit this point:
point=(290470,4.76838e+06)

I tried:
pointInterpolate(XS_geom, pt_bnk.asPoint())
it give me 242.01 when the correct value should be 281.68. It miss the last part of 39.67

Could you test it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment