Skip to content
Merged

proj6 #269

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
82b9173
[WIP] refactor/enumerations https://github.com/mapnik/mapnik/pull/4372
artemp Jan 23, 2023
c368066
[WIP] restore `memory_datasource` https://github.com/mapnik/mapnik/pu…
artemp Jan 24, 2023
372dba1
[WIP] remove redundant declarations
artemp Jan 24, 2023
0d3ed79
convert some unit tests to use pytest [WIP]
artemp Jan 26, 2023
a3ebedc
convert more unit tests to use pytest [WIP]
artemp Jan 30, 2023
f61bfeb
convert even more unit tests to use pytest [WIP]
artemp Jan 31, 2023
114bab7
Add `keys()` method returning `boost::python::list` e.g
artemp Feb 1, 2023
2a92ab0
Unit tests - 'pytest` [WIP]
artemp Feb 1, 2023
6727f11
Upgrade `ogr` and feature id unit tests
artemp Feb 7, 2023
d6e8d1b
Unit tests - markers + image-filters [WIP]
artemp Feb 7, 2023
40cd3c7
Fix deprecated `PyUnicode_FromUnicode` (NOTE: shouldn't assume wchar …
artemp Feb 7, 2023
67f7222
Unit tests - upgrade palette_test
artemp Feb 8, 2023
0697787
Unit tests - upgrade `printing` module to use `pypdf` package + updat…
artemp Feb 8, 2023
8b6d6fe
Unit tests - upgrade parameters_test
artemp Feb 8, 2023
494752d
Unit tests - upgrade postgis_test
artemp Feb 8, 2023
45ed937
Unit tests [WIP]
artemp Feb 9, 2023
d8a6e05
Unite test pycaro [WIP]
artemp Feb 10, 2023
c79c837
Fix class names to allow pickling support
artemp Feb 15, 2023
6338188
Unit tests - pickling test
artemp Feb 15, 2023
b872f14
Unit test - remove 'osm' plugin test
artemp Feb 15, 2023
af89241
Unit test - png encoding/suite [WIP]
artemp Feb 15, 2023
5dacb72
remove unused definition
artemp Feb 15, 2023
60aadcc
Add missing converter for mapnik::path_expression_ptr
artemp Feb 17, 2023
73b4904
Unit tests - upgrade all to `pytest` + fix paths logic
artemp Feb 17, 2023
54ab6ff
Unit tests - fix webp_encoding_test
artemp Feb 23, 2023
e76b221
Unit tests - update images
artemp Feb 23, 2023
839c98a
Unit tests - update submodules
artemp Feb 23, 2023
115a6d5
format
artemp Feb 23, 2023
d7980cd
Unit test - compositing - comment out unique colours test as per com…
artemp Feb 23, 2023
d97b230
mapnik.printing (PyPDF) - fix proj transformations
artemp Feb 23, 2023
687b2c7
unit test - remove run_all()
artemp Feb 23, 2023
72b6667
Remove 'expanded' + add 'definition' and 'description'
artemp Feb 24, 2023
9954669
projection_test - update to use proj_transform
artemp Feb 24, 2023
2be9862
Unit tests - add 'images_almost_equal(im1, im2, tol)` + update reproj…
artemp Feb 24, 2023
2fd5dc7
Merge pull request #268 from mapnik/pytest
artemp Feb 24, 2023
9540bae
Update visual test data
artemp Feb 22, 2024
7887072
Update test data
artemp Feb 22, 2024
9045155
Update reference image (marker-text-line-scale-factor)
artemp Feb 22, 2024
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
18 changes: 9 additions & 9 deletions mapnik/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def __init__(self, *args, **kwargs):
Box2d.__init__(self, *args, **kwargs)


class _Coord(Coord, _injector()):
class Coord(_mapnik.Coord, _injector()):
"""
Represents a point with two coordinates (either lon/lat or x/y).

Expand Down Expand Up @@ -183,7 +183,7 @@ def inverse(self, projection):
return inverse_(self, projection)


class _Box2d(Box2d, _injector()):
class Box2d(_mapnik.Box2d, _injector()):
"""
Represents a spatial envelope (i.e. bounding box).

Expand Down Expand Up @@ -238,7 +238,7 @@ def inverse(self, projection):
return inverse_(self, projection)


class _Projection(Projection, _injector()):
class Projection(_mapnik.Projection, _injector()):

def __repr__(self):
return "Projection('%s')" % self.params()
Expand Down Expand Up @@ -266,15 +266,15 @@ def inverse(self, obj):
return inverse_(obj, self)


class _Feature(Feature, _injector()):
class Feature(_mapnik.Feature, _injector()):
__geo_interface__ = property(lambda self: json.loads(self.to_geojson()))


class _Geometry(Geometry, _injector()):
class Geometry(_mapnik.Geometry, _injector()):
__geo_interface__ = property(lambda self: json.loads(self.to_geojson()))


class _Datasource(Datasource, _injector()):
class Datasource(_mapnik.Datasource, _injector()):

def featureset(self, fields = None, variables = {}):
query = Query(self.envelope())
Expand All @@ -291,13 +291,13 @@ def all_features(self, fields=None, variables={}):
return self.__iter__(fields, variables)


class _Color(Color, _injector()):
class Color(_mapnik.Color, _injector()):

def __repr__(self):
return "Color(R=%d,G=%d,B=%d,A=%d)" % (self.r, self.g, self.b, self.a)


class _SymbolizerBase(SymbolizerBase, _injector()):
class SymbolizerBase(_mapnik.SymbolizerBase, _injector()):
# back compatibility

@property
Expand Down Expand Up @@ -804,7 +804,7 @@ def make_it(feat, idx):
return itertools.imap(make_it, features, itertools.count(1))


class _TextSymbolizer(TextSymbolizer, _injector()):
class TextSymbolizer(_mapnik.TextSymbolizer, _injector()):

@property
def name(self):
Expand Down
71 changes: 34 additions & 37 deletions mapnik/printing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

"""Mapnik classes to assist in creating printable maps."""

from __future__ import absolute_import, print_function

import logging
import math

from mapnik import Box2d, Coord, Geometry, Layer, Map, Projection, Style, render
from mapnik import Box2d, Coord, Geometry, Layer, Map, Projection, ProjTransform, Style, render
from mapnik.printing.conversions import m2pt, m2px
from mapnik.printing.formats import pagesizes
from mapnik.printing.scales import any_scale, default_scale, deg_min_sec_scale, sequence_scale
Expand All @@ -25,12 +22,12 @@
HAS_PANGOCAIRO_MODULE = False

try:
from PyPDF2 import PdfFileReader, PdfFileWriter
from PyPDF2.generic import (ArrayObject, DecodedStreamObject, DictionaryObject, FloatObject, NameObject,
NumberObject, TextStringObject)
HAS_PYPDF2 = True
from pypdf import PdfReader, PdfWriter
from pypdf.generic import (ArrayObject, DecodedStreamObject, DictionaryObject, FloatObject, NameObject,
NumberObject, TextStringObject)
HAS_PYPDF = True
except ImportError:
HAS_PYPDF2 = False
HAS_PYPDF = False

"""
Style of centering to use with the map.
Expand Down Expand Up @@ -90,7 +87,7 @@ def __init__(self,
Args:
pagesize: tuple of page size in meters, see predefined sizes in mapnik.formats module
margin: page margin in meters
box: the box to render the map into. Must be within page area, margin excluded.
box: the box to render the map into. Must be within page area, margin excluded.
This should be a Mapnik Box2d object. Default is the full page without margin.
percent_box: similar to box argument but specified as a percent (0->1) of the full page size.
If both box and percent_box are specified percent_box will be used.
Expand All @@ -104,7 +101,7 @@ def __init__(self,
be a value from the mapnik.utils.centering class. The default is to center on the maps constrained
axis. Typically this will be horizontal for portrait pages and vertical for landscape pages.
is_latlon: whether the map is in lat lon degrees or not.
use_ocg_layers: create OCG layers in the PDF, requires PyPDF2
use_ocg_layers: create OCG layers in the PDF, requires pypdf
font_name: the font name used each time text is written (e.g., legend titles, representative fraction, etc.)
"""
self._pagesize = pagesize
Expand Down Expand Up @@ -563,7 +560,7 @@ def render_scale(self, m, ctx=None, width=0.05, num_divisions=3, bar_size=8.0, w

Args:
m: the Map object to render the scale for
ctx: A cairo context to render the scale into. If this is None, we create a context and find out
ctx: A cairo context to render the scale into. If this is None, we create a context and find out
the best location for the scale bar
width: the width of area available for rendering the scale bar (in meters)
num_divisions: the number of divisions for the scale bar
Expand Down Expand Up @@ -737,7 +734,7 @@ def render_graticule_on_map(self, m, dec_degrees=True, grid_layer_name="Graticul

# renders the vertical graticule axes
self._render_graticule_axes_and_text(
m,
m,
p2,
latlon_bounds,
latlon_buffer,
Expand Down Expand Up @@ -1119,7 +1116,7 @@ def convert_pdf_pages_to_layers(self, filename, layer_names=None, reverse_all_bu
Takes a multi pages PDF as input and converts each page to a layer in a single page PDF.

Note:
requires PyPDF2 to be available
requires pypdf to be available

Args:
layer_names should be a sequence of the user visible names of the layers, if not given
Expand All @@ -1128,17 +1125,17 @@ def convert_pdf_pages_to_layers(self, filename, layer_names=None, reverse_all_bu
if output_name is not provided a temporary file will be used for the conversion which
will then be copied back over the source file.
"""
if not HAS_PYPDF2:
raise RuntimeError("PyPDF2 not available; PyPDF2 required to convert pdf pages to layers")
if not HAS_PYPDF:
raise RuntimeError("pypdf not available; pypdf required to convert pdf pages to layers")

with open(filename, "rb+") as f:
file_reader = PdfFileReader(f)
file_writer = PdfFileWriter()
file_reader = PdfReader(f)
file_writer = PdfWriter()

template_page_size = file_reader.pages[0].mediaBox
output_pdf = file_writer.addBlankPage(
width=template_page_size.getWidth(),
height=template_page_size.getHeight())
template_page_size = file_reader.pages[0].mediabox
output_pdf = file_writer.add_blank_page(
width=template_page_size.width,
height=template_page_size.height)

content_key = NameObject('/Contents')
output_pdf[content_key] = ArrayObject()
Expand All @@ -1149,15 +1146,15 @@ def convert_pdf_pages_to_layers(self, filename, layer_names=None, reverse_all_bu
(properties, ocgs) = self._make_ocg_layers(file_reader, file_writer, output_pdf, layer_names)

properties_key = NameObject('/Properties')
output_pdf[resource_key][properties_key] = file_writer._addObject(properties)
output_pdf[resource_key][properties_key] = file_writer._add_object(properties)

ocproperties = DictionaryObject()
ocproperties[NameObject('/OCGs')] = ocgs

default_view = self._get_pdf_default_view(ocgs, reverse_all_but_last)
ocproperties[NameObject('/D')] = file_writer._addObject(default_view)
ocproperties[NameObject('/D')] = file_writer._add_object(default_view)

file_writer._root_object[NameObject('/OCProperties')] = file_writer._addObject(ocproperties)
file_writer._root_object[NameObject('/OCProperties')] = file_writer._add_object(ocproperties)

f.seek(0)
file_writer.write(f)
Expand Down Expand Up @@ -1189,7 +1186,7 @@ def _make_ocg_layers(self, file_reader, file_writer, output_pdf, layer_names=Non
page[NameObject(
'/Contents')] = ArrayObject((ocgs_start, page['/Contents'], ocg_end))

output_pdf.mergePage(page)
output_pdf.merge_page(page)

ocg = DictionaryObject()
ocg[NameObject('/Type')] = NameObject('/OCG')
Expand All @@ -1199,7 +1196,7 @@ def _make_ocg_layers(self, file_reader, file_writer, output_pdf, layer_names=Non
else:
ocg[NameObject('/Name')] = TextStringObject('Layer %d' % (idx + 1))

indirect_ocg = file_writer._addObject(ocg)
indirect_ocg = file_writer._add_object(ocg)
properties[ocg_name] = indirect_ocg
ocgs.append(indirect_ocg)

Expand Down Expand Up @@ -1238,20 +1235,20 @@ def add_geospatial_pdf_header(self, m, filename, epsg=None, wkt=None):
The epsg code or the wkt text of the projection must be provided.
Must be called *after* the page has had .finish() called.
"""
if not HAS_PYPDF2:
raise RuntimeError("PyPDF2 not available; PyPDF2 required to add geospatial header to PDF")
if not HAS_PYPDF:
raise RuntimeError("pypdf not available; pypdf required to add geospatial header to PDF")

if not any((epsg,wkt)):
raise RuntimeError("EPSG or WKT required to add geospatial header to PDF")

with open(filename, "rb+") as f:
file_reader = PdfFileReader(f)
file_writer = PdfFileWriter()
file_reader = PdfReader(f)
file_writer = PdfWriter()

# preserve OCProperties at document root if we have one
if file_reader.trailer['/Root'].has_key(NameObject('/OCProperties')):
if NameObject('/OCProperties') in file_reader.trailer['/Root']:
file_writer._root_object[NameObject('/OCProperties')] = file_reader.trailer[
'/Root'].getObject()[NameObject('/OCProperties')]
'/Root'].get_object()[NameObject('/OCProperties')]

for page in file_reader.pages:
gcs = DictionaryObject()
Expand All @@ -1265,7 +1262,7 @@ def add_geospatial_pdf_header(self, m, filename, epsg=None, wkt=None):
measure = self._get_pdf_measure(m, gcs)
page[NameObject('/VP')] = self._get_pdf_vp(measure)

file_writer.addPage(page)
file_writer.add_page(page)

f.seek(0)
file_writer.write(f)
Expand Down Expand Up @@ -1318,11 +1315,11 @@ def _get_pdf_gpts(self, m):
"""
gpts = ArrayObject()

proj = Projection(m.srs)
tr = ProjTransform(Projection(m.srs), Projection("epsg:4326"))
env = m.envelope()
for x in ((env.minx, env.miny), (env.minx, env.maxy),
for p in ((env.minx, env.miny), (env.minx, env.maxy),
(env.maxx, env.maxy), (env.maxx, env.miny)):
latlon_corner = proj.inverse(Coord(*x))
latlon_corner = tr.forward(Coord(*p))
# these are in lat,lon order according to the specification
gpts.append(FloatObject(str(latlon_corner.y)))
gpts.append(FloatObject(str(latlon_corner.x)))
Expand Down
12 changes: 8 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import subprocess
import sys
import glob
import pkg_resources

from distutils import sysconfig
from ctypes.util import find_library

Expand Down Expand Up @@ -230,19 +232,21 @@ def run(self):
if os.environ.get("PYCAIRO", "false") == "true":
try:
extra_comp_args.append('-DHAVE_PYCAIRO')
print("-I%s/include/pycairo".format(sys.exec_prefix))
extra_comp_args.append("-I{0}/include/pycairo".format(sys.exec_prefix))
dist = pkg_resources.get_distribution('pycairo')
print(dist.location)
print("-I%s/cairo/include".format(dist.location))
extra_comp_args.append("-I{0}/cairo/include".format(dist.location))
#extra_comp_args.extend(check_output(["pkg-config", '--cflags', 'pycairo']).strip().split(' '))
#linkflags.extend(check_output(["pkg-config", '--libs', 'pycairo']).strip().split(' '))
except:
raise Exception("Failed to find compiler options for pycairo")

if sys.platform == 'darwin':
extra_comp_args.append('-mmacosx-version-min=10.11')
extra_comp_args.append('-mmacosx-version-min=13.0')
# silence warning coming from boost python macros which
# would is hard to silence via pragma
extra_comp_args.append('-Wno-parentheses-equality')
linkflags.append('-mmacosx-version-min=10.11')
linkflags.append('-mmacosx-version-min=13.0')
else:
linkflags.append('-lrt')
linkflags.append('-Wl,-z,origin')
Expand Down
8 changes: 3 additions & 5 deletions src/mapnik_enumeration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,17 @@ class enumeration_ :
using namespace boost::python::converter;
return base_type::base::to_python(
registered<native_type>::converters.m_class_object
, static_cast<long>( v ));
, static_cast<long>(native_type(v)));

}
};

void init() {
boost::python::implicitly_convertible<native_type, EnumWrapper>();
boost::python::to_python_converter<EnumWrapper, converter >();

for (unsigned i = 0; i < EnumWrapper::MAX; ++i)
for (auto const& kv : EnumWrapper::lookupMap())
{
// Register the strings already defined for this enum.
base_type::value( EnumWrapper::get_string( i ), native_type( i ) );
base_type::value(kv.second.c_str(), kv.first);
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/mapnik_gamma_method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ void export_gamma_method()
using namespace boost::python;

mapnik::enumeration_<mapnik::gamma_method_e>("gamma_method")
.value("POWER", mapnik::GAMMA_POWER)
.value("LINEAR",mapnik::GAMMA_LINEAR)
.value("NONE", mapnik::GAMMA_NONE)
.value("THRESHOLD", mapnik::GAMMA_THRESHOLD)
.value("MULTIPLY", mapnik::GAMMA_MULTIPLY)
.value("POWER", mapnik::gamma_method_enum::GAMMA_POWER)
.value("LINEAR",mapnik::gamma_method_enum::GAMMA_LINEAR)
.value("NONE", mapnik::gamma_method_enum::GAMMA_NONE)
.value("THRESHOLD", mapnik::gamma_method_enum::GAMMA_THRESHOLD)
.value("MULTIPLY", mapnik::gamma_method_enum::GAMMA_MULTIPLY)
;

}
6 changes: 4 additions & 2 deletions src/mapnik_projection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@ void export_projection ()
.def ("params", make_function(&projection::params,
return_value_policy<copy_const_reference>()),
"Returns the PROJ string for this projection.\n")
.def ("expanded",&projection::expanded,
"normalize PROJ definition by expanding epsg:XXXX syntax\n")
.def ("definition",&projection::definition,
"Return projection definition\n")
.def ("description", &projection::description,
"Returns projection description")
.add_property ("geographic", &projection::is_geographic,
"This property is True if the projection is a geographic projection\n"
"(i.e. it uses lon/lat coordinates)\n")
Expand Down
13 changes: 4 additions & 9 deletions src/mapnik_raster_colorizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ using mapnik::colorizer_stop;
using mapnik::colorizer_stops;
using mapnik::colorizer_mode_enum;
using mapnik::color;
using mapnik::COLORIZER_INHERIT;
using mapnik::COLORIZER_LINEAR;
using mapnik::COLORIZER_DISCRETE;
using mapnik::COLORIZER_EXACT;


namespace {
void add_stop(raster_colorizer_ptr & rc, colorizer_stop & stop)
Expand Down Expand Up @@ -196,10 +191,10 @@ void export_raster_colorizer()
;

enum_<colorizer_mode_enum>("ColorizerMode")
.value("COLORIZER_INHERIT", COLORIZER_INHERIT)
.value("COLORIZER_LINEAR", COLORIZER_LINEAR)
.value("COLORIZER_DISCRETE", COLORIZER_DISCRETE)
.value("COLORIZER_EXACT", COLORIZER_EXACT)
.value("COLORIZER_INHERIT", colorizer_mode_enum::COLORIZER_INHERIT)
.value("COLORIZER_LINEAR", colorizer_mode_enum::COLORIZER_LINEAR)
.value("COLORIZER_DISCRETE", colorizer_mode_enum::COLORIZER_DISCRETE)
.value("COLORIZER_EXACT", colorizer_mode_enum::COLORIZER_EXACT)
.export_values()
;

Expand Down
4 changes: 2 additions & 2 deletions src/mapnik_style.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ void export_style()
using namespace boost::python;

mapnik::enumeration_<mapnik::filter_mode_e>("filter_mode")
.value("ALL",mapnik::FILTER_ALL)
.value("FIRST",mapnik::FILTER_FIRST)
.value("ALL",mapnik::filter_mode_enum::FILTER_ALL)
.value("FIRST",mapnik::filter_mode_enum::FILTER_FIRST)
;

class_<rules>("Rules",init<>("default ctor"))
Expand Down
Loading