from geometry import *
from bbox import BBox
import utilsDEPRECATED! we use shapely.geometry.MultiPolygon instead
Complex polygons
class MultiPolygon(SolidGeometry): def __init__(self, contours):
self.__area = None
self.__areas = None
self.__centroid = None
self.apply_contours(contours)constructs a Polygon from contours
@staticmethod
def fromPoly(poly):
contours = []
for i in range(len(poly)):
pts = poly.contour(i)
contours.append(pts)
return MultiPolygon(contours)
def apply_contours(self, contours): self.contours = contours
from Polygon import Polygon as GPCPoly
poly = GPCPoly()
skip = 0
for pts_ in contours:
pts = []
for pt in pts_:
if 'deleted' in pt and pt.deleted is True:
skip += 1
continue
pts.append((pt[0], pt[1]))
ishole = utils.is_clockwise(pts)
if len(pts) > 2:
poly.addContour(pts, ishole)
self.poly = poly def area(self):
if self.__area is not None:
return self.__area
self.__area = self.poly.area()
return self.__areareturns array of areas of all sub-polygons areas of holes are < 0
def areas(self): if self.__areas is not None:
return self.__areas
a = []
for i in range(len(self.poly)):
t = self.poly.area(i)
if self.poly.isHole(i):
t *= -1
a.append(t)
self.__areas = a
return areturns the center of gravity for this polygon
def centroid(self): if self.__centroid is not None:
return self.__centroid
self.__centroid = self.poly.center()
return self.__centroidsmart bounding box
def bbox(self, min_area=0): bb = []
bbox = BBox()
if min_area == 0:
bb.append(self.poly.boundingBox())
else:
areas = self.areas()
max_a = max(areas)
for i in range(len(self.poly)):
if self.poly.isHole(i):
continue
a = areas[i]
if a < max_a * min_area:
continue
bb.append(self.poly.boundingBox(i))
for b in bb:
bbox.update((b[0], b[2]))
bbox.update((b[1], b[2]))
bbox.update((b[0], b[3]))
bbox.update((b[1], b[3]))
return bboxreturns a new multi-polygon whose contours are projected to a map projection
def project(self, proj): in_contours = self.contours
out_contours = []
for pts in in_contours:
pcont = proj.plot(pts)
if pcont != None:
out_contours += pcont
return MultiPolygon(out_contours)returns a new multi-polygon whose contours are projected to a new view
def project_view(self, view): contours = self.contours
out = []
for contour in contours:
out_c = []
for pt in contour:
pt = view.project(pt)
out_c.append(pt)
out.append(out_c)
self.contours = out
out_poly = MultiPolygon(out)
return out_poly def crop_to(self, view_bounds):
poly = self.poly & view_bounds.poly
return MultiPolygon.fromPoly(poly) def substract_geom(self, geom):
if not isinstance(geom, MultiPolygon):
raise NotImplementedError('substraction is allowed for polygons only, yet')
poly = self.poly - geom.poly
return MultiPolygon.fromPoly(poly)constructs a svg representation of this polygon
def to_svg(self, svg, round): path_str = ""
if round is False:
fmt = '%f,%f'
else:
fmt = '%.' + str(round) + 'f'
fmt = fmt + ',' + fmt
for pts in self.contours:
cont_str = ""
kept = []
for pt in pts:
if 'deleted' in pt and pt.deleted is True:
continue
kept.append(pt)
if len(kept) <= 3:
continue
for pt in kept:
if cont_str == "":
cont_str = "M"
else:
cont_str += "L"
cont_str += fmt % pt
cont_str += "Z "
path_str += cont_str
if path_str == "":
return None
path = svg.node('path', d=path_str)
return path def is_empty(self):
return len(self.contours) == 0 def unify(self, point_store, precision=None):
from kartograph.simplify import unify_polygons
contours = self.contours
contours = unify_polygons(contours, point_store, precision)
self.apply_contours(contours) def points(self):
return self.contoursis called after the points of this geometry are changed from outside this class
def update(self): self.apply_contours(self.contours) def to_kml(self, round=None):
from pykml.factory import KML_ElementMaker as KML
poly = KML.Polygon(
KML.tesselate("1")
)
outer = KML.outerBoundaryIs()
inner = KML.innerBoundaryIs()
has_inner = False
for i in range(len(self.poly)):
cnt = self.poly[i]
coords = ''
for p in cnt:
coords += ','.join(map(str, p)) + ' '
ring = KML.LinearRing(
KML.coordinates(coords)
)hole = self.poly.isHole(i) if hole == False:
outer.append(ring)else: inner.append(ring) has_inner = True
poly.append(outer)
if has_inner:
poly.append(inner)
return polysplits the geometry into several line segments
def to_line_segments(self): self.lines = [] def from_line_segments(self):
self.lines = []class Polygon(SolidGeometry): def __init__(self, points):
self.__area = None
self.__centroid = None
self.points = points def area(self):
if self.__area is not None:
return self.__area
a = 0
pts = self.points
for i in range(len(pts) - 1):
p0 = pts[i]
p1 = pts[i + 1]
a += p0.x * p1.y - p1.x * p0.y
self.__area = abs(a) * .5
return self.__area def project(self, proj):
self.invalidate()
self.points = proj.plot(self.points)