I am using OGR Distance in Python to determine the shortest distance between a point and a line. My results are completely different then the ones I get using QGIS. I assume the units OGR uses depend on the coordinate system? Could it be that OGR uses degrees? If so how could I convert these to meters?
My code looks like this:
import ogr
driver = ogr.GetDriverByName('ESRI Shapefile')
roads = driver.Open('G:/Basedata/OR/infra/TigerRoads2010/OR_TIGERroads_2010_merge.shp', 0)
point = driver.Open('U:/My Documents/Tool/shp/testareacentro.shp', 0)
roadslayer = roads.GetLayer()
pointl = point.GetLayer()
roadsfeature = roadslayer.GetNextFeature()
pointf = pointl.GetNextFeature()
roadgeom = roadsfeature.GetGeometryRef()
pointgeom = pointf.GetGeometryRef()
dist = pointgeom.Distance(roadgeom)
print dist
The reason why my distance is off, is because I only compared the first feature.
This will code will give the same results as in QGIS:
import ogr
driver = ogr.GetDriverByName('ESRI Shapefile')
lineshp = driver.Open('U:/My Documents/Tool/shp/line.shp', 0)
linelyr = lineshp.GetLayer()
pointshp = driver.Open('U:/My Documents/Tool/shp/point.shp', 0)
pointlyr = pointshp.GetLayer()
linefeat = linelyr.GetNextFeature()
pointfeat = pointlyr.GetNextFeature()
point_geom = pointfeat.GetGeometryRef()
distlist = []
while linefeat:
line_geom = linefeat.GetGeometryRef()
dist = point_geom.Distance(line_geom)
distlist.append(dist)
linefeat.Destroy()
linefeat = linelyr.GetNextFeature()
print min(distlist)
Related
I have this very long jupyter notebook
#!/usr/bin/env python
# coding: utf-8
# In[1]:
#Setting Environment
from ipyleaflet import Map, basemaps, Marker, Polygon
import pyodbc
import json
#Getting ODBC Connection
cnxn = pyodbc.connect('DRIVER={ODBC Driver 18 for SQL Server};SERVER=<<SERVER>>;DATABASE=<<DATABASE>>;UID=<<USER>>;PWD=<<PWD>>;TrustServerCertificate=yes;')
cursor = cnxn.cursor()
#center function
def centroid(vertexes):
_x_list = [vertex [0] for vertex in vertexes]
_y_list = [vertex [1] for vertex in vertexes]
_len = len(vertexes)
_x = sum(_x_list) / _len
_y = sum(_y_list) / _len
return(_x, _y)
# In[2]:
#set TBL1
TBL1=9543
# In[17]:
#getting Polygon GEOJSON
cursor.execute(f"SELECT geography.ReorientObject().ToString() FROM DB1..TBL1 WHERE id = {TBL1}")
top = 0
bottom = 90
left = 0
right = -90
geography = cursor.fetchval()
geography = geography.replace('POLYGON ((','').replace('))', '').split(', ')
nodes = []
for node in geography:
node = node.split(' ')
top = float(node[1]) if float(node[1]) > top else top
bottom = float(node[1]) if float(node[1]) < bottom else bottom
left = float(node[0]) if float(node[0]) < left else left
right = float(node[0]) if float(node[0]) > right else right
nodes.append((float(node[1]),float(node[0])))
nodes
# In[18]:
print(top, bottom)
print(left, right)
# In[24]:
#getting Points
cursor.execute(f"""
select TBL2.[TBL2_ID]
,TBL2.LAT
,TBL2.LONG
,TBL1.[User]
,TBL1.[ID]
from DB1..TBL2, DB1..[TBL1]
where 1 = TBL1.[geography].ReorientObject().STContains(geography::Point(TBL2.LAT, TBL2.LONG, 4326))
and TBL1.id = {TBL1}
and TBL2.LAT between {bottom} and {top}
and TBL2.LONG between {left} and {right};""")
points = cursor.fetchall()
print(len(points))
print(points[0:10])
# In[25]:
center = centroid(nodes)
zoom = 12
m = Map(basemap=basemaps.OpenStreetMap.Mapnik, zoom=zoom, center=center)
poly = Polygon(
locations=nodes,
color="green",
fill_color="green"
)
m.add_layer(poly)
for point in points:
marker = Marker(location=(point[1], point[2]), title=str(point[0]), draggable=False)
m.add_layer(marker)
m
# In[ ]:
Line 17 returns:
[(40.71601696448174, -74.00765417724092),
(40.71839144945969, -74.01160238891084),
(40.72613233284465, -74.00872706084688),
(40.72525421067396, -74.00568007140596),
(40.723888219823266, -74.00619505553682),
(40.71900945220738, -73.99632452636202),
(40.71507365242344, -73.99902819304903),
(40.718554082317965, -74.00559424071749),
(40.71601696448174, -74.00765417724092)]
Line 17 returns over 4000 points, however, the last line shows the map that has all the points OUTSIDE the polygon with no reason. We added the clause ReorientObject(), but it looks like we are still seeing the bad runs.
See image below:
What am I missing? The intent is only to get the points inside.
I've been trying to set up a script to automatically assign connector displacement boundary conditions. When I run the script it all looks fine in the GUI (wires are created, BCs are created and assigned the right value), but when I submit I get the following error: "Element connectivity is missing for element x of type "CONN3D2" and the element connectivity is in fact missing in the input file. I assign the edges by using the midpoints between the wire start and ends, but for some reason it doesn't assign them to the elements. This is my connector assignment function:
def assignConnectors(self):
p = self.m.parts[self.partName]
a = self.m.rootAssembly
a.Instance(name=self.instanceName, part=p, dependent=ON)
e = a.edges
n = a.instances[self.instanceName].nodes
#allelements = p.Set(name='allElements', elements=self.listObjElem)
elset = a.instances[self.instanceName].elements
elsetAssembly = a.Set('assemblyElements', elements=elset)
a.regenerate()
v1 = a.instances[self.instanceName].vertices
rows = len(self.listConstraints)
columns = len(self.listConstraints[0])
total = rows*columns
listObjNode=[];
self.listObjElem=[];
self.listObjConnector=[];
for j,pairElem in enumerate(self.listElem):
p1 = a.getCoordinates(self.listNodes[pairElem[0]-1])
p2 = a.getCoordinates(self.listNodes[pairElem[1]-1])
#print(p1,p2)
wires = a.WirePolyLine(points=((p1,p2),), mergeType=IMPRINT, meshable=OFF)
a.regenerate()
pt1 = a.getCoordinates(self.listNodes[pairElem[0]-1])
pt2 = a.getCoordinates(self.listNodes[pairElem[1]-1])
print(pt1,pt2)
pt11 = np.asarray(pt1[0])
pt12 = np.asarray(pt1[1])
pt13 = np.asarray(pt1[2])
pt21 = np.asarray(pt2[0])
pt22 = np.asarray(pt2[1])
pt23 = np.asarray(pt2[2])
new_p1 = (pt11+pt21)/2
new_p2 = (pt12+pt22)/2
new_p3 = (pt13+pt23)/2
new_p = tuple([new_p1,new_p2,new_p3])
print(new_p)
a = self.m.rootAssembly
e = a.edges
edges1 = e.findAt((new_p, ))
print(edges1)
region = a.Set(edges = edges1, name='Set'+str(j))
self.m.ConnectorSection(name='ConnSect-1'+str(j),translationalType=AXIAL)
csa = a.SectionAssignment(sectionName='ConnSect-1'+str(j), region=region)
self.m.ConnDisplacementBC(name='BC-'+str(j+total), createStepName=self.stepName, fastenerSetName='Set'+str(j), u1=float(self.listElongations[j]), u2=UNSET, u3=UNSET, ur1=UNSET, ur2=UNSET, ur3=UNSET, amplitude=UNSET, fixed=OFF, distributionType=UNIFORM)
a.regenerate()
Am I assigning the elements wrong somehow?
Thanks a lot for any help!
I have a google earth engine javascript code to detect water pixel in the closest date SAR imagery. Link of the code: https://code.earthengine.google.com/0a35eea49123a5390b822bac7afc1b0c. I can run the code in GEE and returning exactly what I required (1 if the location is above water and 0 when it above land).
I have tried to develop the following code which is returning the dictionary, not the single expected output.
import ee, datetime
ee.Initialize()
waterThresh = -16;
angle_threshold_1 = ee.Number(45.4);
angle_threshold_2 = ee.Number(31.66);
class AltimeterExtraction(object):
def __init__(self, locationfile = './Bin/Location_Data.txt'):
filecontent = open(locationfile, 'r')
content = csv.DictReader(filecontent, delimiter='\t')
def watertestpoint(self, lat=10.55587,lon=89.89789, date1='2019-04-05'):
lat = ee.Number(lat)
lon = ee.Number(lon)
datep = datetime.datetime.strptime(date1, "%Y-%m-%d")
date2 = datep + datetime.timedelta(days = -10)
point = ee.Geometry.Point([lon,lat])
S1 = ee.ImageCollection('COPERNICUS/S1_GRD').filterBounds(point).filterDate(date2, date1)
S1 = S1.map(self.maskByAngle)
S1 = S1.select('VV').median().rename('VV')
S1 = S1.focal_median(50,'circle','meters').rename('VV')
WaterMask = S1.lt(waterThresh)
flag = WaterMask.reduceRegion(**{
'reducer': ee.Reducer.mean(),
'geometry': point,
'scale': 10
});
return flag.get('VV')
def maskByAngle(self, img):
I = ee.Image(img)
angle = I.select('angle')
mask1 = angle.lt(angle_threshold_1)
mask2 = angle.gt(angle_threshold_2)
I = I.updateMask(mask1)
return I.updateMask(mask2)
P = AltimeterExtraction()
x= P.watertestpoint()
print x
Are there any ways to get the single value instead of the dictionary from python? I need the binary output (0 or 1) from the function.
You should add .getInfo() while printing to get the actual value from that point. Earth Engine process all of the data on the server side so you have to explicitly call .getInfo() to return the information.
Here is an example I used:
P = AltimeterExtraction()
x= P.watertestpoint(lat=20.5564,lon=94.818,date1='2019-03-30')
print(x.getInfo())
I have been battling for days to read coordinates LineString using fastkml library in python.
I have imported geometry module in my main program. I am reading like this.
My kml file is stored in string called doc
X = Geometry
Z=x._get,_coordinates(doc)
I got an error that says
the module object has no attributes find
from fastkml import kml
import re
from fastkml.geometry import Geometry
from lxml import etree
from xml.etree import ElementTree
from io import StringIO, BytesIO
def print_child_features(element):
if not getattr(element, 'features', None):
return
for feature in element.features():
y = feature.to_string()
return y
def print_child2_features(element):
""" Prints the name of every child node of the given element, recursively """
if not getattr(element, 'features', None):
return
for feature in element.features():
print feature.name
print_child2_features(feature)
def get_distance(coordinates_str):
"""gets distance of one path from coordinates string in form of:
14.81363432237944,53.57016581501523,0 14.81411766813742,53.56923005549378,0 14.81880340335202,53.56879451890311 ...
look at:
http://code.google.com/intl/pl-PL/apis/kml/documentation/kmlreference.html#coordinates
"""
sum_distance = 0.0
arr = []
coordinates = []
if ' ' in coordinates_str:
arr = coordinates_str.split(' ')
if len(arr) > 1:
for s in arr:
if ',' in s:
pt = s.split(',')
pos_latt = (float(pt[0].strip()), 0, 0)
pos_long = (float(pt[1].strip()), 0, 0)
position = (pos_latt, pos_long)
coordinates.append(position)
if coordinates:
for i in range(len(coordinates) - 1):
start = coordinates[i]
stop = coordinates[i + 1]
sum_distance += distance.points2distance(start, stop)
return sum_distance
if name == 'main':
#fname = input("Enter KML file name ")
fname = "DBN.kml"
k = kml.KML()
with open(fname) as kmlFile:
k.from_string(kmlFile.read())
x = Geometry()
doc = print_child_features(k)
z= x._get_coordinates(doc)
print z
length=0
if length <= 10:
print("Transciver is LR")
elif length > 10 and length <= 40:
print("Transciver is ER")
else:
print("Transciver is ER")
I did not get the code you have written. But I have written code to read coordinates from Linestrings and other Geometries using fastkml library, so I can help.
# import necessary modules
from fastkml import kml, geometry
k = kml.KML() # create fastkml object
k.from_string(doc.encode('utf-8')) # read doc string
document = list(k.features())
self.parse_placemarks(document)
# parse features throughout the KML File
def parse_placemarks(self, document):
for feature in document:
if isinstance(feature, kml.Placemark): # when there is no folder
placemark = feature
self.parse_geometries(placemark)
for feature in document:
if isinstance(feature, kml.Folder):
self.parse_placemarks(list(feature.features()))
if isinstance(feature, kml.Document):
self.parse_placemarks(list(feature.features()))
# parse geometry
def parse_geometries(self, placemark):
if hasattr(placemark, "geometry"):
if isinstance(placemark.geometry, geometry.LineString):
self.linestring(placemark)
# parse linestring
def linestring(self, line):
x, y = self.compute_coordinates(line.geometry)
# find coordinates
def compute_coordinates(self, geometry):
lons = []
lats = []
for coordinates in geometry.coords:
lons.append(coordinates[0])
lats.append(coordinates[1])
return (lons, lats)
You can find how to extract coordinates of other geometries and more about fastkml here : https://medium.com/#wwaryan/the-definite-only-guide-to-fastkml-58b8e19b8454
Trying to use the latitude and longitude that is returned by geopy to create a shapefile. The shapefile creator part works line if I give it a set of numbers (44.977753, -93.2650108) but it will not work with the returned data lat_long. My thought is that it needs a "," but I dont know.
from geopy.geocoders import GoogleV3
import csv
import ogr, os
def geopy():
loc = raw_input("What location? ")
geolocator = GoogleV3()
location = geolocator.geocode(loc, exactly_one=True)
if location != None:
Address = location.address
lat_long = location.latitude, location.longitude
latitude = str(location.latitude)
longitude = str(location.longitude)
print Address, latitude, longitude
print""
else:
print "There is no geographic information to return for the word in input. \n"
# Input data
pointCoord = lat_long
fieldName = 'test'
fieldType = ogr.OFTString
fieldValue = 'test'
outSHPfn = "output file"
# create the spatial reference, WGS84
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
# Create the output shapefile
shpDriver = ogr.GetDriverByName("ESRI Shapefile")
if os.path.exists(outSHPfn):
shpDriver.DeleteDataSource(outSHPfn)
outDataSource = shpDriver.CreateDataSource(outSHPfn)
outLayer = outDataSource.CreateLayer(outSHPfn, srs, geom_type = ogr.wkbPoint )
#create point geometry
point = ogr.Geometry(ogr.wkbPoint)
point.AddPoint(pointCoord[0],pointCoord[1])
# create a field
idField = ogr.FieldDefn(fieldName, fieldType)
outLayer.CreateField(idField)
# Create the feature and set values
featureDefn = outLayer.GetLayerDefn()
outFeature = ogr.Feature(featureDefn)
outFeature.SetGeometry(point)
outFeature.SetField(fieldName, fieldValue)
outLayer.CreateFeature(outFeature)
geopy()
Need to add a loop to put the latitude and longitude in a list. This code will create a point shapefile of any location you give it.
from geopy.geocoders import GoogleV3
import csv
import ogr, os
def geopy(location):
"""This function takes the word given about
and uses GoogleV3 to search for a location. If a
location is found it then returns the Address, latitude and longitude.
It then prints that information to a .CSV"""
geolocator = GoogleV3()
loc_input = raw_input("Add the location you would like data back for: ")
location = geolocator.geocode(loc_input, exactly_one=True)
if location != None:
Address = location.address
lat_lon = location.latitude, location.longitude
latitude = str(location.latitude)
longitude = str(location.longitude)
print Address, latitude, longitude
print""
#Converts lat_long to a list for use in making the shapefile.
list_lat = []
for i in range(1):
list_lat.append(lat_lon)
for list_of_lat_lon in list_lat:
print""
#Calls list_of_lat_lon for the shapefile function
shapefile(list_of_lat_lon)
# If there is no location data to return it prints the below line and does not create a shapefile
else:
print "There is no geographic information to return for the word in input. \n"
def shapefile(list_of_lat_lon):
"""This function uses the GDAL to return a ESRi shapefile
it uses the latitude and longitude in the list_of_lat_lon list.
"""
# Input data
pointCoord = list_of_lat_lon
fieldName = 'Lat'
fieldType = ogr.OFTString
fieldValue = 'test'
outSHPfn = "Input file location"
# create the spatial reference, WGS84
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
# Create the output shapefile
shpDriver = ogr.GetDriverByName("ESRI Shapefile")
if os.path.exists(outSHPfn):
shpDriver.DeleteDataSource(outSHPfn)
outDataSource = shpDriver.CreateDataSource(outSHPfn)
outLayer = outDataSource.CreateLayer(outSHPfn, srs, geom_type = ogr.wkbPoint )
#create point geometry longitude first then latitude
point = ogr.Geometry(ogr.wkbPoint)
point.AddPoint(pointCoord[1],pointCoord[0])
# create a field
idField = ogr.FieldDefn(fieldName, fieldType)
outLayer.CreateField(idField)
# Create the feature and set values
featureDefn = outLayer.GetLayerDefn()
outFeature = ogr.Feature(featureDefn)
outFeature.SetGeometry(point)
outFeature.SetField(fieldName, fieldValue)
outLayer.CreateFeature(outFeature)
geopy(location)