def isPpaWithinServiceArea(pal_records, ppa_zone_geometry):
    """Check if the ppa zone geometry with in service area then return True.

  Checks the ppa zone geometry's boundary and interior intersect only with the
  interior of the service area (not its boundary or exterior).

  Args:
    pal_records: A list of pal records to compute service area based on
      census_tracts.
    ppa_zone_geometry: A PPA polygon dictionary in GeoJSON format.

  Returns:
    A value is the boolean with the value as True if the ppa zone geometry's
      boundary and interior intersect with in the interior of the service
      area otherwise value as false.

  """
    # Get the census tract for each pal record and convert it to Shapely
    # geometry.
    census_tracts_for_pal = [
        utils.ToShapely(
            drive.census_tract_driver.GetCensusTract(
                pal['license']['licenseAreaIdentifier'])['features'][0]
            ['geometry']) for pal in pal_records
    ]
    pal_service_area = ops.cascaded_union(census_tracts_for_pal)

    # Convert GeoJSON dictionary to Shapely object.
    ppa_zone_shapely_geometry = utils.ToShapely(ppa_zone_geometry)

    return ppa_zone_shapely_geometry.buffer(-1e-6).within(pal_service_area)
Example #2
0
  def test_ClippedPpaByCensusWithSmallHoles(self):
    # Configuring for -96dBm circle above 40km
    wf_hybrid.CalcHybridPropagationLoss = testutils.FakePropagationPredictor(
        dist_type='REAL', factor=1.0, offset=(96+30-0.1) - 45.0)

    ppa_zone = ppa.PpaCreationModel(TestPpa.devices[1:], TestPpa.pal_records[1:])
    ppa_zone = json.loads(ppa_zone)

    census_zone = utils.ToShapely(
        drive.census_tract_driver.GetCensusTract('06027000100')
        ['features'][0]['geometry'])
    self.assertTrue(utils.ToShapely(ppa_zone).buffer(-1e-6).within(census_zone))
    def test_toshapely(self):
        poly = sgeo.Point(0, 0).buffer(1)
        poly_json = utils.ToGeoJson(poly)

        # Test for a generic geometry object.
        poly2 = utils.ToShapely(poly)
        self.assertEqual(poly2.difference(poly).area, 0)
        self.assertEqual(poly.difference(poly2).area, 0)

        # Test for a string geojson.
        poly2 = utils.ToShapely(poly_json)
        self.assertEqual(poly2.difference(poly).area, 0)
        self.assertEqual(poly.difference(poly2).area, 0)
 def test_shrinks_polygon(self):
     with open(os.path.join(TEST_DIR, 'test_shrink.json'), 'r') as fd:
         ppa = json.load(fd)
     geometry = ppa['features'][0]['geometry']
     self.assertTrue(geometry['type'], 'Polygon')
     spoly = utils.ToShapely(geometry)
     mpoly = sgeo.MultiPolygon(
         [sgeo.Point(0, 0).buffer(1),
          sgeo.Point(2, 0).buffer(0.1)])
     poly1 = utils.ShrinkAndCleanPolygon(geometry, 1e-2)
     poly2 = utils.ShrinkAndCleanPolygon(spoly, 1e-2)
     self.assertTrue(poly2.area < spoly.area)
     with self.assertRaises(ValueError):
         poly = utils.ShrinkAndCleanPolygon(mpoly, 1e-2)
     self.assertEqual(poly1['type'], 'Polygon')
     self.assertTrue(isinstance(poly2, sgeo.Polygon))
     spoly1 = utils.ToShapely(poly1)
     self.assertEqual(poly2.difference(spoly1).area, 0)
     self.assertEqual(spoly1.difference(poly2).area, 0)
  def test_ClippedPpaByCensus(self):
    # Configuring for -96dBm circle above 40km
    wf_hybrid.CalcHybridPropagationLoss = testutils.FakePropagationPredictor(
        dist_type='REAL', factor=1.0, offset=(96+30-0.1) - 45.0)
    expected_ppa = sgeo.Polygon([(-80.3, 30.3), (-80.7, 30.3),
                                 (-80.7, 30.7), (-80.3, 30.7)])

    ppa_zone = ppa.PpaCreationModel(TestPpa.devices, TestPpa.pal_records)
    ppa_zone = json.loads(ppa_zone)

    self.assertAlmostSamePolygon(
        utils.ToShapely(ppa_zone), expected_ppa, 0.001)
  def test_SimplePpaCircle(self):
    # Configuring for -96dBm circle at 16km includes
    wf_hybrid.CalcHybridPropagationLoss = testutils.FakePropagationPredictor(
        dist_type='REAL', factor=1.0, offset=(96+30-0.1) - 16.0)
    expected_ppa = sgeo.Polygon(
        [vincenty.GeodesicPoint(
            TestPpa.devices[0]['installationParam']['latitude'],
            TestPpa.devices[0]['installationParam']['longitude'],
            dist_km=16.0, bearing=angle)[1::-1]  # reverse to lng,lat
         for angle in xrange(360)])

    ppa_zone = ppa.PpaCreationModel(TestPpa.devices, TestPpa.pal_records)
    ppa_zone = json.loads(ppa_zone)

    self.assertAlmostSamePolygon(
        utils.ToShapely(ppa_zone), expected_ppa, 0.001)
    def test_grid_complex(self):
        with open(os.path.join(TEST_DIR, 'test_geocollection.json'),
                  'r') as fd:
            json_geo = json.load(fd)

        shape_geo = utils.ToShapely(json_geo)
        exp_pts = {(-95, 40), (-95.5, 40.5), (-95.5, 40), (-96, 40),
                   (-96.5, 40.5), (-96.5, 40)}
        pts = utils.GridPolygon(json_geo, res_arcsec=1800)
        self.assertSetEqual(set(pts), exp_pts)

        pts = utils.GridPolygon(shape_geo, res_arcsec=1800)
        self.assertSetEqual(set(pts), exp_pts)

        pts = utils.GridPolygon(ops.unary_union(shape_geo), res_arcsec=1800)
        self.assertSetEqual(set(pts), exp_pts)
Example #8
0
def getCbsdsWithinPolygon(cbsds, polygon):
    """Returns the list of all CBSDs within a polygon protection area.

  The returned CBSDs can lie either within the polygon or on its boundary.

  Args:
    cbsds: List of |CbsdData| dictionaries as defined in the SAS-SAS specification.
    polygon: A GeoJSON object containing polygon information.
  """
    cbsds_within_polygon = []
    polygon = utils.ToShapely(polygon['features'][0]['geometry'])
    for cbsd in cbsds:
        if not cbsd['grants']:
            continue
        cbsd_lat = cbsd['registration']['installationParam']['latitude']
        cbsd_lon = cbsd['registration']['installationParam']['longitude']
        point = sgeo.Point(cbsd_lon, cbsd_lat)
        # If the CBSD is within the polygon and has grants then add it to the list
        # TODO: check the need for touches() check
        if (polygon.contains(point) or polygon.touches(point)):
            cbsds_within_polygon.append(cbsd)

    return cbsds_within_polygon
def DpaProtectionPoints(dpa_name, dpa_geometry, protection_points_method=None):
    """Gets the protection points for a DPA.

  Args:
    dpa_name: The DPA name.
    dpa_geometry: The DPA geometry as a |shapely.Polygon/MultiPolygon or Point|.
    method: Three ways are supported for getting the protection points:
      + a path pointing to the file holding the protected points location defined as a
        geojson MultiPoint or Point geometry. The path can be either absolute or relative
        to the running script (normally the `harness/` directory).
      + 'default(<parameters>)': A simple default method. Parameters is a tuple defining
        the number of points to use for different part of the DPA:
          num_pts_front_border: Number of points in the front border
          num_pts_back_border: Number of points in the back border
          num_pts_front_zone: Number of points in the front zone
          num_pts_back_zone: Number of points in the back zone
          front_us_border_buffer_km: Buffering of US border for delimiting front/back.
          min_dist_front_border_pts_km: Minimum distance between front border points (km).
          min_dist_back_border_pts_km: Minimum distance between back border points (km).
          min_dist_front_zone_pts_km: Minimum distance between front zone points (km).
          min_dist_back_zone_pts_km: Minimum distance between back zone points (km).
        Example of encoding:
          'default (200,50,20,5)'
        Note the default values are (25, 10, 10, 5, 40, 0.2, 1, 0.5, 3)
        Only the passed parameters will be redefined.
        The result are only approximate (actual distance and number of points may differ).
      + other 'my_method(p1, p2, ..pk)': The 'my_method` will be used, and passing to it
        the parameters p1, p2,... The method must have been registered as a builder method
        using `RegisterMethod()`.

  Returns:
     A list of protection points, each one being a (longitude, latitude) namedtuple.

  Raises:
    IOError: if the provided file cannot be found.
    ValueError: in case of other errors, such as invalid file or parameters.
  """
    def _ExtractBuilder(method):
        idx = method.find('(')
        if idx == -1:
            return None
        name = method[:idx].strip().lower()
        params = method[idx:].strip()
        params = ast.literal_eval(params)
        return name, params

    if not protection_points_method:
        return _DefaultProtectionPoints(dpa_name, dpa_geometry)

    builder = _ExtractBuilder(protection_points_method)
    if builder:
        # Custom or default builder
        name, params = builder
        builder_fn = _builder_methods[name]
        protection_points = builder_fn(dpa_name, dpa_geometry, *params)

    else:
        # Using a geojson file
        protection_points_file = protection_points_method
        if not os.path.isfile(protection_points_file):
            raise IOError(
                'Protected point definition file for DPA `%s` not found at location:'
                '%s' % (dpa_name, protection_points_file))
        with open(protection_points_file, 'r') as fd:
            mpoints = utils.ToShapely(json.load(fd))
        if isinstance(mpoints, sgeo.Point):
            mpoints = sgeo.MultiPoint([mpoints])
        if not isinstance(mpoints, sgeo.MultiPoint):
            raise ValueError(
                'Protected point definition file for DPA `%s` not a valid MultiPoint'
                ' geoJSON file.' % dpa_name)
        protection_points = [
            ProtectionPoint(longitude=pt.x, latitude=pt.y) for pt in mpoints
        ]

    # Check validity of generated points
    if isinstance(dpa_geometry, sgeo.Point):
        if len(protection_points) != 1:
            raise ValueError(
                'Multiple protection points for single point DPA `%s`.' %
                dpa_name)
        pt = sgeo.Point(protection_points[0].longitude,
                        protection_points[0].latitude)
        if not pt.within(dpa_geometry.buffer(0.0005)):
            raise ValueError(
                'Point for single point DPA `%s` is outside zone: %.5f %.5f' %
                (dpa_name, pt.x, pt.y))
    else:
        mpoint = sgeo.MultiPoint([(pt.longitude, pt.latitude)
                                  for pt in protection_points])
        mpoint_inside = dpa_geometry.buffer(0.0005).intersection(mpoint)
        if len(mpoint) != len(mpoint_inside):
            raise ValueError('Some points for DPA `%s` are outside zone.' %
                             dpa_name)

    if not protection_points:
        raise ValueError('No valid points generated for DPA `%s`.' % dpa_name)

    return protection_points