polygon showing up in Google Earth - simpleKML - python

background - I'm trying to create a circular polygon and add it to a kml using simpleKML.
The kml knows that there should be a polygon added, and it has the proper colour, width, and description, but whenever I zoom to the location it leads me to coordinates 0,0 and no polygon.
My code to create the polygon looks like:
pol = kml.newpolygon(name=pnt.name)
pol.description = ("A buffer for " + pnt.name)
pol.innerboundaryis = [newCoord]
pol.style.linestyle.color = simplekml.Color.green
pol.style.linestyle.width = 5
pol.style.polystyle.color = simplekml.Color.changealphaint(100, simplekml.Color.green)
where 'newCoord' is a 2D array with all of the lat/long information stored in it.
Because I thought the array might not format the data properly I tried to form a simple triangular polygon using the code:
pol1 = kml.newpolygon(name=pnt.name)
pol1.innerboundaryis = [(46.714,-75.6667),(44.60796,-74.502),(46.13910,-74.57411),(46.714,-75.6667)]
pol1.style.linestyle.color = simplekml.Color.green
pol1.style.linestyle.width = 5
pol1.style.polystyle.color = simplekml.Color.changealphaint(100, simplekml.Color.green)
but it has the same issue as the first.
I've tried forming the polygon with both .innerboundaryis() and .outerboundaryis() without success and I'm running out of ideas.
edit: I should add that I'm opening the kml file in Google Earth

There is almost no documentation on this issue online so I figured I would post the answer to my question for anyone who has this issue in the future.
This is the code that I used that got the polygon working.
newCoords = []
pol = kml.newpolygon(name=pnt.name)
pol.description = ("A buffer for " + pnt.name)
if pnt.name in bufferList:
bufferRange = input('Enter the buffer range. ' )
for i in range(360):
newCoords.append( ( math to calculate Lat, math to calculate Long ) )
pol.outerboundaryis.coords.addcoordinates([newCoords[i]])
pol.style.linestyle.color = simplekml.Color.green
pol.style.linestyle.width = 5
pol.style.polystyle.color = simplekml.Color.changealphaint(100, simplekml.Color.green)
You need to put your coordinates into a list before adding them to the polygon's outer boundary using the 'coords.addcoordinates()' function. Additionally it must be a one dimensional list, so both the latitude and longitude coordinate must be stored in the same place.
You can input floats directly with '.outerboundaryis()', example:
pol.outerboundaryis = [(18.333868,-34.038274), (18.370618,-34.034421),
(18.350616,-34.051677),(18.333868,-34.038274)]
But '.addcoordinates()' only accepts lists and integers.

Related

Closing holes in mesh while retaining point cloud shape

I have a ply file that I am attempting to turn into a mesh for the purposes of ray tracing. It looks like this is the open3d visualizer and is supposed to represent a part of a city:
I used open3d to get make the following mesh as following(kdtree is just to get small number of points as file is huge):
input_file = "san.ply"
pcd = o3d.io.read_point_cloud(input_file)
point_cloud_in_numpy = np.asarray(pcd.points)
color = np.asarray(pcd.colors)
kd = scipy.spatial.cKDTree(point_cloud_in_numpy) #create kdtree for fast querying
near = kd.query_ball_point([0, 0, 0], 100)
items = point_cloud_in_numpy[near]
colors = color[near]
pcd2 = o3d.geometry.PointCloud()
pcd2.colors = o3d.utility.Vector3dVector(colors)
pcd2.points = o3d.utility.Vector3dVector(items)
pcd2.estimate_normals()
distances = pcd2.compute_nearest_neighbor_distance()
avg_dist = np.mean(distances)
radius = 2 * avg_dist
mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(
pcd2,
o3d.utility.DoubleVector([radius, radius * 2]))
vertices = np.asarray(mesh.vertices)
faces = np.asarray(mesh.triangles)
o3d.visualization.draw_geometries([mesh])
However, when graphing the mesh, we get something that looks like this:
Many holes and just not at all optimal for ray tracing. I also tried using the create_from_point_cloud_poisson method instead however I kept on getting the following error:
[ERROR] /Users/yixing/repo/Open3D/build/poisson/src/ext_poisson/PoissonRecon/Src/FEMTree.IsoSurface.specialized.inl (Line 1463)
operator()
Failed to close loop [6: 87 64 18] | (113981): (2752,2560,2196)
which I found no way to fix online. I tried looking around but the best I found was pymeshfix which doesn't even work because "The input is assumed to represent a single closed solid object", which my point cloud is obviously not. I'm just looking for a good way to perform surface reconstruction that lets me keep the shape of the city while also fixing all the holes and making all surfaces created by points near eachother surfaces watertight.
Maybe you can close the holes with fill_holes() from the tensor-based TriangleMesh:
mesh = o3d.t.geometry.TriangleMesh.from_legacy(mesh).fill_holes().to_legacy()
fill_holes() takes a parameter for max. hole sizes to be closed
http://www.open3d.org/docs/latest/python_api/open3d.t.geometry.TriangleMesh.html#open3d.t.geometry.TriangleMesh.fill_holes

Display a map on streamlit by retrieving the data with an api

I would like to display a map on STREAMLIT by retrieving the data with an api.
I want to use the following result (it gives me the districts for a city in France) :
https://public.opendatasoft.com/api/records/1.0/search/?dataset=georef-france-iris-millesime&q=Lille&sort=year&facet=year&facet=reg_name&facet=dep_name&facet=arrdep_name&facet=ze2020_name&facet=bv2012_name&facet=epci_name&facet=ept_name&facet=com_name&facet=com_arm_name&facet=iris_name&facet=iris_area_code&facet=iris_type&refine.year=2020&refine.com_name=Lille
I try to have this (a geojson) :
POLYGON ((3.069402968274157 50.63987328751279, 3.069467907250858 50.63988940474122,...)
but i have this :
coordinates": [
[
[
3.061943586904849,
50.636758694822056
],
[
3.061342144816787,
50.63651758657737
],...]]
I'm looking for but have no idea how to get the data to be recognized to create a map.
Do you have any advice on how to convert the result of the api into geojson ?
Thanks for your help !
Here is how I would generate your geojson polygons from your API results:
import json
from geojson import Polygon
# Load the content of the API response
file = open('data.json')
data = json.load(file)
# This array will contain your polygons for each district
polygons = []
# Iterate through the response records
for record in data["records"]:
# This array will contain coordinates to draw a polygon
coordinates = []
# Iterate through the coordinates of the record
for coord in record["fields"]["geo_shape"]["coordinates"][0]:
lon = coord[0] # Longitude
lat = coord[1] # Latitude
# /!\ Order of lon & lat might be wrong here
coordinates.append((lon, lat))
# Append a new Polygon object to the polygons array
# (Note that there are outer brackets, I'm not sure if you can
# store all polygons in a single Polygon object)
polygons.append(Polygon([coordinates]))
print(polygons)
# Do something with your polygons here...
Your initial definition of a Polygon seems wrong to me, you should check this link: https://github.com/jazzband/geojson#polygon.
After looking around a bit, I think Streamlit might not be the best option to display your map as it does not seem to support drawing polygons (I might be wrong here). If that is the case, you should have a look at GeoPandas.

How to add a point with XY coordinates inside a Feature Class in arcpy?

I am fairly new to arcpy and I've literally spent the day trying to figure out how to add a point with XY coordinates inside a Feature Class in arcpy. Here's the code I have right now:
coordinates = raw_input("Please enter longitude and latitude as floats split by a space: ")
c_split = coordinates.split()
lng = float(c_split[0])
lat = float(c_split[1])
spatial_reference = arcpy.SpatialReference(3857)
arcpy.CreateFeatureclass_management('D:\Documents\GIS_DATA\buildings_sample_8', "center.shp", "POINT", "", "DISABLED", "DISABLED", spatial_reference)
center = "center.shp"
cursor = arcpy.da.InsertCursor('D:\Documents\GIS_DATA\buildings_sample_8\center.shp', ["SHAPE#XY"])
xy = (lng, lat)
cursor.insertRow([xy])
This manages to create the shapefile center.shp within the appropriate directory, but I am not able to add the user-entered longitude and latitude values to the point, making the point appear at the default 0, 0.
This is probably a super easy question, but I haven't been able to find the documentation online.
Thank you!
try changing this:
xy = (lng, lat)
to this:
xy = arcpy.Point(lng, lat)
I'm guessing your coordinate floating point is indeed a point (.) and not a comma (,) otherwise you'll get an error trying to create the Point (Input value is not numeric).

How to use ezdxf to find location of mirrored entities like blocks/circles?

How do you calculate the location of a block or an insert entity that has been mirrored?
There is a circle inside a 'wb' insert/block entity. I'm trying to identify it's location on msp and draw a circle it. There are 2 'wb' blocks in the attached DXF file, one of which is mirrored.
DXF File link: https://drive.google.com/file/d/1T1XFeH6Q2OFdieIZdfIGNarlZ8tQK8XE/view?usp=sharing
import ezdxf
from ezdxf.math import Vector
DXFFILE = 'washbasins.dxf'
OUTFILE = 'encircle.dxf'
dwg = ezdxf.readfile(DXFFILE)
msp = dwg.modelspace()
dwg.layers.new(name='MyCircles', dxfattribs={'color': 4})
def get_first_circle_center(block_layout):
block = block_layout.block
base_point = Vector(block.dxf.base_point)
circles = block_layout.query('CIRCLE')
if len(circles):
circle = circles[0] # take first circle
center = Vector(circle.dxf.center)
return center - base_point
else:
return Vector(0, 0, 0)
# block definition to examine
block_layout = dwg.blocks.get('wb')
offset = get_first_circle_center(block_layout)
for e in msp.query('INSERT[name=="wb"]'):
scale = e.get_dxf_attrib('xscale', 1) # assume uniform scaling
_offset = offset.rotate_deg(e.get_dxf_attrib('rotation', 0)) * scale
location = e.dxf.insert + _offset
msp.add_circle(center=location, radius=3, dxfattribs={'layer': 'MyCircles'})
dwg.saveas(OUTFILE)
The above code doesn't work for the block that is mirrored in the AutoCAD file. It's circle is drawn at a very different location. For a block placed through the mirror command, the entity.dxf.insert and entity.dxf.rotation returns a point and rotation that is different than that if the block was placed there by copying and rotating.
Kindly help in such cases. Similarly, how will we handle lines and circle entities? Kindly share python functions/code for the same.
Since you are obtaining the circle center relative to the block definition base point, you will need to construct a 4x4 transformation matrix which encodes the X-Y-Z scale, rotation & orientation of each block reference encountered within your for loop.
The ezdxf library usefully includes the Matrix44 class which will take care of the matrix multiplication for you. The construction of such a matrix will be something along the lines of the following:
import math
import ezdxf
from ezdxf.math import OCS, Matrix44
ocs = math.OCS(e.dxf.extrusion)
Matrix44.chain
(
Matrix44.ucs(ocs.ux, ocs.uy, ocs.uz),
Matrix44.z_rotate(e.get_dxf_attrib('rotation', 0)),
Matrix44.scale
(
e.get_dxf_attrib('xscale', 1),
e.get_dxf_attrib('yscale', 1),
e.get_dxf_attrib('zscale', 1)
)
)
You can then use this matrix to transform the coordinates of the circle centre from the coordinate system relative to the block definition, to that relative to the block reference, i.e. the Object Coordinate System (OCS).
After transformation, you will also need to translate the coordinates using a vector calculated as the difference between the block reference insertion point and the block definition base point following transformation using the above matrix.
mat = Matrix44.chain ...
vec = e.dxf.insert - mat.transform(block.dxf.base_point)
Then the final location becomes:
location = mat.transform(circle.dxf.center) + vec

how to determine if a point is inside a polygon using geojson and shapely

I am hoping to create a region on a map and be able to automatically determine if points (coordinates) are inside that region. I'm using a geojson file of the entire US and coordinates for New York City for this example.
Geojson: https://github.com/johan/world.geo.json
I have read the shapely documentation and just can't figure out why my results are returning False. Any help would be much appreciated.
import json
from shapely.geometry import shape, GeometryCollection, Point
with open('USA.geo.json', 'r') as f:
js = json.load(f)
point = Point(40.712776, -74.005974)
for feature in js['features']:
polygon = shape(feature['geometry'])
if polygon.contains(point):
print ('Found containing polygon:', feature)
I'm hoping to print the contained coordinates, but nothing is printed.
You need to swap the values of the Point() around:
point = Point(-74.005974, 40.712776)
The dataset you're using has the longitude first and the latitude second in their coordinates.

Categories