Last active
September 29, 2015 14:54
-
-
Save giohappy/f2abde1549aa2775b5aa to your computer and use it in GitHub Desktop.
Lenght along linestring to point
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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?