def arcgis_to_pyprt(feature_set): """arcgis_to_pyprt(feature_set) -> List[InitialShape] This function allows converting an ArcGIS FeatureSet into a list of PyPRT InitialShape instances. You then typically call the ModelGenerator constructor with the return value if this function as parameter. Parameters: feature_set: FeatureSet Returns: List[InitialShape] """ initial_geometries = [] for feature in feature_set.features: try: geo = Geometry(feature.geometry) if geo.type == 'Polygon': coord = geo.coordinates()[0] coord_remove_last = coord[:-1] coord_inverse = np.flip(coord_remove_last, axis=0) if coord.shape[1] == 2: # we have to add a dimension coord_inverse[:, 1] *= -1 coord_add_dim = np.insert(coord_inverse, 1, 0, axis=1) coord_fin = np.reshape( coord_add_dim, (1, coord_add_dim.shape[0] * coord_add_dim.shape[1])) elif coord.shape[1] == 3: # need to swap the 1 and 2 columns coord_inverse[:, 1] *= -1 coord_swap_dim = coord_inverse.copy() temp = np.copy(coord_swap_dim[:, 1]) coord_swap_dim[:, 1] = coord_swap_dim[:, 2] coord_swap_dim[:, 2] = temp coord_fin = np.reshape( coord_swap_dim, (1, coord_swap_dim.shape[0] * coord_swap_dim.shape[1])) initial_geometry = pyprt.InitialShape(coord_fin.tolist()[0]) initial_geometries.append(initial_geometry) except: print("This feature is not valid: ") print(feature) print() return initial_geometries
def get_terrain_map(lat_lon = [0,0], sample_dist = 10, extent = 100, heading = 0, show_plot = False, verbosity = False): # gis = GIS("pro") # gis = GIS(url="http://virginiatech.maps.arcgis.com", client_id="rluxzSWjZS6TfeXs", username="******", password="******", verify_cert=False) gis = GIS(username="******",password="******") if verbosity: print("Successfully logged in as: " + gis.properties.user.username) elv_map = gis.content.get('58a541efc59545e6b7137f961d7de883') elv_layer = elv_map.layers[0] if len(lat_lon) > 2: print("Error, too many lat long points provided") return -1 xy = lat_lon2meters(lat_lon[0], lat_lon[1]) cen_pt = list(xy) lhc_pt = [cen_pt[0] - extent/2, cen_pt[1] - extent/2] # lefthand corner point max_samples = 30 # api limitation! if extent > max_samples*sample_dist: # multiple calls are required fac = factorization(int(extent/sample_dist)) if len(fac) == 1: # random prime number incomming sc = fac[0] cc = 1 else: sc = np.max(fac[fac <= max_samples]) fac = np.delete(fac,np.argmax(fac[fac <= max_samples])) cc = np.prod(fac) else: # single call suffices cc = 1 sc = int(np.round(extent/sample_dist)) sample_extents = sc * sample_dist if verbosity: print("total calls: {}".format(np.square(cc))) # set max values elv_layer.extent['xmin'] = lhc_pt[0] elv_layer.extent['xmax'] = lhc_pt[0] + extent elv_layer.extent['ymin'] = lhc_pt[1] elv_layer.extent['ymax'] = lhc_pt[1] + extent # print(elv_layer.extent) # house keeping, initialize with empty lists x = np.empty([0,sc*cc]) y = np.empty([0,sc*cc]) e = np.empty([0,sc*cc]) data = [] for j in range(cc): # outter loop for y values # lists of values for a single row, reset at every y iteration x_row = np.empty([sc,0]) y_row = np.empty([sc,0]) e_row = np.empty([sc,0]) for i in range(cc): # inner loop for x values O_O x_values = [np.linspace(lhc_pt[0] + i * sample_extents, lhc_pt[0] + (i + 1 - 1/sc) * sample_extents, sc)] y_values = [np.linspace(lhc_pt[1] + j * sample_extents, lhc_pt[1] + (j + 1 - 1/sc) * sample_extents, sc)] [X,Y] = np.meshgrid(x_values, y_values) # put in rotation here geo_points = [point_rotation(origin = [cen_pt[0],cen_pt[1]],pt = [xp,yp],ang = heading) for xv,yv in zip(X,Y) for xp,yp in zip(xv,yv)] # print(points) g = Geometry({"points": geo_points, "spatialReference": 3857}) failed = True while failed: # keep trying until it works try: elv_samples = elv_layer.get_samples(g, sample_count=len(g.coordinates()), out_fields='location,values,value,resolution') failed = False except TimeoutError: print("failed call, trying again...") failed = True # extract location info JANK INCOMING xs = np.array([e['location']['x'] for e in elv_samples], dtype=float).reshape([sc,sc]) ys = np.array([e['location']['y'] for e in elv_samples], dtype=float).reshape([sc,sc]) es = np.array([e['values'][0] for e in elv_samples], dtype=float).reshape([sc,sc]) if not np.all(xs == X) or not np.all(ys == Y): # xs = np.array([e['location']['x'] for e in elv_samples], dtype=float) # ys = np.array([e['location']['y'] for e in elv_samples], dtype=float) qs = np.stack([xs.reshape(len(elv_samples)), ys.reshape(len(elv_samples))]).T es = es.reshape(len(elv_samples)) # data came back in weird ordering, need to re-order print("re-ordering data ...") es_square = np.zeros([sc,sc]) for scx in range(sc): for scy in range(sc): # maybe the least efficient way to do this idx = np.where(np.all(np.abs(qs - np.asarray([X[scx,scy],Y[scx,scy]])) <= 1e-9,axis = 1)) # print(idx) try: es_square[scx,scy] = es[idx] except ValueError as e: print("hellfire") es = es_square print("done re-ordering") # then just the tuple of all data_temp = [] for s in elv_samples: xy_spun = point_rotation(origin = [cen_pt[0],cen_pt[1]],pt = [s['location']['x'],s['location']['y']],ang = -heading) # spin back to original frame data_temp.append((xy_spun[0], xy_spun[1],s['values'][0])) # data_temp = [(xy_spun[0], xy_spun[1],e['values'][0]) for e in elv_samples] # data_temp = [(e['location']['x'],e['location']['y'],e['values'][0]) for e in elv_samples] data = data + data_temp # append to larger arrays x_row = np.append(x_row, xs, axis=1) y_row = np.append(y_row, ys, axis=1) e_row = np.append(e_row, es, axis=1) x = np.append(x, x_row, axis=0) y = np.append(y, y_row, axis=0) e = np.append(e, e_row, axis=0) # flip elevation data up to down to match other layers e = np.flipud(e) # interpolate terrain to match size/resolution of other layers c = np.int(extent/sample_dist) scale_factor = 3/20 # factor to get 6.66667m mapping from 1m mapping (1/6.6667) scaled_extent = np.ceil(scale_factor*extent).astype(np.int) factor = scaled_extent/e.shape[0] e_interp = ndimage.zoom(e, factor, order = 3) if show_plot: # Attaching 3D axis to the figure grid_x, grid_y = np.mgrid[min(x):max(x):100j, min(y):max(y):100j] points = np.array([x, y]) grid_z = griddata(points.transpose(), z, (grid_x, grid_y), method='cubic', fill_value=np.mean(z)) print(grid_z) fig = plt.figure() ax = fig.gca(projection='3d') ax.plot_surface(grid_x, grid_y, grid_z, cmap='viridis') if verbosity: print("x min: {}".format(np.min(x))) print("x max: {}".format(np.max(x))) print("x max - min: {}".format(np.max(x)-np.min(x))) print("x spacing: {}".format(abs(x[0][0] - x[0][1]))) print("y min: {}".format(np.min(y))) print("y max: {}".format(np.max(y))) print("y max - min: {}".format(np.max(y)-np.min(y))) return [e,e_interp,x,y,data,lat_lon]