Getting (some) points of a polygon - python

I am trying to grab the vertices from a polygon and do some stuff to them to recreate the polygon in a new location/rotation (essentially this: https://community.esri.com/thread/46497). The example code below is not exactly what I am doing, but showcases the issue. The code would work except that after it grabs the last vertex of the polygon, it throws an error message which breaks the script and stops everything else from running to draw the new polygon. Otherwise, if I go through my code line-by-line I can continue on and create the new polygon feature:
AttributeError: 'NoneType' object has no attribute 'X'
Is there a way that I can use the loop to run through all except the "last" vertex, which either has an issue or doesn't exist?
import arcpy
import os
import random
import math
pa = 'protected_areas' # protected areas
sr = arcpy.Describe(pa).spatialReference # spatial ref
sa = 'study_area' # study area
x = [] # placeholder
with arcpy.da.SearchCursor(pa,'SHAPE#',spatial_reference=sr) as cursor: # for each polygon
for row in cursor:
centroid = row[0].centroid # calculate centroid
poly = row[0]
for part in poly: # for each polygon part
for pnt in part: # for each vertex
x.append(pnt.X)

You can iterate over an index and skip the las element, changing
for pnt in part: # for each vertex
x.append(pnt.X)
To
for k in range(len(pnt)-1): # for each vertex
x.append(pnt[k].X)
Hope it helps

Related

How to add Point to the LineString?

I am working on vessel tracking. I have setup route path, and vessel current position. Now my aim is to add that current position point to the path and update it. and calculate the length of linestring and time duration of whole line(start to end) and remain line(from current position to end).
Now my main question is how can add the point to the LineString in order to update the route?
Below, I have provided the my input linestring and current point data. also output of line and point.
Data:
p = {'route': [{'path': [[51.51309, 0.4836599999999862],
[51.512222970577746, 0.4838196951935174],
[51.50817683327391, 0.4845649394298732],
.
.
[26.160997649670072, 56.29158290493038],
[25.234004681463745, 55.29187512793891],
[25.035363331133816, 55.07765203286928],
[25.00255, 55.10811000000001]],
'type': 'SEA'}]}
l_path=p['route'][0]['path']
path = LineString(l_path)
I want to connect this point to the linestring:
position = Point(13.752724664396988, 56.42578125)
Line and point output:
Thanks in advance.
I have update the path my connecting with the point but still not getting the desire output. Because, using below code vessel taking long path which is causing me a issue in with wrong length and time.
from shapely.geometry import LineString
from shapely.ops import transform
from functools import partial
import pyproj
from shapely.ops import split
from itertools import chain
total_path=p['route'][0]['path'][1:-1] ##### Total path
total_line = LineString(total_path)
project = partial(
pyproj.transform,
pyproj.Proj('EPSG:4326'),
pyproj.Proj('EPSG:32633'))
total_ls = transform(project, total_line)
total_ls
total_distance = total_ls.length/1852 ######Tortal distance in NM
print(total_distance, "Distance")
current_pin = (13.752724664396988, 56.42578125)
position = Point(current_pin)
all_points_coords = chain(total_line.coords,position.coords)
all_points = map(Point, all_points_coords)
new_line = LineString(sorted(all_points, key=total_line.project))
new_ls = transform(project, new_line)
new_distance = new_ls.length/1852
print(new_distance,"New distance")
new_ls
## remain distance from current position
remain = LineString(new_line.coords[new_line.coords[:].index(current_pin):])
remain = transform(project, remain)
r_distance = remain.length/1852
print(r_distance,"remain distance")
remain

Sorting the mesh vertices in Blender

I'm creating an application that requires the vertices array of the mesh to be sorted in a particular way, to access them more easily: from left to right then downwards to upwards (in the xy plane) like this:
[indexes][1]
My code successfully does that, but the resulting mesh is all glitched out:
[resulting mesh][2]
I think it's likely that the new edges are causing the problem, but haven't found a way to fix them. Here's the mesh sorting code I wrote:
# This example assumes we have a mesh object selected
import bpy
import bmesh
#Weights for order. Left>>Right Down>>Up
def order(vector):
return vector[0]+200*vector[1]
# Get the active mesh
me = bpy.context.object.data
verts=[]
# Get a BMesh representation
bm = bmesh.new() # create an empty BMesh
bm.from_mesh(me) # fill it in from a Mesh
#Convert current verts to tuple list (x,y,z)
i=0
for v in bm.verts:
verts.append((v.co.x,v.co.y,v.co.z))
# Sort the verts.
verts.sort(key=order)
#Assign the sorted vertices to the mesh
i=0
for v in bm.verts:
v.co.x,v.co.y,v.co.z = verts[i]
i+=1
#Debugging edges (possible problem?)
for v in bm.edges:
if i<10:
print(v)
i+=1
# Finish up, write the bmesh back to the mesh
bm.verts.index_update()
bm.to_mesh(me)
#bmesh.update_edit_mesh(me)
bm.free() # free and prevent further access
Is there any way to rearrange the edges? Or any post processing trick I can do on the mesh, anything helps.
Thanks in advance.
[1]: https://i.stack.imgur.com/iuoBc.png
[2]: https://i.stack.imgur.com/atxvF.png

How to cut vertices and faces connected to points lower than some value in pyvista?

So when one exports r.out.vtk from Grass GIS we get a bad surface with -99999 points instead of nulls:
I want to remove them, yet a simple clip is not enough:
pd = pv.read('./pid1.vtk')
pd = pd.clip((0,1,1), invert=False).extract_surface()
p.add_mesh(pd ) #add atoms to scene
p.show()
resulting in:
So I wonder how to keep from it only top (> -999) points and connected vertices - in order to get only the top plane (it is curved\not flat actually) using pyvista?
link to example .vtk
There is an easy way to do this and there isn't...
You could use pyvista's threshold filter with all_scalars=True as long as you have only one set of scalars:
import pyvista as pv
pd = pv.read('./pid1.vtk')
pd = pd.threshold(-999, all_scalars=True)
plotter = pv.Plotter()
plotter.add_mesh(pd) #add atoms to scene
plotter.show()
Since all_scalars starts filtering based on every scalar array, this will only do what you'd expect if there are no other scalars. Furthermore, unfortunately there seems to be a bug in pyvista (expected to be fixed in version 0.32.0) which makes the use of this keyword impossible.
What you can do in the meantime (if you don't want to use pyvista's main branch before the fix is released) is to threshold the data yourself using numpy:
import pyvista as pv
pd = pv.read('./pid1.vtk')
scalars = pd.active_scalars
keep_inds = (scalars > -999).nonzero()[0]
pd = pd.extract_points(keep_inds, adjacent_cells=False)
plotter = pv.Plotter()
plotter.add_mesh(pd) #add atoms to scene
plotter.show()
The main point of both all_scalars (in threshold) and adjacent_cells (in extract_points) is to only keep cells where every point satisfies the condition.
With both of the above I get the following figure using your data:

Python - How to Check Point in a Polygon?

Below is my coding to check whether a point does exist in a polygon, but the result is False, could you help me?
# Importing Libraries
import shapefile
from shapely.geometry import shape, Point
# Opening the Vector Map
shp_path = "ADMINISTRASIDESA.shp"
# read your shapefile
r = shapefile.Reader(shp_path)
# get the shapes
shapes = r.shapes()
# build a shapely polygon from your shape
polygon = shape(shapes[0])
print(polygon)
# result :
# POLYGON ((106.701396169 -6.34824620099992, 106.7015891380001 -6.349042349999891,
# 106.701707619 -6.349551940999955, 106.701828711 -6.350008714999912, ... ))
def checkpo(lon, lat):
# build a shapely point from your geopoint
point = Point(lon, lat)
# the contains function does exactly what you want
return polygon.contains(point)
mygeolon = 106.701396169
mygeolat = -6.34824620099992
print(checkpo(mygeolon, mygeolat))
# why result = False ???
# create point
point = Point(mygeolon,mygeolat)
# check if polygon contains point
print(polygon.contains(point))
# why result = False ???
# check if a point is in the polygon
print(point.within(polygon))
# why result = False ???
I already set the longitude and latitude that listed in the polygon,
but when it is checked, it returns False ???
Please help me.
According to Shapely documentation :
object.contains(other)
Returns True if no points of other lie in the exterior of the object and at least one point of the interior of other lies in the interior of object.
(...)
A line’s endpoints are part of its boundary and are therefore not contained.
What you need is object.covers.
Returns True if every point of other is a point on the interior or boundary of
object. This is similar to object.contains(other) except that this
does not require any interior points of other to lie in the interior
of object.
https://shapely.readthedocs.io/en/latest/manual.html

Vtk inserts incorrect color between nodes when mapping texture to mesh

Hi I am trying to map a texture to 3d mesh using Mayavi and Python bindings of vtk. I am visualising an .obj wavefront. This obj is 3D photograph of a face. The texture image is a composite of three 2D photographs.
Each node in the mesh has an (uv) co-ordinate in the image, which defines its color. Different regions of the mesh draw their colours from different sections of the image. To illustrate this I have replaced the actual texture image with this one:
And mapped this to the mesh instead.
The problem I am having is illustrated around the nose. At the border between red and green there is an outline of blue. Closer inspection of this region in wireframe mode shows that it is not a problem with the uv mapping, but with how vtk is interpolating colour between two nodes. For some reason it is adding a piece of blue in between two nodes where one is red and one is green.
This causes serious problems when visualising using the real texture
Is there a way to force vtk to choose the colour of one or the other neighbouring nodes for the colour between them? I tried turning "edge-clamping" on, but this did not achieve anything.
The code that I am using is below and you can access the files in question from here https://www.dropbox.com/sh/ipel0avsdiokr10/AADmUn1-qmsB3vX7BZObrASPa?dl=0
but I hope this is a simple solution.
from numpy import *
from mayavi import mlab
from tvtk.api import tvtk
import os
from vtk.util import numpy_support
def obj2array(f):
"""function for reading a Wavefront obj"""
if type(f)==str:
if os.path.isfile(f)==False:
raise ValueError('obj2array: unable to locate file ' + str(f))
f =open(f)
vertices = list()
connectivity = list()
uv = list()
vt = list()
fcount = 0
for l in f:
line = l.rstrip('\n')
data = line.split()
if len(data)==0:
pass
else:
if data[0] == 'v':
vertices.append(atleast_2d(array([float(item) for item in data[1:4]])))
elif data[0]=='vt':
uv.append(atleast_2d(array([float(item) for item in data[1:3]])))
elif data[0]=='f':
nverts = len(data)-1 # number of vertices comprising each face
if fcount == 0: #on first face establish face format
fcount = fcount + 1
if data[1].find('/')==-1: #Case 1
case = 1
elif data[1].find('//')==True:
case = 4
elif len(data[1].split('/'))==2:
case = 2
elif len(data[1].split('/'))==3:
case = 3
if case == 1:
f = atleast_2d([int(item) for item in data[1:len(data)]])
connectivity.append(f)
if case == 2:
splitdata = [item.split('/') for item in data[1:len(data)]]
f = atleast_2d([int(item[0]) for item in splitdata])
connectivity.append(f)
if case == 3:
splitdata = [item.split('/') for item in data[1:len(data)]]
f = atleast_2d([int(item[0]) for item in splitdata])
connectivity.append(f)
if case == 4:
splitdata = [item.split('//') for item in data[1:len(data)]]
f = atleast_2d([int(item[0]) for item in splitdata])
connectivity.append(f)
vertices = concatenate(vertices, axis = 0)
if len(uv)==0:
uv=None
else:
uv = concatenate(uv, axis = 0)
if len(connectivity) !=0:
try:
conarray = concatenate(connectivity, axis=0)
except ValueError:
if triangulate==True:
conarray=triangulate_mesh(connectivity,vertices)
else:
raise ValueError('obj2array: not all faces triangles?')
if conarray.shape[1]==4:
if triangulate==True:
conarray=triangulate_mesh(connectivity,vertices)
return vertices, conarray,uv
# load texture image
texture_img = tvtk.Texture(interpolate = 1,edge_clamp=1)
texture_img.input = tvtk.BMPReader(file_name='HM_1_repose.bmp').output
#load obj
verts, triangles, uv = obj2array('HM_1_repose.obj')
# make 0-indexed
triangles = triangles-1
surf = mlab.triangular_mesh(verts[:,0],verts[:,1],verts[:,2],triangles)
tc=numpy_support.numpy_to_vtk(uv)
pd = surf.mlab_source.dataset._vtk_obj.GetPointData()
pd.SetTCoords(tc)
surf.actor.actor.mapper.scalar_visibility=False
surf.actor.enable_texture = True
surf.actor.actor.texture = texture_img
mlab.show(stop=True)
You can turn off all interpolation (change interpolate = 1 to interpolate = 0 in your example), but there is not a way to turn off interpolation at just the places where it would interpolate across sub-images of the texture – at least not without writing your own fragment shader. This will likely look crude.
Another solution would be to create 3 texture images with transparent texels at each location that is not part of the actor's face. Then render the same geometry with the same texture coordinates but a different image each time (i.e., have 3 actors each with the same polydata but a different texture image).
I just ran into this exact problem as well and found that the reason this happens is because VTK assumes there's a 1-to-1 relationship between points in the polydata and uv coordinates when rendering the actor and associated vtkTexture. However, in my case and the case of OP, there are neighboring triangles that are mapped to different sections the the image, so they have very different uv coordinates. The points that share these neighboring faces can only have one uv coordinate (or Tcoord) associated with it, but they actually need 2 (or more, depending on your case).
My solution was to loop through and duplicate these points that lie on the the seams/borders and create a new vtkCellArray with triangles with these duplicated pointIds. Then I simply replaced the vtkPolyData Polys() list with the new triangles. It would have been much easier to duplicate the points and update the existing pointIds for each of the triangles that needed it, but I couldn't find a way to update the cells properly.

Categories

Resources