Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
018b7da
Fixes for 1.11
hunt3ri Jul 26, 2018
99e03f1
Try 3.6
hunt3ri Jul 26, 2018
4a8fe3c
Test
hunt3ri Jul 26, 2018
66c319a
File permissions
hunt3ri Jul 26, 2018
cd6807e
Remove cruft
hunt3ri Jul 26, 2018
7b89af9
Remove script for creation of default app.py as provided in EFS (#12)
alastaircarson Aug 13, 2018
9b4e050
Remove run-as lines for now so mapproxy runs as root
alastaircarson Aug 15, 2018
eae4b66
Test privs
hunt3ri Aug 16, 2018
c733e49
Remove RunAs items as running as root is easier within docker with ma…
alastaircarson Aug 17, 2018
8f9ff66
Set chdir correctly
hunt3ri Sep 5, 2018
22849dd
Resolve conflict
hunt3ri Sep 5, 2018
dc492a3
Pin python version 3.6.6
hunt3ri Oct 31, 2018
976fc70
Update mapproxy processes
hunt3ri Nov 25, 2018
d749b69
Revert to Python 3.4
hunt3ri Nov 25, 2018
c5b528d
Update Dockerfile to allow build of old python. UPdate docker-compose…
alastaircarson Dec 11, 2018
8591ffb
Add PG8000 dependency and run dos2unix on start.sh
alastaircarson Dec 12, 2018
2608738
Tune uwsgi concurrency
hunt3ri Dec 13, 2018
9bbd633
Reduce number of mapproxy threads
hunt3ri Dec 17, 2018
725afbb
Pin geojson to 2.4.1 to stop errors
hunt3ri Oct 31, 2019
10b0a7e
python base image from 3.4 to 3.11
ranjeet-idox Sep 26, 2024
0b714a2
added python3.5
ranjeet-idox Sep 27, 2024
cdabda4
python 3.7
ranjeet-idox Sep 29, 2024
08c81f2
geom.py
ranjeet-idox Sep 30, 2024
6108ba2
updates
Nov 4, 2024
a0909f2
use local app.py for now
Nov 4, 2024
bfc871d
commit test directory - to test separately from the mapproxy repo
Nov 4, 2024
fb3226d
Added new library in docker file werkzeug
mariojlunam May 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
tilestore
cache_data/
mapproxy/mapproxy

# Pycharm
.idea/
5 changes: 3 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ services:
max-file: "10"
ports:
- "80:80"
- "443:443"
links:
- mapproxy:mapproxy
mapproxy:
Expand All @@ -26,6 +25,8 @@ services:
- "8080"
- "1717"
volumes:
- ~/mapproxy:/mapproxy
# - c:\code\themapcloud-mapproxy:/mapproxy/config
- c:\code\MapProxy-Docker\mapproxy\test_dir\config:/mapproxy/config
- c:\code\MapProxy-Docker\mapproxy\test_dir\cache:/mapproxy/cache
environment:
- MAPPROXY_ENV=staging
48 changes: 22 additions & 26 deletions mapproxy/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,40 +1,36 @@
#--------- Generic stuff all our Dockerfiles should start with so we get caching ------------
FROM python:3.4
MAINTAINER thinkWhere Ltd<[email protected]>
FROM python:3.13-slim-bookworm

# Based on the docker recipe by Tim Sutton https://github.com/kartoza/docker-mapproxy
RUN apt-get update && apt-get install --no-install-recommends -y \
dos2unix \
python3-yaml \
python3-pil \
python3-pyproj \
python3-lxml \
python3-dev \
python3-shapely \
libgeos-dev \
libgdal-dev \
build-essential \
&& apt-get clean && rm -rf /var/lib/apt/lists/*

# Use local cached debs from host (saves your bandwidth!)
# Change ip below to that of your apt-cacher-ng host
# Or comment this line out if you do not with to use caching
#
# libjpeg-dev \
# zlib1g-dev \
# libfreetype6-dev \
# python-virtualenv \

RUN apt-get -y update

#-------------Application Specific Stuff ----------------------------------------------------

RUN apt-get install -y \
python-imaging \
python-yaml \
libproj0 \
libgeos-dev \
python-lxml \
libgdal-dev \
build-essential \
python3-dev \
libjpeg-dev \
zlib1g-dev \
libfreetype6-dev \
python-virtualenv
RUN pip install --upgrade pip
RUN pip install Shapely Pillow MapProxy==1.9.0 uwsgi requests geojson
RUN pip install Shapely Pillow MapProxy==3.1.0 requests geojson pg8000 uwsgi werkzeug
RUN pip install --pre schematics

ADD uwsgi.ini /uwsgi.ini
RUN chmod 0755 /uwsgi.ini
ADD start.sh /start.sh
RUN dos2unix /start.sh
RUN chmod 0755 /start.sh

# Temp fix for coverages until next version of MapProxy available
# COPY geom.py /usr/local/lib/python3.4/site-packages/mapproxy/util/geom.py
#COPY geom.py /usr/local/lib/python3.7/site-packages/mapproxy/util/geom.py

#USER www-data
# Now launch mappproxy in the foreground
Expand Down
295 changes: 295 additions & 0 deletions mapproxy/geom_original.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
# This file is part of the MapProxy project.
# Copyright (C) 2010 Omniscale <http://omniscale.de>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import division

import os
import json
import codecs
from functools import partial
from contextlib import closing

from mapproxy.grid import tile_grid
from mapproxy.compat import string_type, text_type

import logging
log_config = logging.getLogger('mapproxy.config.coverage')

try:
import shapely.wkt
import shapely.geometry
import shapely.ops
import shapely.prepared
try:
# shapely >=1.6
from shapely.errors import ReadingError
except ImportError:
from shapely.geos import ReadingError
geom_support = True
except ImportError:
geom_support = False

class GeometryError(Exception):
pass

class EmptyGeometryError(Exception):
pass

class CoverageReadError(Exception):
pass

def require_geom_support():
if not geom_support:
raise ImportError('Shapely required for geometry support')


def load_datasource(datasource, where=None):
"""
Loads polygons from WKT text files or OGR datasources.

Returns a list of Shapely Polygons.
"""
# check if it is a wkt or geojson file
if os.path.exists(os.path.abspath(datasource)):
with open(os.path.abspath(datasource), 'rb') as fp:
data = fp.read(50)
if data.lower().lstrip().startswith((b'polygon', b'multipolygon')):
return load_polygons(datasource)
# only load geojson directly if we don't have a filter
if where is None and data and data.startswith(b'{'):
return load_geojson(datasource)
# otherwise pass to OGR
return load_ogr_datasource(datasource, where=where)

def load_ogr_datasource(datasource, where=None):
"""
Loads polygons from any OGR datasource.

Returns a list of Shapely Polygons.
"""
from mapproxy.util.ogr import OGRShapeReader, OGRShapeReaderError

polygons = []
try:
with closing(OGRShapeReader(datasource)) as reader:
for wkt in reader.wkts(where):
if not isinstance(wkt, text_type):
wkt = wkt.decode()
try:
geom = shapely.wkt.loads(wkt)
except ReadingError as ex:
raise GeometryError(ex)
if geom.type == 'Polygon':
polygons.append(geom)
elif geom.type == 'MultiPolygon':
for p in geom:
polygons.append(p)
else:
log_config.warn('skipping %s geometry from %s: not a Polygon/MultiPolygon',
geom.type, datasource)
except OGRShapeReaderError as ex:
raise CoverageReadError(ex)

return polygons

def load_polygons(geom_files):
"""
Loads WKT polygons from one or more text files.

Returns a list of Shapely Polygons.
"""
polygons = []
if isinstance(geom_files, string_type):
geom_files = [geom_files]

for geom_file in geom_files:
# open with utf-8-sig encoding to get rid of UTF8 BOM from MS Notepad
with codecs.open(geom_file, encoding='utf-8-sig') as f:
polygons.extend(load_polygon_lines(f, source=geom_files))

return polygons

def load_geojson(datasource):
with open(datasource) as f:
geojson = json.load(f)
t = geojson.get('type')
if not t:
raise CoverageReadError("not a GeoJSON")
geometries = []
if t == 'FeatureCollection':
for f in geojson.get('features'):
geom = f.get('geometry')
if geom:
geometries.append(geom)
elif t == 'Feature':
if 'geometry' in geojson:
geometries.append(geojson['geometry'])
elif t in ('Polygon', 'MultiPolygon'):
geometries.append(geojson)
else:
log_config.warn('skipping feature of type %s from %s: not a Polygon/MultiPolygon',
t, datasource)

polygons = []
for geom in geometries:
geom = shapely.geometry.asShape(geom)
if geom.type == 'Polygon':
polygons.append(geom)
elif geom.type == 'MultiPolygon':
for p in geom:
polygons.append(p)
else:
log_config.warn('ignoring non-polygon geometry (%s) from %s',
geom.type, datasource)

return polygons

def load_polygon_lines(line_iter, source='<string>'):
polygons = []
for line in line_iter:
if not line.strip():
continue
geom = shapely.wkt.loads(line)
if geom.type == 'Polygon':
polygons.append(geom)
elif geom.type == 'MultiPolygon':
for p in geom:
polygons.append(p)
else:
log_config.warn('ignoring non-polygon geometry (%s) from %s',
geom.type, source)

return polygons

def build_multipolygon(polygons, simplify=False):
if not polygons:
raise EmptyGeometryError('no polygons')

if len(polygons) == 1:
geom = polygons[0]
if simplify:
geom = simplify_geom(geom)
return geom.bounds, geom

if simplify:
polygons = [simplify_geom(g) for g in polygons]

# eliminate any self-overlaps
mp = shapely.ops.cascaded_union(polygons)

return mp.bounds, mp

def simplify_geom(geom):
bounds = geom.bounds
if not bounds:
raise EmptyGeometryError('Empty geometry given')
w, h = bounds[2] - bounds[0], bounds[3] - bounds[1]
tolerance = min((w/1e6, h/1e6))
geom = geom.simplify(tolerance, preserve_topology=True)
if not geom.is_valid:
geom = geom.buffer(0)
return geom

def bbox_polygon(bbox):
"""
Create Polygon that covers the given bbox.
"""
return shapely.geometry.Polygon((
(bbox[0], bbox[1]),
(bbox[2], bbox[1]),
(bbox[2], bbox[3]),
(bbox[0], bbox[3]),
))

def transform_geometry(from_srs, to_srs, geometry):
transf = partial(transform_xy, from_srs, to_srs)

if geometry.type == 'Polygon':
result = transform_polygon(transf, geometry)
elif geometry.type == 'MultiPolygon':
result = transform_multipolygon(transf, geometry)
else:
raise ValueError('cannot transform %s' % geometry.type)

if not result.is_valid:
result = result.buffer(0)
return result

def transform_polygon(transf, polygon):
ext = transf(polygon.exterior.xy)
ints = [transf(ring.xy) for ring in polygon.interiors]
return shapely.geometry.Polygon(ext, ints)

def transform_multipolygon(transf, multipolygon):
transformed_polygons = []
for polygon in multipolygon:
transformed_polygons.append(transform_polygon(transf, polygon))
return shapely.geometry.MultiPolygon(transformed_polygons)

def transform_xy(from_srs, to_srs, xy):
return list(from_srs.transform_to(to_srs, list(zip(*xy))))

def flatten_to_polygons(geometry):
"""
Return a list of all polygons of this (multi)`geometry`.
"""
if geometry.type == 'Polygon':
return [geometry]

if geometry.type == 'MultiPolygon':
return list(geometry)

if hasattr(geometry, 'geoms'):
# GeometryCollection or MultiLineString? return list of all polygons
geoms = []
for part in geometry.geoms:
if part.type == 'Polygon':
geoms.append(part)

if geoms:
return geoms

return []

def load_expire_tiles(expire_dir, grid=None):
if grid is None:
grid = tile_grid(3857, origin='nw')
tiles = set()

def parse(filename):
with open(filename) as f:
try:
for line in f:
if not line:
continue
tile = tuple(map(int, line.split('/')))
tiles.add(tile)
except:
log_config.warn('found error in %s, skipping rest of file', filename)

if os.path.isdir(expire_dir):
for root, dirs, files in os.walk(expire_dir):
for name in files:
filename = os.path.join(root, name)
parse(filename)
else:
parse(expire_dir)

boxes = []
for tile in tiles:
z, x, y = tile
boxes.append(shapely.geometry.box(*grid.tile_bbox((x, y, z))))

return boxes
Loading