예제 #1
0
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]