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)
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)
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()
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
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
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
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
def tell_user(x): raise TopologicalError(x)