1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
# Copyright (C) 2003 by Intevation GmbH
# Authors:
# Bernhard Herzog <bh@intevation.de>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with the software for details.
"""Mock geometric/geographic objects"""
from __future__ import generators
__version__ = "$Revision: 1593 $"
# $Source$
# $Id: mockgeo.py 1593 2003-08-15 14:10:27Z bh $
class SimpleShape:
def __init__(self, shapeid, points):
self.shapeid = shapeid
self.points = points
def Points(self):
return self.points
def ShapeID(self):
return self.shapeid
def RawData(self):
return self.points
def compute_bbox(self):
xs = []
ys = []
for part in self.Points():
for x, y in part:
xs.append(x)
ys.append(y)
return (min(xs), min(ys), max(xs), max(ys))
class SimpleShapeStore:
"""A simple shapestore object which holds its data in memory"""
def __init__(self, shapetype, shapes, table):
"""Initialize the simple shapestore object.
The shapetype should be one of the predefined SHAPETYPE_*
constants. shapes is a list of shape definitions. Each
definitions is a list of lists of tuples as returned by the
Shape's Points() method. The table argument should be an object
implementing the table interface and contain with one row for
each shape.
"""
self.shapetype = shapetype
self.shapes = shapes
self.table = table
assert table.NumRows() == len(shapes)
def ShapeType(self):
return self.shapetype
def Table(self):
return self.table
def NumShapes(self):
return len(self.shapes)
def Shape(self, index):
return SimpleShape(index, self.shapes[index])
def BoundingBox(self):
xs = []
ys = []
for shape in self.shapes:
for part in shape:
for x, y in part:
xs.append(x)
ys.append(y)
return (min(xs), min(ys), max(xs), max(ys))
def ShapesInRegion(self, bbox):
left, bottom, right, top = bbox
if left > right:
left, right = right, left
if bottom > top:
bottom, top = top, bottom
for i in xrange(len(self.shapes)):
shape = SimpleShape(i, self.shapes[i])
sleft, sbottom, sright, stop = shape.compute_bbox()
if (left <= sright and right >= sleft
and top >= sbottom and bottom <= stop):
yield shape
def AllShapes(self):
for i in xrange(len(self.shapes)):
yield SimpleShape(i, self.shapes[i])
class AffineProjection:
"""Projection-like object implemented with an affine transformation
The transformation matrix is defined by a list of six floats:
[m11, m21, m12, m22, v1, v2]
This list is essentially in the same form as used in PostScript.
This interpreted as the following transformation of (x, y):
/ x \ / m11 m12 \ / x \ / v1 \
T * | | = | | | | + | |
\ y / \ m21 m22 / \ y / \ v2 /
or, in homogeneous coordinates:
/ m11 m12 v1 \ / x \
| | | |
^= | m21 m22 v2 | | y |
| | | |
\ 0 0 1 / \ 1 /
Obviously this is not a real geographic projection, but it's useful
in test cases because it's simple and the result is easily computed
in advance.
"""
def __init__(self, coeff):
self.coeff = coeff
# determine the inverse transformation right away. We trust that
# an inverse exist for the transformations used in the Thuban
# test suite.
m11, m21, m12, m22, v1, v2 = coeff
det = float(m11 * m22 - m12 * m21)
n11 = m22 / det
n12 = -m12 / det
n21 = -m21 / det
n22 = m11 / det
self.inv = [n11, n21, n12, n22, -n11*v1 - n12*v2, -n21*v1 - n22*v2]
def _apply(self, matrix, x, y):
m11, m21, m12, m22, v1, v2 = matrix
return (m11 * x + m12 * y + v1), (m21 * x + m22 * y + v2)
def Forward(self, x, y):
return self._apply(self.coeff, x, y)
def Inverse(self, x, y):
return self._apply(self.inv, x, y)
|