Beispiel #1
0
 def _validate_geometry(geom):
     if geom is not None:
         simple = models.DBSession.query(func.ST_IsSimple(geom)).scalar()
         if not simple:
             raise TopologicalError("Not simple")
         valid = models.DBSession.query(func.ST_IsValid(geom)).scalar()
         if not valid:
             reason = models.DBSession.query(func.ST_IsValidReason(geom)).scalar()
             raise TopologicalError(reason)
Beispiel #2
0
 def _validate_geometry(self, geom):
     validate = self.settings.get("geometry_validation", False)
     if validate and geom is not None:
         simple = DBSession.query(func.ST_IsSimple(geom)).scalar()
         if not simple:
             raise TopologicalError("Not simple")
         valid = DBSession.query(func.ST_IsValid(geom)).scalar()
         if not valid:
             reason = DBSession.query(func.ST_IsValidReason(geom)).scalar()
             raise TopologicalError(reason)
Beispiel #3
0
    def parallel_offset(self,
                        distance,
                        side,
                        resolution=16,
                        join_style=JOIN_STYLE.round,
                        mitre_limit=1.0):
        """Returns a LineString or MultiLineString geometry at a distance from
        the object on its right or its left side.

        Distance must be a positive float value. The side parameter may be
        'left' or 'right'. The resolution of the buffer around each vertex of
        the object increases by increasing the resolution keyword parameter or
        third positional parameter.

        The join style is for outside corners between line segments. Accepted
        values are JOIN_STYLE.round (1), JOIN_STYLE.mitre (2), and
        JOIN_STYLE.bevel (3).

        The mitre ratio limit is used for very sharp corners. It is the ratio
        of the distance from the corner to the end of the mitred offset corner.
        When two line segments meet at a sharp angle, a miter join will extend
        far beyond the original geometry. To prevent unreasonable geometry, the
        mitre limit allows controlling the maximum length of the join corner.
        Corners with a ratio which exceed the limit will be beveled."""

        try:
            return geom_factory(self.impl['parallel_offset'](
                self, distance, resolution, join_style, mitre_limit,
                bool(side == 'left')))
        except OSError:
            raise TopologicalError()
Beispiel #4
0
 def __call__(self, this, other, *args):
     self._validate(this)
     self._validate(other, stop_prepared=True)
     product = self.fn(this._geom, other._geom, *args)
     if product is None:
         if not this.is_valid:
             raise TopologicalError(
                 "The operation '%s' produced a null geometry. Likely cause is invalidity of the geometry %s"
                 % (self.fn.__name__, repr(this)))
         elif not other.is_valid:
             raise TopologicalError(
                 "The operation '%s' produced a null geometry. Likely cause is invalidity of the 'other' geometry %s"
                 % (self.fn.__name__, repr(other)))
         else:
             raise TopologicalError(
                 "This operation produced a null geometry. Reason: unknown")
     return product
Beispiel #5
0
 def __call__(self, this, other, *args):
     self._validate(this)
     self._validate(other, stop_prepared=True)
     product = self.fn(this._geom, other._geom, *args)
     if product is None:
         err = TopologicalError(
             "This operation could not be performed. Reason: unknown")
         self._check_topology(err, this, other)
     return product
Beispiel #6
0
    def _check_topology(self, err, *geoms):
        """Raise TopologicalError if geoms are invalid.

        Else, raise original error.
        """
        for geom in geoms:
            if not geom.is_valid:
                raise TopologicalError(
                    "The operation '%s' could not be performed. "
                    "Likely cause is invalidity of the geometry %s" %
                    (self.fn.__name__, repr(geom)))
        raise err
Beispiel #7
0
def polylabel(polygon, tolerance=0.1):
    if not polygon.is_valid:
        raise TopologicalError('Invalid polygon')
    minx, miny, maxx, maxy = polygon.bounds
    width = maxx - minx
    height = maxy - miny
    cell_size = min(width, height)
    h = cell_size / 2.0
    cell_queue = []

    # First best cell approximation is one constructed from the centroid
    # of the polygon
    x, y = polygon.centroid.coords[0]
    best_cell = MyCell(x, y, 0, polygon)

    # Special case for rectangular polygons avoiding floating point error
    bbox_cell = MyCell(minx + width / 2.0, miny + height / 2, 0, polygon)
    if bbox_cell.distance > best_cell.distance:
        best_cell = bbox_cell

    # build a regular square grid covering the polygon
    x = minx
    while x < maxx:
        y = miny
        while y < maxy:
            heappush(cell_queue, MyCell(x + h, y + h, h, polygon))
            y += cell_size
        x += cell_size

    # minimum priority queue
    while cell_queue:
        cell = heappop(cell_queue)

        # update the best cell if we find a better one
        if cell.distance > best_cell.distance:
            best_cell = cell

        # continue to the next iteration if we cant find a better solution
        # based on tolerance
        if cell.max_distance - best_cell.distance <= tolerance:
            continue

        # split the cell into quadrants
        h = cell.h / 2.0
        heappush(cell_queue, MyCell(cell.x - h, cell.y - h, h, polygon))
        heappush(cell_queue, MyCell(cell.x + h, cell.y - h, h, polygon))
        heappush(cell_queue, MyCell(cell.x - h, cell.y + h, h, polygon))
        heappush(cell_queue, MyCell(cell.x + h, cell.y + h, h, polygon))

    return best_cell.centroid
Beispiel #8
0
 def tell_user(x):
     raise TopologicalError(x)