diff --git a/CHANGELOG b/CHANGELOG.md similarity index 96% rename from CHANGELOG rename to CHANGELOG.md index 8dfa52f59..66bc71981 100644 --- a/CHANGELOG +++ b/CHANGELOG.md @@ -1,8 +1,4 @@ -# $Id: CHANGELOG 776 2008-12-7 01:30:27Z dane $ - ----------------- -Mapnik Changelog ----------------- +# Mapnik Changelog A simple log of core changes affecting Mapnik usage. @@ -11,10 +7,9 @@ Developers: Please commit along with changes. For a complete change history, see the SVN log. -Mapnik 2.1.0 ------------- +## Mapnik 2.1.0 -- Removed mutex locking during reprojection if using >= proj 4.7 (#1072) +- Fix Markers rendering so that ellipse height/width units are pixels (previously were unintentially radii) - Removed PointDatasource - use more robust MemoryDatasource instead (#1032) @@ -26,11 +21,12 @@ Mapnik 2.1.0 - Added parameter in OGR plugin to select a layer by SQL query (besides name or index): see http://www.gdal.org/ogr/ogr_sql.html for specifications (kunitoki) (#472) -- Added suppport for output maps as tiff files (addresses #967 partially) +- Added support for output maps as tiff files (addresses #967 partially) + +- Added support for justify-alignment=auto. This is the new default. (#1125) -Mapnik 2.0.0 ------------- +## Mapnik 2.0.0 - Add minimum-path-length property to text_symbolizer to allow labels to be placed only on lines of a certain length (#865) @@ -119,8 +115,7 @@ Mapnik 2.0.0 - Implement MarkersSymbolizer in Cairo render and improve the markers placement finder. (#553) -Mapnik 0.7.2 Release --------------------- +# Mapnik 0.7.2 Release - Added forward compatibility for Mapnik 2.0 XML syntax (https://trac.mapnik.org/wiki/Mapnik2/Changes) @@ -163,8 +158,7 @@ Mapnik 0.7.2 Release - Fixed reading of label_position_tolerance on text_symbolizer and height for building_symbolizer -Mapnik 0.7.0 Release --------------------- +# Mapnik 0.7.0 Release (Packaged from r1574) @@ -203,13 +197,13 @@ Mapnik 0.7.0 Release * Valid Usages include: - - (Select ST_Union(geom) as geom from table where ST_Intersects(geometry,!bbox!)) as map - + + (Select ST_Union(geom) as geom from table where ST_Intersects(geometry,!bbox!)) as map + - - (Select * from table where geom && !bbox!) as map - + + (Select * from table where geom && !bbox!) as map + - PostGIS Plugin: Added 'scale_denominator' substitution ability in sql query string (#415/#465) @@ -305,8 +299,7 @@ Mapnik 0.7.0 Release -Mapnik 0.6.1 Release --------------------- +# Mapnik 0.6.1 Release (Packaged from r1247) @@ -390,8 +383,7 @@ Mapnik 0.6.1 Release -Mapnik 0.6.0 Release --------------------- +# Mapnik 0.6.0 Release (Packaged from r1066) diff --git a/Makefile b/Makefile index 51a2abbab..624f1cb69 100755 --- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ uninstall: python scons/scons.py uninstall test: + @python tests/visual_tests/test.py + @tests/cpp_tests/font_registration_test + @tests/cpp_tests/params_test @python tests/run_tests.py -q pep8: @@ -26,4 +29,7 @@ pep8: @pep8 -r --select=W293 -q --filename=*.py `pwd`/tests/ | xargs gsed -i 's/^[ \r\t]*$//' @pep8 -r --select=W391 -q --filename=*.py `pwd`/tests/ | xargs gsed -i -e :a -e '/^\n*$/{$d;N;ba' -e '}' +grind: + @valgrind --leak-check=full tests/cpp_tests/font_registration_test + .PHONY: clean reset uninstall test install diff --git a/SConstruct b/SConstruct index 28d3cb94f..c014b9bb5 100644 --- a/SConstruct +++ b/SConstruct @@ -768,7 +768,7 @@ def GetMapnikLibVersion(context): int main() { - std::cout << MAPNIK_VERSION << std::endl; + std::cout << MAPNIK_VERSION_STRING << std::endl; return 0; } @@ -778,11 +778,7 @@ int main() context.Result(ret[0]) if not ret[1]: return [] - version = int(ret[1].strip()) - patch_level = version % 100 - minor_version = version / 100 % 1000 - major_version = version / 100000 - return [major_version,minor_version,patch_level] + return ret[1].strip() def icu_at_least_four_two(context): ret = context.TryRun(""" @@ -1072,7 +1068,7 @@ if not preconfigured: # libxml2 should be optional but is currently not # https://github.com/mapnik/mapnik/issues/913 - if conf.parse_config('XML2_CONFIG'): + if conf.parse_config('XML2_CONFIG',checks='--cflags'): env['HAS_LIBXML2'] = True LIBSHEADERS = [ @@ -1382,14 +1378,13 @@ if not preconfigured: # fetch the mapnik version header in order to set the # ABI version used to build libmapnik.so on linux in src/build.py abi = conf.GetMapnikLibVersion() - abi_fallback = [2,0,0] + abi_fallback = "2.0.1-pre" if not abi: color_print(1,'Problem encountered parsing mapnik version, falling back to %s' % abi_fallback) - env['ABI_VERSION'] = abi_fallback - else: - env['ABI_VERSION'] = abi - env['MAPNIK_VERSION_STRING'] = '.'.join(['%d' % i for i in env['ABI_VERSION']]) + abi = abi_fallback + env['ABI_VERSION'] = abi.replace('-pre','').split('.') + env['MAPNIK_VERSION_STRING'] = abi # Common C++ flags. if env['THREADING'] == 'multi': @@ -1411,7 +1406,9 @@ if not preconfigured: pthread = '-pthread' # Common debugging flags. - debug_flags = '-g -DDEBUG -DMAPNIK_DEBUG' + # http://lists.fedoraproject.org/pipermail/devel/2010-November/144952.html + debug_flags = '-g -fno-omit-frame-pointer -DDEBUG -DMAPNIK_DEBUG' + ndebug_flags = '-DNDEBUG' @@ -1719,7 +1716,7 @@ if not HELP_REQUESTED: # build C++ tests # not ready for release - #SConscript('tests/cpp_tests/build.py') + SConscript('tests/cpp_tests/build.py') # not ready for release #if env['SVG_RENDERER']: diff --git a/bindings/python/mapnik/__init__.py b/bindings/python/mapnik/__init__.py index 9fa035211..8cf54f1d9 100644 --- a/bindings/python/mapnik/__init__.py +++ b/bindings/python/mapnik/__init__.py @@ -120,7 +120,7 @@ class _Coord(Coord,_injector): Returns the easting (x) and northing (y) as a coordinate pair. - + Example: Project the geographic coordinates of the city center of Stuttgart into the local map projection (GK Zone 3/DHDN, EPSG 31467) @@ -136,7 +136,7 @@ class _Coord(Coord,_injector): into the geographic space. The x component is considered to be the easting, the y component to be the northing. - + Returns the longitude (x) and latitude (y) as a coordinate pair. @@ -153,8 +153,8 @@ class _Coord(Coord,_injector): class _Box2d(Box2d,_injector): """ Represents a spatial envelope (i.e. bounding box). - - + + Following operators are defined for Box2d: Addition: @@ -285,12 +285,12 @@ def Datasource(**keywords): Create a Mapnik Datasource using a dictionary of parameters. Keywords must include: - + type='plugin_name' # e.g. type='gdal' - + See the convenience factory methods of each input plugin for details on additional required keyword arguments. - + """ return CreateDatasource(keywords) @@ -322,7 +322,7 @@ def PostGIS(**keywords): Required keyword arguments: dbname -- database name to connect to table -- table name or subselect query - + *Note: if using subselects for the 'table' value consider also passing the 'geometry_field' and 'srid' and 'extent_from_subquery' options and/or specifying the 'geometry_table' option. @@ -572,13 +572,6 @@ def Geos(**keywords): keywords['type'] = 'geos' return CreateDatasource(keywords) -def mapnik_version_string(version=mapnik_version()): - """Return the Mapnik version as a string.""" - patch_level = version % 100 - minor_version = version / 100 % 1000 - major_version = version / 100000 - return '%s.%s.%s' % ( major_version, minor_version,patch_level) - def mapnik_version_from_string(version_string): """Return the Mapnik version from a string.""" n = version_string.split('.') @@ -598,112 +591,3 @@ def register_fonts(path=fontscollectionpath,valid_extensions=['.ttf','.otf','.tt # auto-register known plugins and fonts register_plugins() register_fonts() - -# Explicitly export API members to avoid namespace pollution -# and ensure correct documentation processing -__all__ = [ - # classes - 'CharProperties', - 'Color', - 'Coord', - 'Palette', - #'ColorBand', - 'CompositeOp', - 'DatasourceCache', - 'MemoryDatasource', - 'Box2d', - 'Feature', - 'Featureset', - 'FontEngine', - 'FontSet', - 'FormattingNode', - 'FormattingText', - 'FormattingFormat', - 'FormattingList', - 'FormattingExpressionFormat', - 'Geometry2d', - 'Image', - 'ImageView', - 'Grid', - 'GridView', - 'Layer', - 'Layers', - 'LinePatternSymbolizer', - 'LineSymbolizer', - 'Map', - 'MarkersSymbolizer', - 'Names', - 'Path', - 'Parameter', - 'Parameters', - 'PointSymbolizer', - 'PolygonPatternSymbolizer', - 'PolygonSymbolizer', - 'ProcessedText', - 'ProjTransform', - 'Projection', - 'Query', - 'RasterSymbolizer', - 'RasterColorizer', - 'Rule', 'Rules', - 'ShieldSymbolizer', - 'Singleton', - 'Stroke', - 'Style', - 'Symbolizer', - 'Symbolizers', - 'TextPlacements', - 'TextPlacementInfo', - 'TextSymbolizer', - 'TextSymbolizerProperties', - 'ViewTransform', - # enums - 'aspect_fix_mode', - 'point_placement', - 'label_placement', - 'line_cap', - 'line_join', - 'text_transform', - 'vertical_alignment', - 'horizontal_alignment', - 'justify_alignment', - 'pattern_alignment', - 'filter_mode', - # functions - # datasources - 'Datasource', - 'CreateDatasource', - 'Shapefile', - 'PostGIS', - 'Raster', - 'Gdal', - 'Occi', - 'Ogr', - 'SQLite', - 'Osm', - 'Kismet', - # version and environment - 'mapnik_version_string', - 'mapnik_version', - 'has_cairo', - 'has_pycairo', - # factory methods - 'Expression', - 'PathExpression', - # load/save/render - 'load_map', - 'load_map_from_string', - 'save_map', - 'save_map_to_string', - 'render', - 'render_grid', - 'render_tile_to_file', - 'render_to_file', - # other - 'register_plugins', - 'register_fonts', - 'scale_denominator', - # deprecated - 'Filter', - 'Envelope', - ] diff --git a/bindings/python/mapnik/printing.py b/bindings/python/mapnik/printing.py index 5e6456bd9..8c15d8a8c 100644 --- a/bindings/python/mapnik/printing.py +++ b/bindings/python/mapnik/printing.py @@ -43,7 +43,7 @@ except ImportError: class centering: """Style of centering to use with the map, the default is constrained - + none: map will be placed flush with the margin/box in the top left corner constrained: map will be centered on the most constrained axis (for a portrait page and a square map this will be horizontally) @@ -167,7 +167,7 @@ def sequence_scale(scale,scale_sequence): """Default scale helper, this rounds scale to a 'sensible' value""" factor = math.floor(math.log10(scale)) norm = scale/(10**factor) - + for s in scale_sequence: if norm <= s: return s*10**factor @@ -199,7 +199,7 @@ def deg_min_sec_scale(scale): return x else: return x - + def format_deg_min_sec(value): deg = math.floor(value) min = math.floor((value-deg)/(1.0/60)) @@ -219,12 +219,12 @@ def convert_pdf_pages_to_layers(filename,output_name=None,layer_names=(),reverse opens the given multipage PDF and converts each page to be a layer in a single page PDF layer_names should be a sequence of the user visible names of the layers, if not given or if shorter than num pages generic names will be given to the unnamed layers - + 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. - + requires pyPdf >= 1.13 to be available""" - + if not HAS_PYPDF: raise Exception("pyPdf Not available") @@ -235,13 +235,13 @@ def convert_pdf_pages_to_layers(filename,output_name=None,layer_names=(),reverse else: (outfd,outfilename) = tempfile.mkstemp(dir=os.path.dirname(filename)) outfile = os.fdopen(outfd,'wb') - + i = pyPdf.PdfFileReader(infile) o = pyPdf.PdfFileWriter() - + template_page_size = i.pages[0].mediaBox op = o.addBlankPage(width=template_page_size.getWidth(),height=template_page_size.getHeight()) - + contentkey = pyPdf.generic.NameObject('/Contents') resourcekey = pyPdf.generic.NameObject('/Resources') propertieskey = pyPdf.generic.NameObject('/Properties') @@ -249,7 +249,7 @@ def convert_pdf_pages_to_layers(filename,output_name=None,layer_names=(),reverse op[resourcekey] = pyPdf.generic.DictionaryObject() properties = pyPdf.generic.DictionaryObject() ocgs = pyPdf.generic.ArrayObject() - + for (i, p) in enumerate(i.pages): # first start an OCG for the layer ocgname = pyPdf.generic.NameObject('/oc%d' % i) @@ -262,9 +262,9 @@ def convert_pdf_pages_to_layers(filename,output_name=None,layer_names=(),reverse p[pyPdf.generic.NameObject('/Contents')].append(ocgend) else: p[pyPdf.generic.NameObject('/Contents')] = pyPdf.generic.ArrayObject((ocgstart,p['/Contents'],ocgend)) - + op.mergePage(p) - + ocg = pyPdf.generic.DictionaryObject() ocg[pyPdf.generic.NameObject('/Type')] = pyPdf.generic.NameObject('/OCG') if len(layer_names) > i: @@ -274,9 +274,9 @@ def convert_pdf_pages_to_layers(filename,output_name=None,layer_names=(),reverse indirect_ocg = o._addObject(ocg) properties[ocgname] = indirect_ocg ocgs.append(indirect_ocg) - + op[resourcekey][propertieskey] = o._addObject(properties) - + ocproperties = pyPdf.generic.DictionaryObject() ocproperties[pyPdf.generic.NameObject('/OCGs')] = ocgs defaultview = pyPdf.generic.DictionaryObject() @@ -289,16 +289,16 @@ def convert_pdf_pages_to_layers(filename,output_name=None,layer_names=(),reverse else: defaultview[pyPdf.generic.NameObject('/Order')] = pyPdf.generic.ArrayObject(reversed(ocgs)) defaultview[pyPdf.generic.NameObject('/OFF')] = pyPdf.generic.ArrayObject() - + ocproperties[pyPdf.generic.NameObject('/D')] = o._addObject(defaultview) - + o._root.getObject()[pyPdf.generic.NameObject('/OCProperties')] = o._addObject(ocproperties) - + o.write(outfile) - + outfile.close() infile.close() - + if not output_name: os.rename(outfilename, filename) @@ -318,7 +318,7 @@ class PDFPrinter: is_latlon=False, use_ocg_layers=False): """Creates a cairo surface and context to render a PDF with. - + pagesize: tuple of page size in meters, see predefined sizes in pagessizes dict (default a4) margin: page margin in meters (default 0.01) box: box within the page to render the map into (will not render over margin). This should be @@ -348,54 +348,54 @@ class PDFPrinter: self._centering = centering self._is_latlon = is_latlon self._use_ocg_layers = use_ocg_layers - + self._s = None self._layer_names = [] self._filename = None - + self.map_box = None self.scale = None - + # don't both to round the scale if they are not preserving the aspect ratio if not preserve_aspect: self._scale = any_scale - + if percent_box: self._box = Box2d(percent_box[0]*pagesize[0],percent_box[1]*pagesize[1], percent_box[2]*pagesize[0],percent_box[3]*pagesize[1]) if not HAS_PYCAIRO_MODULE: raise Exception("PDF rendering only available when pycairo is available") - + self.font_name = "DejaVu Sans" - + def finish(self): if self._s: self._s.finish() self._s = None - + if self._use_ocg_layers: convert_pdf_pages_to_layers(self._filename,layer_names=self._layer_names + ["Legend and Information"],reverse_all_but_last=True) - + def add_geospatial_pdf_header(self,m,filename,epsg=None,wkt=None): """ Postprocessing step to add geospatial PDF information to PDF file as per PDF standard 1.7 extension level 3 (also in draft PDF v2 standard at time of writing) - + one of either the epsg code or wkt text for the projection must be provided - + Should be called *after* the page has had .finish() called""" if HAS_PYPDF and (epsg or wkt): infile=file(filename,'rb') (outfd,outfilename) = tempfile.mkstemp(dir=os.path.dirname(filename)) outfile = os.fdopen(outfd,'wb') - + i=pyPdf.PdfFileReader(infile) o=pyPdf.PdfFileWriter() - + # preserve OCProperties at document root if we have one if i.trailer['/Root'].has_key(pyPdf.generic.NameObject('/OCProperties')): o._root.getObject()[pyPdf.generic.NameObject('/OCProperties')] = i.trailer['/Root'].getObject()[pyPdf.generic.NameObject('/OCProperties')] - + for p in i.pages: gcs = pyPdf.generic.DictionaryObject() gcs[pyPdf.generic.NameObject('/Type')]=pyPdf.generic.NameObject('/PROJCS') @@ -403,7 +403,7 @@ class PDFPrinter: gcs[pyPdf.generic.NameObject('/EPSG')]=pyPdf.generic.NumberObject(int(epsg)) if wkt: gcs[pyPdf.generic.NameObject('/WKT')]=pyPdf.generic.TextStringObject(wkt) - + measure = pyPdf.generic.DictionaryObject() measure[pyPdf.generic.NameObject('/Type')]=pyPdf.generic.NameObject('/Measure') measure[pyPdf.generic.NameObject('/Subtype')]=pyPdf.generic.NameObject('/GEO') @@ -414,7 +414,7 @@ class PDFPrinter: measure[pyPdf.generic.NameObject('/Bounds')]=bounds measure[pyPdf.generic.NameObject('/LPTS')]=bounds gpts=pyPdf.generic.ArrayObject() - + proj=Projection(m.srs) env=m.envelope() for x in ((env.minx, env.miny), (env.minx, env.maxy), (env.maxx, env.maxy), (env.maxx, env.miny)): @@ -423,31 +423,31 @@ class PDFPrinter: gpts.append(pyPdf.generic.FloatObject(str(latlon_corner.y))) gpts.append(pyPdf.generic.FloatObject(str(latlon_corner.x))) measure[pyPdf.generic.NameObject('/GPTS')]=gpts - + vp=pyPdf.generic.DictionaryObject() vp[pyPdf.generic.NameObject('/Type')]=pyPdf.generic.NameObject('/Viewport') bbox=pyPdf.generic.ArrayObject() - + for x in self.map_box: bbox.append(pyPdf.generic.FloatObject(str(x))) vp[pyPdf.generic.NameObject('/BBox')]=bbox vp[pyPdf.generic.NameObject('/Measure')]=measure - + vpa = pyPdf.generic.ArrayObject() vpa.append(vp) p[pyPdf.generic.NameObject('/VP')]=vpa o.addPage(p) - + o.write(outfile) infile=None outfile.close() os.rename(outfilename,filename) - - + + def get_context(self): """allow access so that extra 'bits' can be rendered to the page directly""" return cairo.Context(self._s) - + def get_width(self): return self._pagesize[0] @@ -456,7 +456,7 @@ class PDFPrinter: def get_margin(self): return self._margin - + def write_text(self,ctx,text,box_width=None,size=10, fill_color=(0.0, 0.0, 0.0), alignment=None): if HAS_PANGOCAIRO_MODULE: (attr,t,accel) = pango.parse_markup(text) @@ -474,7 +474,7 @@ class PDFPrinter: pctx.set_source_rgb(*fill_color) pctx.show_layout(l) return l.get_pixel_extents()[0] - + else: ctx.rel_move_to(0,size) ctx.select_font_face(self.font_name, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) @@ -489,18 +489,18 @@ class PDFPrinter: elif HAS_PYCAIRO_MODULE: return cairo.Context(self._s) return None - + def _get_render_area(self): """return a bounding box with the area of the page we are allowed to render out map to in page coordinates (i.e. meters) """ # take off our page margins render_area = Box2d(self._margin,self._margin,self._pagesize[0]-self._margin,self._pagesize[1]-self._margin) - + #then if user specified a box to render get intersection with that if self._box: return render_area.intersect(self._box) - + return render_area def _get_render_area_size(self): @@ -513,7 +513,7 @@ class PDFPrinter: available_area = self._get_render_area_size() map_aspect = m.envelope().width()/m.envelope().height() page_aspect = available_area[0]/available_area[1] - + return map_aspect > page_aspect def _get_meta_info_corner(self,render_size,m): @@ -526,7 +526,7 @@ class PDFPrinter: else: x += render_size[0]+0.005 y = self._margin - + return (x,y) def _get_render_corner(self,render_size,m): @@ -535,9 +535,9 @@ class PDFPrinter: x=available_area[0] y=available_area[1] - + h_is_contrained = self._is_h_contrained(m) - + if (self._centering == centering.both or self._centering == centering.horizontal or (self._centering == centering.constrained and h_is_contrained) or @@ -550,26 +550,26 @@ class PDFPrinter: (self._centering == centering.unconstrained and h_is_contrained)): y+=(available_area.height()-render_size[1])/2 return (x,y) - + def _get_map_pixel_size(self, width_page_m, height_page_m): """for a given map size in paper coordinates return a tuple of the map 'pixel' size we should create at the defined resolution""" return (int(m2px(width_page_m,self._resolution)), int(m2px(height_page_m,self._resolution))) - + def render_map(self,m, filename): """Render the given map to filename""" - + # store this for later so we can post process the PDF self._filename = filename - + # work out the best scale to render out map at given the available space (eff_width,eff_height) = self._get_render_area_size() map_aspect = m.envelope().width()/m.envelope().height() page_aspect = eff_width/eff_height - + scalex=m.envelope().width()/eff_width scaley=m.envelope().height()/eff_height - + scale=max(scalex,scaley) rounded_mapscale=self._scale(scale) @@ -581,26 +581,26 @@ class PDFPrinter: maph=mapw*(1/map_aspect) else: mapw=maph*map_aspect - + # set the map size so that raster elements render at the correct resolution m.resize(*self._get_map_pixel_size(mapw,maph)) # calculate the translation for the map starting point (tx,ty) = self._get_render_corner((mapw,maph),m) - + # create our cairo surface and context and then render the map into it self._s = cairo.PDFSurface(filename, m2pt(self._pagesize[0]),m2pt(self._pagesize[1])) ctx=cairo.Context(self._s) - + for l in m.layers: # extract the layer names for naming layers if we use OCG self._layer_names.append(l.name) - + layer_map = Map(m.width,m.height,m.srs) layer_map.layers.append(l) for s in l.styles: layer_map.append_style(s,m.find_style(s)) layer_map.zoom_to_box(m.envelope()) - + def render_map(): ctx.save() ctx.translate(m2pt(tx),m2pt(ty)) @@ -608,7 +608,7 @@ class PDFPrinter: ctx.scale(72.0/self._resolution,72.0/self._resolution) render(layer_map, ctx) ctx.restore() - + # antimeridian render_map() if self._is_latlon and (m.envelope().minx < -180 or m.envelope().maxx > 180): @@ -621,10 +621,10 @@ class PDFPrinter: render_map() # restore the original env m.zoom_to_box(old_env) - + if self._use_ocg_layers: self._s.show_page() - + self.scale = rounded_mapscale self.map_box = Box2d(tx,ty,tx+mapw,ty+maph) @@ -640,7 +640,7 @@ class PDFPrinter: if p2.inverse(m.envelope().center()).y > latlon_bounds.maxy: latlon_bounds = Box2d(latlon_bounds.miny,latlon_bounds.maxy,latlon_bounds.maxx,latlon_bounds.miny+360) - + latlon_mapwidth = latlon_bounds.width() # render an extra 20% so we generally won't miss the ends of lines latlon_buffer = 0.2*latlon_mapwidth @@ -649,7 +649,7 @@ class PDFPrinter: else: latlon_divsize = deg_min_sec_scale(latlon_mapwidth/7.0) latlon_interpsize = latlon_mapwidth/m.width - + self._render_lat_lon_axis(m,p2,latlon_bounds.minx,latlon_bounds.maxx,latlon_bounds.miny,latlon_bounds.maxy,latlon_buffer,latlon_interpsize,latlon_divsize,dec_degrees,True) self._render_lat_lon_axis(m,p2,latlon_bounds.miny,latlon_bounds.maxy,latlon_bounds.minx,latlon_bounds.maxx,latlon_buffer,latlon_interpsize,latlon_divsize,dec_degrees,False) @@ -658,21 +658,21 @@ class PDFPrinter: ctx.set_source_rgb(1,0,0) ctx.set_line_width(1) latlon_labelsize = 6 - + ctx.translate(m2pt(self.map_box.minx),m2pt(self.map_box.miny)) ctx.rectangle(0,0,m2pt(self.map_box.width()),m2pt(self.map_box.height())) ctx.clip() - + ctx.select_font_face("DejaVu", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) ctx.set_font_size(latlon_labelsize) - + box_top = self.map_box.height() if not is_x_axis: ctx.translate(m2pt(self.map_box.width()/2),m2pt(self.map_box.height()/2)) ctx.rotate(-math.pi/2) ctx.translate(-m2pt(self.map_box.height()/2),-m2pt(self.map_box.width()/2)) box_top = self.map_box.width() - + for xvalue in round_grid_generator(x1 - latlon_buffer,x2 + latlon_buffer,latlon_divsize): yvalue = y1 - latlon_buffer start_cross = None @@ -693,12 +693,12 @@ class PDFPrinter: ctx.move_to(start.x,start.y) ctx.line_to(end.x,end.y) ctx.stroke() - + if cmp(start.y, 0) != cmp(end.y,0): start_cross = end.x if cmp(start.y,m2pt(self.map_box.height())) != cmp(end.y, m2pt(self.map_box.height())): end_cross = end.x - + if dec_degrees: line_text = "%g" % (xvalue) else: @@ -712,19 +712,19 @@ class PDFPrinter: def render_on_map_scale(self,m): (div_size,page_div_size) = self._get_sensible_scalebar_size(m) - + first_value_x = (math.floor(m.envelope().minx / div_size) + 1) * div_size first_value_x_percent = (first_value_x-m.envelope().minx)/m.envelope().width() self._render_scale_axis(first_value_x,first_value_x_percent,self.map_box.minx,self.map_box.maxx,page_div_size,div_size,self.map_box.miny,self.map_box.maxy,True) - + first_value_y = (math.floor(m.envelope().miny / div_size) + 1) * div_size first_value_y_percent = (first_value_y-m.envelope().miny)/m.envelope().height() self._render_scale_axis(first_value_y,first_value_y_percent,self.map_box.miny,self.map_box.maxy,page_div_size,div_size,self.map_box.minx,self.map_box.maxx,False) - + if self._use_ocg_layers: self._s.show_page() self._layer_names.append("Coordinate Grid Overlay") - + def _get_sensible_scalebar_size(self,m,width=-1): # aim for about 8 divisions across the map # also make sure we can fit the bar with in page area width if specified @@ -744,7 +744,7 @@ class PDFPrinter: ctx.set_source_rgb(*stroke_color) ctx.rectangle(x,y,w,h) ctx.stroke() - + if text: ctx.move_to(x+1,y) self.write_text(ctx,text,fill_color=[1-z for z in fill_color],size=h-2) @@ -758,14 +758,14 @@ class PDFPrinter: label_value = first-div_size if self._is_latlon and label_value < -180: label_value += 360 - + ctx=cairo.Context(self._s) - + if not is_x_axis: ctx.translate(m2pt(self.map_box.center().x),m2pt(self.map_box.center().y)) ctx.rotate(-math.pi/2) ctx.translate(-m2pt(self.map_box.center().y),-m2pt(self.map_box.center().x)) - + while value < end: ctx.move_to(m2pt(value),m2pt(boundary_start)) ctx.line_to(m2pt(value),m2pt(boundary_end)) @@ -775,7 +775,7 @@ class PDFPrinter: for bar in (m2pt(boundary_start)-border_size,m2pt(boundary_end)): self._render_box(ctx,m2pt(prev),bar,m2pt(value-prev),border_size,text,fill_color=fill) - + prev = value value+=page_div_size fill = [1-z for z in fill] @@ -787,18 +787,18 @@ class PDFPrinter: for bar in (m2pt(boundary_start)-border_size,m2pt(boundary_end)): self._render_box(ctx,m2pt(prev),bar,m2pt(end-prev),border_size,fill_color=fill) - + def render_scale(self,m,ctx=None,width=0.05): """ m: map to render scale for ctx: A cairo context to render the scale to. If this is None (the default) then automatically create a context and choose the best location for the scale bar. width: Width of area available to render scale bar in (in m) - + will return the size of the rendered scale block in pts """ - + (w,h) = (0,0) - + # don't render scale if we are lat lon # dont report scale if we have warped the aspect ratio if self._preserve_aspect and not self._is_latlon: @@ -808,15 +808,15 @@ class PDFPrinter: ctx=cairo.Context(self._s) (tx,ty) = self._get_meta_info_corner((self.map_box.width(),self.map_box.height()),m) ctx.translate(tx,ty) - + (div_size,page_div_size) = self._get_sensible_scalebar_size(m, width/box_count) - + div_unit = "m" if div_size > 1000: div_size /= 1000 div_unit = "km" - + text = "0%s" % div_unit ctx.save() if width > 0: @@ -846,7 +846,7 @@ class PDFPrinter: text_ext=self.write_text(ctx,"Scale 1:%d" % self.scale,box_width=box_width,size=font_size, alignment=alignment) h+=text_ext[3]+2 - + return (w,h) def render_legend(self,m, page_break=False, ctx=None, collumns=1,width=None, height=None, item_per_rule=False, attribution={}, legend_item_box_size=(0.015,0.0075)): @@ -858,7 +858,7 @@ class PDFPrinter: collumns: number of collumns available in legend box attribution: additional text that will be rendered in gray under the layer name. keyed by layer name legend_item_box_size: two tuple with width and height of legend item box size in meters - + will return the size of the rendered block in pts """ @@ -879,7 +879,7 @@ class PDFPrinter: else: cwidth = None current_collumn = 0 - + processed_layers = [] for l in reversed(m.layers): have_layer_header = False @@ -888,7 +888,7 @@ class PDFPrinter: if layer_title in processed_layers: continue processed_layers.append(layer_title) - + # check through the features to find which combinations of styles are active # for each unique combination add a legend entry for f in l.datasource.all_features(): @@ -913,20 +913,20 @@ class PDFPrinter: active_rules = tuple(active_rules) if added_styles.has_key(active_rules): continue - + added_styles[active_rules] = (f,rule_text) if not item_per_rule: break else: added_styles[l] = (None,None) - + legend_items = added_styles.keys() legend_items.sort() for li in legend_items: if True: (f,rule_text) = added_styles[li] - - + + legend_map_size = (int(m2pt(legend_item_box_size[0])),int(m2pt(legend_item_box_size[1]))) lemap=Map(legend_map_size[0],legend_map_size[1],srs=m.srs) if m.background: @@ -967,11 +967,11 @@ class PDFPrinter: for s in l.styles: lelayer.styles.append(s) lemap.layers.append(lelayer) - + if f is None or f.envelope().width() != 0: lemap.zoom_all() lemap.zoom(1.1) - + item_size = legend_map_size[1] if not have_layer_header: item_size += 8 @@ -998,7 +998,7 @@ class PDFPrinter: ctx.save() render(lemap, ctx) ctx.restore() - + ctx.rectangle(0,0,*legend_map_size) ctx.set_source_rgb(0.5,0.5,0.5) ctx.set_line_width(1) @@ -1017,12 +1017,12 @@ class PDFPrinter: if attribution.has_key(layer_title): e=self.write_text(ctx, attribution[layer_title], m2pt(cwidth-legend_item_box_size[0]-0.005), 6, fill_color=(0.5,0.5,0.5)) legend_text_size += e[3] - + if legend_text_size > legend_entry_size: legend_entry_size=legend_text_size - + y+=legend_entry_size +2 if y > h: h = y return (w,h) - + diff --git a/bindings/python/mapnik_font_engine.cpp b/bindings/python/mapnik_font_engine.cpp index 3992b1287..1b2596e3c 100644 --- a/bindings/python/mapnik_font_engine.cpp +++ b/bindings/python/mapnik_font_engine.cpp @@ -42,6 +42,7 @@ void export_font_engine() .def("register_fonts",&freetype_engine::register_fonts) .def("face_names",&freetype_engine::face_names) .staticmethod("register_font") + .staticmethod("register_fonts") .staticmethod("face_names") ; } diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 858c53437..5ade76573 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -125,7 +125,7 @@ bool painted(mapnik::image_32 const& im) void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c) { im.setPixel(x, y, c.rgba()); -} +} boost::shared_ptr open_from_file(std::string const& filename) { diff --git a/bindings/python/mapnik_layer.cpp b/bindings/python/mapnik_layer.cpp index a37843b7f..512d895b4 100644 --- a/bindings/python/mapnik_layer.cpp +++ b/bindings/python/mapnik_layer.cpp @@ -54,7 +54,7 @@ struct layer_pickle_suite : boost::python::pickle_suite { s.append(style_names[i]); } - return boost::python::make_tuple(l.clear_label_cache(),l.getMinZoom(),l.getMaxZoom(),l.isQueryable(),l.datasource()->params(),l.cache_features(),s); + return boost::python::make_tuple(l.clear_label_cache(),l.min_zoom(),l.max_zoom(),l.queryable(),l.datasource()->params(),l.cache_features(),s); } static void @@ -72,11 +72,11 @@ struct layer_pickle_suite : boost::python::pickle_suite l.set_clear_label_cache(extract(state[0])); - l.setMinZoom(extract(state[1])); + l.set_min_zoom(extract(state[1])); - l.setMaxZoom(extract(state[2])); + l.set_max_zoom(extract(state[2])); - l.setQueryable(extract(state[3])); + l.set_queryable(extract(state[3])); mapnik::parameters params = extract(state[4]); l.set_datasource(datasource_cache::instance()->create(params)); @@ -128,7 +128,7 @@ void export_layer() "box2d(-1.0,-1.0,0.0,0.0) # default until a datasource is loaded\n" ) - .def("visible", &layer::isVisible, + .def("visible", &layer::visible, "Return True if this layer's data is active and visible at a given scale.\n" "\n" "Otherwise returns False.\n" @@ -149,8 +149,8 @@ void export_layer() ) .add_property("active", - &layer::isActive, - &layer::setActive, + &layer::active, + &layer::set_active, "Get/Set whether this layer is active and will be rendered.\n" "\n" "Usage:\n" @@ -199,8 +199,8 @@ void export_layer() ) .add_property("maxzoom", - &layer::getMaxZoom, - &layer::setMaxZoom, + &layer::max_zoom, + &layer::set_max_zoom, "Get/Set the maximum zoom lever of the layer.\n" "\n" "Usage:\n" @@ -214,8 +214,8 @@ void export_layer() ) .add_property("minzoom", - &layer::getMinZoom, - &layer::setMinZoom, + &layer::min_zoom, + &layer::set_min_zoom, "Get/Set the minimum zoom lever of the layer.\n" "\n" "Usage:\n" @@ -244,8 +244,8 @@ void export_layer() ) .add_property("queryable", - &layer::isQueryable, - &layer::setQueryable, + &layer::queryable, + &layer::set_queryable, "Get/Set whether this layer is queryable.\n" "\n" "Usage:\n" diff --git a/bindings/python/mapnik_line_symbolizer.cpp b/bindings/python/mapnik_line_symbolizer.cpp index 062d52618..9c7053b90 100644 --- a/bindings/python/mapnik_line_symbolizer.cpp +++ b/bindings/python/mapnik_line_symbolizer.cpp @@ -62,5 +62,9 @@ void export_line_symbolizer() (&line_symbolizer::get_stroke, return_value_policy()), &line_symbolizer::set_stroke) + .add_property("smooth", + &line_symbolizer::smooth, + &line_symbolizer::set_smooth, + "smooth value (0..1.0)") ; } diff --git a/bindings/python/mapnik_map.cpp b/bindings/python/mapnik_map.cpp index 9e1287420..542cc08f3 100644 --- a/bindings/python/mapnik_map.cpp +++ b/bindings/python/mapnik_map.cpp @@ -117,11 +117,8 @@ struct map_pickle_suite : boost::python::pickle_suite std::vector& (Map::*layers_nonconst)() = &Map::layers; std::vector const& (Map::*layers_const)() const = &Map::layers; - -mapnik::parameters& (Map::*attr_nonconst)() = &Map::get_extra_attributes; mapnik::parameters& (Map::*params_nonconst)() = &Map::get_extra_parameters; - mapnik::feature_type_style find_style(mapnik::Map const& m, std::string const& name) { boost::optional style = m.find_style(name); @@ -482,7 +479,6 @@ void export_map() ) .def("__deepcopy__",&map_deepcopy) - .add_property("extra_attributes",make_function(attr_nonconst,return_value_policy()),"TODO") .add_property("parameters",make_function(params_nonconst,return_value_policy()),"TODO") .add_property("aspect_fix_mode", diff --git a/bindings/python/mapnik_markers_symbolizer.cpp b/bindings/python/mapnik_markers_symbolizer.cpp index df0ae4606..17d860f11 100644 --- a/bindings/python/mapnik_markers_symbolizer.cpp +++ b/bindings/python/mapnik_markers_symbolizer.cpp @@ -60,7 +60,8 @@ struct markers_symbolizer_pickle_suite : boost::python::pickle_suite static boost::python::tuple getstate(markers_symbolizer const& p) { - return boost::python::make_tuple(p.get_allow_overlap());//,p.get_opacity()); + return boost::python::make_tuple(p.get_allow_overlap(), + p.get_ignore_placement());//,p.get_opacity()); } static void @@ -77,7 +78,8 @@ struct markers_symbolizer_pickle_suite : boost::python::pickle_suite } p.set_allow_overlap(extract(state[0])); - //p.set_opacity(extract(state[1])); + p.set_ignore_placement(extract(state[1])); + //p.set_opacity(extract(state[2])); } @@ -108,8 +110,19 @@ void export_markers_symbolizer() &markers_symbolizer::get_opacity, &markers_symbolizer::set_opacity, "Set/get the text opacity") + .add_property("ignore_placement", + &markers_symbolizer::get_ignore_placement, + &markers_symbolizer::set_ignore_placement) .add_property("transform", &mapnik::get_svg_transform, &mapnik::set_svg_transform) + .add_property("width", + &markers_symbolizer::get_width, + &markers_symbolizer::set_width, + "Set/get the marker width") + .add_property("height", + &markers_symbolizer::get_height, + &markers_symbolizer::set_height, + "Set/get the marker height") ; } diff --git a/bindings/python/mapnik_polygon_symbolizer.cpp b/bindings/python/mapnik_polygon_symbolizer.cpp index 4b4fb1b1a..dd809ac5d 100644 --- a/bindings/python/mapnik_polygon_symbolizer.cpp +++ b/bindings/python/mapnik_polygon_symbolizer.cpp @@ -84,7 +84,11 @@ void export_polygon_symbolizer() .add_property("gamma_method", &polygon_symbolizer::get_gamma_method, &polygon_symbolizer::set_gamma_method, - "Set/get the gamma correction method of the polygon") + "gamma correction method") + .add_property("smooth", + &polygon_symbolizer::smooth, + &polygon_symbolizer::set_smooth, + "smooth value (0..1.0)") ; } diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index e0591977a..4a4f5c4c9 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -279,6 +279,11 @@ unsigned mapnik_version() return MAPNIK_VERSION; } +std::string mapnik_version_string() +{ + return MAPNIK_VERSION_STRING; +} + // indicator for jpeg read/write support within libmapnik bool has_jpeg() { @@ -573,6 +578,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("save_map_to_string", &save_map_to_string, save_map_to_string_overloads()); def("mapnik_version", &mapnik_version,"Get the Mapnik version number"); + def("mapnik_version_string", &mapnik_version_string,"Get the Mapnik version string"); def("has_jpeg", &has_jpeg, "Get jpeg read/write support status"); def("has_cairo", &has_cairo, "Get cairo library status"); def("has_pycairo", &has_pycairo, "Get pycairo module status"); diff --git a/bindings/python/mapnik_text_placement.cpp b/bindings/python/mapnik_text_placement.cpp index 12c8dfa55..13de8478b 100644 --- a/bindings/python/mapnik_text_placement.cpp +++ b/bindings/python/mapnik_text_placement.cpp @@ -40,15 +40,15 @@ using namespace mapnik; /* Notes: -Overriding functions in inherited classes: -boost.python documentation doesn't really tell you how to do it. -But this helps: -http://www.gamedev.net/topic/446225-inheritance-in-boostpython/ + Overriding functions in inherited classes: + boost.python documentation doesn't really tell you how to do it. + But this helps: + http://www.gamedev.net/topic/446225-inheritance-in-boostpython/ -register_ptr_to_python is required for wrapped classes, but not for unwrapped. + register_ptr_to_python is required for wrapped classes, but not for unwrapped. -Functions don't have to be members of the class, but can also be -normal functions taking a ref to the class as first parameter. + Functions don't have to be members of the class, but can also be + normal functions taking a ref to the class as first parameter. */ namespace { @@ -261,7 +261,7 @@ struct TextPlacementsWrap: text_placements, wrapper struct TextPlacementInfoWrap: text_placement_info, wrapper { TextPlacementInfoWrap(text_placements const* parent, - double scale_factor_) + double scale_factor_) : text_placement_info(parent, scale_factor_) { @@ -329,6 +329,7 @@ void export_text_placement() .value("LEFT",J_LEFT) .value("MIDDLE",J_MIDDLE) .value("RIGHT",J_RIGHT) + .value("AUTO", J_AUTO) ; enumeration_("text_transform") @@ -339,7 +340,7 @@ void export_text_placement() ; class_("TextSymbolizer", - init<>()) + init<>()) .def(init()) .add_property("placements", &text_symbolizer::get_placement_options, @@ -357,7 +358,7 @@ void export_text_placement() class_with_converter - ("TextSymbolizerProperties") + ("TextSymbolizerProperties") .def_readwrite_convert("label_placement", &text_symbolizer_properties::label_placement) .def_readwrite_convert("horizontal_alignment", &text_symbolizer_properties::halign) .def_readwrite_convert("justify_alignment", &text_symbolizer_properties::jalign) @@ -381,15 +382,15 @@ void export_text_placement() .add_property ("format_tree", &text_symbolizer_properties::format_tree, &text_symbolizer_properties::set_format_tree); - /* from_xml, to_xml operate on mapnik's internal XML tree and don't make sense in python. - add_expressions isn't useful in python either. The result is only needed by - attribute_collector (which isn't exposed in python) and - it just calls add_expressions of the associated formatting tree. - set_old_style expression is just a compatibility wrapper and doesn't need to be exposed in python. */ - ; + /* from_xml, to_xml operate on mapnik's internal XML tree and don't make sense in python. + add_expressions isn't useful in python either. The result is only needed by + attribute_collector (which isn't exposed in python) and + it just calls add_expressions of the associated formatting tree. + set_old_style expression is just a compatibility wrapper and doesn't need to be exposed in python. */ + ; class_ - ("CharProperties") + ("CharProperties") .def(init()) //Copy constructor .def_readwrite("face_name", &char_properties::face_name) .def_readwrite("fontset", &char_properties::fontset) @@ -407,9 +408,9 @@ void export_text_placement() ; class_, - boost::noncopyable> - ("TextPlacements") + boost::shared_ptr, + boost::noncopyable> + ("TextPlacements") .def_readwrite("defaults", &text_placements::defaults) .def("get_placement_info", pure_virtual(&text_placements::get_placement_info)) /* TODO: add_expressions() */ @@ -417,10 +418,10 @@ void export_text_placement() register_ptr_to_python >(); class_, - boost::noncopyable> - ("TextPlacementInfo", - init()) + boost::shared_ptr, + boost::noncopyable> + ("TextPlacementInfo", + init()) .def("next", pure_virtual(&text_placement_info::next)) .def("get_actual_label_spacing", &text_placement_info::get_actual_label_spacing) .def("get_actual_minimum_distance", &text_placement_info::get_actual_minimum_distance) @@ -432,27 +433,27 @@ void export_text_placement() class_, - boost::noncopyable> - ("ProcessedText", no_init) + boost::shared_ptr, + boost::noncopyable> + ("ProcessedText", no_init) .def("push_back", &processed_text::push_back) .def("clear", &processed_text::clear) ; class_, - boost::noncopyable> - ("ExpressionSet") + boost::shared_ptr, + boost::noncopyable> + ("ExpressionSet") .def("insert", &insert_expression); - ; + ; //TODO: Python namespace class_, - boost::noncopyable> - ("FormattingNode") + boost::shared_ptr, + boost::noncopyable> + ("FormattingNode") .def("apply", pure_virtual(&formatting::node::apply)) .def("add_expressions", &formatting::node::add_expressions, @@ -462,10 +463,10 @@ void export_text_placement() class_, - bases, - boost::noncopyable> - ("FormattingText", init()) + boost::shared_ptr, + bases, + boost::noncopyable> + ("FormattingText", init()) .def(init()) .def("apply", &formatting::text_node::apply, &TextNodeWrap::default_apply) .add_property("text", @@ -476,10 +477,10 @@ void export_text_placement() class_with_converter, - bases, - boost::noncopyable> - ("FormattingFormat") + boost::shared_ptr, + bases, + boost::noncopyable> + ("FormattingFormat") .def_readwrite_convert("text_size", &formatting::format_node::text_size) .def_readwrite_convert("face_name", &formatting::format_node::face_name) .def_readwrite_convert("character_spacing", &formatting::format_node::character_spacing) @@ -499,10 +500,10 @@ void export_text_placement() register_ptr_to_python >(); class_, - bases, - boost::noncopyable> - ("FormattingList", init<>()) + boost::shared_ptr, + bases, + boost::noncopyable> + ("FormattingList", init<>()) .def(init()) .def("append", &formatting::list_node::push_back) .def("apply", &formatting::list_node::apply, &ListNodeWrap::default_apply) @@ -510,15 +511,15 @@ void export_text_placement() .def("__getitem__", &ListNodeWrap::get_item) .def("__setitem__", &ListNodeWrap::set_item) .def("append", &ListNodeWrap::append) - ; + ; register_ptr_to_python >(); class_, - bases, - boost::noncopyable> - ("FormattingExpressionFormat") + boost::shared_ptr, + bases, + boost::noncopyable> + ("FormattingExpressionFormat") .def_readwrite("text_size", &formatting::expression_format::text_size) .def_readwrite("face_name", &formatting::expression_format::face_name) .def_readwrite("character_spacing", &formatting::expression_format::character_spacing) diff --git a/bindings/python/mapnik_threads.hpp b/bindings/python/mapnik_threads.hpp index b1ac3f4e6..85789ff61 100644 --- a/bindings/python/mapnik_threads.hpp +++ b/bindings/python/mapnik_threads.hpp @@ -29,8 +29,8 @@ namespace mapnik { class python_thread { /* Docs: - http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock - */ + http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock + */ public: static void unblock() { @@ -38,8 +38,8 @@ public: if (state.get()) { std::cerr << "ERROR: Python threads are already unblocked. " - "Unblocking again will loose the current state and " - "might crash later. Aborting!\n"; + "Unblocking again will loose the current state and " + "might crash later. Aborting!\n"; abort(); //This is a serious error and can't be handled in any other sane way } #endif @@ -59,9 +59,9 @@ public: if (thread_support && !state.get()) { std::cerr << "ERROR: Trying to restore python thread state, " - "but no state is saved. Can't continue and also " - "can't raise an exception because the python " - "interpreter might be non-function. Aborting!\n"; + "but no state is saved. Can't continue and also " + "can't raise an exception because the python " + "interpreter might be non-function. Aborting!\n"; abort(); } #endif diff --git a/bindings/python/python_optional.hpp b/bindings/python/python_optional.hpp index da3279f2f..7707f0053 100644 --- a/bindings/python/python_optional.hpp +++ b/bindings/python/python_optional.hpp @@ -102,8 +102,8 @@ struct python_optional : public boost::noncopyable /** This class works around a bug in boost python. - See http://osdir.com/ml/python.c++/2003-11/msg00158.html - */ + See http://osdir.com/ml/python.c++/2003-11/msg00158.html +*/ template class class_with_converter : public boost::python::class_ { @@ -131,8 +131,8 @@ public: self& def_readwrite_convert(char const* name, D const& d, char const* doc=0) { this->add_property(name, - boost::python::make_getter(d, boost::python::return_value_policy()), - boost::python::make_setter(d, boost::python::default_call_policies())); + boost::python::make_getter(d, boost::python::return_value_policy()), + boost::python::make_setter(d, boost::python::default_call_policies())); return *this; } }; diff --git a/demo/python/rundemo.py b/demo/python/rundemo.py index 0fda7526d..bd9639a4b 100644 --- a/demo/python/rundemo.py +++ b/demo/python/rundemo.py @@ -138,7 +138,9 @@ qcdrain_lyr.datasource = mapnik.Shapefile(file='../data/qcdrainage') qcdrain_style = mapnik.Style() qcdrain_rule = mapnik.Rule() qcdrain_rule.filter = mapnik.Expression('[HYC] = 8') -qcdrain_rule.symbols.append(mapnik.PolygonSymbolizer(mapnik.Color(153, 204, 255))) +sym = mapnik.PolygonSymbolizer(mapnik.Color(153, 204, 255)) +sym.smooth = 1.0 # very smooth +qcdrain_rule.symbols.append(sym) qcdrain_style.rules.append(qcdrain_rule) m.append_style('drainage', qcdrain_style) diff --git a/demo/viewer/layerlistmodel.cpp b/demo/viewer/layerlistmodel.cpp index b6dae0d20..68280dce1 100644 --- a/demo/viewer/layerlistmodel.cpp +++ b/demo/viewer/layerlistmodel.cpp @@ -49,7 +49,7 @@ QVariant LayerListModel::data(QModelIndex const& index,int role) const else if (role == Qt::DecorationRole) { double scale = map_->scale(); - if (map_->layers().at(index.row()).isVisible(scale)) + if (map_->layers().at(index.row()).visible(scale)) { return QIcon(":/images/globe.png"); } @@ -60,7 +60,7 @@ QVariant LayerListModel::data(QModelIndex const& index,int role) const } else if (role == Qt::CheckStateRole) { - if (map_->layers().at(index.row()).isActive()) + if (map_->layers().at(index.row()).active()) return QVariant(Qt::Checked); else return QVariant(Qt::Unchecked); @@ -92,7 +92,7 @@ bool LayerListModel::setData(const QModelIndex &index, { int status = value.toInt(); std::vector & layers = const_cast& >(map_->layers()); - layers.at(index.row()).setActive(status); + layers.at(index.row()).set_active(status); emit dataChanged(index, index); return true; } diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index f9a29ee45..103b4d9cd 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "mapwidget.hpp" #include "info_dialog.hpp" @@ -157,7 +158,7 @@ void MapWidget::mousePressEvent(QMouseEvent* e) if (int(index) != selectedLayer_) continue; layer & layer = map_->layers()[index]; - if (!layer.isVisible(scale_denom)) continue; + if (!layer.visible(scale_denom)) continue; std::string name = layer.name(); double x = e->x(); double y = e->y(); @@ -487,7 +488,7 @@ void MapWidget::updateMap() } catch (mapnik::config_error & ex) { - std::cerr << ex.what() << std::endl; + std::cerr << ex.what() << std::endl; } catch (...) { diff --git a/include/mapnik/agg_helpers.hpp b/include/mapnik/agg_helpers.hpp new file mode 100644 index 000000000..e605194fe --- /dev/null +++ b/include/mapnik/agg_helpers.hpp @@ -0,0 +1,91 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_AGG_HELPERS_HPP +#define MAPNIK_AGG_HELPERS_HPP + +#include "agg_gamma_functions.h" +#include "agg_math_stroke.h" + +namespace mapnik { + +template +void set_gamma_method(T0 const& obj, T1 & ras_ptr) +{ + switch (obj.get_gamma_method()) + { + case GAMMA_POWER: + ras_ptr->gamma(agg::gamma_power(obj.get_gamma())); + break; + case GAMMA_LINEAR: + ras_ptr->gamma(agg::gamma_linear(0.0, obj.get_gamma())); + break; + case GAMMA_NONE: + ras_ptr->gamma(agg::gamma_none()); + break; + case GAMMA_THRESHOLD: + ras_ptr->gamma(agg::gamma_threshold(obj.get_gamma())); + break; + case GAMMA_MULTIPLY: + ras_ptr->gamma(agg::gamma_multiply(obj.get_gamma())); + break; + default: + ras_ptr->gamma(agg::gamma_power(obj.get_gamma())); + } +} + +template +void set_join_caps(Stroke const& stroke_, PathType & stroke) +{ + line_join_e join=stroke_.get_line_join(); + switch (join) + { + case MITER_JOIN: + stroke.generator().line_join(agg::miter_join); + break; + case MITER_REVERT_JOIN: + stroke.generator().line_join(agg::miter_join); + break; + case ROUND_JOIN: + stroke.generator().line_join(agg::round_join); + break; + default: + stroke.generator().line_join(agg::bevel_join); + } + + line_cap_e cap=stroke_.get_line_cap(); + switch (cap) + { + case BUTT_CAP: + stroke.generator().line_cap(agg::butt_cap); + break; + case SQUARE_CAP: + stroke.generator().line_cap(agg::square_cap); + break; + default: + stroke.generator().line_cap(agg::round_cap); + } +} + +} + +#endif //MAPNIK_AGG_HELPERS_HPP diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index 4522e3aeb..d7e09049a 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -29,10 +29,6 @@ #include #include #include -//#include - -// agg -//#include "agg_trans_affine.h" // boost #include @@ -67,10 +63,10 @@ public: ~agg_renderer(); void start_map_processing(Map const& map); void end_map_processing(Map const& map); - void start_layer_processing(layer const& lay); + void start_layer_processing(layer const& lay, box2d const& query_extent); void end_layer_processing(layer const& lay); void render_marker(pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity); - + void process(point_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans); @@ -123,7 +119,7 @@ private: face_manager font_manager_; boost::shared_ptr detector_; boost::scoped_ptr ras_ptr; - + box2d query_extent_; void setup(Map const &m); }; } diff --git a/include/mapnik/boolean.hpp b/include/mapnik/boolean.hpp new file mode 100644 index 000000000..bc9b46cc4 --- /dev/null +++ b/include/mapnik/boolean.hpp @@ -0,0 +1,99 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +#ifndef MAPNIK_BOOLEAN_HPP +#define MAPNIK_BOOLEAN_HPP + +// std +#include + +// boost +#include + +namespace mapnik +{ +/** Helper for class bool */ +class boolean { +public: + boolean(): b_(false) {} + boolean(bool b) : b_(b) {} + boolean(boolean const& b) : b_(b.b_) {} + + operator bool() const + { + return b_; + } + + boolean & operator = (boolean const& other) + { + b_ = other.b_; + return * this; + } + + boolean & operator = (bool other) + { + b_ = other; + return * this; + } + +private: + bool b_; +}; + +/** Special stream input operator for boolean values */ +template +std::basic_istream & +operator >> ( std::basic_istream & s, boolean & b ) +{ + std::string word; + s >> word; + boost::algorithm::to_lower(word); + if ( s ) + { + if ( word == "true" || word == "yes" || word == "on" || + word == "1") + { + b = true; + } + else if ( word == "false" || word == "no" || word == "off" || + word == "0") + { + b = false; + } + else + { + s.setstate( std::ios::failbit ); + } + } + return s; +} + +template +std::basic_ostream & +operator << ( std::basic_ostream & s, boolean const& b ) +{ + s << ( b ? "true" : "false" ); + return s; +} + +} + +#endif // MAPNIK_BOOLEAN_HPP diff --git a/include/mapnik/cairo_renderer.hpp b/include/mapnik/cairo_renderer.hpp index 1c11e605c..dd37ac906 100644 --- a/include/mapnik/cairo_renderer.hpp +++ b/include/mapnik/cairo_renderer.hpp @@ -78,7 +78,7 @@ protected: public: ~cairo_renderer_base(); void start_map_processing(Map const& map); - void start_layer_processing(layer const& lay); + void start_layer_processing(layer const& lay, box2d const& query_extent); void end_layer_processing(layer const& lay); void process(point_symbolizer const& sym, mapnik::feature_ptr const& feature, @@ -132,6 +132,7 @@ protected: face_manager font_manager_; cairo_face_manager face_manager_; label_collision_detector4 detector_; + box2d query_extent_; }; template diff --git a/include/mapnik/color.hpp b/include/mapnik/color.hpp index c7f2de610..ad9806276 100644 --- a/include/mapnik/color.hpp +++ b/include/mapnik/color.hpp @@ -137,6 +137,14 @@ public: std::string to_hex_string() const; }; +template +std::basic_ostream & +operator << ( std::basic_ostream & s, mapnik::color const& c ) +{ + std::string hex_string( c.to_string() ); + s << hex_string; + return s; +} } diff --git a/include/mapnik/color_factory.hpp b/include/mapnik/color_factory.hpp index 3d92cb193..418c244a0 100644 --- a/include/mapnik/color_factory.hpp +++ b/include/mapnik/color_factory.hpp @@ -25,134 +25,26 @@ // mapnik #include -#include -#include // boost #include -#include - -// boost 1.41 -> 1.44 compatibility, to be removed in mapnik 2.1 (dane) -#if BOOST_VERSION >= 104500 -#include namespace mapnik { +class color; + +template struct css_color_grammar; class MAPNIK_DECL color_factory : boost::noncopyable { public: - static void init_from_string(color & c, std::string const& css_color) - { - typedef std::string::const_iterator iterator_type; - typedef mapnik::css_color_grammar css_color_grammar; - - css_color_grammar g; - iterator_type first = css_color.begin(); - iterator_type last = css_color.end(); - bool result = - boost::spirit::qi::phrase_parse(first, - last, - g, - boost::spirit::ascii::space, - c); - if (!result) - { - throw config_error(std::string("Failed to parse color value: ") + - "Expected a CSS color, but got '" + css_color + "'"); - } - } + static void init_from_string(color & c, std::string const& css_color); static bool parse_from_string(color & c, std::string const& css_color, - mapnik::css_color_grammar const& g) - { - std::string::const_iterator first = css_color.begin(); - std::string::const_iterator last = css_color.end(); - bool result = - boost::spirit::qi::phrase_parse(first, - last, - g, - boost::spirit::ascii::space, - c); - return result && (first == last); - } + mapnik::css_color_grammar const& g); - static color from_string(std::string const& css_color) - { - color c; - init_from_string(c,css_color); - return c; - } + static color from_string(std::string const& css_color); }; } -#else -#include - -namespace mapnik { - -class MAPNIK_DECL color_factory : boost::noncopyable -{ -public: - - static bool parse_from_string(color & c, std::string const& css_color, - mapnik::css_color_grammar const& g) - { - std::string::const_iterator first = css_color.begin(); - std::string::const_iterator last = css_color.end(); - mapnik::css css_; - bool result = - boost::spirit::qi::phrase_parse(first, - last, - g, - boost::spirit::ascii::space, - css_); - if (result && (first == last)) - { - c.set_red(css_.r); - c.set_green(css_.g); - c.set_blue(css_.b); - c.set_alpha(css_.a); - return true; - } - return false; - } - - static void init_from_string(color & c, std::string const& css_color) - { - typedef std::string::const_iterator iterator_type; - typedef mapnik::css_color_grammar css_color_grammar; - - css_color_grammar g; - iterator_type first = css_color.begin(); - iterator_type last = css_color.end(); - mapnik::css css_; - bool result = - boost::spirit::qi::phrase_parse(first, - last, - g, - boost::spirit::ascii::space, - css_); - if (!result) - { - throw config_error(std::string("Failed to parse color value: ") + - "Expected a CSS color, but got '" + css_color + "'"); - } - c.set_red(css_.r); - c.set_green(css_.g); - c.set_blue(css_.b); - c.set_alpha(css_.a); - } - - static color from_string(std::string const& css_color) - { - color c; - init_from_string(c,css_color); - return c; - } -}; -} - -#endif - #endif // MAPNIK_COLOR_FACTORY_HPP diff --git a/include/mapnik/config.hpp b/include/mapnik/config.hpp index d25d74f62..88399b19c 100644 --- a/include/mapnik/config.hpp +++ b/include/mapnik/config.hpp @@ -25,8 +25,6 @@ // Windows DLL support -#define MAPNIK_SUPPORTS_GRID_RENDERER - #ifdef _WINDOWS # define MAPNIK_EXP __declspec (dllexport) # define MAPNIK_IMP __declspec (dllimport) diff --git a/include/mapnik/config_error.hpp b/include/mapnik/config_error.hpp index ad06fba58..a889bc39e 100644 --- a/include/mapnik/config_error.hpp +++ b/include/mapnik/config_error.hpp @@ -28,31 +28,28 @@ namespace mapnik { +class xml_node; class config_error : public std::exception { public: - config_error(): - what_() {} - - config_error( std::string const& what ) : - what_( what ) - { - } + config_error(std::string const& what); + config_error(std::string const& what, xml_node const& node); + config_error(std::string const& what, unsigned line_number, std::string const& filename); virtual ~config_error() throw() {} - virtual const char * what() const throw() - { - return what_.c_str(); - } - - void append_context(std::string const& ctx) const - { - what_ += " " + ctx; - } + virtual const char * what() const throw(); + void append_context(const std::string & ctx) const; + void append_context(const std::string & ctx, xml_node const& node) const; + void append_context(xml_node const& node) const; protected: mutable std::string what_; + mutable unsigned line_number_; + mutable std::string file_; + mutable std::string node_name_; + mutable std::string msg_; }; + } #endif // MAPNIK_CONFIG_ERROR_HPP diff --git a/include/mapnik/ctrans.hpp b/include/mapnik/ctrans.hpp index 43219ad29..31c62f391 100644 --- a/include/mapnik/ctrans.hpp +++ b/include/mapnik/ctrans.hpp @@ -72,16 +72,16 @@ template struct MAPNIK_DECL coord_transform2 { typedef std::size_t size_type; - typedef typename Geometry::value_type value_type; + //typedef typename Geometry::value_type value_type; coord_transform2(Transform const& t, - Geometry const& geom, + Geometry & geom, proj_transform const& prj_trans) : t_(t), geom_(geom), prj_trans_(prj_trans) {} - unsigned vertex(double *x, double *y) const + unsigned vertex(double *x, double *y) { unsigned command = SEG_MOVETO; bool ok = false; @@ -115,7 +115,7 @@ struct MAPNIK_DECL coord_transform2 private: Transform const& t_; - Geometry const& geom_; + Geometry & geom_; proj_transform const& prj_trans_; }; @@ -397,9 +397,9 @@ public: sx_(1.0), sy_(1.0) { - if (extent_.width()) + if (extent_.width() > 0) sx_ = static_cast(width_) / extent_.width(); - if (extent_.height()) + if (extent_.height() > 0) sy_ = static_cast(height_) / extent_.height(); } diff --git a/include/mapnik/expression.hpp b/include/mapnik/expression.hpp index 4192c2a81..8862aed76 100644 --- a/include/mapnik/expression.hpp +++ b/include/mapnik/expression.hpp @@ -26,7 +26,6 @@ // mapnik #include #include -#include // stl #include @@ -35,6 +34,7 @@ namespace mapnik { typedef boost::shared_ptr expression_ptr; +template struct expression_grammar; class expression_factory { diff --git a/include/mapnik/expression_grammar.hpp b/include/mapnik/expression_grammar.hpp index b5d478c5e..702e18a9b 100644 --- a/include/mapnik/expression_grammar.hpp +++ b/include/mapnik/expression_grammar.hpp @@ -229,7 +229,7 @@ struct expression_grammar : qi::grammar ("\\r", '\r')("\\t", '\t')("\\v", '\v')("\\\\", '\\') ("\\\'", '\'')("\\\"", '\"') ; - + #if BOOST_VERSION > 104500 quote_char %= char_('\'') | char_('"'); ustring %= omit[quote_char[_a = _1]] @@ -237,7 +237,7 @@ struct expression_grammar : qi::grammar >> lit(_a); attr %= '[' >> no_skip[+~char_(']')] >> ']'; #else - ustring %= lit('\'') + ustring %= lit('\'') >> *(unesc_char | "\\x" >> hex | (char_ - lit('\''))) >> lit('\''); attr %= '[' >> lexeme[+(char_ - ']')] >> ']'; diff --git a/include/mapnik/feature.hpp b/include/mapnik/feature.hpp index 9b636824d..fa517101c 100644 --- a/include/mapnik/feature.hpp +++ b/include/mapnik/feature.hpp @@ -99,11 +99,11 @@ public: feature_impl(context_ptr const& ctx, int id) : id_(id), - ctx_(ctx), - data_(ctx_->mapping_.size()), - geom_cont_(), - raster_() - {} + ctx_(ctx), + data_(ctx_->mapping_.size()), + geom_cont_(), + raster_() + {} inline int id() const { return id_;} @@ -163,25 +163,25 @@ public: { context_type::map_type::const_iterator itr = ctx_->mapping_.find(key); if (itr != ctx_->mapping_.end()) - return get(itr->second); - else - throw std::out_of_range(std::string("Key does not exist: '") + key + "'"); + return get(itr->second); + else + throw std::out_of_range(std::string("Key does not exist: '") + key + "'"); } - + value_type const& get(std::size_t index) const { if (index < data_.size()) return data_[index]; throw std::out_of_range("Index out of range"); } - + boost::optional get_optional(std::size_t index) const { if (index < data_.size()) return boost::optional(data_[index]); return boost::optional(); } - + std::size_t size() const { return data_.size(); @@ -224,13 +224,14 @@ public: box2d envelope() const { + // TODO - cache this box2d result; for (unsigned i=0;i box = geom.envelope(); + box2d const& box = geom.envelope(); result.init(box.minx(),box.miny(),box.maxx(),box.maxy()); } else @@ -273,7 +274,7 @@ public: if (index < data_.size()) { ss << " " << itr->first << ":" << data_[itr->second] << std::endl; - } + } } ss << ")" << std::endl; return ss.str(); diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index b8b91ea7b..a08a6454d 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -46,6 +46,7 @@ extern "C" #include #include #include +#include #ifdef MAPNIK_THREADSAFE #include #endif @@ -153,7 +154,7 @@ class MAPNIK_DECL font_face_set : private boost::noncopyable public: font_face_set(void) : faces_(), - dimension_cache_() {} + dimension_cache_() {} void add(face_ptr face) { @@ -168,11 +169,10 @@ public: glyph_ptr get_glyph(unsigned c) const { - for (std::vector::const_iterator face = faces_.begin(); face != faces_.end(); ++face) + BOOST_FOREACH ( face_ptr const& face, faces_) { - FT_UInt g = (*face)->get_char(c); - - if (g) return boost::make_shared(*face, g); + FT_UInt g = face->get_char(c); + if (g) return boost::make_shared(face, g); } // Final fallback to empty square if nothing better in any font @@ -185,17 +185,17 @@ public: void set_pixel_sizes(unsigned size) { - for (std::vector::iterator face = faces_.begin(); face != faces_.end(); ++face) + BOOST_FOREACH ( face_ptr const& face, faces_) { - (*face)->set_pixel_sizes(size); + face->set_pixel_sizes(size); } } void set_character_sizes(float size) { - for (std::vector::iterator face = faces_.begin(); face != faces_.end(); ++face) + BOOST_FOREACH ( face_ptr const& face, faces_) { - (*face)->set_character_sizes(size); + face->set_character_sizes(size); } } private: @@ -263,7 +263,7 @@ template class MAPNIK_DECL face_manager : private boost::noncopyable { typedef T font_engine_type; - typedef std::map faces; + typedef std::map face_ptr_cache_type; public: face_manager(T & engine) @@ -272,9 +272,9 @@ public: face_ptr get_face(std::string const& name) { - typename faces::iterator itr; - itr = faces_.find(name); - if (itr != faces_.end()) + face_ptr_cache_type::iterator itr; + itr = face_ptr_cache_.find(name); + if (itr != face_ptr_cache_.end()) { return itr->second; } @@ -283,7 +283,7 @@ public: face_ptr face = engine_.create_face(name); if (face) { - faces_.insert(make_pair(name,face)); + face_ptr_cache_.insert(make_pair(name,face)); } return face; } @@ -335,7 +335,7 @@ public: } private: - faces faces_; + face_ptr_cache_type face_ptr_cache_; font_engine_type & engine_; stroker_ptr stroker_; }; diff --git a/include/mapnik/formatting/base.hpp b/include/mapnik/formatting/base.hpp index 47efe70de..7c4f0a144 100644 --- a/include/mapnik/formatting/base.hpp +++ b/include/mapnik/formatting/base.hpp @@ -36,6 +36,7 @@ namespace mapnik { typedef std::set expression_set; class processed_text; +class xml_node; struct char_properties; namespace formatting { @@ -48,7 +49,7 @@ class node public: virtual ~node() {} virtual void to_xml(boost::property_tree::ptree &xml) const; - static node_ptr from_xml(boost::property_tree::ptree const& xml); + static node_ptr from_xml(xml_node const& xml); virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const = 0; virtual void add_expressions(expression_set &output) const; }; diff --git a/include/mapnik/formatting/expression.hpp b/include/mapnik/formatting/expression.hpp index e85b7d973..d3db09691 100644 --- a/include/mapnik/formatting/expression.hpp +++ b/include/mapnik/formatting/expression.hpp @@ -31,7 +31,7 @@ namespace formatting { class expression_format: public node { public: void to_xml(boost::property_tree::ptree &xml) const; - static node_ptr from_xml(boost::property_tree::ptree const& xml); + static node_ptr from_xml(xml_node const& xml); virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const; virtual void add_expressions(expression_set &output) const; @@ -51,7 +51,7 @@ public: private: node_ptr child_; - static expression_ptr get_expression(boost::property_tree::ptree const& xml, std::string name); + static expression_ptr get_expression(xml_node const& xml, std::string name); }; } //ns formatting } //ns mapnik diff --git a/include/mapnik/formatting/format.hpp b/include/mapnik/formatting/format.hpp index 53e09a47f..22bef2d8e 100644 --- a/include/mapnik/formatting/format.hpp +++ b/include/mapnik/formatting/format.hpp @@ -31,7 +31,7 @@ namespace formatting { class format_node: public node { public: void to_xml(boost::property_tree::ptree &xml) const; - static node_ptr from_xml(boost::property_tree::ptree const& xml); + static node_ptr from_xml(xml_node const& xml); virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const; virtual void add_expressions(expression_set &output) const; diff --git a/include/mapnik/formatting/registry.hpp b/include/mapnik/formatting/registry.hpp index 9c2c9df22..1c44e68dd 100644 --- a/include/mapnik/formatting/registry.hpp +++ b/include/mapnik/formatting/registry.hpp @@ -38,16 +38,16 @@ namespace mapnik namespace formatting { -typedef node_ptr (*from_xml_function_ptr)(boost::property_tree::ptree const& xml); +typedef node_ptr (*from_xml_function_ptr)(xml_node const& xml); class registry : public singleton, - private boost::noncopyable + private boost::noncopyable { public: registry(); ~registry() {} void register_name(std::string name, from_xml_function_ptr ptr, bool overwrite=false); - node_ptr from_xml(std::string name, boost::property_tree::ptree const& xml); + node_ptr from_xml(xml_node const& xml); private: std::map map_; }; diff --git a/include/mapnik/formatting/text.hpp b/include/mapnik/formatting/text.hpp index c216b4fc2..8fd1551d8 100644 --- a/include/mapnik/formatting/text.hpp +++ b/include/mapnik/formatting/text.hpp @@ -31,7 +31,7 @@ public: text_node(expression_ptr text): node(), text_(text) {} text_node(std::string text): node(), text_(parse_expression(text)) {} void to_xml(boost::property_tree::ptree &xml) const; - static node_ptr from_xml(boost::property_tree::ptree const& xml); + static node_ptr from_xml(xml_node const& xml); virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const; virtual void add_expressions(expression_set &output) const; diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp index 16eb3c0cc..691bf5404 100644 --- a/include/mapnik/geometry.hpp +++ b/include/mapnik/geometry.hpp @@ -390,7 +390,7 @@ public: } return false; } - + }; typedef geometry geometry_type; diff --git a/include/mapnik/grid/grid_renderer.hpp b/include/mapnik/grid/grid_renderer.hpp index 73cd9a27a..c23d2cb1b 100644 --- a/include/mapnik/grid/grid_renderer.hpp +++ b/include/mapnik/grid/grid_renderer.hpp @@ -63,7 +63,7 @@ public: ~grid_renderer(); void start_map_processing(Map const& map); void end_map_processing(Map const& map); - void start_layer_processing(layer const& lay); + void start_layer_processing(layer const& lay, box2d const& query_extent); void end_layer_processing(layer const& lay); void render_marker(mapnik::feature_ptr const& feature, unsigned int step, pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity); diff --git a/include/mapnik/hextree.hpp b/include/mapnik/hextree.hpp index 36ab40857..50102a812 100644 --- a/include/mapnik/hextree.hpp +++ b/include/mapnik/hextree.hpp @@ -160,7 +160,7 @@ public: ~hextree() {} - + void setMaxColors(unsigned max_colors) { max_colors_ = max_colors; @@ -335,7 +335,7 @@ public: sorted_pal_.reserve(colors_); create_palette_rek(sorted_pal_, root_.get()); - + // sort palette for binary searching in quantization #if BOOST_VERSION >= 104600 boost::sort(sorted_pal_, rgba::mean_sort_cmp()); diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index c6a334ac0..92320c4f8 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -24,11 +24,6 @@ #define MAPNIK_IMAGE_COMPOSITING_HPP // agg -#include "agg_rendering_buffer.h" -#include "agg_rasterizer_scanline_aa.h" -#include "agg_scanline_u.h" -#include "agg_renderer_scanline.h" -#include "agg_pixfmt_rgba.h" namespace mapnik { @@ -69,116 +64,7 @@ enum composite_mode_e }; template -void composite(T1 & im, T2 & im2, composite_mode_e mode) -{ - typedef agg::rgba8 color; - typedef agg::order_bgra order; - typedef agg::pixel32_type pixel_type; - typedef agg::comp_op_adaptor_rgba blender_type; - typedef agg::pixfmt_custom_blend_rgba pixfmt_type; - typedef agg::renderer_base renderer_type; - typedef agg::comp_op_adaptor_rgba blender_type; - typedef agg::renderer_base renderer_type; - - agg::rendering_buffer source(im.getBytes(),im.width(),im.height(),im.width() * 4); - agg::rendering_buffer mask(im2.getBytes(),im2.width(),im2.height(),im2.width() * 4); - - agg::pixfmt_custom_blend_rgba pixf(source); - agg::pixfmt_custom_blend_rgba pixf_mask(mask); - - switch(mode) - { - case clear : - pixf.comp_op(agg::comp_op_clear); - break; - case src: - pixf.comp_op(agg::comp_op_src); - break; - case dst: - pixf.comp_op(agg::comp_op_dst); - break; - case src_over: - pixf.comp_op(agg::comp_op_src_over); - break; - case dst_over: - pixf.comp_op(agg::comp_op_dst_over); - break; - case src_in: - pixf.comp_op(agg::comp_op_src_in); - break; - case dst_in: - pixf.comp_op(agg::comp_op_dst_in); - break; - case src_out: - pixf.comp_op(agg::comp_op_src_out); - break; - case dst_out: - pixf.comp_op(agg::comp_op_dst_out); - break; - case src_atop: - pixf.comp_op(agg::comp_op_src_atop); - break; - case dst_atop: - pixf.comp_op(agg::comp_op_dst_atop); - break; - case _xor: - pixf.comp_op(agg::comp_op_xor); - break; - case plus: - pixf.comp_op(agg::comp_op_plus); - break; - case minus: - pixf.comp_op(agg::comp_op_minus); - break; - case multiply: - pixf.comp_op(agg::comp_op_multiply); - break; - case screen: - pixf.comp_op(agg::comp_op_screen); - break; - case overlay: - pixf.comp_op(agg::comp_op_overlay); - break; - case darken: - pixf.comp_op(agg::comp_op_darken); - break; - case lighten: - pixf.comp_op(agg::comp_op_lighten); - break; - case color_dodge: - pixf.comp_op(agg::comp_op_color_dodge); - break; - case color_burn: - pixf.comp_op(agg::comp_op_color_burn); - break; - case hard_light: - pixf.comp_op(agg::comp_op_hard_light); - break; - case soft_light: - pixf.comp_op(agg::comp_op_soft_light); - break; - case difference: - pixf.comp_op(agg::comp_op_difference); - break; - case exclusion: - pixf.comp_op(agg::comp_op_exclusion); - break; - case contrast: - pixf.comp_op(agg::comp_op_contrast); - break; - case invert: - pixf.comp_op(agg::comp_op_invert); - break; - case invert_rgb: - pixf.comp_op(agg::comp_op_invert_rgb); - break; - } - renderer_type ren(pixf); - agg::renderer_base rb(pixf); - rb.blend_from(pixf_mask,0,0,0,255); +void composite(T1 & im, T2 & im2, composite_mode_e mode); } - -} - #endif // MAPNIK_IMAGE_COMPOSITING_HPP diff --git a/include/mapnik/internal/dump_xml.hpp b/include/mapnik/internal/dump_xml.hpp index 022591f7a..7bdf78f66 100644 --- a/include/mapnik/internal/dump_xml.hpp +++ b/include/mapnik/internal/dump_xml.hpp @@ -1,26 +1,34 @@ #ifndef DUMP_XML_HPP #define DUMP_XML_HPP -#include +#include /* Debug dump ptree XML representation. -*/ -void dump_xml(boost::property_tree::ptree const& xml, unsigned level=0) + */ +void dump_xml(xml_node const& xml, unsigned level=0) { std::string indent; - int i; + unsigned i; for (i=0; ifirst << ", " << aitr->second.value << ", " << aitr->second.processed << ")"; + } + std::cerr << "]" << "\n"; + if (xml.is_text()) std::cerr << indent << "text: '" << xml.text() << "'\n"; + xml_node::const_iterator itr = xml.begin(); + xml_node::const_iterator end = xml.end(); for (; itr!=end; itr++) { - std::cout << indent <<"[" << itr->first << "]" << "\n"; - dump_xml(itr->second, level+1); - std::cout << indent << "[/" << itr->first << "]" << "\n"; + dump_xml(*itr, level+1); } + std::cerr << indent << "[/" << xml.name() << "]" << "\n"; } diff --git a/include/mapnik/label_collision_detector.hpp b/include/mapnik/label_collision_detector.hpp index fa23b7ca0..b913ac0dc 100644 --- a/include/mapnik/label_collision_detector.hpp +++ b/include/mapnik/label_collision_detector.hpp @@ -39,7 +39,7 @@ struct label_collision_detector { typedef std::vector > label_placements; - bool has_plasement(box2d const& box) + bool has_placement(box2d const& box) { label_placements::const_iterator itr=labels_.begin(); for( ; itr !=labels_.end();++itr) @@ -134,7 +134,7 @@ public: }; -//quad tree based label collission detector so labels dont appear within a given distance +//quad tree based label collision detector so labels dont appear within a given distance class label_collision_detector4 : boost::noncopyable { public: diff --git a/include/mapnik/layer.hpp b/include/mapnik/layer.hpp index f9f5826e7..2672d4da6 100644 --- a/include/mapnik/layer.hpp +++ b/include/mapnik/layer.hpp @@ -88,44 +88,44 @@ public: std::vector& styles(); /*! - * @param maxZoom The minimum zoom level to set + * @param max_zoom The minimum zoom level to set */ - void setMinZoom(double minZoom); + void set_min_zoom(double min_zoom); /*! - * @param maxZoom The maximum zoom level to set + * @param max_zoom The maximum zoom level to set */ - void setMaxZoom(double maxZoom); + void set_max_zoom(double max_zoom); /*! * @return the minimum zoom level of the layer. */ - double getMinZoom() const; + double min_zoom() const; /*! * @return the maximum zoom level of the layer. */ - double getMaxZoom() const; + double max_zoom() const; /*! * @brief Set whether this layer is active and will be rendered. */ - void setActive(bool active); + void set_active(bool active); /*! * @return whether this layer is active and will be rendered. */ - bool isActive() const; + bool active() const; /*! * @brief Set whether this layer is queryable. */ - void setQueryable(bool queryable); + void set_queryable(bool queryable); /*! * @return whether this layer is queryable or not. */ - bool isQueryable() const; + bool queryable() const; /*! * @brief Get the visability for a specific scale. @@ -139,7 +139,7 @@ public: * or * scale < maxzoom + 1e-6 */ - bool isVisible(double scale) const; + bool visible(double scale) const; /*! * @param clear_cache Set whether this layer's labels are cached. @@ -195,8 +195,8 @@ private: std::string name_; std::string srs_; - double minZoom_; - double maxZoom_; + double min_zoom_; + double max_zoom_; bool active_; bool queryable_; bool clear_label_cache_; diff --git a/include/mapnik/line_symbolizer.hpp b/include/mapnik/line_symbolizer.hpp index 84c845098..29634db1a 100644 --- a/include/mapnik/line_symbolizer.hpp +++ b/include/mapnik/line_symbolizer.hpp @@ -44,17 +44,20 @@ struct MAPNIK_DECL line_symbolizer : public symbolizer_base explicit line_symbolizer() : symbolizer_base(), stroke_(), - rasterizer_p_(RASTERIZER_FULL) {} + rasterizer_p_(RASTERIZER_FULL), + smooth_(0.0) {} line_symbolizer(stroke const& stroke) : symbolizer_base(), stroke_(stroke), - rasterizer_p_(RASTERIZER_FULL) {} + rasterizer_p_(RASTERIZER_FULL), + smooth_(0.0) {} line_symbolizer(color const& pen,float width=1.0) : symbolizer_base(), stroke_(pen,width), - rasterizer_p_(RASTERIZER_FULL) {} + rasterizer_p_(RASTERIZER_FULL), + smooth_(0.0) {} stroke const& get_stroke() const { @@ -76,9 +79,20 @@ struct MAPNIK_DECL line_symbolizer : public symbolizer_base return rasterizer_p_; } + void set_smooth(double smooth) + { + smooth_ = smooth; + } + + double smooth() const + { + return smooth_; + } + private: stroke stroke_; line_rasterizer_e rasterizer_p_; + double smooth_; }; } diff --git a/include/mapnik/map.hpp b/include/mapnik/map.hpp index f98a90a9c..95663360b 100644 --- a/include/mapnik/map.hpp +++ b/include/mapnik/map.hpp @@ -79,7 +79,6 @@ private: box2d current_extent_; boost::optional > maximum_extent_; std::string base_path_; - parameters extra_attr_; parameters extra_params_; public: @@ -440,21 +439,6 @@ public: */ std::string get_metawriter_property(std::string name) const; - /*! - * @brief Get extra valid attributes of the Map that are not true members - */ - parameters const& get_extra_attributes() const; - - /*! - * @brief Get non-const extra valid attributes of the Map that are not true members - */ - parameters& get_extra_attributes(); - - /*! - * @brief Set extra attributes of the Map - */ - void set_extra_attributes(parameters& attr); - /*! * @brief Get extra, arbitrary Parameters attached to the Map */ diff --git a/include/mapnik/mapped_memory_cache.hpp b/include/mapnik/mapped_memory_cache.hpp index 8836a5049..b26ce81a6 100644 --- a/include/mapnik/mapped_memory_cache.hpp +++ b/include/mapnik/mapped_memory_cache.hpp @@ -49,6 +49,7 @@ struct MAPNIK_DECL mapped_memory_cache : static boost::unordered_map cache_; static bool insert(std::string const& key, mapped_region_ptr); static boost::optional find(std::string const& key, bool update_cache = false); + static void clear(); }; } diff --git a/include/mapnik/marker_cache.hpp b/include/mapnik/marker_cache.hpp index 5b56770b0..2e7f57699 100644 --- a/include/mapnik/marker_cache.hpp +++ b/include/mapnik/marker_cache.hpp @@ -25,14 +25,7 @@ // mapnik #include -#include #include -#include -#include -#include - -// agg -#include "agg_path_storage.h" // boost #include @@ -43,7 +36,7 @@ namespace mapnik { -using namespace mapnik::svg; +class marker; typedef boost::shared_ptr marker_ptr; @@ -57,6 +50,7 @@ struct MAPNIK_DECL marker_cache : static boost::unordered_map cache_; static bool insert(std::string const& key, marker_ptr); static boost::optional find(std::string const& key, bool update_cache = false); + static void clear(); }; } diff --git a/include/mapnik/markers_symbolizer.hpp b/include/mapnik/markers_symbolizer.hpp index b6e78a8c2..ccd249da9 100644 --- a/include/mapnik/markers_symbolizer.hpp +++ b/include/mapnik/markers_symbolizer.hpp @@ -56,6 +56,8 @@ public: explicit markers_symbolizer(); markers_symbolizer(path_expression_ptr filename); markers_symbolizer(markers_symbolizer const& rhs); + void set_ignore_placement(bool ignore_placement); + bool get_ignore_placement() const; void set_allow_overlap(bool overlap); bool get_allow_overlap() const; void set_spacing(double spacing); @@ -76,6 +78,7 @@ public: marker_type_e get_marker_type() const; private: + bool ignore_placement_; bool allow_overlap_; color fill_; double spacing_; diff --git a/include/mapnik/metawriter_factory.hpp b/include/mapnik/metawriter_factory.hpp index d5b8911fd..1af7ff5d7 100644 --- a/include/mapnik/metawriter_factory.hpp +++ b/include/mapnik/metawriter_factory.hpp @@ -30,6 +30,7 @@ #include namespace mapnik { +class xml_node; /** * Creates a metawriter with the properties specified in the property @@ -37,7 +38,7 @@ namespace mapnik { * metawriters, but should provide an easy point to make them a * proper factory method if this is wanted in the future. */ -metawriter_ptr metawriter_create(const boost::property_tree::ptree &pt); +metawriter_ptr metawriter_create(xml_node const& pt); /** * Writes properties into the given property tree representing the diff --git a/include/mapnik/palette.hpp b/include/mapnik/palette.hpp index de58bbe10..a0db170bf 100644 --- a/include/mapnik/palette.hpp +++ b/include/mapnik/palette.hpp @@ -26,7 +26,6 @@ // mapnik #include #include -#include // boost #include diff --git a/include/mapnik/placement_finder.hpp b/include/mapnik/placement_finder.hpp index 662078238..bf8844808 100644 --- a/include/mapnik/placement_finder.hpp +++ b/include/mapnik/placement_finder.hpp @@ -23,13 +23,20 @@ #ifndef MAPNIK_PLACEMENT_FINDER_HPP #define MAPNIK_PLACEMENT_FINDER_HPP -//mapnik +// mapnik #include #include #include #include +#include +#include -//stl + +// agg +#include "agg_conv_clip_polyline.h" + + +// stl #include namespace mapnik @@ -39,6 +46,12 @@ class text_placement_info; class string_info; class text_path; +typedef agg::conv_clip_polyline clipped_geometry_type; +typedef coord_transform2 ClippedPathType; +typedef coord_transform2 PathType; + +typedef label_collision_detector4 DetectorType; + template class placement_finder : boost::noncopyable @@ -124,19 +137,20 @@ private: text_symbolizer_properties const& p; text_placement_info const& pi; /** Length of the longest line after linebreaks. - * Before find_line_breaks() this is the total length of the string. - */ + * Before find_line_breaks() this is the total length of the string. + */ double string_width_; /** Height of the string after linebreaks. - * Before find_line_breaks() this is the total length of the string. - */ + * Before find_line_breaks() this is the total length of the string. + */ double string_height_; /** Height of the tallest font in the first line not including line spacing. - * Used to determine the correct offset for the first line. - */ + * Used to determine the correct offset for the first line. + */ double first_line_space_; vertical_alignment_e valign_; horizontal_alignment_e halign_; + justify_alignment_e jalign_; std::vector line_breaks_; std::vector > line_sizes_; std::queue< box2d > envelopes_; diff --git a/include/mapnik/polygon_symbolizer.hpp b/include/mapnik/polygon_symbolizer.hpp index a4f8706d5..e7a2a85c7 100644 --- a/include/mapnik/polygon_symbolizer.hpp +++ b/include/mapnik/polygon_symbolizer.hpp @@ -35,7 +35,7 @@ namespace mapnik struct MAPNIK_DECL polygon_symbolizer : public symbolizer_base { polygon_symbolizer(); - polygon_symbolizer(color const& fill); + explicit polygon_symbolizer(color const& fill); color const& get_fill() const; void set_fill(color const& fill); void set_opacity(double opacity); @@ -44,12 +44,14 @@ struct MAPNIK_DECL polygon_symbolizer : public symbolizer_base double get_gamma() const; void set_gamma_method(gamma_method_e gamma_method); gamma_method_e get_gamma_method() const; - + void set_smooth(double smooth); + double smooth() const; private: color fill_; double opacity_; double gamma_; gamma_method_e gamma_method_; + double smooth_; }; } diff --git a/include/mapnik/ptree_helpers.hpp b/include/mapnik/ptree_helpers.hpp index 0c3e8bf63..64167b590 100644 --- a/include/mapnik/ptree_helpers.hpp +++ b/include/mapnik/ptree_helpers.hpp @@ -23,450 +23,17 @@ #ifndef MAPNIK_PTREE_HELPERS_HPP #define MAPNIK_PTREE_HELPERS_HPP -// mapnik -#include -#include -#include -#include // boost #include -#include -#include - -// stl -#include -#include namespace mapnik { -template -inline boost::optional fast_cast(std::string const& value); - -template -T get(boost::property_tree::ptree const& node, std::string const& name, bool is_attribute, - T const& default_value); -template -T get(boost::property_tree::ptree const& node, std::string const& name, bool is_attribute); -template -T get_value(boost::property_tree::ptree const& node, std::string const& name); -template -boost::optional get_optional(boost::property_tree::ptree const& node, std::string const& name, - bool is_attribute); - -template -boost::optional get_opt_attr( boost::property_tree::ptree const& node, - std::string const& name) -{ - return get_optional( node, name, true); -} - -template -boost::optional get_opt_child( boost::property_tree::ptree const& node, - std::string const& name) -{ - return get_optional( node, name, false); -} - -template -T get_attr( boost::property_tree::ptree const& node, std::string const& name, - T const& default_value ) -{ - return get( node, name, true, default_value); -} - -template -T get_attr( boost::property_tree::ptree const& node, std::string const& name ) -{ - return get( node, name, true ); -} - - -template -std::basic_ostream & -operator << ( std::basic_ostream & s, mapnik::color const& c ) -{ - std::string hex_string( c.to_string() ); - s << hex_string; - return s; -} - -/** Helper for class bool */ -class boolean { -public: - boolean() : b_(false) {} - boolean(bool b) : b_(b) {} - boolean(boolean const& b) : b_(b.b_) {} - - operator bool() const - { - return b_; - } - boolean & operator = (boolean const& other) - { - b_ = other.b_; - return * this; - } - boolean & operator = (bool other) - { - b_ = other; - return * this; - } -private: - bool b_; -}; - -/** Special stream input operator for boolean values */ -template -std::basic_istream & -operator >> ( std::basic_istream & s, boolean & b ) -{ - std::string word; - s >> word; - if ( s ) - { - if ( word == "true" || word == "yes" || word == "on" || - word == "1") - { - b = true; - } - else if ( word == "false" || word == "no" || word == "off" || - word == "0") - { - b = false; - } - else - { - s.setstate( std::ios::failbit ); - } - } - return s; -} - -template -std::basic_ostream & -operator << ( std::basic_ostream & s, boolean const& b ) -{ - s << ( b ? "true" : "false" ); - return s; -} - template void set_attr(boost::property_tree::ptree & pt, std::string const& name, T const& v) { pt.put("." + name, v); } - -class boolean; - -template -struct name_trait -{ - static std::string name() - { - return ""; - } - // missing name_trait for type ... - // if you get here you are probably using a new type - // in the XML file. Just add a name trait for the new - // type below. - BOOST_STATIC_ASSERT( sizeof(T) == 0 ); -}; - -#define DEFINE_NAME_TRAIT( type, type_name ) \ - template <> \ - struct name_trait \ - { \ - static std::string name() { return std::string("type ") + type_name; } \ - }; - - -DEFINE_NAME_TRAIT( double, "double") -DEFINE_NAME_TRAIT( float, "float") -DEFINE_NAME_TRAIT( unsigned, "unsigned") -DEFINE_NAME_TRAIT( boolean, "boolean") -DEFINE_NAME_TRAIT( int, "integer" ) -DEFINE_NAME_TRAIT( std::string, "string" ) -DEFINE_NAME_TRAIT( color, "color" ) - -template -struct name_trait< mapnik::enumeration > -{ - typedef enumeration Enum; - - static std::string name() - { - std::string value_list("one of ["); - for (unsigned i = 0; i < Enum::MAX; ++i) - { - value_list += Enum::get_string( i ); - if ( i + 1 < Enum::MAX ) value_list += ", "; - } - value_list += "]"; - - return value_list; - } -}; - -template -inline boost::optional fast_cast(std::string const& value) -{ - try - { - return boost::lexical_cast( value ); - } - catch (boost::bad_lexical_cast const& ex) - { - return boost::optional(); - } - -} - -template <> -inline boost::optional fast_cast(std::string const& value) -{ - int result; - if (mapnik::conversions::string2int(value,result)) - return boost::optional(result); - return boost::optional(); -} - -template <> -inline boost::optional fast_cast(std::string const& value) -{ - double result; - if (mapnik::conversions::string2double(value,result)) - return boost::optional(result); - return boost::optional(); -} - -template <> -inline boost::optional fast_cast(std::string const& value) -{ - float result; - if (mapnik::conversions::string2float(value,result)) - return boost::optional(result); - return boost::optional(); -} - -template -T get(boost::property_tree::ptree const& node, - std::string const& name, - bool is_attribute, - T const& default_value) -{ - boost::optional str; - if (is_attribute) - { - str = node.get_optional( std::string(".") + name ); - } - else - { - str = node.get_optional(name + "."); - } - - if ( str ) - { - boost::optional result = fast_cast(*str); - if (result) - { - return *result; - } - else - { - throw config_error(std::string("Failed to parse ") + - (is_attribute ? "attribute" : "child node") + " '" + - name + "'. Expected " + name_trait::name() + - " but got '" + *str + "'"); - } - } - else - { - return default_value; - } -} - -template <> -inline color get(boost::property_tree::ptree const& node, - std::string const& name, - bool is_attribute, - color const& default_value) -{ - boost::optional str; - if (is_attribute) - { - str = node.get_optional( std::string(".") + name ); - } - else - { - str = node.get_optional(name + "."); - } - - if ( str ) - { - try - { - return mapnik::color_factory::from_string((*str).c_str()); - } - catch (...) - { - throw config_error(std::string("Failed to parse ") + - (is_attribute ? "attribute" : "child node") + " '" + - name + "'. Expected " + name_trait::name() + - " but got '" + *str + "'"); - } - } - else - { - return default_value; - } -} - -template -T get(boost::property_tree::ptree const& node, std::string const& name, bool is_attribute) -{ - boost::optional str; - if (is_attribute) - { - str = node.get_optional( std::string(".") + name); - } - else - { - str = node.get_optional(name + "."); - } - - if ( ! str ) - { - throw config_error(std::string("Required ") + - (is_attribute ? "attribute " : "child node ") + - "'" + name + "' is missing"); - } - boost::optional result = fast_cast(*str); - if (result) - { - return *result; - } - else - { - throw config_error(std::string("Failed to parse ") + - (is_attribute ? "attribute" : "child node") + " '" + - name + "'. Expected " + name_trait::name() + - " but got '" + *str + "'"); - } -} - -template -T get_value(boost::property_tree::ptree const& node, std::string const& name) -{ - try - { - /* NOTE: get_child works as long as there is only one child with that name. - If this function is used this used this condition must always be satisfied. - */ - return node.get_child("").get_value(); - } - catch (boost::property_tree::ptree_bad_path) - { - /* If the XML parser did not find any non-empty data element the is no - node. But we don't want to fail here but simply return a - default constructed value of the requested type. - */ - return T(); - } - catch (...) - { - throw config_error(std::string("Failed to parse ") + - name + ". Expected " + name_trait::name() + - " but got '" + node.data() + "'"); - } -} - -template -boost::optional get_optional(boost::property_tree::ptree const& node, - std::string const& name, - bool is_attribute) -{ - boost::optional str; - if (is_attribute) - { - str = node.get_optional( std::string(".") + name); - } - else - { - str = node.get_optional(name + "."); - } - - boost::optional result; - if ( str ) - { - result = fast_cast(*str); - if (!result) - { - throw config_error(std::string("Failed to parse ") + - (is_attribute ? "attribute" : "child node") + " '" + - name + "'. Expected " + name_trait::name() + - " but got '" + *str + "'"); - } - } - - return result; -} - -template <> -inline boost::optional get_optional(boost::property_tree::ptree const& node, - std::string const& name, - bool is_attribute) -{ - if (is_attribute) - { - return node.get_optional( std::string(".") + name); - } - else - { - return node.get_optional(name + "."); - } -} - -template <> -inline boost::optional get_optional(boost::property_tree::ptree const& node, - std::string const& name, - bool is_attribute) -{ - boost::optional str; - if (is_attribute) - { - str = node.get_optional( std::string(".") + name); - } - else - { - str = node.get_optional(name + "."); - } - - boost::optional result; - if ( str ) - { - try - { - result = mapnik::color_factory::from_string((*str).c_str()); - } - catch (...) - { - throw config_error(std::string("Failed to parse ") + - (is_attribute ? "attribute" : "child node") + " '" + - name + "'. Expected " + name_trait::name() + - " but got '" + *str + "'"); - } - } - - return result; -} - -static inline bool has_child(boost::property_tree::ptree const& node, std::string const& name) -{ - boost::optional str = node.get_optional(name); - return str; -} - } // end of namespace mapnik #endif // MAPNIK_PTREE_HELPERS_HPP diff --git a/include/mapnik/raster_colorizer.hpp b/include/mapnik/raster_colorizer.hpp index 74fcf4853..8903d60f2 100644 --- a/include/mapnik/raster_colorizer.hpp +++ b/include/mapnik/raster_colorizer.hpp @@ -39,7 +39,6 @@ // mapnik #include -#include #include #include #include diff --git a/include/mapnik/symbolizer_helpers.hpp b/include/mapnik/symbolizer_helpers.hpp index bae7e25d9..58063b6ab 100644 --- a/include/mapnik/symbolizer_helpers.hpp +++ b/include/mapnik/symbolizer_helpers.hpp @@ -55,7 +55,8 @@ public: double scale_factor, CoordTransform const& t, FaceManagerT &font_manager, - DetectorT &detector) + DetectorT &detector, + box2d const& query_extent) : sym_(sym), feature_(feature), prj_trans_(prj_trans), @@ -64,6 +65,7 @@ public: detector_(detector), writer_(sym.get_metawriter()), dims_(0, 0, width, height), + query_extent_(query_extent), text_(font_manager, scale_factor), angle_(0.0), placement_valid_(false), @@ -100,7 +102,7 @@ protected: DetectorT & detector_; metawriter_with_properties writer_; box2d dims_; - + box2d const& query_extent_; //Processing processed_text text_; /* Using list instead of vector, because we delete random elements and need iterators to stay valid. */ @@ -137,10 +139,11 @@ public: unsigned width, unsigned height, double scale_factor, - CoordTransform const& t, - FaceManagerT & font_manager, - DetectorT & detector) : - text_symbolizer_helper(sym, feature, prj_trans, width, height, scale_factor, t, font_manager, detector), + CoordTransform const &t, + FaceManagerT &font_manager, + DetectorT &detector, + box2d const& query_extent) : + text_symbolizer_helper(sym, feature, prj_trans, width, height, scale_factor, t, font_manager, detector, query_extent), sym_(sym) { this->points_on_line_ = true; diff --git a/include/mapnik/text_placements/list.hpp b/include/mapnik/text_placements/list.hpp index e6e0adaea..923df0c9d 100644 --- a/include/mapnik/text_placements/list.hpp +++ b/include/mapnik/text_placements/list.hpp @@ -38,7 +38,7 @@ public: text_symbolizer_properties & add(); text_symbolizer_properties & get(unsigned i); unsigned size() const; - static text_placements_ptr from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets); + static text_placements_ptr from_xml(xml_node const &xml, fontset_map const & fontsets); private: std::vector list_; friend class text_placement_info_list; diff --git a/include/mapnik/text_placements/registry.hpp b/include/mapnik/text_placements/registry.hpp index c171a5089..f3bd123bf 100644 --- a/include/mapnik/text_placements/registry.hpp +++ b/include/mapnik/text_placements/registry.hpp @@ -39,17 +39,17 @@ namespace placements { typedef text_placements_ptr (*from_xml_function_ptr)( - boost::property_tree::ptree const& xml, fontset_map const & fontsets); + xml_node const& xml, fontset_map const & fontsets); class registry : public singleton, - private boost::noncopyable + private boost::noncopyable { public: registry(); ~registry() {} void register_name(std::string name, from_xml_function_ptr ptr, bool overwrite=false); text_placements_ptr from_xml(std::string name, - boost::property_tree::ptree const& xml, + xml_node const& xml, fontset_map const & fontsets); private: std::map map_; diff --git a/include/mapnik/text_placements/simple.hpp b/include/mapnik/text_placements/simple.hpp index 4173ab87a..59c57d87e 100644 --- a/include/mapnik/text_placements/simple.hpp +++ b/include/mapnik/text_placements/simple.hpp @@ -52,7 +52,7 @@ public: text_placement_info_ptr get_placement_info(double scale_factor) const; void set_positions(std::string positions); std::string get_positions(); - static text_placements_ptr from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets); + static text_placements_ptr from_xml(xml_node const &xml, fontset_map const & fontsets); private: std::string positions_; std::vector direction_; diff --git a/include/mapnik/text_properties.hpp b/include/mapnik/text_properties.hpp index dbf21f8d7..7b6ab953a 100644 --- a/include/mapnik/text_properties.hpp +++ b/include/mapnik/text_properties.hpp @@ -54,7 +54,7 @@ struct char_properties { char_properties(); /** Construct object from XML. */ - void from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets); + void from_xml(xml_node const &sym, fontset_map const & fontsets); /** Write object to XML ptree. */ void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, char_properties const& dfl=char_properties()) const; std::string face_name; @@ -110,6 +110,7 @@ enum justify_alignment J_LEFT = 0, J_MIDDLE, J_RIGHT, + J_AUTO, justify_alignment_MAX }; @@ -124,7 +125,7 @@ struct text_symbolizer_properties { text_symbolizer_properties(); /** Load all values from XML ptree. */ - void from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets); + void from_xml(xml_node const &sym, fontset_map const & fontsets); /** Save all values to XML ptree (but does not create a new parent node!). */ void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_symbolizer_properties const &dfl=text_symbolizer_properties()) const; diff --git a/include/mapnik/util/conversions.hpp b/include/mapnik/util/conversions.hpp index 1b38dee3d..b57f55ff9 100644 --- a/include/mapnik/util/conversions.hpp +++ b/include/mapnik/util/conversions.hpp @@ -20,26 +20,25 @@ * *****************************************************************************/ -#ifndef MAPNIK_CONVERSIONS_UTIL_HPP -#define MAPNIK_CONVERSIONS_UTIL_HPP +#ifndef MAPNIK_UTIL_CONVERSIONS_HPP +#define MAPNIK_UTIL_CONVERSIONS_HPP // mapnik // stl #include -namespace mapnik { namespace conversions { +namespace mapnik { namespace util { -bool string2int(const char * value, int & result); -bool string2int(std::string const& value, int & result); - -bool string2double(std::string const& value, double & result); -bool string2double(const char * value, double & result); - -bool string2float(std::string const& value, float & result); -bool string2float(const char * value, float & result); + bool string2int(const char * value, int & result); + bool string2int(std::string const& value, int & result); -} -} + bool string2double(std::string const& value, double & result); + bool string2double(const char * value, double & result); -#endif // MAPNIK_CONVERSIONS_UTIL_HPP + bool string2float(std::string const& value, float & result); + bool string2float(const char * value, float & result); + +}} + +#endif // MAPNIK_UTIL_CONVERSIONS_HPP diff --git a/include/mapnik/util/dasharray_parser.hpp b/include/mapnik/util/dasharray_parser.hpp new file mode 100644 index 000000000..e1e4c1271 --- /dev/null +++ b/include/mapnik/util/dasharray_parser.hpp @@ -0,0 +1,69 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_UTIL_DASHARRAY_PARSER_HPP +#define MAPNIK_UTIL_DASHARRAY_PARSER_HPP + +#include +#include +#include +#include + +namespace mapnik { namespace util { + +template +bool parse_dasharray(Iterator first, Iterator last, std::vector& dasharray) +{ + using qi::double_; + using qi::phrase_parse; + using qi::_1; + using qi::lit; + using qi::char_; +#if BOOST_VERSION > 104200 + using qi::no_skip; +#else + using qi::lexeme; +#endif + using phoenix::push_back; + // SVG + // dasharray ::= (length | percentage) (comma-wsp dasharray)? + // no support for 'percentage' as viewport is unknown at load_map + // + bool r = phrase_parse(first, last, + (double_[push_back(phoenix::ref(dasharray), _1)] % +#if BOOST_VERSION > 104200 + no_skip[char_(", ")] +#else + lexeme[char_(", ")] +#endif + | lit("none")), + qi::ascii::space); + + if (first != last) + return false; + + return r; +} + +}} + +#endif // MAPNIK_UTIL_DASHARRAY_PARSER_HPP diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp index d657d974c..a3cef23b4 100644 --- a/include/mapnik/value.hpp +++ b/include/mapnik/value.hpp @@ -26,7 +26,6 @@ // mapnik #include #include -#include // boost #include diff --git a/include/mapnik/version.hpp b/include/mapnik/version.hpp index b79c0f666..b5a96d8ea 100644 --- a/include/mapnik/version.hpp +++ b/include/mapnik/version.hpp @@ -23,6 +23,28 @@ #ifndef MAPNIK_VERSION_HPP #define MAPNIK_VERSION_HPP -#define MAPNIK_VERSION 200000 +#define MAPNIK_VERSION_IS_RELEASE 0 + +#define MAPNIK_MAJOR_VERSION 2 +#define MAPNIK_MINOR_VERSION 1 +#define MAPNIK_PATCH_VERSION 0 + +#define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION) + +#ifndef MAPNIK_STRINGIFY +#define MAPNIK_STRINGIFY(n) MAPNIK_STRINGIFY_HELPER(n) +#define MAPNIK_STRINGIFY_HELPER(n) #n +#endif + +#if MAPNIK_VERSION_IS_RELEASE +# define MAPNIK_VERSION_STRING MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \ + MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \ + MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION) + +#else +# define MAPNIK_VERSION_STRING MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \ + MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \ + MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION) "-pre" +#endif #endif // MAPNIK_VERSION_HPP diff --git a/include/mapnik/vertex_vector.hpp b/include/mapnik/vertex_vector.hpp index e326aa284..85bcd8857 100644 --- a/include/mapnik/vertex_vector.hpp +++ b/include/mapnik/vertex_vector.hpp @@ -55,16 +55,16 @@ public: // required for iterators support typedef boost::tuple value_type; typedef std::size_t size_type; - + private: unsigned num_blocks_; unsigned max_blocks_; coord_type** vertices_; unsigned char** commands_; size_type pos_; - + public: - + vertex_vector() : num_blocks_(0), max_blocks_(0), @@ -114,7 +114,7 @@ public: *y = (*vertex); return commands_[block] [pos & block_mask]; } - + private: void allocate_block(unsigned block) { diff --git a/include/mapnik/libxml2_loader.hpp b/include/mapnik/xml_loader.hpp similarity index 82% rename from include/mapnik/libxml2_loader.hpp rename to include/mapnik/xml_loader.hpp index 105a5f8b2..b102b61eb 100644 --- a/include/mapnik/libxml2_loader.hpp +++ b/include/mapnik/xml_loader.hpp @@ -23,16 +23,14 @@ #ifndef MAPNIK_LIBXML2_LOADER_HPP #define MAPNIK_LIBXML2_LOADER_HPP -// boost -#include - // stl #include namespace mapnik { -void read_xml2( std::string const & filename, boost::property_tree::ptree & pt); -void read_xml2_string( std::string const & str, boost::property_tree::ptree & pt, std::string const & base_path=""); +class xml_node; +void read_xml(std::string const & filename, xml_node &node); +void read_xml_string(std::string const & str, xml_node &node, std::string const & base_path=""); } #endif // MAPNIK_LIBXML2_LOADER_HPP diff --git a/include/mapnik/xml_node.hpp b/include/mapnik/xml_node.hpp new file mode 100644 index 000000000..f0db516e1 --- /dev/null +++ b/include/mapnik/xml_node.hpp @@ -0,0 +1,137 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_XML_NODE_H +#define MAPNIK_XML_NODE_H + +//mapnik +#include + + +//boost +#include + +//stl +#include +#include +#include +#include + +namespace mapnik +{ +class xml_tree; + +class xml_attribute +{ +public: + xml_attribute(std::string const& value); + std::string value; + mutable bool processed; +}; + +class node_not_found: public std::exception +{ +public: + node_not_found(std::string node_name); + virtual const char* what() const throw(); + ~node_not_found() throw (); +private: + std::string node_name_; +}; + +class attribute_not_found: public std::exception +{ +public: + attribute_not_found(std::string const& node_name, std::string const& attribute_name); + virtual const char* what() const throw(); + ~attribute_not_found() throw (); +private: + std::string node_name_; + std::string attribute_name_; +}; + +class more_than_one_child: public std::exception +{ +public: + more_than_one_child(std::string const& node_name); + virtual const char* what() const throw(); + ~more_than_one_child() throw (); +private: + std::string node_name_; +}; + +class xml_node +{ +public: + typedef std::list::const_iterator const_iterator; + typedef std::map attribute_map; + xml_node(xml_tree &tree, std::string name, unsigned line=0, bool text_node = false); + + std::string const& name() const; + std::string const& text() const; + std::string const& filename() const; + bool is_text() const; + bool is(std::string const& name) const; + + xml_node &add_child(std::string const& name, unsigned line=0, bool text_node = false); + void add_attribute(std::string const& name, std::string const& value); + attribute_map const& get_attributes() const; + + bool processed() const; + void set_processed(bool processed) const; + + unsigned line() const; + + const_iterator begin() const; + const_iterator end() const; + + xml_node & get_child(std::string const& name); + xml_node const& get_child(std::string const& name) const; + xml_node const* get_opt_child(std::string const& name) const; + bool has_child(std::string const& name) const; + + template + boost::optional get_opt_attr(std::string const& name) const; + + template + T get_attr(std::string const& name, T const& default_value) const; + template + T get_attr(std::string const& name) const; + + std::string get_text() const; + + template + T get_value() const; +private: + xml_tree &tree_; + std::string name_; + std::list children_; + attribute_map attributes_; + bool text_node_; + unsigned line_; + mutable bool processed_; + static std::string xml_text; +}; + +} //ns mapnik + +#endif // MAPNIK_XML_NODE_H diff --git a/include/mapnik/xml_tree.hpp b/include/mapnik/xml_tree.hpp new file mode 100644 index 000000000..27893d262 --- /dev/null +++ b/include/mapnik/xml_tree.hpp @@ -0,0 +1,62 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_XML_TREE_H +#define MAPNIK_XML_TREE_H +//mapnik +#include +#include + +// boost +#include + +#if BOOST_VERSION >= 104500 +#include +#else +#include +#endif + +//stl +#include + + +namespace mapnik +{ +class xml_tree +{ +public: + xml_tree(std::string const& encoding="utf8"); + void set_filename(std::string fn); + std::string const& filename() const; + xml_node &root(); +private: + xml_node node_; + std::string file_; + transcoder tr_; +public: + mapnik::css_color_grammar color_grammar; + mapnik::expression_grammar expr_grammar; +}; + +} //ns mapnik + +#endif // MAPNIK_XML_TREE_H diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp index b2848509f..dc0b27c5e 100644 --- a/plugins/input/csv/csv_datasource.cpp +++ b/plugins/input/csv/csv_datasource.cpp @@ -6,6 +6,7 @@ #include #include #include +#include // mapnik #include @@ -14,7 +15,7 @@ #include #include #include -#include // mapnik::boolean +#include // stl #include @@ -45,7 +46,8 @@ csv_datasource::csv_datasource(parameters const& params, bool bind) manual_headers_(boost::trim_copy(*params_.get("headers", ""))), strict_(*params_.get("strict", false)), quiet_(*params_.get("quiet", false)), - filesize_max_(*params_.get("filesize_max", 20.0)) // MB + filesize_max_(*params_.get("filesize_max", 20.0)), // MB + ctx_(boost::make_shared()) { /* TODO: general: @@ -391,7 +393,6 @@ void csv_datasource::parse_csv(T& stream, bool extent_initialized = false; std::size_t num_headers = headers_.size(); - ctx_ = boost::make_shared(); for (std::size_t i = 0; i < headers_.size(); ++i) { ctx_->push(headers_[i]); diff --git a/plugins/input/gdal/gdal_datasource.cpp b/plugins/input/gdal/gdal_datasource.cpp index a19842413..1bdf85ce1 100644 --- a/plugins/input/gdal/gdal_datasource.cpp +++ b/plugins/input/gdal/gdal_datasource.cpp @@ -25,7 +25,7 @@ #include "gdal_featureset.hpp" // mapnik -#include +#include #include #include diff --git a/plugins/input/geos/geos_datasource.cpp b/plugins/input/geos/geos_datasource.cpp index 9fcc8c4ab..ddf649ede 100644 --- a/plugins/input/geos/geos_datasource.cpp +++ b/plugins/input/geos/geos_datasource.cpp @@ -30,7 +30,7 @@ #include // mapnik -#include +#include #include // boost diff --git a/plugins/input/kismet/kismet_datasource.cpp b/plugins/input/kismet/kismet_datasource.cpp index 7780b078d..00f604789 100644 --- a/plugins/input/kismet/kismet_datasource.cpp +++ b/plugins/input/kismet/kismet_datasource.cpp @@ -33,7 +33,7 @@ #include // mapnik -#include +#include // boost #include diff --git a/plugins/input/occi/occi_datasource.cpp b/plugins/input/occi/occi_datasource.cpp index b99698d22..e4d3fa4a3 100644 --- a/plugins/input/occi/occi_datasource.cpp +++ b/plugins/input/occi/occi_datasource.cpp @@ -25,7 +25,7 @@ #include "occi_featureset.hpp" // mapnik -#include +#include #include // boost diff --git a/plugins/input/occi/occi_featureset.cpp b/plugins/input/occi/occi_featureset.cpp index 1cf17a3aa..3a09200f3 100644 --- a/plugins/input/occi/occi_featureset.cpp +++ b/plugins/input/occi/occi_featureset.cpp @@ -373,7 +373,7 @@ void occi_featureset::convert_ordinates(mapnik::feature_ptr feature, if (! is_single_geom && elem_size > SDO_ELEM_INFO_SIZE) { geometry_type* geom = new geometry_type(geom_type); - + for (int i = SDO_ELEM_INFO_SIZE; i < elem_size; i+=3) { int next_offset = elem_info[i]; diff --git a/plugins/input/ogr/ogr_datasource.cpp b/plugins/input/ogr/ogr_datasource.cpp index 84458760d..1e7122b51 100644 --- a/plugins/input/ogr/ogr_datasource.cpp +++ b/plugins/input/ogr/ogr_datasource.cpp @@ -33,7 +33,7 @@ #include // mapnik -#include +#include #include // boost diff --git a/plugins/input/osm/osm_datasource.cpp b/plugins/input/osm/osm_datasource.cpp index 7c4db20c2..90cebc0fe 100644 --- a/plugins/input/osm/osm_datasource.cpp +++ b/plugins/input/osm/osm_datasource.cpp @@ -52,6 +52,7 @@ DATASOURCE_PLUGIN(osm_datasource) osm_datasource::osm_datasource(const parameters& params, bool bind) : datasource (params), + extent_(), type_(datasource::Vector), desc_(*params_.get("type"), *params_.get("encoding", "utf-8")) { @@ -71,13 +72,11 @@ void osm_datasource::bind() const std::string url = *params_.get("url", ""); std::string bbox = *params_.get("bbox", ""); - bool do_process = false; // load the data - // if we supplied a filename, load from file if (url != "" && bbox != "") { - // otherwise if we supplied a url and a bounding box, load from the url + // if we supplied a url and a bounding box, load from the url #ifdef MAPNIK_DEBUG std::clog << "Osm Plugin: loading_from_url: url=" << url << " bbox=" << bbox << std::endl; #endif @@ -85,44 +84,40 @@ void osm_datasource::bind() const { throw datasource_exception("Error loading from URL"); } - - do_process = true; } else if (osm_filename != "") { - if ((osm_data_= dataset_deliverer::load_from_file(osm_filename, parser)) == NULL) + // if we supplied a filename, load from file + if ((osm_data_ = dataset_deliverer::load_from_file(osm_filename, parser)) == NULL) { std::ostringstream s; s << "OSM Plugin: Error loading from file '" << osm_filename << "'"; throw datasource_exception(s.str()); } - - do_process = true; + } else { + throw datasource_exception("OSM Plugin: Neither 'file' nor 'url' and 'bbox' specified"); } - if (do_process == true) + + osm_tag_types tagtypes; + tagtypes.add_type("maxspeed", mapnik::Integer); + tagtypes.add_type("z_order", mapnik::Integer); + + osm_data_->rewind(); + + // Need code to get the attributes of all the data + std::set keys = osm_data_->get_keys(); + + // Add the attributes to the datasource descriptor - assume they are + // all of type String + for (std::set::iterator i = keys.begin(); i != keys.end(); i++) { - osm_tag_types tagtypes; - tagtypes.add_type("maxspeed", mapnik::Integer); - tagtypes.add_type("z_order", mapnik::Integer); - - osm_data_->rewind(); - - // Need code to get the attributes of all the data - std::set keys = osm_data_->get_keys(); - - // Add the attributes to the datasource descriptor - assume they are - // all of type String - for (std::set::iterator i = keys.begin(); i != keys.end(); i++) - { - desc_.add_descriptor(attribute_descriptor(*i, tagtypes.get_type(*i))); - } - - // Get the bounds of the data and set extent_ accordingly - bounds b = osm_data_->get_bounds(); - extent_ = box2d(b.w, b.s, b.e, b.n); + desc_.add_descriptor(attribute_descriptor(*i, tagtypes.get_type(*i))); } + // Get the bounds of the data and set extent_ accordingly + bounds b = osm_data_->get_bounds(); + extent_ = box2d(b.w, b.s, b.e, b.n); is_bound_ = true; } @@ -149,7 +144,7 @@ layer_descriptor osm_datasource::get_descriptor() const featureset_ptr osm_datasource::features(const query& q) const { - if (! is_bound_) bind(); + if (!is_bound_) bind(); filter_in_box filter(q.get_bbox()); // so we need to filter osm features by bbox here... @@ -162,7 +157,7 @@ featureset_ptr osm_datasource::features(const query& q) const featureset_ptr osm_datasource::features_at_point(coord2d const& pt) const { - if (! is_bound_) bind(); + if (!is_bound_) bind(); filter_at_point filter(pt); // collect all attribute names @@ -185,8 +180,7 @@ featureset_ptr osm_datasource::features_at_point(coord2d const& pt) const box2d osm_datasource::envelope() const { - if (! is_bound_) bind(); - + if (!is_bound_) bind(); return extent_; } @@ -194,4 +188,4 @@ boost::optional osm_datasource::get_geometry_typ { if (! is_bound_) bind(); return boost::optional(mapnik::datasource::Collection); -} \ No newline at end of file +} diff --git a/plugins/input/osm/osmparser.cpp b/plugins/input/osm/osmparser.cpp index fcc7b5d53..9b83d2b79 100644 --- a/plugins/input/osm/osmparser.cpp +++ b/plugins/input/osm/osmparser.cpp @@ -103,6 +103,11 @@ void osmparser::startElement(xmlTextReaderPtr reader, const xmlChar *name) xmlFree(xk); xmlFree(xv); } + if (xmlTextReaderIsEmptyElement(reader)) + { + // Fake endElement for empty nodes + endElement(name); + } } void osmparser::endElement(const xmlChar* name) diff --git a/plugins/input/postgis/postgis_datasource.cpp b/plugins/input/postgis/postgis_datasource.cpp index 8e7556ed7..316ee02c1 100644 --- a/plugins/input/postgis/postgis_datasource.cpp +++ b/plugins/input/postgis/postgis_datasource.cpp @@ -26,7 +26,7 @@ // mapnik #include -#include +#include #include #include @@ -175,7 +175,7 @@ void postgis_datasource::bind() const if (srid_c != NULL) { int result; - if (mapnik::conversions::string2int(srid_c,result)) + if (mapnik::util::string2int(srid_c,result)) srid_ = result; } } @@ -205,7 +205,7 @@ void postgis_datasource::bind() const if (srid_c != NULL) { int result; - if (mapnik::conversions::string2int(srid_c,result)) + if (mapnik::util::string2int(srid_c,result)) srid_ = result; } } @@ -681,22 +681,22 @@ box2d postgis_datasource::envelope() const shared_ptr rs = conn->executeQuery(s.str()); if (rs->next() && !rs->isNull(0)) { - double lox; - double loy; - double hix; - double hiy; - if (mapnik::conversions::string2double(rs->getValue(0),lox) && - mapnik::conversions::string2double(rs->getValue(1),loy) && - mapnik::conversions::string2double(rs->getValue(2),hix) && - mapnik::conversions::string2double(rs->getValue(3),hiy)) - { - extent_.init(lox,loy,hix,hiy); - extent_initialized_ = true; - } - else - { - std::clog << boost::format("Postgis Plugin: warning: could not determine extent from query: %s\n") % s.str() << std::endl; - } + double lox; + double loy; + double hix; + double hiy; + if (mapnik::util::string2double(rs->getValue(0),lox) && + mapnik::util::string2double(rs->getValue(1),loy) && + mapnik::util::string2double(rs->getValue(2),hix) && + mapnik::util::string2double(rs->getValue(3),hiy)) + { + extent_.init(lox,loy,hix,hiy); + extent_initialized_ = true; + } + else + { + std::clog << boost::format("Postgis Plugin: warning: could not determine extent from query: %s\n") % s.str() << std::endl; + } } rs->close(); } diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp index f4bbfe4b2..177413fee 100644 --- a/plugins/input/postgis/postgis_featureset.cpp +++ b/plugins/input/postgis/postgis_featureset.cpp @@ -162,7 +162,7 @@ feature_ptr postgis_featureset::next() { std::string str = mapnik::sql_utils::numeric2string(buf); double val; - if (mapnik::conversions::string2double(str,val)) + if (mapnik::util::string2double(str,val)) feature->put(name,val); } else diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index 3abc6d72e..2d08d117b 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -48,9 +48,9 @@ raster_featureset::raster_featureset(LookupPolicy const& policy, extent_(extent), bbox_(q.get_bbox()), curIter_(policy_.begin()), - endIter_(policy_.end()) + endIter_(policy_.end()), + ctx_(boost::make_shared()) { - ctx_ = boost::make_shared(); } template diff --git a/plugins/input/rasterlite/rasterlite_datasource.cpp b/plugins/input/rasterlite/rasterlite_datasource.cpp index e9cd0bf69..ac609f357 100644 --- a/plugins/input/rasterlite/rasterlite_datasource.cpp +++ b/plugins/input/rasterlite/rasterlite_datasource.cpp @@ -29,7 +29,7 @@ #include // mapnik -#include +#include #include using mapnik::datasource; diff --git a/plugins/input/shape/dbfile.cpp b/plugins/input/shape/dbfile.cpp index 9e09a14f3..4af77c654 100644 --- a/plugins/input/shape/dbfile.cpp +++ b/plugins/input/shape/dbfile.cpp @@ -127,7 +127,7 @@ void dbf_file::add_attribute(int col, mapnik::transcoder const& tr, Feature & f) if (col>=0 && col::shape_index_featureset(filterT const& filter, std::string const& shape_name, int row_limit) : filter_(filter), + ctx_(boost::make_shared()), shape_(shape), tr_(new transcoder(encoding)), row_limit_(row_limit), count_(0) { - ctx_ = boost::make_shared(); shape_.shp().skip(100); setup_attributes(ctx_, attribute_names, shape_name, shape_,attr_ids_); - + boost::shared_ptr index = shape_.index(); if (index) { diff --git a/plugins/input/shape/shape_io.cpp b/plugins/input/shape/shape_io.cpp index 4ace58937..81677677b 100644 --- a/plugins/input/shape/shape_io.cpp +++ b/plugins/input/shape/shape_io.cpp @@ -103,12 +103,12 @@ void shape_io::read_polyline(mapnik::geometry_container & geom) { shape_file::record_type record(reclength_ * 2 - 36); shp_.read_record(record); - + int num_parts = record.read_ndr_integer(); int num_points = record.read_ndr_integer(); if (num_parts == 1) { - geometry_type* line = new geometry_type(mapnik::LineString); + geometry_type* line = new geometry_type(mapnik::LineString); record.skip(4); double x = record.read_double(); double y = record.read_double(); @@ -132,7 +132,7 @@ void shape_io::read_polyline(mapnik::geometry_container & geom) int start, end; for (int k = 0; k < num_parts; ++k) { - geometry_type* line = new geometry_type(mapnik::LineString); + geometry_type* line = new geometry_type(mapnik::LineString); start = parts[k]; if (k == num_parts - 1) { @@ -179,11 +179,11 @@ void shape_io::read_polygon(mapnik::geometry_container & geom) { shape_file::record_type record(reclength_ * 2 - 36); shp_.read_record(record); - + int num_parts = record.read_ndr_integer(); int num_points = record.read_ndr_integer(); std::vector parts(num_parts); - + for (int i = 0; i < num_parts; ++i) { parts[i] = record.read_ndr_integer(); diff --git a/plugins/input/sqlite/sqlite_datasource.cpp b/plugins/input/sqlite/sqlite_datasource.cpp index 02e184d3a..77015ef82 100644 --- a/plugins/input/sqlite/sqlite_datasource.cpp +++ b/plugins/input/sqlite/sqlite_datasource.cpp @@ -26,7 +26,7 @@ #include "sqlite_utils.hpp" // mapnik -#include +#include #include #include #include diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index ac618ee56..9b4279114 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -24,9 +24,9 @@ // mapnik #include #include +#include #include #include -#include #include #include #include @@ -201,16 +201,18 @@ void agg_renderer::end_map_processing(Map const& ) } template -void agg_renderer::start_layer_processing(layer const& lay) +void agg_renderer::start_layer_processing(layer const& lay, box2d const& query_extent) { #ifdef MAPNIK_DEBUG std::clog << "start layer processing : " << lay.name() << "\n"; std::clog << "datasource = " << lay.datasource().get() << "\n"; + std::clog << "query_extent = " << query_extent << "\n"; #endif if (lay.clear_label_cache()) { detector_->clear(); } + query_extent_ = query_extent; } template @@ -246,7 +248,7 @@ void agg_renderer::render_marker(pixel_position const& pos, marker const& mar mtx *= agg::trans_affine_scaling(scale_factor_); // render the marker at the center of the marker box mtx.translate(pos.x+0.5 * marker.width(), pos.y+0.5 * marker.height()); - + using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); svg_path_adapter svg_path(stl_storage); svg_renderer #include #include +#include #include #include @@ -42,6 +43,7 @@ #include "agg_span_allocator.h" #include "agg_span_pattern_rgba.h" #include "agg_renderer_outline_image.h" +#include "agg_conv_clip_polyline.h" namespace mapnik { @@ -50,7 +52,8 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - typedef coord_transform2 path_type; + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; typedef agg::line_image_pattern pattern_type; typedef agg::renderer_base renderer_base; typedef agg::renderer_outline_image renderer_type; @@ -74,6 +77,7 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, if (!pat) return; + box2d ext = query_extent_ * 1.1; renderer_base ren_base(pixf); agg::pattern_filter_bilinear_rgba8 filter; pattern_source source(*(*pat)); @@ -82,15 +86,17 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, // TODO - should be sensitive to buffer size ren.clip_box(0,0,width_,height_); rasterizer_type ras(ren); - metawriter_with_properties writer = sym.get_metawriter(); + //metawriter_with_properties writer = sym.get_metawriter(); for (unsigned i=0;inum_geometries();++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { - path_type path(t_,geom,prj_trans); + clipped_geometry_type clipped(geom); + clipped.clip_box(ext.minx(),ext.miny(),ext.maxx(),ext.maxy()); + path_type path(t_,clipped,prj_trans); ras.add_path(path); - if (writer.first) writer.first->add_line(path, *feature, t_, writer.second); + //if (writer.first) writer.first->add_line(path, *feature, t_, writer.second); } } } diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 76d0e3668..6046e116e 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -23,6 +23,7 @@ // mapnik #include +#include #include #include @@ -38,8 +39,8 @@ #include "agg_conv_dash.h" #include "agg_renderer_outline_aa.h" #include "agg_rasterizer_outline_aa.h" - - +#include "agg_conv_clip_polyline.h" +#include "agg_conv_smooth_poly1.h" // stl #include @@ -51,7 +52,6 @@ void agg_renderer::process(line_symbolizer const& sym, proj_transform const& prj_trans) { typedef agg::renderer_base ren_base; - typedef coord_transform2 path_type; stroke const& stroke_ = sym.get_stroke(); color const& col = stroke_.get_color(); @@ -63,13 +63,15 @@ void agg_renderer::process(line_symbolizer const& sym, agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4); agg::pixfmt_rgba32_plain pixf(buf); + box2d ext = query_extent_ * 1.1; if (sym.get_rasterizer() == RASTERIZER_FAST) { typedef agg::renderer_outline_aa renderer_type; typedef agg::rasterizer_outline_aa rasterizer_type; + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; agg::line_profile_aa profile; - //agg::line_profile_aa profile(stroke_.get_width() * scale_factor_, agg::gamma_none()); profile.width(stroke_.get_width() * scale_factor_); ren_base base_ren(pixf); renderer_type ren(base_ren, profile); @@ -81,10 +83,12 @@ void agg_renderer::process(line_symbolizer const& sym, for (unsigned i=0;inum_geometries();++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { - path_type path(t_,geom,prj_trans); + clipped_geometry_type clipped(geom); + clipped.clip_box(ext.minx(),ext.miny(),ext.maxx(),ext.maxy()); + path_type path(t_,clipped,prj_trans); ras.add_path(path); } } @@ -98,97 +102,98 @@ void agg_renderer::process(line_symbolizer const& sym, ren_base renb(pixf); renderer ren(renb); ras_ptr->reset(); - switch (stroke_.get_gamma_method()) - { - case GAMMA_POWER: - ras_ptr->gamma(agg::gamma_power(stroke_.get_gamma())); - break; - case GAMMA_LINEAR: - ras_ptr->gamma(agg::gamma_linear(0.0, stroke_.get_gamma())); - break; - case GAMMA_NONE: - ras_ptr->gamma(agg::gamma_none()); - break; - case GAMMA_THRESHOLD: - ras_ptr->gamma(agg::gamma_threshold(stroke_.get_gamma())); - break; - case GAMMA_MULTIPLY: - ras_ptr->gamma(agg::gamma_multiply(stroke_.get_gamma())); - break; - default: - ras_ptr->gamma(agg::gamma_power(stroke_.get_gamma())); - } - metawriter_with_properties writer = sym.get_metawriter(); + set_gamma_method(stroke_, ras_ptr); + + //metawriter_with_properties writer = sym.get_metawriter(); for (unsigned i=0;inum_geometries();++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { - path_type path(t_,geom,prj_trans); - if (stroke_.has_dash()) { - agg::conv_dash dash(path); - dash_array const& d = stroke_.get_dash_array(); - dash_array::const_iterator itr = d.begin(); - dash_array::const_iterator end = d.end(); - for (;itr != end;++itr) + if (sym.smooth() > 0.0) { - dash.add_dash(itr->first * scale_factor_, - itr->second * scale_factor_); + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; + typedef agg::conv_smooth_poly1_curve smooth_type; + clipped_geometry_type clipped(geom); + clipped.clip_box(ext.minx(),ext.miny(),ext.maxx(),ext.maxy()); + path_type path(t_,clipped,prj_trans); + smooth_type smooth(path); + smooth.smooth_value(sym.smooth()); + agg::conv_dash dash(smooth); + dash_array const& d = stroke_.get_dash_array(); + dash_array::const_iterator itr = d.begin(); + dash_array::const_iterator end = d.end(); + for (;itr != end;++itr) + { + dash.add_dash(itr->first * scale_factor_, + itr->second * scale_factor_); + } + agg::conv_stroke > stroke(dash); + set_join_caps(stroke_,stroke); + stroke.generator().miter_limit(4.0); + stroke.generator().width(stroke_.get_width() * scale_factor_); + ras_ptr->add_path(stroke); } - - agg::conv_stroke > stroke(dash); - - line_join_e join=stroke_.get_line_join(); - if ( join == MITER_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == MITER_REVERT_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == ROUND_JOIN) - stroke.generator().line_join(agg::round_join); else - stroke.generator().line_join(agg::bevel_join); - - line_cap_e cap=stroke_.get_line_cap(); - if (cap == BUTT_CAP) - stroke.generator().line_cap(agg::butt_cap); - else if (cap == SQUARE_CAP) - stroke.generator().line_cap(agg::square_cap); - else - stroke.generator().line_cap(agg::round_cap); - - stroke.generator().miter_limit(4.0); - stroke.generator().width(stroke_.get_width() * scale_factor_); - ras_ptr->add_path(stroke); + { + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; + clipped_geometry_type clipped(geom); + clipped.clip_box(ext.minx(),ext.miny(),ext.maxx(),ext.maxy()); + path_type path(t_,clipped,prj_trans); + agg::conv_dash dash(path); + dash_array const& d = stroke_.get_dash_array(); + dash_array::const_iterator itr = d.begin(); + dash_array::const_iterator end = d.end(); + for (;itr != end;++itr) + { + dash.add_dash(itr->first * scale_factor_, + itr->second * scale_factor_); + } + agg::conv_stroke > stroke(dash); + set_join_caps(stroke_,stroke); + stroke.generator().miter_limit(4.0); + stroke.generator().width(stroke_.get_width() * scale_factor_); + ras_ptr->add_path(stroke); + } } else { - agg::conv_stroke stroke(path); - line_join_e join=stroke_.get_line_join(); - if ( join == MITER_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == MITER_REVERT_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == ROUND_JOIN) - stroke.generator().line_join(agg::round_join); + if (sym.smooth() > 0.0) + { + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; + typedef agg::conv_smooth_poly1_curve smooth_type; + clipped_geometry_type clipped(geom); + clipped.clip_box(ext.minx(),ext.miny(),ext.maxx(),ext.maxy()); + path_type path(t_,clipped,prj_trans); + smooth_type smooth(path); + smooth.smooth_value(sym.smooth()); + agg::conv_stroke stroke(smooth); + set_join_caps(stroke_,stroke); + stroke.generator().miter_limit(4.0); + stroke.generator().width(stroke_.get_width() * scale_factor_); + ras_ptr->add_path(stroke); + } else - stroke.generator().line_join(agg::bevel_join); - - line_cap_e cap=stroke_.get_line_cap(); - if (cap == BUTT_CAP) - stroke.generator().line_cap(agg::butt_cap); - else if (cap == SQUARE_CAP) - stroke.generator().line_cap(agg::square_cap); - else - stroke.generator().line_cap(agg::round_cap); - - stroke.generator().miter_limit(4.0); - stroke.generator().width(stroke_.get_width() * scale_factor_); - ras_ptr->add_path(stroke); - if (writer.first) writer.first->add_line(path, *feature, t_, writer.second); + { + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; + clipped_geometry_type clipped(geom); + clipped.clip_box(ext.minx(),ext.miny(),ext.maxx(),ext.maxy()); + path_type path(t_,clipped,prj_trans); + agg::conv_stroke stroke(path); + set_join_caps(stroke_,stroke); + stroke.generator().miter_limit(4.0); + stroke.generator().width(stroke_.get_width() * scale_factor_); + ras_ptr->add_path(stroke); + } + //if (writer.first) writer.first->add_line(path, *feature, t_, writer.second); } } } diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index c1e75c3f5..17bf44f60 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,7 @@ #include "agg_path_storage.h" #include "agg_ellipse.h" #include "agg_conv_stroke.h" - +#include "agg_conv_clip_polyline.h" namespace mapnik { @@ -50,7 +51,9 @@ void agg_renderer::process(markers_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - typedef coord_transform2 path_type; + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; + typedef agg::pixfmt_rgba32_plain pixfmt; typedef agg::renderer_base renderer_base; typedef agg::renderer_scanline_aa_solid renderer_solid; @@ -104,7 +107,7 @@ void agg_renderer::process(markers_symbolizer const& sym, for (unsigned i=0; inum_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); // TODO - merge this code with point_symbolizer rendering if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) { @@ -131,7 +134,9 @@ void agg_renderer::process(markers_symbolizer const& sym, } else { - path_type path(t_,geom,prj_trans); + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); markers_placement placement(path, extent, *detector_, sym.get_spacing() * scale_factor_, sym.get_max_error(), @@ -166,6 +171,8 @@ void agg_renderer::process(markers_symbolizer const& sym, unsigned s_a=col.alpha(); double w = sym.get_width(); double h = sym.get_height(); + double rx = w/2.0; + double ry = h/2.0; arrow arrow_; box2d extent; @@ -206,7 +213,7 @@ void agg_renderer::process(markers_symbolizer const& sym, for (unsigned i=0; inum_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); //if (geom.num_points() <= 1) continue; if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) { @@ -220,7 +227,7 @@ void agg_renderer::process(markers_symbolizer const& sym, if (sym.get_allow_overlap() || detector_->has_placement(label_ext)) { - agg::ellipse c(x, y, w, h); + agg::ellipse c(x, y, rx, ry); marker.concat_path(c); ras_ptr->add_path(marker); ren.color(agg::rgba8(r, g, b, int(a*sym.get_opacity()))); @@ -239,7 +246,8 @@ void agg_renderer::process(markers_symbolizer const& sym, ren.color(agg::rgba8(s_r, s_g, s_b, int(s_a*stroke_.get_opacity()))); agg::render_scanlines(*ras_ptr, sl_line, ren); } - detector_->insert(label_ext); + if (!sym.get_ignore_placement()) + detector_->insert(label_ext); if (writer.first) writer.first->add_box(label_ext, *feature, t_, writer.second); } } @@ -249,7 +257,9 @@ void agg_renderer::process(markers_symbolizer const& sym, if (marker_type == ARROW) marker.concat_path(arrow_); - path_type path(t_,geom,prj_trans); + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); markers_placement placement(path, extent, *detector_, sym.get_spacing() * scale_factor_, sym.get_max_error(), @@ -263,7 +273,7 @@ void agg_renderer::process(markers_symbolizer const& sym, if (marker_type == ELLIPSE) { // todo proper bbox - this is buggy - agg::ellipse c(x_t, y_t, w, h); + agg::ellipse c(x_t, y_t, rx, ry); marker.concat_path(c); agg::trans_affine matrix; matrix *= agg::trans_affine_translation(-x_t,-y_t); diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 967ebd082..d29f6d15c 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 5867b3fae..56e1293ef 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -23,7 +23,9 @@ // mapnik #include +#include #include +#include #include #include @@ -38,8 +40,7 @@ #include "agg_span_allocator.h" #include "agg_span_pattern_rgba.h" #include "agg_image_accessors.h" - - +#include "agg_conv_clip_polygon.h" namespace mapnik { @@ -48,7 +49,8 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - typedef coord_transform2 path_type; + typedef agg::conv_clip_polygon clipped_geometry_type; + typedef coord_transform2 path_type; typedef agg::renderer_base ren_base; typedef agg::wrap_mode_repeat wrap_x_type; typedef agg::wrap_mode_repeat wrap_y_type; @@ -71,26 +73,7 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, agg::scanline_u8 sl; ras_ptr->reset(); - switch (sym.get_gamma_method()) - { - case GAMMA_POWER: - ras_ptr->gamma(agg::gamma_power(sym.get_gamma())); - break; - case GAMMA_LINEAR: - ras_ptr->gamma(agg::gamma_linear(0.0, sym.get_gamma())); - break; - case GAMMA_NONE: - ras_ptr->gamma(agg::gamma_none()); - break; - case GAMMA_THRESHOLD: - ras_ptr->gamma(agg::gamma_threshold(sym.get_gamma())); - break; - case GAMMA_MULTIPLY: - ras_ptr->gamma(agg::gamma_multiply(sym.get_gamma())); - break; - default: - ras_ptr->gamma(agg::gamma_power(sym.get_gamma())); - } + set_gamma_method(sym,ras_ptr); std::string filename = path_processor_type::evaluate( *sym.get_filename(), *feature); boost::optional marker; @@ -133,9 +116,11 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, if (align == LOCAL_ALIGNMENT) { double x0=0,y0=0; - if (num_geometries>0) + if (num_geometries>0) // FIXME: hmm...? { - path_type path(t_,feature->get_geometry(0),prj_trans); + clipped_geometry_type clipped(feature->get_geometry(0)); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); path.vertex(&x0,&y0); } offset_x = unsigned(width_-x0); @@ -144,15 +129,17 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, span_gen_type sg(img_src, offset_x, offset_y); renderer_type rp(renb,sa, sg); - metawriter_with_properties writer = sym.get_metawriter(); + //metawriter_with_properties writer = sym.get_metawriter(); for (unsigned i=0;iget_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 2) { - path_type path(t_,geom,prj_trans); + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); ras_ptr->add_path(path); - if (writer.first) writer.first->add_polygon(path, *feature, t_, writer.second); + //if (writer.first) writer.first->add_polygon(path, *feature, t_, writer.second); } } agg::render_scanlines(*ras_ptr, sl, rp); diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index d0c378091..0cc902b04 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -23,6 +23,7 @@ // mapnik #include +#include #include #include @@ -34,7 +35,8 @@ #include "agg_scanline_u.h" // for polygon_symbolizer #include "agg_renderer_scanline.h" - +#include "agg_conv_clip_polygon.h" +#include "agg_conv_smooth_poly1.h" // stl #include @@ -45,7 +47,6 @@ void agg_renderer::process(polygon_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - typedef coord_transform2 path_type; typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_aa_solid renderer; @@ -60,40 +61,42 @@ void agg_renderer::process(polygon_symbolizer const& sym, unsigned g=fill_.green(); unsigned b=fill_.blue(); unsigned a=fill_.alpha(); - renb.clip_box(0,0,width_,height_); + //renb.clip_box(0,0,width_,height_); renderer ren(renb); - - ras_ptr->reset(); - switch (sym.get_gamma_method()) - { - case GAMMA_POWER: - ras_ptr->gamma(agg::gamma_power(sym.get_gamma())); - break; - case GAMMA_LINEAR: - ras_ptr->gamma(agg::gamma_linear(0.0, sym.get_gamma())); - break; - case GAMMA_NONE: - ras_ptr->gamma(agg::gamma_none()); - break; - case GAMMA_THRESHOLD: - ras_ptr->gamma(agg::gamma_threshold(sym.get_gamma())); - break; - case GAMMA_MULTIPLY: - ras_ptr->gamma(agg::gamma_multiply(sym.get_gamma())); - break; - default: - ras_ptr->gamma(agg::gamma_power(sym.get_gamma())); - } - metawriter_with_properties writer = sym.get_metawriter(); + ras_ptr->reset(); + + set_gamma_method(sym,ras_ptr); + + //metawriter_with_properties writer = sym.get_metawriter(); + box2d inflated_extent = query_extent_ * 1.1; for (unsigned i=0;inum_geometries();++i) { - geometry_type const& geom=feature->get_geometry(i); + geometry_type & geom=feature->get_geometry(i); if (geom.num_points() > 2) { - path_type path(t_,geom,prj_trans); - ras_ptr->add_path(path); - if (writer.first) writer.first->add_polygon(path, *feature, t_, writer.second); + if (sym.smooth() > 0.0) + { + typedef agg::conv_clip_polygon clipped_geometry_type; + typedef coord_transform2 path_type; + typedef agg::conv_smooth_poly1_curve smooth_type; + clipped_geometry_type clipped(geom); + clipped.clip_box(inflated_extent.minx(),inflated_extent.miny(),inflated_extent.maxx(),inflated_extent.maxy()); + path_type path(t_,clipped,prj_trans); + smooth_type smooth(path); + smooth.smooth_value(sym.smooth()); + ras_ptr->add_path(smooth); + } + else + { + typedef agg::conv_clip_polygon clipped_geometry_type; + typedef coord_transform2 path_type; + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); + ras_ptr->add_path(path); + } + //if (writer.first) writer.first->add_polygon(path, *feature, t_, writer.second); } } ren.color(agg::rgba8(r, g, b, int(a * sym.get_opacity()))); diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index 31c0c6507..e88a00f9c 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -46,7 +46,7 @@ void agg_renderer::process(shield_symbolizer const& sym, sym, *feature, prj_trans, width_, height_, scale_factor_, - t_, font_manager_, *detector_); + t_, font_manager_, *detector_, query_extent_); text_renderer ren(pixmap_, font_manager_, *(font_manager_.get_stroker())); diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index e548346ef..9564f1746 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -38,7 +38,7 @@ void agg_renderer::process(text_symbolizer const& sym, sym, *feature, prj_trans, width_, height_, scale_factor_, - t_, font_manager_, *detector_); + t_, font_manager_, *detector_, query_extent_); text_renderer ren(pixmap_, font_manager_, *(font_manager_.get_stroker())); diff --git a/src/build.py b/src/build.py index c25bc2fb5..34ba537d1 100644 --- a/src/build.py +++ b/src/build.py @@ -73,6 +73,7 @@ if env['THREADING'] == 'multi': if env['RUNTIME_LINK'] == 'static': if 'icuuc' in env['ICU_LIB_NAME']: lib_env['LIBS'].append('icudata') + lib_env['LIBS'].append('icui18n') else: if env['INTERNAL_LIBAGG']: lib_env['LIBS'].insert(0, 'agg') @@ -83,7 +84,7 @@ else: if env['PLATFORM'] == 'Darwin': mapnik_libname = 'libmapnik.dylib' else: - mapnik_libname = 'libmapnik.so.' + ("%d.%d" % (ABI_VERSION[0],ABI_VERSION[1])) + mapnik_libname = 'libmapnik.so.' + ("%d.%d" % (int(ABI_VERSION[0]),int(ABI_VERSION[1]))) if env['PLATFORM'] == 'Darwin': if env['FULL_LIB_PATH']: @@ -91,7 +92,7 @@ if env['PLATFORM'] == 'Darwin': else: lib_path = mapnik_libname mapnik_lib_link_flag += ' -Wl,-install_name,%s' % lib_path - _d = {'version':env['MAPNIK_VERSION_STRING']} + _d = {'version':env['MAPNIK_VERSION_STRING'].replace('-pre','')} mapnik_lib_link_flag += ' -current_version %(version)s -compatibility_version %(version)s' % _d elif env['PLATFORM'] == 'SunOS': if env['CXX'].startswith('CC'): @@ -105,6 +106,7 @@ source = Split( """ color.cpp conversions.cpp + image_compositing.cpp box2d.cpp building_symbolizer.cpp datasource_cache.cpp @@ -178,6 +180,8 @@ source = Split( text_placements/list.cpp text_placements/simple.cpp text_properties.cpp + xml_tree.cpp + config_error.cpp """ ) @@ -299,7 +303,7 @@ if env['XMLPARSER'] == 'libxml2' and env['HAS_LIBXML2']: env2 = lib_env.Clone() env2.Append(CXXFLAGS = '-DHAVE_LIBXML2') libmapnik_cxxflags.append('-DHAVE_LIBXML2') - fixup = ['load_map.cpp','libxml2_loader.cpp'] + fixup = ['libxml2_loader.cpp'] for cpp in fixup: if cpp in source: source.remove(cpp) @@ -307,6 +311,12 @@ if env['XMLPARSER'] == 'libxml2' and env['HAS_LIBXML2']: source.insert(0,env2.StaticObject(cpp)) else: source.insert(0,env2.SharedObject(cpp)) +else: + source += Split( + """ + rapidxml_loader.cpp + """ + ) if env['CUSTOM_LDFLAGS']: linkflags = '%s %s' % (env['CUSTOM_LDFLAGS'], mapnik_lib_link_flag) @@ -334,7 +344,7 @@ if env['PLATFORM'] != 'Darwin': major, minor, micro = ABI_VERSION - soFile = "%s.%d.%d.%d" % (os.path.basename(str(mapnik[0])), major, minor, micro) + soFile = "%s.%d.%d.%d" % (os.path.basename(str(mapnik[0])), int(major), int(minor), int(micro)) target = os.path.join(env['MAPNIK_LIB_BASE_DEST'], soFile) if 'uninstall' not in COMMAND_LINE_TARGETS: @@ -345,7 +355,7 @@ if env['PLATFORM'] != 'Darwin': # Install symlinks - target1 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], "%s.%d.%d" % (os.path.basename(str(mapnik[0])),major, minor)) + target1 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], "%s.%d.%d" % (os.path.basename(str(mapnik[0])),int(major), int(minor))) target2 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], os.path.basename(str(mapnik[0]))) if 'uninstall' not in COMMAND_LINE_TARGETS: if 'install' in COMMAND_LINE_TARGETS: diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 85cc7592d..589247e0f 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -29,8 +29,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -50,6 +50,11 @@ #include #include +// agg +#include "agg_conv_clip_polyline.h" +#include "agg_conv_clip_polygon.h" +#include "agg_conv_smooth_poly1.h" + // stl #ifdef MAPNIK_DEBUG #include @@ -249,8 +254,7 @@ cairo_face_ptr cairo_face_manager::get_face(face_ptr face) } else { - entry = cairo_face_ptr(new cairo_face(font_engine_, face)); - + entry = boost::make_shared(font_engine_, face); cache_.insert(std::make_pair(face, entry)); } @@ -628,7 +632,7 @@ cairo_renderer_base::cairo_renderer_base(Map const& m, Cairo::RefPtr()), font_manager_(*font_engine_), face_manager_(font_engine_,font_manager_), detector_(box2d(-m.buffer_size() ,-m.buffer_size() , m.width() + m.buffer_size() ,m.height() + m.buffer_size())) @@ -696,16 +700,18 @@ void cairo_renderer_base::start_map_processing(Map const& map) context_->show_page(); } - void cairo_renderer_base::start_layer_processing(layer const& lay) + void cairo_renderer_base::start_layer_processing(layer const& lay, box2d const& query_extent) { #ifdef MAPNIK_DEBUG std::clog << "start layer processing : " << lay.name() << "\n"; std::clog << "datasource = " << lay.datasource().get() << "\n"; + std::clog << "query_extent = " << query_extent << "\n"; #endif if (lay.clear_label_cache()) { detector_.clear(); } + query_extent_ = query_extent; } void cairo_renderer_base::end_layer_processing(layer const&) @@ -719,24 +725,40 @@ void cairo_renderer_base::start_map_processing(Map const& map) mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - typedef coord_transform2 path_type; cairo_context context(context_); - context.set_color(sym.get_fill(), sym.get_opacity()); - + box2d inflated_extent = query_extent_ * 1.1; for (unsigned i = 0; i < feature->num_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); - + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 2) { - path_type path(t_, geom, prj_trans); - - context.add_path(path); - context.fill(); + if (sym.smooth() > 0.0) + { + typedef agg::conv_clip_polygon clipped_geometry_type; + typedef coord_transform2 path_type; + typedef agg::conv_smooth_poly1_curve smooth_type; + clipped_geometry_type clipped(geom); + clipped.clip_box(inflated_extent.minx(),inflated_extent.miny(),inflated_extent.maxx(),inflated_extent.maxy()); + path_type path(t_,clipped,prj_trans); + smooth_type smooth(path); + smooth.smooth_value(sym.smooth()); + context.add_agg_path(smooth); + } + else + { + typedef agg::conv_clip_polygon clipped_geometry_type; + typedef coord_transform2 path_type; + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); + context.add_path(path); + } } } + // fill polygon + context.fill(); } void cairo_renderer_base::process(building_symbolizer const& sym, @@ -853,35 +875,36 @@ void cairo_renderer_base::start_map_processing(Map const& map) mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - typedef coord_transform2 path_type; + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; - cairo_context context(context_); mapnik::stroke const& stroke_ = sym.get_stroke(); - + cairo_context context(context_); context.set_color(stroke_.get_color(), stroke_.get_opacity()); + context.set_line_join(stroke_.get_line_join()); + context.set_line_cap(stroke_.get_line_cap()); + context.set_miter_limit(4.0); + context.set_line_width(stroke_.get_width()); + if (stroke_.has_dash()) + { + context.set_dash(stroke_.get_dash_array()); + } for (unsigned i = 0; i < feature->num_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { - cairo_context context(context_); - path_type path(t_, geom, prj_trans); + //cairo_context context(context_); + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); - if (stroke_.has_dash()) - { - context.set_dash(stroke_.get_dash_array()); - } - - context.set_line_join(stroke_.get_line_join()); - context.set_line_cap(stroke_.get_line_cap()); - context.set_miter_limit(4.0); - context.set_line_width(stroke_.get_width()); context.add_path(path); - context.stroke(); } } + context.stroke(); } void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity) @@ -903,7 +926,7 @@ void cairo_renderer_base::start_map_processing(Map const& map) typedef coord_transform2 path_type; mapnik::path_ptr vmarker = *marker.get_vector_data(); - + using namespace mapnik::svg; agg::pod_bvector const & attributes_ = vmarker->attributes(); for(unsigned i = 0; i < attributes_.size(); ++i) { @@ -1054,8 +1077,7 @@ void cairo_renderer_base::start_map_processing(Map const& map) sym, *feature, prj_trans, detector_.extent().width(), detector_.extent().height(), 1.0 /*scale_factor*/, - t_, font_manager_, detector_); - + t_, font_manager_, detector_, query_extent_); cairo_context context(context_); while (helper.next()) { @@ -1075,7 +1097,8 @@ void cairo_renderer_base::start_map_processing(Map const& map) mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - typedef coord_transform2 path_type; + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; std::string filename = path_processor_type::evaluate( *sym.get_filename(), *feature); boost::optional marker = mapnik::marker_cache::instance()->find(filename,true); @@ -1093,11 +1116,14 @@ void cairo_renderer_base::start_map_processing(Map const& map) for (unsigned i = 0; i < feature->num_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { - path_type path(t_, geom, prj_trans); + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); + double length(0); double x0(0), y0(0); double x, y; @@ -1144,7 +1170,8 @@ void cairo_renderer_base::start_map_processing(Map const& map) mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - typedef coord_transform2 path_type; + typedef agg::conv_clip_polygon clipped_geometry_type; + typedef coord_transform2 path_type; cairo_context context(context_); std::string filename = path_processor_type::evaluate( *sym.get_filename(), *feature); @@ -1159,12 +1186,13 @@ void cairo_renderer_base::start_map_processing(Map const& map) for (unsigned i = 0; i < feature->num_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 2) { - path_type path(t_, geom, prj_trans); - + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); context.add_path(path); context.fill(); } @@ -1229,10 +1257,11 @@ void cairo_renderer_base::start_map_processing(Map const& map) for (unsigned i = 0; i < feature->num_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { + path_type path(t_, geom, prj_trans); markers_placement placement(path, arrow_.extent(), detector_, sym.get_spacing(), sym.get_max_error(), sym.get_allow_overlap()); @@ -1252,7 +1281,7 @@ void cairo_renderer_base::start_map_processing(Map const& map) mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { - text_symbolizer_helper, label_collision_detector4> helper(sym, *feature, prj_trans, detector_.extent().width(), detector_.extent().height(), 1.0 /*scale_factor*/, t_, font_manager_, detector_); + text_symbolizer_helper, label_collision_detector4> helper(sym, *feature, prj_trans, detector_.extent().width(), detector_.extent().height(), 1.0 /*scale_factor*/, t_, font_manager_, detector_, query_extent_); cairo_context context(context_); diff --git a/src/color.cpp b/src/color.cpp index c70e01f5e..80464ccbb 100644 --- a/src/color.cpp +++ b/src/color.cpp @@ -25,11 +25,23 @@ // mapnik #include #include +#include + // boost #include +#include + // stl #include +// boost 1.41 -> 1.44 compatibility, to be removed in mapnik 2.1 (dane) +#if BOOST_VERSION >= 104500 +#include +#else +#include +#endif + + namespace mapnik { color::color( std::string const& css_string) @@ -81,5 +93,90 @@ std::string color::to_hex_string() const } } + +/****************************************************************************/ +void color_factory::init_from_string(color & c, std::string const& css_color) +{ + typedef std::string::const_iterator iterator_type; + typedef mapnik::css_color_grammar css_color_grammar; + + css_color_grammar g; + iterator_type first = css_color.begin(); + iterator_type last = css_color.end(); + // boost 1.41 -> 1.44 compatibility, to be removed in mapnik 2.1 (dane) +#if BOOST_VERSION >= 104500 + bool result = + boost::spirit::qi::phrase_parse(first, + last, + g, + boost::spirit::ascii::space, + c); + if (!result) + { + throw config_error(std::string("Failed to parse color value: ") + + "Expected a CSS color, but got '" + css_color + "'"); + } +#else + mapnik::css css_; + bool result = + boost::spirit::qi::phrase_parse(first, + last, + g, + boost::spirit::ascii::space, + css_); + if (!result) + { + throw config_error(std::string("Failed to parse color value: ") + + "Expected a CSS color, but got '" + css_color + "'"); + } + c.set_red(css_.r); + c.set_green(css_.g); + c.set_blue(css_.b); + c.set_alpha(css_.a); +#endif +} + +bool color_factory::parse_from_string(color & c, std::string const& css_color, + mapnik::css_color_grammar const& g) +{ + std::string::const_iterator first = css_color.begin(); + std::string::const_iterator last = css_color.end(); + // boost 1.41 -> 1.44 compatibility, to be removed in mapnik 2.1 (dane) +#if BOOST_VERSION >= 104500 + bool result = + boost::spirit::qi::phrase_parse(first, + last, + g, + boost::spirit::ascii::space, + c); + return result && (first == last); +#else + mapnik::css css_; + bool result = + boost::spirit::qi::phrase_parse(first, + last, + g, + boost::spirit::ascii::space, + css_); + if (result && (first == last)) + { + c.set_red(css_.r); + c.set_green(css_.g); + c.set_blue(css_.b); + c.set_alpha(css_.a); + return true; + } + return false; +#endif +} + + +color color_factory::from_string(std::string const& css_color) +{ + color c; + init_from_string(c, css_color); + return c; +} + } diff --git a/src/config_error.cpp b/src/config_error.cpp new file mode 100644 index 000000000..714f5a5e2 --- /dev/null +++ b/src/config_error.cpp @@ -0,0 +1,55 @@ +#include +#include + +namespace mapnik +{ + +config_error::config_error(std::string const& what) + : what_(what), line_number_(0), file_(), node_name_(), msg_() +{ +} + + +config_error::config_error(std::string const& what, xml_node const& node) + : what_(what), line_number_(node.line()), file_(node.filename()), node_name_(node.name()), msg_() +{ +} + + +config_error::config_error(std::string const& what, unsigned line_number, std::string const& filename) + : what_(what), line_number_(line_number), file_(filename), node_name_(), msg_() +{ + +} + +char const* config_error::what() const throw() +{ + std::stringstream s; + s << file_; + if (line_number_ > 0) s << " line " << line_number_; + if (!node_name_.empty()) s << " in node "<< node_name_; + if (line_number_ > 0 || !file_.empty()) s << ": "; + s << what_; + msg_ = s.str(); //Avoid returning pointer to dead object + return msg_.c_str(); +} + +void config_error::append_context(std::string const& ctx) const +{ + what_ += " " + ctx; +} + +void config_error::append_context(std::string const& ctx, xml_node const& node) const +{ + append_context(ctx); + append_context(node); +} + +void config_error::append_context(xml_node const& node) const +{ + if (!line_number_) line_number_ = node.line(); + if (node_name_.empty()) node_name_ = node.name(); + if (file_.empty()) file_ = node.filename(); +} + +} diff --git a/src/conversions.cpp b/src/conversions.cpp index 7debd7a6c..76e9d0531 100644 --- a/src/conversions.cpp +++ b/src/conversions.cpp @@ -23,21 +23,21 @@ // boost #include -#define BOOST_SPIRIT_AUTO(domain_, name, expr) \ - typedef boost::proto::result_of:: \ - deep_copy::type name##_expr_type; \ - BOOST_SPIRIT_ASSERT_MATCH( \ - boost::spirit::domain_::domain, name##_expr_type); \ - BOOST_AUTO(name, boost::proto::deep_copy(expr)); \ +#define BOOST_SPIRIT_AUTO(domain_, name, expr) \ + typedef boost::proto::result_of:: \ + deep_copy::type name##_expr_type; \ + BOOST_SPIRIT_ASSERT_MATCH( \ + boost::spirit::domain_::domain, name##_expr_type); \ + BOOST_AUTO(name, boost::proto::deep_copy(expr)); \ -namespace mapnik { namespace conversions { +namespace mapnik { namespace util { using namespace boost::spirit; -BOOST_SPIRIT_AUTO(qi, INTEGER, qi::int_); -BOOST_SPIRIT_AUTO(qi, FLOAT, qi::float_); -BOOST_SPIRIT_AUTO(qi, DOUBLE, qi::double_); +BOOST_SPIRIT_AUTO(qi, INTEGER, qi::int_) +BOOST_SPIRIT_AUTO(qi, FLOAT, qi::float_) +BOOST_SPIRIT_AUTO(qi, DOUBLE, qi::double_) bool string2int(const char * value, int & result) { diff --git a/src/expression.cpp b/src/expression.cpp index 9223021bc..84cd6b0ec 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -24,6 +24,7 @@ #include #include #include +#include // boost #include @@ -50,8 +51,8 @@ expression_ptr expression_factory::compile(std::string const& str,transcoder con } bool expression_factory::parse_from_string(expression_ptr const& expr, - std::string const& str, - mapnik::expression_grammar const& g) + std::string const& str, + mapnik::expression_grammar const& g) { std::string::const_iterator itr = str.begin(); std::string::const_iterator end = str.end(); diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index 18e05cd9e..7cb02042b 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -112,7 +112,7 @@ void feature_style_processor::apply() BOOST_FOREACH ( layer const& lyr, m_.layers() ) { - if (lyr.isVisible(scale_denom)) + if (lyr.visible(scale_denom)) { std::set names; apply_to_layer(lyr, p, proj, scale_denom, names); @@ -146,7 +146,7 @@ void feature_style_processor::apply(mapnik::layer const& lyr, std::se double scale_denom = mapnik::scale_denominator(m_,proj.is_geographic()); scale_denom *= scale_factor_; - if (lyr.isVisible(scale_denom)) + if (lyr.visible(scale_denom)) { apply_to_layer(lyr, p, proj, scale_denom, names); } @@ -203,7 +203,7 @@ void feature_style_processor::apply_to_layer(layer const& lay, Proces return; } - p.start_layer_processing(lay); + #if defined(RENDERING_STATS) progress_timer layer_timer(std::clog, "rendering total for layer: '" + lay.name() + "'"); @@ -248,9 +248,11 @@ void feature_style_processor::apply_to_layer(layer const& lay, Proces layer_ext.clip(map_ext); // forward project layer extent back into native projection if (!prj_trans.forward(layer_ext, PROJ_ENVELOPE_POINTS)) + { std::clog << "WARNING: layer " << lay.name() << " extent " << layer_ext << " in map projection " << " did not reproject properly back to layer projection\n"; + } } else { @@ -262,13 +264,14 @@ void feature_style_processor::apply_to_layer(layer const& lay, Proces } box2d query_ext = m_.get_current_extent(); - box2d unbuffered_extent = m_.get_current_extent(); prj_trans.forward(query_ext, PROJ_ENVELOPE_POINTS); - query::resolution_type res(m_.width()/query_ext.width(), - m_.height()/query_ext.height()); - - query q(layer_ext,res,scale_denom,unbuffered_extent); + double qw = query_ext.width()>0 ? query_ext.width() : 1; + double qh = query_ext.height()>0 ? query_ext.height() : 1; + query::resolution_type res(m_.width()/qw, + m_.height()/qh); + query q(layer_ext,res,scale_denom,m_.get_current_extent()); + p.start_layer_processing(lay, query_ext); std::vector active_styles; attribute_collector collector(names); double filt_factor = 1; diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 754a106dd..cef4551d8 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -30,6 +30,7 @@ // boost #include #include +#include #include // icu @@ -70,11 +71,10 @@ bool freetype_engine::is_font_file(std::string const& file_name) bool freetype_engine::register_font(std::string const& file_name) { - if (!boost::filesystem::is_regular_file(file_name) || !is_font_file(file_name)) return false; #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); #endif - FT_Library library; + FT_Library library = 0; FT_Error error = FT_Init_FreeType(&library); if (error) { @@ -82,36 +82,47 @@ bool freetype_engine::register_font(std::string const& file_name) } FT_Face face = 0; + int num_faces = 0; + bool success = false; // some font files have multiple fonts in a file // the count is in the 'root' face library[0] // see the FT_FaceRec in freetype.h - for ( int i = 0; face == 0 || i < face->num_faces; i++ ) { + for ( int i = 0; face == 0 || i < num_faces; i++ ) { // if face is null then this is the first face error = FT_New_Face (library,file_name.c_str(),i,&face); if (error) { - FT_Done_FreeType(library); - return false; + break; } + // store num_faces locally, after FT_Done_Face it can not be accessed any more + if (!num_faces) + num_faces = face->num_faces; // some fonts can lack names, skip them // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec - if (face->family_name && face->style_name) { + if (face->family_name && face->style_name) + { + success = true; std::string name = std::string(face->family_name) + " " + std::string(face->style_name); name2file_.insert(std::make_pair(name, std::make_pair(i,file_name))); - FT_Done_Face(face); - //FT_Done_FreeType(library); - //return true; - } else { - FT_Done_Face(face); - FT_Done_FreeType(library); + } + else + { std::ostringstream s; - s << "Error: unable to load invalid font file which lacks identifiable family and style name: '" - << file_name << "'"; - throw std::runtime_error(s.str()); + s << "Warning: unable to load font file '" << file_name << "' "; + if (!face->family_name && !face->style_name) + s << "which lacks both a family name and style name"; + else if (face->family_name) + s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name"; + else if (face->style_name) + s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name"; + std::clog << s.str() << std::endl; } } - FT_Done_FreeType(library); - return true; + if (face) + FT_Done_Face(face); + if (library) + FT_Done_FreeType(library); + return success; } bool freetype_engine::register_fonts(std::string const& dir, bool recurse) @@ -125,26 +136,24 @@ bool freetype_engine::register_fonts(std::string const& dir, bool recurse) return mapnik::freetype_engine::register_font(dir); boost::filesystem::directory_iterator end_itr; + bool success = false; for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr) { +#if (BOOST_FILESYSTEM_VERSION == 3) + std::string const& file_name = itr->path().string(); +#else // v2 + std::string const& file_name = itr->string(); +#endif if (boost::filesystem::is_directory(*itr) && recurse) { -#if (BOOST_FILESYSTEM_VERSION == 3) - if (!register_fonts(itr->path().string(), true)) return false; -#else // v2 - if (!register_fonts(itr->string(), true)) return false; -#endif + success = register_fonts(file_name, true); } - else + else if (boost::filesystem::is_regular_file(file_name) && is_font_file(file_name)) { -#if (BOOST_FILESYSTEM_VERSION == 3) - mapnik::freetype_engine::register_font(itr->path().string()); -#else // v2 - mapnik::freetype_engine::register_font(itr->string()); -#endif + success = mapnik::freetype_engine::register_font(file_name); } } - return true; + return success; } @@ -178,7 +187,7 @@ face_ptr freetype_engine::create_face(std::string const& family_name) &face); if (!error) { - return face_ptr (new font_face(face)); + return boost::make_shared(face); } } return face_ptr(); @@ -190,7 +199,7 @@ stroker_ptr freetype_engine::create_stroker() FT_Error error = FT_Stroker_New(library_, &s); if (!error) { - return stroker_ptr(new stroker(s)); + return boost::make_shared(s); } return stroker_ptr(); } diff --git a/src/formatting/base.cpp b/src/formatting/base.cpp index e9c1ff3e7..3b88d581c 100644 --- a/src/formatting/base.cpp +++ b/src/formatting/base.cpp @@ -23,6 +23,7 @@ #include #include #include +#include // boost #include @@ -38,18 +39,18 @@ void node::to_xml(boost::property_tree::ptree &xml) const #endif } -node_ptr node::from_xml(boost::property_tree::ptree const& xml) +node_ptr node::from_xml(xml_node const& xml) { list_node *list = new list_node(); node_ptr list_ptr(list); - boost::property_tree::ptree::const_iterator itr = xml.begin(); - boost::property_tree::ptree::const_iterator end = xml.end(); + xml_node::const_iterator itr = xml.begin(); + xml_node::const_iterator end = xml.end(); for (; itr != end; ++itr) { - if (itr->first == "" || itr->first == "" || itr->first == "Placement") + if (itr->name() == "Placement") { continue; } - node_ptr n = registry::instance()->from_xml(itr->first, itr->second); + node_ptr n = registry::instance()->from_xml(*itr); if (n) list->push_back(n); } if (list->get_children().size() == 1) { diff --git a/src/formatting/expression.cpp b/src/formatting/expression.cpp index 0ee7598bd..5dfff9972 100644 --- a/src/formatting/expression.cpp +++ b/src/formatting/expression.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // boost @@ -37,7 +38,7 @@ namespace formatting using boost::property_tree::ptree; void expression_format::to_xml(boost::property_tree::ptree &xml) const { - ptree &new_node = xml.push_back(ptree::value_type("Format", ptree()))->second; + ptree &new_node = xml.push_back(ptree::value_type("ExpressionFormat", ptree()))->second; if (face_name) set_attr(new_node, "face-name", to_expression_string(*face_name)); if (text_size) set_attr(new_node, "size", to_expression_string(*text_size)); if (character_spacing) set_attr(new_node, "character-spacing", to_expression_string*character_spacing); @@ -51,7 +52,7 @@ void expression_format::to_xml(boost::property_tree::ptree &xml) const if (child_) child_->to_xml(new_node); } -node_ptr expression_format::from_xml(ptree const& xml) +node_ptr expression_format::from_xml(xml_node const& xml) { expression_format *n = new expression_format(); node_ptr np(n); @@ -72,9 +73,9 @@ node_ptr expression_format::from_xml(ptree const& xml) return np; } -expression_ptr expression_format::get_expression(ptree const& xml, std::string name) +expression_ptr expression_format::get_expression(xml_node const& xml, std::string name) { - boost::optional tmp = get_opt_attr(xml, name); + boost::optional tmp = xml.get_opt_attr(name); if (tmp) return parse_expression(*tmp); return expression_ptr(); } @@ -84,25 +85,25 @@ void expression_format::apply(char_properties const& p, const Feature &feature, { char_properties new_properties = p; if (face_name) new_properties.face_name = - boost::apply_visitor(evaluate(feature), *face_name).to_string(); + boost::apply_visitor(evaluate(feature), *face_name).to_string(); if (text_size) new_properties.text_size = - boost::apply_visitor(evaluate(feature), *text_size).to_double(); + boost::apply_visitor(evaluate(feature), *text_size).to_double(); if (character_spacing) new_properties.character_spacing = - boost::apply_visitor(evaluate(feature), *character_spacing).to_double(); + boost::apply_visitor(evaluate(feature), *character_spacing).to_double(); if (line_spacing) new_properties.line_spacing = - boost::apply_visitor(evaluate(feature), *line_spacing).to_double(); + boost::apply_visitor(evaluate(feature), *line_spacing).to_double(); if (text_opacity) new_properties.text_opacity = - boost::apply_visitor(evaluate(feature), *text_opacity).to_double(); + boost::apply_visitor(evaluate(feature), *text_opacity).to_double(); if (wrap_before) new_properties.wrap_before = - boost::apply_visitor(evaluate(feature), *wrap_before).to_bool(); + boost::apply_visitor(evaluate(feature), *wrap_before).to_bool(); if (wrap_char) new_properties.wrap_char = - boost::apply_visitor(evaluate(feature), *character_spacing).to_unicode()[0]; + boost::apply_visitor(evaluate(feature), *character_spacing).to_unicode()[0]; // if (fill) new_properties.fill = // boost::apply_visitor(evaluate(feature), *fill).to_color(); // if (halo_fill) new_properties.halo_fill = // boost::apply_visitor(evaluate(feature), *halo_fill).to_color(); if (halo_radius) new_properties.halo_radius = - boost::apply_visitor(evaluate(feature), *halo_radius).to_double(); + boost::apply_visitor(evaluate(feature), *halo_radius).to_double(); if (child_) { child_->apply(new_properties, feature, output); diff --git a/src/formatting/format.cpp b/src/formatting/format.cpp index 860896dce..f1fad9d3e 100644 --- a/src/formatting/format.cpp +++ b/src/formatting/format.cpp @@ -21,6 +21,7 @@ *****************************************************************************/ #include #include +#include namespace mapnik { using boost::property_tree::ptree; @@ -44,7 +45,7 @@ void format_node::to_xml(ptree &xml) const } -node_ptr format_node::from_xml(ptree const& xml) +node_ptr format_node::from_xml(xml_node const& xml) { format_node *n = new format_node(); node_ptr np(n); @@ -52,19 +53,19 @@ node_ptr format_node::from_xml(ptree const& xml) node_ptr child = node::from_xml(xml); n->set_child(child); - n->face_name = get_opt_attr(xml, "face-name"); + n->face_name = xml.get_opt_attr("face-name"); /*TODO: Fontset is problematic. We don't have the fontsets pointer here... */ - n->text_size = get_opt_attr(xml, "size"); - n->character_spacing = get_opt_attr(xml, "character-spacing"); - n->line_spacing = get_opt_attr(xml, "line-spacing"); - n->text_opacity = get_opt_attr(xml, "opactity"); - boost::optional wrap = get_opt_attr(xml, "wrap-before"); + n->text_size = xml.get_opt_attr("size"); + n->character_spacing = xml.get_opt_attr("character-spacing"); + n->line_spacing = xml.get_opt_attr("line-spacing"); + n->text_opacity = xml.get_opt_attr("opactity"); + boost::optional wrap = xml.get_opt_attr("wrap-before"); if (wrap) n->wrap_before = *wrap; - n->wrap_char = get_opt_attr(xml, "wrap-character"); - n->text_transform = get_opt_attr(xml, "text-transform"); - n->fill = get_opt_attr(xml, "fill"); - n->halo_fill = get_opt_attr(xml, "halo-fill"); - n->halo_radius = get_opt_attr(xml, "halo-radius"); + n->wrap_char = xml.get_opt_attr("wrap-character"); + n->text_transform = xml.get_opt_attr("text-transform"); + n->fill = xml.get_opt_attr("fill"); + n->halo_fill = xml.get_opt_attr("halo-fill"); + n->halo_radius = xml.get_opt_attr("halo-radius"); return np; } diff --git a/src/formatting/registry.cpp b/src/formatting/registry.cpp index 2c3a29a4a..527c81d71 100644 --- a/src/formatting/registry.cpp +++ b/src/formatting/registry.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include namespace mapnik { @@ -46,10 +48,11 @@ void registry::register_name(std::string name, from_xml_function_ptr ptr, bool o } } -node_ptr registry::from_xml(std::string name, const boost::property_tree::ptree &xml) +node_ptr registry::from_xml(xml_node const& xml) { - std::map::const_iterator itr = map_.find(name); - if (itr == map_.end()) throw config_error("Unknown element '" + name + "'"); + std::map::const_iterator itr = map_.find(xml.name()); + if (itr == map_.end()) throw config_error("Unknown element '" + xml.name() + "'", xml); + xml.set_processed(true); return itr->second(xml); } } //ns formatting diff --git a/src/formatting/text.cpp b/src/formatting/text.cpp index bfe3e80b2..3377c9e4b 100644 --- a/src/formatting/text.cpp +++ b/src/formatting/text.cpp @@ -26,9 +26,7 @@ #include #include #include - -// boost -#include +#include namespace mapnik { @@ -45,12 +43,11 @@ void text_node::to_xml(ptree &xml) const } -node_ptr text_node::from_xml(boost::property_tree::ptree const& xml) +node_ptr text_node::from_xml(xml_node const& xml) { - std::string data = xml.data(); - boost::trim(data); + std::string data = xml.text(); if (data.empty()) return node_ptr(); //No text - return node_ptr(new text_node(parse_expression(data, "utf8"))); + return boost::make_shared(parse_expression(data, "utf8")); } void text_node::apply(char_properties const& p, Feature const& feature, processed_text &output) const diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index 754356a46..067c23b55 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -29,9 +29,9 @@ #include +#include #include #include -#include #include #include #include @@ -97,11 +97,12 @@ void grid_renderer::end_map_processing(Map const& ) } template -void grid_renderer::start_layer_processing(layer const& lay) +void grid_renderer::start_layer_processing(layer const& lay, box2d const& query_extent) { #ifdef MAPNIK_DEBUG std::clog << "start layer processing : " << lay.name() << "\n"; std::clog << "datasource = " << lay.datasource().get() << "\n"; + std::clog << "query_extent = " << query_extent << "\n"; #endif if (lay.clear_label_cache()) { @@ -144,7 +145,7 @@ void grid_renderer::render_marker(mapnik::feature_ptr const& feature, unsigne mtx *= agg::trans_affine_scaling(scale_factor_*(1.0/step)); // render the marker at the center of the marker box mtx.translate(pos.x+0.5 * marker.width(), pos.y+0.5 * marker.height()); - + using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); svg_path_adapter svg_path(stl_storage); svg_renderer::process(line_pattern_symbolizer const& sym, for (unsigned i=0;inum_geometries();++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { path_type path(t_,geom,prj_trans); diff --git a/src/grid/process_line_symbolizer.cpp b/src/grid/process_line_symbolizer.cpp index ba0ab2f8a..baa32c988 100644 --- a/src/grid/process_line_symbolizer.cpp +++ b/src/grid/process_line_symbolizer.cpp @@ -63,7 +63,7 @@ void grid_renderer::process(line_symbolizer const& sym, for (unsigned i=0;inum_geometries();++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { path_type path(t_,geom,prj_trans); diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 0c01f1849..b5367cb51 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -104,7 +105,7 @@ void grid_renderer::process(markers_symbolizer const& sym, bool placed = false; for (unsigned i=0; inum_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() <= 1) { std::clog << "### Warning svg markers not supported yet for points within markers_symbolizer\n"; @@ -147,6 +148,9 @@ void grid_renderer::process(markers_symbolizer const& sym, h = sym.get_height()/res; } + double rx = w/2.0; + double ry = h/2.0; + arrow arrow_; box2d extent; @@ -181,7 +185,7 @@ void grid_renderer::process(markers_symbolizer const& sym, for (unsigned i=0; inum_geometries(); ++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) { geom.label_position(&x,&y); @@ -194,7 +198,7 @@ void grid_renderer::process(markers_symbolizer const& sym, if (sym.get_allow_overlap() || detector_.has_placement(label_ext)) { - agg::ellipse c(x, y, w, h); + agg::ellipse c(x, y, rx, ry); agg::path_storage marker; marker.concat_path(c); ras_ptr->add_path(marker); @@ -231,7 +235,7 @@ void grid_renderer::process(markers_symbolizer const& sym, if (marker_type == ELLIPSE) { // todo proper bbox - this is buggy - agg::ellipse c(x_t, y_t, w, h); + agg::ellipse c(x_t, y_t, rx, ry); marker.concat_path(c); agg::trans_affine matrix; matrix *= agg::trans_affine_translation(-x_t,-y_t); diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp index 2db4dd5c2..2c3e2b634 100644 --- a/src/grid/process_point_symbolizer.cpp +++ b/src/grid/process_point_symbolizer.cpp @@ -29,7 +29,7 @@ #include #include #include - +#include #include // stl diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp index 89aae4590..ef6ddc076 100644 --- a/src/grid/process_polygon_pattern_symbolizer.cpp +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -60,7 +60,7 @@ void grid_renderer::process(polygon_pattern_symbolizer const& sym, for (unsigned i=0;inum_geometries();++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 2) { path_type path(t_,geom,prj_trans); diff --git a/src/grid/process_polygon_symbolizer.cpp b/src/grid/process_polygon_symbolizer.cpp index bb5e1aa0a..6c973a7dd 100644 --- a/src/grid/process_polygon_symbolizer.cpp +++ b/src/grid/process_polygon_symbolizer.cpp @@ -59,7 +59,7 @@ void grid_renderer::process(polygon_symbolizer const& sym, ras_ptr->reset(); for (unsigned i=0;inum_geometries();++i) { - geometry_type const& geom = feature->get_geometry(i); + geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 2) { path_type path(t_,geom,prj_trans); diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index 9c85b1344..29ce6236f 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -44,12 +44,13 @@ void grid_renderer::process(shield_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { + box2d query_extent; shield_symbolizer_helper, label_collision_detector4> helper( sym, *feature, prj_trans, width_, height_, scale_factor_, - t_, font_manager_, detector_); + t_, font_manager_, detector_, query_extent); bool placement_found = false; diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index 0f49a6862..b83b3ae38 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -32,12 +32,14 @@ void grid_renderer::process(text_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { + box2d query_extent; text_symbolizer_helper, label_collision_detector4> helper( sym, *feature, prj_trans, width_, height_, scale_factor_ * (1.0/pixmap_.get_resolution()), - t_, font_manager_, detector_); + t_, font_manager_, detector_, + query_extent); bool placement_found = false; text_renderer ren(pixmap_, font_manager_, *(font_manager_.get_stroker())); diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp new file mode 100644 index 000000000..84516a87c --- /dev/null +++ b/src/image_compositing.cpp @@ -0,0 +1,151 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +// mapnik +#include +#include + +// agg +#include "agg_rendering_buffer.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_scanline_u.h" +#include "agg_renderer_scanline.h" +#include "agg_pixfmt_rgba.h" + + +namespace mapnik +{ + + +template +void composite(T1 & im, T2 & im2, composite_mode_e mode) +{ + typedef agg::rgba8 color; + typedef agg::order_rgba order; + typedef agg::pixel32_type pixel_type; + typedef agg::comp_op_adaptor_rgba blender_type; + typedef agg::pixfmt_custom_blend_rgba pixfmt_type; + typedef agg::renderer_base renderer_type; + + agg::rendering_buffer source(im.getBytes(),im.width(),im.height(),im.width() * 4); + agg::rendering_buffer mask(im2.getBytes(),im2.width(),im2.height(),im2.width() * 4); + + agg::pixfmt_custom_blend_rgba pixf(source); + pixf.premultiply(); + agg::pixfmt_custom_blend_rgba pixf_mask(mask); + + switch(mode) + { + case clear : + pixf.comp_op(agg::comp_op_clear); + break; + case src: + pixf.comp_op(agg::comp_op_src); + break; + case dst: + pixf.comp_op(agg::comp_op_dst); + break; + case src_over: + pixf.comp_op(agg::comp_op_src_over); + break; + case dst_over: + pixf.comp_op(agg::comp_op_dst_over); + break; + case src_in: + pixf.comp_op(agg::comp_op_src_in); + break; + case dst_in: + pixf.comp_op(agg::comp_op_dst_in); + break; + case src_out: + pixf.comp_op(agg::comp_op_src_out); + break; + case dst_out: + pixf.comp_op(agg::comp_op_dst_out); + break; + case src_atop: + pixf.comp_op(agg::comp_op_src_atop); + break; + case dst_atop: + pixf.comp_op(agg::comp_op_dst_atop); + break; + case _xor: + pixf.comp_op(agg::comp_op_xor); + break; + case plus: + pixf.comp_op(agg::comp_op_plus); + break; + case minus: + pixf.comp_op(agg::comp_op_minus); + break; + case multiply: + pixf.comp_op(agg::comp_op_multiply); + break; + case screen: + pixf.comp_op(agg::comp_op_screen); + break; + case overlay: + pixf.comp_op(agg::comp_op_overlay); + break; + case darken: + pixf.comp_op(agg::comp_op_darken); + break; + case lighten: + pixf.comp_op(agg::comp_op_lighten); + break; + case color_dodge: + pixf.comp_op(agg::comp_op_color_dodge); + break; + case color_burn: + pixf.comp_op(agg::comp_op_color_burn); + break; + case hard_light: + pixf.comp_op(agg::comp_op_hard_light); + break; + case soft_light: + pixf.comp_op(agg::comp_op_soft_light); + break; + case difference: + pixf.comp_op(agg::comp_op_difference); + break; + case exclusion: + pixf.comp_op(agg::comp_op_exclusion); + break; + case contrast: + pixf.comp_op(agg::comp_op_contrast); + break; + case invert: + pixf.comp_op(agg::comp_op_invert); + break; + case invert_rgb: + pixf.comp_op(agg::comp_op_invert_rgb); + break; + } + renderer_type ren(pixf); + agg::renderer_base rb(pixf); + rb.blend_from(pixf_mask,0,0,0,255); +} + + +template void composite(mapnik::image_data_32 & im, mapnik::image_data_32 & im2, composite_mode_e mode); + +} diff --git a/src/image_util.cpp b/src/image_util.cpp index c3cee7610..cde2ba9e2 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -45,6 +45,7 @@ extern "C" #ifdef HAVE_CAIRO #include +#include #endif #include @@ -57,7 +58,6 @@ extern "C" #include // agg -//#include "agg_conv_transform.h" #include "agg_image_accessors.h" #include "agg_pixfmt_rgba.h" #include "agg_rasterizer_scanline_aa.h" @@ -158,7 +158,7 @@ void handle_png_options(std::string const& type, if (*colors < 0) throw ImageWriterException("invalid color parameter: unavailable for true color images"); - if (!mapnik::conversions::string2int(t.substr(2),*colors) || *colors < 0 || *colors > 256) + if (!mapnik::util::string2int(t.substr(2),*colors) || *colors < 0 || *colors > 256) throw ImageWriterException("invalid color parameter: " + t.substr(2)); } else if (boost::algorithm::starts_with(t, "t=")) @@ -166,14 +166,14 @@ void handle_png_options(std::string const& type, if (*colors < 0) throw ImageWriterException("invalid trans_mode parameter: unavailable for true color images"); - if (!mapnik::conversions::string2int(t.substr(2),*trans_mode) || *trans_mode < 0 || *trans_mode > 2) + if (!mapnik::util::string2int(t.substr(2),*trans_mode) || *trans_mode < 0 || *trans_mode > 2) throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2)); } else if (boost::algorithm::starts_with(t, "g=")) { if (*colors < 0) throw ImageWriterException("invalid gamma parameter: unavailable for true color images"); - if (!mapnik::conversions::string2double(t.substr(2),*gamma) || *gamma < 0) + if (!mapnik::util::string2double(t.substr(2),*gamma) || *gamma < 0) { throw ImageWriterException("invalid gamma parameter: " + t.substr(2)); } @@ -186,7 +186,7 @@ void handle_png_options(std::string const& type, #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) */ - if (!mapnik::conversions::string2int(t.substr(2),*compression) + if (!mapnik::util::string2int(t.substr(2),*compression) || *compression < Z_DEFAULT_COMPRESSION || *compression > Z_BEST_COMPRESSION) { @@ -317,7 +317,7 @@ void save_to_stream(T const& image, std::string const& val = t.substr(4); if (!val.empty()) { - if (!mapnik::conversions::string2int(val,quality) || quality < 0 || quality > 100) + if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100) { throw ImageWriterException("invalid jpeg quality: '" + val + "'"); } @@ -372,17 +372,40 @@ void save_to_cairo_file(mapnik::Map const& map, unsigned width = map.width(); unsigned height = map.height(); if (type == "pdf") + { +#if defined(CAIRO_HAS_PDF_SURFACE) surface = Cairo::PdfSurface::create(filename,width,height); +#else + throw ImageWriterException("PDFSurface not supported in the cairo backend"); +#endif + } +#if defined(CAIRO_HAS_SVG_SURFACE) else if (type == "svg") + { surface = Cairo::SvgSurface::create(filename,width,height); + } +#endif +#if defined(CAIRO_HAS_PS_SURFACE) else if (type == "ps") + { surface = Cairo::PsSurface::create(filename,width,height); + } +#endif +#if defined(CAIRO_HAS_IMAGE_SURFACE) else if (type == "ARGB32") + { surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32,width,height); + } else if (type == "RGB24") + { surface = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24,width,height); + } +#endif else + { throw ImageWriterException("unknown file type: " + type); + } + Cairo::RefPtr context = Cairo::Context::create(surface); // TODO - expose as user option diff --git a/src/json/feature_collection_parser.cpp b/src/json/feature_collection_parser.cpp index fbf9c2b19..a7f2a418a 100644 --- a/src/json/feature_collection_parser.cpp +++ b/src/json/feature_collection_parser.cpp @@ -33,29 +33,29 @@ namespace mapnik { namespace json { #if BOOST_VERSION >= 104700 -template -feature_collection_parser::feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr) - : grammar_(new feature_collection_grammar(ctx,tr)) {} + template + feature_collection_parser::feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr) + : grammar_(new feature_collection_grammar(ctx,tr)) {} -template -feature_collection_parser::~feature_collection_parser() {} + template + feature_collection_parser::~feature_collection_parser() {} #endif -template -bool feature_collection_parser::parse(iterator_type first, iterator_type last, std::vector & features) -{ + template + bool feature_collection_parser::parse(iterator_type first, iterator_type last, std::vector & features) + { #if BOOST_VERSION >= 104700 - using namespace boost::spirit; - return qi::phrase_parse(first, last, *grammar_, standard_wide::space, features); + using namespace boost::spirit; + return qi::phrase_parse(first, last, *grammar_, standard_wide::space, features); #else - std::ostringstream s; - s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; - throw std::runtime_error("mapnik::feature_collection_parser::parse() requires at least boost 1.47 while your build was compiled against boost " + s.str()); - return false; + std::ostringstream s; + s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; + throw std::runtime_error("mapnik::feature_collection_parser::parse() requires at least boost 1.47 while your build was compiled against boost " + s.str()); + return false; #endif -} + } -template class feature_collection_parser ; -template class feature_collection_parser > >; -}} + template class feature_collection_parser ; + template class feature_collection_parser > >; + }} diff --git a/src/json/geojson_generator.cpp b/src/json/geojson_generator.cpp index c25440ded..750489690 100644 --- a/src/json/geojson_generator.cpp +++ b/src/json/geojson_generator.cpp @@ -32,30 +32,30 @@ namespace mapnik { namespace json { -feature_generator::feature_generator() - : grammar_(new feature_generator_grammar()) {} - -feature_generator::~feature_generator() {} + feature_generator::feature_generator() + : grammar_(new feature_generator_grammar()) {} -bool feature_generator::generate(std::string & geojson, mapnik::Feature const& f) -{ - sink_type sink(geojson); - return karma::generate(sink, *grammar_,f); -} + feature_generator::~feature_generator() {} + + bool feature_generator::generate(std::string & geojson, mapnik::Feature const& f) + { + sink_type sink(geojson); + return karma::generate(sink, *grammar_,f); + } -geometry_generator::geometry_generator() - : grammar_(new multi_geometry_generator_grammar()) {} + geometry_generator::geometry_generator() + : grammar_(new multi_geometry_generator_grammar()) {} -geometry_generator::~geometry_generator() {} + geometry_generator::~geometry_generator() {} -bool geometry_generator::generate(std::string & geojson, mapnik::geometry_container const& g) -{ - sink_type sink(geojson); - return karma::generate(sink, *grammar_,g); -} + bool geometry_generator::generate(std::string & geojson, mapnik::geometry_container const& g) + { + sink_type sink(geojson); + return karma::generate(sink, *grammar_,g); + } -}} + }} #else @@ -65,22 +65,22 @@ bool geometry_generator::generate(std::string & geojson, mapnik::geometry_contai namespace mapnik { namespace json { -bool feature_generator::generate(std::string & geojson, mapnik::Feature const& f) -{ - std::ostringstream s; - s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; - throw std::runtime_error("feature_generator::generate() requires at least boost 1.47 while your build was compiled against boost " + s.str()); - return false; -} + bool feature_generator::generate(std::string & geojson, mapnik::Feature const& f) + { + std::ostringstream s; + s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; + throw std::runtime_error("feature_generator::generate() requires at least boost 1.47 while your build was compiled against boost " + s.str()); + return false; + } -bool geometry_generator::generate(std::string & geojson, mapnik::geometry_container const& g) -{ - std::ostringstream s; - s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; - throw std::runtime_error("geometry_generator::generate() requires at least boost 1.47 while your build was compiled against boost " + s.str()); - return false; -} + bool geometry_generator::generate(std::string & geojson, mapnik::geometry_container const& g) + { + std::ostringstream s; + s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; + throw std::runtime_error("geometry_generator::generate() requires at least boost 1.47 while your build was compiled against boost " + s.str()); + return false; + } -}} + }} #endif diff --git a/src/layer.cpp b/src/layer.cpp index e0e32d475..9d4d1cb42 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -38,8 +38,8 @@ namespace mapnik layer::layer(std::string const& name, std::string const& srs) : name_(name), srs_(srs), - minZoom_(0), - maxZoom_(std::numeric_limits::max()), + min_zoom_(0), + max_zoom_(std::numeric_limits::max()), active_(true), queryable_(false), clear_label_cache_(false), @@ -50,8 +50,8 @@ layer::layer(std::string const& name, std::string const& srs) layer::layer(const layer& rhs) : name_(rhs.name_), srs_(rhs.srs_), - minZoom_(rhs.minZoom_), - maxZoom_(rhs.maxZoom_), + min_zoom_(rhs.min_zoom_), + max_zoom_(rhs.max_zoom_), active_(rhs.active_), queryable_(rhs.queryable_), clear_label_cache_(rhs.clear_label_cache_), @@ -76,8 +76,8 @@ void layer::swap(const layer& rhs) { name_=rhs.name_; srs_ = rhs.srs_; - minZoom_=rhs.minZoom_; - maxZoom_=rhs.maxZoom_; + min_zoom_=rhs.min_zoom_; + max_zoom_=rhs.max_zoom_; active_=rhs.active_; queryable_=rhs.queryable_; clear_label_cache_ = rhs.clear_label_cache_; @@ -124,47 +124,47 @@ std::vector & layer::styles() return styles_; } -void layer::setMinZoom(double minZoom) +void layer::set_min_zoom(double min_zoom) { - minZoom_=minZoom; + min_zoom_=min_zoom; } -void layer::setMaxZoom(double maxZoom) +void layer::set_max_zoom(double max_zoom) { - maxZoom_=maxZoom; + max_zoom_=max_zoom; } -double layer::getMinZoom() const +double layer::min_zoom() const { - return minZoom_; + return min_zoom_; } -double layer::getMaxZoom() const +double layer::max_zoom() const { - return maxZoom_; + return max_zoom_; } -void layer::setActive(bool active) +void layer::set_active(bool active) { active_=active; } -bool layer::isActive() const +bool layer::active() const { return active_; } -bool layer::isVisible(double scale) const +bool layer::visible(double scale) const { - return isActive() && scale >= minZoom_ - 1e-6 && scale < maxZoom_ + 1e-6; + return active() && scale >= min_zoom_ - 1e-6 && scale < max_zoom_ + 1e-6; } -void layer::setQueryable(bool queryable) +void layer::set_queryable(bool queryable) { queryable_=queryable; } -bool layer::isQueryable() const +bool layer::queryable() const { return queryable_; } diff --git a/src/libxml2_loader.cpp b/src/libxml2_loader.cpp index af9ff4de9..d95e145ca 100644 --- a/src/libxml2_loader.cpp +++ b/src/libxml2_loader.cpp @@ -22,26 +22,27 @@ #ifdef HAVE_LIBXML2 -#include - +// mapnik +#include +#include #include +// boost #include -#include #include #include +// libxml #include #include #include #include +// stl #include -using boost::property_tree::ptree; using namespace std; -//#define DEFAULT_OPTIONS (XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA) #define DEFAULT_OPTIONS (XML_PARSE_NOERROR | XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA) namespace mapnik @@ -50,14 +51,14 @@ class libxml2_loader : boost::noncopyable { public: libxml2_loader(const char *encoding = NULL, int options = DEFAULT_OPTIONS, const char *url = NULL) : - ctx_( 0 ), - encoding_( encoding ), - options_( options ), - url_( url ) + ctx_(0), + encoding_(encoding), + options_(options), + url_(url) { LIBXML_TEST_VERSION; ctx_ = xmlNewParserCtxt(); - if ( ! ctx_ ) + if (!ctx_) { throw std::runtime_error("Failed to create parser context."); } @@ -71,19 +72,19 @@ public: } } - void load( std::string const& filename, ptree & pt ) + void load(std::string const& filename, xml_node &node) { boost::filesystem::path path(filename); - if ( !boost::filesystem::exists( path ) ) { - throw config_error(string("Could not load map file '") + - filename + "': File does not exist"); + if (!boost::filesystem::exists(path)) + { + throw config_error(string("Could not load map file: File does not exist"), 0, filename); } xmlDocPtr doc = xmlCtxtReadFile(ctx_, filename.c_str(), encoding_, options_); - if ( !doc ) + if (!doc) { - xmlError * error = xmlCtxtGetLastError( ctx_ ); + xmlError * error = xmlCtxtGetLastError(ctx_); if (error) { std::ostringstream os; @@ -91,15 +92,7 @@ public: os << ": " << std::endl << error->message; // remove CR std::string msg = os.str().substr(0, os.str().size() - 1); - config_error ex( msg ); - - os.str(""); - os << "(encountered in file '" << error->file << "' at line " - << error->line << ")"; - - ex.append_context( os.str() ); - - throw ex; + throw config_error(msg, error->line, error->file); } } @@ -110,21 +103,21 @@ public: << std::endl; } */ - load(doc, pt); + load(doc, node); } - void load( const int fd, ptree & pt ) + void load(const int fd, xml_node &node) { xmlDocPtr doc = xmlCtxtReadFd(ctx_, fd, url_, encoding_, options_); - load(doc, pt); + load(doc, node); } - void load_string( std::string const& buffer, ptree & pt, std::string const & base_path ) + void load_string(std::string const& buffer, xml_node &node, std::string const & base_path) { if (!base_path.empty()) { boost::filesystem::path path(base_path); - if ( ! boost::filesystem::exists( path ) ) { + if (!boost::filesystem::exists(path)) { throw config_error(string("Could not locate base_path '") + base_path + "': file or directory does not exist"); } @@ -132,12 +125,12 @@ public: xmlDocPtr doc = xmlCtxtReadMemory(ctx_, buffer.data(), buffer.length(), base_path.c_str(), encoding_, options_); - load(doc, pt); + load(doc, node); } - void load( const xmlDocPtr doc, ptree & pt ) + void load(const xmlDocPtr doc, xml_node &node) { - if ( !doc ) + if (!doc) { xmlError * error = xmlCtxtGetLastError( ctx_ ); std::ostringstream os; @@ -146,10 +139,10 @@ public: { os << ": " << std::endl << error->message; } - throw config_error(os.str()); + throw config_error(os.str(), error->line, error->file); } - int iXIncludeReturn = xmlXIncludeProcessFlags( doc, options_ ); + int iXIncludeReturn = xmlXIncludeProcessFlags(doc, options_); if (iXIncludeReturn < 0) { @@ -157,64 +150,48 @@ public: throw config_error("XML XInclude error. One or more files failed to load."); } - xmlNode * root = xmlDocGetRootElement( doc ); - if ( ! root ) { + xmlNode * root = xmlDocGetRootElement(doc); + if (!root) { xmlFreeDoc(doc); throw config_error("XML document is empty."); } - populate_tree( root, pt ); + populate_tree(root, node); xmlFreeDoc(doc); } private: - void append_attributes( xmlAttr * attributes, ptree & pt) + void append_attributes(xmlAttr *attributes, xml_node &node) { - if (attributes) + for (; attributes; attributes = attributes->next ) { - ptree::iterator it = pt.push_back( ptree::value_type( "", ptree() )); - ptree & attr_list = it->second; - xmlAttr * cur_attr = attributes; - for (; cur_attr; cur_attr = cur_attr->next ) - { - ptree::iterator it = attr_list.push_back( - ptree::value_type( (char*)cur_attr->name, ptree() )); - it->second.put_value( (char*) cur_attr->children->content ); - } + node.add_attribute((char *)attributes->name, (char *)attributes->children->content); } } - void populate_tree( xmlNode * node, ptree & pt ) + void populate_tree(xmlNode *cur_node, xml_node &node) { - xmlNode * cur_node = node; - for (; cur_node; cur_node = cur_node->next ) { switch (cur_node->type) { case XML_ELEMENT_NODE: { - ptree::iterator it = pt.push_back( ptree::value_type( - (char*)cur_node->name, ptree() )); - append_attributes( cur_node->properties, it->second); - populate_tree( cur_node->children, it->second ); + + xml_node &new_node = node.add_child((char *)cur_node->name, cur_node->line, false); + append_attributes(cur_node->properties, new_node); + populate_tree(cur_node->children, new_node); } break; case XML_TEXT_NODE: { std::string trimmed = boost::algorithm::trim_copy(std::string((char*)cur_node->content)); - if (trimmed.empty()) break; - ptree::iterator it = pt.push_back(ptree::value_type("", ptree())); - it->second.put_value(trimmed); + if (trimmed.empty()) break; //Don't add empty text nodes + node.add_child(trimmed, cur_node->line, true); } break; case XML_COMMENT_NODE: - { - ptree::iterator it = pt.push_back( - ptree::value_type( "", ptree() )); - it->second.put_value( (char*) cur_node->content ); - } - break; + break; default: break; @@ -228,15 +205,15 @@ private: const char *url_; }; -void read_xml2( std::string const & filename, boost::property_tree::ptree & pt) +void read_xml(std::string const & filename, xml_node &node) { libxml2_loader loader; - loader.load( filename, pt ); + loader.load(filename, node); } -void read_xml2_string( std::string const & str, boost::property_tree::ptree & pt, std::string const & base_path) +void read_xml_string(std::string const & str, xml_node &node, std::string const & base_path) { libxml2_loader loader; - loader.load_string( str, pt, base_path ); + loader.load_string(str, node, base_path); } } // end of namespace mapnik diff --git a/src/load_map.cpp b/src/load_map.cpp index eea4353a8..68239b48a 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -22,6 +22,7 @@ // mapnik #include +#include #include #include #include @@ -33,11 +34,7 @@ #include #include #include - -#include -#ifdef HAVE_LIBXML2 -#include -#endif +#include #include #include @@ -51,6 +48,8 @@ #include #include #include +#include +#include // boost #include @@ -68,13 +67,12 @@ // stl #include +#include using boost::lexical_cast; using boost::bad_lexical_cast; using boost::tokenizer; -using boost::property_tree::ptree; -using std::cerr; using std::endl; namespace mapnik @@ -83,51 +81,48 @@ using boost::optional; class map_parser : boost::noncopyable { public: - map_parser( bool strict, std::string const& filename = "" ) : - strict_( strict ), - filename_( filename ), + map_parser(bool strict, std::string const& filename = "") : + strict_(strict), + filename_(filename), relative_to_xml_(true), - font_manager_(font_engine_), - color_grammar_(), - // TODO - use xml encoding? - tr_("utf8"), - expr_grammar_(tr_) - {} + font_manager_(font_engine_) + {} - void parse_map(Map & map, ptree const & sty, std::string const& base_path=""); + void parse_map(Map & map, xml_node const& sty, std::string const& base_path); private: - void parse_map_include( Map & map, ptree const & include); - void parse_style(Map & map, ptree const & sty); - void parse_layer(Map & map, ptree const & lay); - void parse_metawriter(Map & map, ptree const & lay); - void parse_metawriter_in_symbolizer(symbolizer_base &sym, ptree const &pt); + void parse_map_include(Map & map, xml_node const& include); + void parse_style(Map & map, xml_node const& sty); + void parse_layer(Map & map, xml_node const& lay); + void parse_metawriter(Map & map, xml_node const& lay); + void parse_metawriter_in_symbolizer(symbolizer_base &sym, xml_node const& pt); - void parse_fontset(Map & map, ptree const & fset); - void parse_font(font_set & fset, ptree const & f); + void parse_fontset(Map & map, xml_node const & fset); + void parse_font(font_set & fset, xml_node const& f); - void parse_rule(feature_type_style & style, ptree const & r); + void parse_rule(feature_type_style & style, xml_node const & r); - void parse_point_symbolizer(rule & rule, ptree const & sym); - void parse_line_pattern_symbolizer(rule & rule, ptree const & sym); - void parse_polygon_pattern_symbolizer(rule & rule, ptree const & sym); - void parse_text_symbolizer(rule & rule, ptree const & sym); - void parse_shield_symbolizer(rule & rule, ptree const & sym); - void parse_line_symbolizer(rule & rule, ptree const & sym); - void parse_polygon_symbolizer(rule & rule, ptree const & sym); - void parse_building_symbolizer(rule & rule, ptree const & sym ); - void parse_raster_symbolizer(rule & rule, ptree const & sym ); - void parse_markers_symbolizer(rule & rule, ptree const & sym ); + void parse_point_symbolizer(rule & rule, xml_node const& sym); + void parse_line_pattern_symbolizer(rule & rule, xml_node const& sym); + void parse_polygon_pattern_symbolizer(rule & rule, xml_node const& sym); + void parse_text_symbolizer(rule & rule, xml_node const& sym); + void parse_shield_symbolizer(rule & rule, xml_node const& sym); + void parse_line_symbolizer(rule & rule, xml_node const& sym); + void parse_polygon_symbolizer(rule & rule, xml_node const& sym); + void parse_building_symbolizer(rule & rule, xml_node const& sym); + void parse_raster_symbolizer(rule & rule, xml_node const& sym); + void parse_markers_symbolizer(rule & rule, xml_node const& sym); - void parse_raster_colorizer(raster_colorizer_ptr const& rc, ptree const& node ); - void parse_stroke(stroke & strk, ptree const & sym); - expression_ptr parse_expr(std::string const& expr); + void parse_raster_colorizer(raster_colorizer_ptr const& rc, xml_node const& node); + void parse_stroke(stroke & strk, xml_node const & sym); - void ensure_font_face( std::string const& face_name ); + void ensure_font_face(std::string const& face_name); + void find_unused_nodes(xml_node const& root); + void find_unused_nodes_recursive(xml_node const& node, std::stringstream &error_text); - std::string ensure_relative_to_xml( boost::optional opt_path ); - void ensure_attrs( ptree const& sym, std::string name, std::string attrs); + + std::string ensure_relative_to_xml(boost::optional opt_path); boost::optional get_opt_color_attr(boost::property_tree::ptree const& node, - std::string const& name); + std::string const& name); bool strict_; std::string filename_; @@ -137,156 +132,57 @@ private: face_manager font_manager_; std::map file_sources_; std::map fontsets_; - mapnik::css_color_grammar color_grammar_; - mapnik::transcoder tr_; - mapnik::expression_grammar expr_grammar_; - }; -void remove_empty_text_nodes(ptree &pt) -{ - ptree::iterator itr = pt.begin(); - ptree::iterator end = pt.end(); - while (itr!=end) - { - if (itr->first == "") { - std::string trimmed = boost::algorithm::trim_copy(itr->second.data()); - if (trimmed.empty()) { - itr = pt.erase(itr); - } else { - itr++; - } - } else { - remove_empty_text_nodes(itr->second); - itr++; - } - } -} - -//#include +#include void load_map(Map & map, std::string const& filename, bool strict) { - ptree pt; -#ifdef HAVE_LIBXML2 - read_xml2(filename, pt); -#else - try - { - read_xml(filename, pt, boost::property_tree::xml_parser::no_concat_text|boost::property_tree::xml_parser::no_comments); - remove_empty_text_nodes(pt); - } - catch (const boost::property_tree::xml_parser_error & ex) - { - throw config_error( ex.what() ); - } + // TODO - use xml encoding? + xml_tree tree("utf8"); + tree.set_filename(filename); + read_xml(filename, tree.root()); + map_parser parser(strict, filename); + parser.parse_map(map, tree.root(), ""); +#ifdef MAPNIK_DEBUG + dump_xml(tree.root()); #endif - map_parser parser( strict, filename); - parser.parse_map(map, pt); } void load_map_string(Map & map, std::string const& str, bool strict, std::string base_path) { - if (str.empty()) - { - throw config_error( "Cannot load map, XML string is empty" ) ; - } - - ptree pt; -#ifdef HAVE_LIBXML2 + // TODO - use xml encoding? + xml_tree tree("utf8"); if (!base_path.empty()) - read_xml2_string(str, pt, base_path); // accept base_path passed into function + read_xml_string(str, tree.root(), base_path); // accept base_path passed into function else - read_xml2_string(str, pt, map.base_path()); // default to map base_path -#else - try - { - std::istringstream s(str); - // TODO - support base_path? - read_xml(s, pt, boost::property_tree::xml_parser::no_concat_text|boost::property_tree::xml_parser::no_comments); - remove_empty_text_nodes(pt); - } - catch (const boost::property_tree::xml_parser_error & ex) - { - throw config_error( ex.what() ) ; - } -#endif - - map_parser parser( strict, base_path); - parser.parse_map(map, pt, base_path); + read_xml_string(str, tree.root(), map.base_path()); // default to map base_path + map_parser parser(strict, base_path); + parser.parse_map(map, tree.root(), base_path); } -expression_ptr map_parser::parse_expr(std::string const& str) -{ - expression_ptr expr(boost::make_shared(true)); - if (!expression_factory::parse_from_string(expr,str,expr_grammar_)) - { - throw mapnik::config_error( "Failed to parse expression: '" + str + "'" ); - } - return expr; - -} - -boost::optional map_parser::get_opt_color_attr(boost::property_tree::ptree const& node, - std::string const& name) -{ - - boost::optional str = node.get_optional( std::string(".") + name); - boost::optional result; - if (str && !str->empty()) - { - mapnik::color c; - if (mapnik::color_factory::parse_from_string(c,*str,color_grammar_)) - { - result.reset(c); - } - else - { - throw config_error(std::string("Failed to parse attribute ") + - name + "'. Expected color" + - " but got '" + *str + "'"); - } - } - return result; -} - -void map_parser::parse_map( Map & map, ptree const & pt, std::string const& base_path ) +void map_parser::parse_map(Map & map, xml_node const& pt, std::string const& base_path) { try { - ptree const & map_node = pt.get_child("Map"); - - std::ostringstream s(""); - s << "background-color," - << "background-image," - << "srs," - << "buffer-size," - << "paths-from-xml," - << "minimum-version," - << "font-directory," - << "maximum-extent," - << "base"; - ensure_attrs(map_node, "Map", s.str()); - + xml_node const& map_node = pt.get_child("Map"); try { - parameters extra_attr; - // Check if relative paths should be interpreted as relative to/from XML location // Default is true, and map_parser::ensure_relative_to_xml will be called to modify path - optional paths_from_xml = get_opt_attr(map_node, "paths-from-xml"); + optional paths_from_xml = map_node.get_opt_attr("paths-from-xml"); if (paths_from_xml) { relative_to_xml_ = *paths_from_xml; } - optional base_path_from_xml = get_opt_attr(map_node, "base"); + optional base_path_from_xml = map_node.get_opt_attr("base"); if (!base_path.empty()) { - map.set_base_path( base_path ); + map.set_base_path(base_path); } else if (base_path_from_xml) { - map.set_base_path( *base_path_from_xml ); + map.set_base_path(*base_path_from_xml); } else { @@ -298,30 +194,30 @@ void map_parser::parse_map( Map & map, ptree const & pt, std::string const& base std::string base = xml_path.branch_path().string(); #endif - map.set_base_path( base ); + map.set_base_path(base); } - optional bgcolor = get_opt_color_attr(map_node, "background-color"); + optional bgcolor = map_node.get_opt_attr("background-color"); if (bgcolor) { - map.set_background( * bgcolor ); + map.set_background(*bgcolor); } - optional image_filename = get_opt_attr(map_node, "background-image"); + optional image_filename = map_node.get_opt_attr("background-image"); if (image_filename) { map.set_background_image(ensure_relative_to_xml(image_filename)); } - map.set_srs( get_attr(map_node, "srs", map.srs() )); + map.set_srs(map_node.get_attr("srs", map.srs())); - optional buffer_size = get_opt_attr(map_node,"buffer-size"); + optional buffer_size = map_node.get_opt_attr("buffer-size"); if (buffer_size) { map.set_buffer_size(*buffer_size); } - optional maximum_extent = get_opt_attr(map_node,"maximum-extent"); + optional maximum_extent = map_node.get_opt_attr("maximum-extent"); if (maximum_extent) { box2d box; @@ -332,33 +228,37 @@ void map_parser::parse_map( Map & map, ptree const & pt, std::string const& base else { std::ostringstream s_err; - s << "failed to parse 'maximum-extent'"; - if ( strict_ ) + s_err << "failed to parse 'maximum-extent'"; + if (strict_) throw config_error(s_err.str()); else - std::clog << "### WARNING: " << s.str() << std::endl; + std::clog << "### WARNING: " << s_err.str() << std::endl; } } - optional font_directory = get_opt_attr(map_node,"font-directory"); + optional font_directory = map_node.get_opt_attr("font-directory"); if (font_directory) { - extra_attr["font-directory"] = *font_directory; - freetype_engine::register_fonts( ensure_relative_to_xml(font_directory), false); + if (!freetype_engine::register_fonts(ensure_relative_to_xml(font_directory), false)) + { + if (strict_) + { + throw config_error(std::string("Failed to load fonts from: ") + *font_directory); + } + } } - optional min_version_string = get_opt_attr(map_node, "minimum-version"); + optional min_version_string = map_node.get_opt_attr("minimum-version"); if (min_version_string) { - extra_attr["minimum-version"] = *min_version_string; boost::char_separator sep("."); - boost::tokenizer > tokens(*min_version_string,sep); + boost::tokenizer > tokens(*min_version_string, sep); unsigned i = 0; bool success = false; int n[3]; - for (boost::tokenizer >::iterator beg=tokens.begin(); - beg!=tokens.end();++beg) + for (boost::tokenizer >::iterator beg = tokens.begin(); + beg != tokens.end(); ++beg) { try { @@ -387,234 +287,180 @@ void map_parser::parse_map( Map & map, ptree const & pt, std::string const& base } } - - map.set_extra_attributes(extra_attr); } catch (const config_error & ex) { - ex.append_context("(in node Map)"); + ex.append_context(map_node); throw; } - parse_map_include( map, map_node ); + parse_map_include(map, map_node); } - catch (const boost::property_tree::ptree_bad_path &) + catch (node_not_found const&) { throw config_error("Not a map file. Node 'Map' not found."); } + find_unused_nodes(pt); } -void map_parser::parse_map_include( Map & map, ptree const & include ) +void map_parser::parse_map_include(Map & map, xml_node const& include) { - ptree::const_iterator itr = include.begin(); - ptree::const_iterator end = include.end(); - - for (; itr != end; ++itr) + try { - ptree::value_type const& v = *itr; + xml_node::const_iterator itr = include.begin(); + xml_node::const_iterator end = include.end(); - if (v.first == "Include") + for (; itr != end; ++itr) { - parse_map_include( map, v.second ); - } - else if (v.first == "Style") - { - parse_style( map, v.second ); - } - else if (v.first == "Layer") - { - parse_layer(map, v.second ); - } - else if (v.first == "FontSet") - { - parse_fontset(map, v.second); - } - else if (v.first == "MetaWriter") - { - parse_metawriter(map, v.second); - } - else if (v.first == "FileSource") - { - std::string name = get_attr( v.second, "name"); - std::string value = get_value( v.second, ""); - file_sources_[name] = value; - } - else if (v.first == "Datasource") - { - std::string name = get_attr(v.second, "name", std::string("Unnamed")); - parameters params; - ptree::const_iterator paramIter = v.second.begin(); - ptree::const_iterator endParam = v.second.end(); - for (; paramIter != endParam; ++paramIter) + if (itr->is_text()) continue; + if (itr->is("Include")) { - ptree const& param = paramIter->second; - - if (paramIter->first == "Parameter") - { - std::string name = get_attr(param, "name"); - std::string value = get_value( param, - "datasource parameter"); - params[name] = value; - } - else if( paramIter->first != "" && - paramIter->first != "") - { - throw config_error(std::string("Unknown child node in ") + - "'Datasource'. Expected 'Parameter' but got '" + - paramIter->first + "'"); - } + parse_map_include(map, *itr); } - datasource_templates_[name] = params; - } - else if (v.first == "Parameters") - { - std::string name = get_attr(v.second, "name", std::string("Unnamed")); - parameters & params = map.get_extra_parameters(); - ptree::const_iterator paramIter = v.second.begin(); - ptree::const_iterator endParam = v.second.end(); - for (; paramIter != endParam; ++paramIter) + else if (itr->is("Style")) { - ptree const& param = paramIter->second; - - if (paramIter->first == "Parameter") + parse_style(map, *itr); + } + else if (itr->is("Layer")) + { + parse_layer(map, *itr); + } + else if (itr->is("FontSet")) + { + parse_fontset(map, *itr); + } + else if (itr->is("MetaWriter")) + { + parse_metawriter(map, *itr); + } + else if (itr->is("FileSource")) + { + std::string name = itr->get_attr("name"); + std::string value = itr->get_text(); + file_sources_[name] = value; + } + else if (itr->is("Datasource")) + { + std::string name = itr->get_attr("name", std::string("Unnamed")); + parameters params; + xml_node::const_iterator paramIter = itr->begin(); + xml_node::const_iterator endParam = itr->end(); + for (; paramIter != endParam; ++paramIter) { - std::string name = get_attr(param, "name"); - bool is_string = true; - boost::optional type = get_opt_attr(param, "type"); - if (type) + if (paramIter->is("Parameter")) { - if (*type == "int") - { - is_string = false; - int value = get_value( param,"parameter"); - params[name] = value; - } - else if (*type == "float") - { - is_string = false; - double value = get_value( param,"parameter"); - params[name] = value; - } - } - - if (is_string) - { - std::string value = get_value( param, - "parameter"); + std::string name = paramIter->get_attr("name"); + std::string value = paramIter->get_text(); params[name] = value; } } - else if( paramIter->first != "" && - paramIter->first != "" ) + datasource_templates_[name] = params; + } + else if (itr->is("Parameters")) + { + std::string name = itr->get_attr("name", std::string("Unnamed")); + parameters & params = map.get_extra_parameters(); + xml_node::const_iterator paramIter = itr->begin(); + xml_node::const_iterator endParam = itr->end(); + for (; paramIter != endParam; ++paramIter) { - throw config_error(std::string("Unknown child node in ") + - "'Parameters'. Expected 'Parameter' but got '" + - paramIter->first + "'"); + if (paramIter->is("Parameter")) + { + std::string name = paramIter->get_attr("name"); + bool is_string = true; + boost::optional type = paramIter->get_opt_attr("type"); + if (type) + { + if (*type == "int") + { + is_string = false; + int value = paramIter->get_value(); + params[name] = value; + } + else if (*type == "float") + { + is_string = false; + double value = paramIter->get_value(); + params[name] = value; + } + } + + if (is_string) + { + std::string value = paramIter->get_text(); + params[name] = value; + } + } } } } - else if (v.first != "" && - v.first != "") - { - throw config_error(std::string("Unknown child node in 'Map': '") + - v.first + "'"); - } + } catch (const config_error & ex) { + ex.append_context(include); + throw; } - map.init_metawriters(); } -void map_parser::parse_style( Map & map, ptree const & sty ) +void map_parser::parse_style(Map & map, xml_node const& sty) { - std::ostringstream s(""); - s << "name," - << "filter-mode"; - ensure_attrs(sty, "Style", s.str()); - std::string name(""); try { - name = get_attr(sty, "name"); + name = sty.get_attr("name"); feature_type_style style; - filter_mode_e filter_mode = get_attr(sty, "filter-mode", FILTER_ALL); + filter_mode_e filter_mode = sty.get_attr("filter-mode", FILTER_ALL); style.set_filter_mode(filter_mode); - ptree::const_iterator ruleIter = sty.begin(); - ptree::const_iterator endRule = sty.end(); + xml_node::const_iterator ruleIter = sty.begin(); + xml_node::const_iterator endRule = sty.end(); for (; ruleIter!=endRule; ++ruleIter) { - ptree::value_type const& rule_tag = *ruleIter; - if (rule_tag.first == "Rule") + if (ruleIter->is("Rule")) { - parse_rule( style, rule_tag.second ); - } - else if (rule_tag.first != "" && - rule_tag.first != "" ) - { - throw config_error(std::string("Unknown child node in 'Style'. ") + - "Expected 'Rule' but got '" + rule_tag.first + "'"); + parse_rule(style, *ruleIter); } } map.insert_style(name, style); - } catch (const config_error & ex) { - if ( ! name.empty() ) { - ex.append_context(std::string("in style '") + name + "'"); - } - ex.append_context(std::string("in map '") + filename_ + "'"); + ex.append_context(std::string("in style '") + name + "'", sty); throw; } } -void map_parser::parse_metawriter(Map & map, ptree const & pt) +void map_parser::parse_metawriter(Map & map, xml_node const& pt) { - ensure_attrs(pt, "MetaWriter", "name,type,file,default-output,output-empty,pixel-coordinates"); std::string name(""); metawriter_ptr writer; try { - name = get_attr(pt, "name"); + name = pt.get_attr("name"); writer = metawriter_create(pt); map.insert_metawriter(name, writer); - } catch (const config_error & ex) { - if (!name.empty()) { - ex.append_context(std::string("in meta writer '") + name + "'"); - } - ex.append_context(std::string("in map '") + filename_ + "'"); - throw; + ex.append_context(std::string("in meta writer '") + name + "'", pt); } } -void map_parser::parse_fontset( Map & map, ptree const & fset ) +void map_parser::parse_fontset(Map & map, xml_node const& fset) { - ensure_attrs(fset, "FontSet", "name,Font"); std::string name(""); try { - name = get_attr(fset, "name"); + name = fset.get_attr("name"); font_set fontset(name); - ptree::const_iterator itr = fset.begin(); - ptree::const_iterator end = fset.end(); + xml_node::const_iterator itr = fset.begin(); + xml_node::const_iterator end = fset.end(); for (; itr != end; ++itr) { - ptree::value_type const& font_tag = *itr; - - if (font_tag.first == "Font") + if (itr->is("Font")) { - parse_font(fontset, font_tag.second); - } - else if (font_tag.first != "" && - font_tag.first != "" ) - { - throw config_error(std::string("Unknown child node in 'FontSet'. ") + - "Expected 'Font' but got '" + font_tag.first + "'"); + parse_font(fontset, *itr); } } @@ -624,22 +470,17 @@ void map_parser::parse_fontset( Map & map, ptree const & fset ) // when it's parsed fontsets_.insert(pair(name, fontset)); } catch (const config_error & ex) { - if ( ! name.empty() ) { - ex.append_context(std::string("in FontSet '") + name + "'"); - } - ex.append_context(std::string("in map '") + filename_ + "'"); + ex.append_context(std::string("in FontSet '") + name + "'", fset); throw; } } -void map_parser::parse_font(font_set & fset, ptree const & f) +void map_parser::parse_font(font_set &fset, xml_node const& f) { - ensure_attrs(f, "Font", "face-name"); - - optional face_name = get_opt_attr(f, "face-name"); + optional face_name = f.get_opt_attr("face-name"); if (face_name) { - if ( strict_ ) + if (strict_) { ensure_font_face(*face_name); } @@ -647,89 +488,77 @@ void map_parser::parse_font(font_set & fset, ptree const & f) } else { - throw config_error(std::string("Must have 'face-name' set")); + throw config_error("Must have 'face-name' set", f); } } -void map_parser::parse_layer( Map & map, ptree const & lay ) +void map_parser::parse_layer(Map & map, xml_node const& lay) { std::string name; - std::ostringstream s(""); - s << "name," - << "srs," - << "status," - << "minzoom," - << "maxzoom," - << "queryable," - << "clear-label-cache," - << "cache-features," - << "group-by"; - ensure_attrs(lay, "Layer", s.str()); try { - name = get_attr(lay, "name", std::string("Unnamed")); + name = lay.get_attr("name", std::string("Unnamed")); // XXX if no projection is given inherit from map? [DS] - std::string srs = get_attr(lay, "srs", map.srs()); + std::string srs = lay.get_attr("srs", map.srs()); layer lyr(name, srs); - optional status = get_opt_attr(lay, "status"); + optional status = lay.get_opt_attr("status"); if (status) { - lyr.setActive( * status ); + lyr.set_active(* status); } - optional minZoom = get_opt_attr(lay, "minzoom"); - if (minZoom) + optional min_zoom = lay.get_opt_attr("minzoom"); + if (min_zoom) { - lyr.setMinZoom( * minZoom ); + lyr.set_min_zoom(* min_zoom); } - optional maxZoom = get_opt_attr(lay, "maxzoom"); - if (maxZoom) + + optional max_zoom = lay.get_opt_attr("maxzoom"); + if (max_zoom) { - lyr.setMaxZoom( * maxZoom ); + lyr.set_max_zoom(* max_zoom); } - optional queryable = get_opt_attr(lay, "queryable"); + optional queryable = lay.get_opt_attr("queryable"); if (queryable) { - lyr.setQueryable( * queryable ); + lyr.set_queryable(* queryable); } optional clear_cache = - get_opt_attr(lay, "clear-label-cache"); + lay.get_opt_attr("clear-label-cache"); if (clear_cache) { - lyr.set_clear_label_cache( * clear_cache ); + lyr.set_clear_label_cache(* clear_cache); } optional cache_features = - get_opt_attr(lay, "cache-features"); + lay.get_opt_attr("cache-features"); if (cache_features) { - lyr.set_cache_features( * cache_features ); + lyr.set_cache_features(* cache_features); } optional group_by = - get_opt_attr(lay, "group-by"); + lay.get_opt_attr("group-by"); if (group_by) { - lyr.set_group_by( * group_by ); + lyr.set_group_by(* group_by); } - ptree::const_iterator itr2 = lay.begin(); - ptree::const_iterator end2 = lay.end(); + xml_node::const_iterator child = lay.begin(); + xml_node::const_iterator end = lay.end(); - for(; itr2 != end2; ++itr2) + for(; child != end; ++child) { - ptree::value_type const& child = *itr2; - if (child.first == "StyleName") + if (child->is("StyleName")) { - ensure_attrs(child.second, "StyleName", "none"); - std::string style_name = get_value(child.second, "style name"); + std::string style_name = child->get_text(); if (style_name.empty()) { std::ostringstream ss; @@ -744,39 +573,27 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) lyr.add_style(style_name); } } - else if (child.first == "Datasource") + else if (child->is("Datasource")) { - ensure_attrs(child.second, "Datasource", "base"); parameters params; - optional base = get_opt_attr( child.second, "base" ); - if( base ) + optional base = child->get_opt_attr("base"); + if(base) { std::map::const_iterator base_itr = datasource_templates_.find(*base); if (base_itr!=datasource_templates_.end()) params = base_itr->second; } - ptree::const_iterator paramIter = child.second.begin(); - ptree::const_iterator endParam = child.second.end(); + xml_node::const_iterator paramIter = child->begin(); + xml_node::const_iterator endParam = child->end(); for (; paramIter != endParam; ++paramIter) { - ptree const& param = paramIter->second; - - if (paramIter->first == "Parameter") + if (paramIter->is("Parameter")) { - ensure_attrs(param, "Parameter", "name"); - std::string name = get_attr(param, "name"); - std::string value = get_value( param, - "datasource parameter"); + std::string name = paramIter->get_attr("name"); + std::string value = paramIter->get_text(); params[name] = value; } - else if( paramIter->first != "" && - paramIter->first != "" ) - { - throw config_error(std::string("Unknown child node in ") + - "'Datasource'. Expected 'Parameter' but got '" + - paramIter->first + "'"); - } } boost::optional base_param = params.get("base"); @@ -798,9 +615,9 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) lyr.set_datasource(ds); } - catch (const std::exception & ex ) + catch (const std::exception & ex) { - throw config_error( ex.what() ); + throw config_error(ex.what()); } catch (...) @@ -808,174 +625,156 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) throw config_error("Unknown exception occured attempting to create datasoure for layer '" + lyr.name() + "'"); } } - else if (child.first != "" && - child.first != "") - { - throw config_error(std::string("Unknown child node in 'Layer'. ") + - "Expected 'StyleName' or 'Datasource' but got '" + - child.first + "'"); - } } - map.addLayer(lyr); - } catch (const config_error & ex) { - if ( ! name.empty() ) + if (!name.empty()) { - ex.append_context(std::string("(encountered during parsing of layer '") + name + "' in map '" + filename_ + "')"); + ex.append_context(std::string(" encountered during parsing of layer '") + name + "'", lay); } throw; } } -void map_parser::parse_rule( feature_type_style & style, ptree const & r ) +void map_parser::parse_rule(feature_type_style & style, xml_node const& r) { - ensure_attrs(r, "Rule", "name"); std::string name; try { - name = get_attr( r, "name", std::string()); + name = r.get_attr("name", std::string()); rule rule(name); - optional filter_expr = - get_opt_child( r, "Filter"); - if (filter_expr) + xml_node const* child = r.get_opt_child("Filter"); + if (child) { - rule.set_filter(parse_expr(*filter_expr)); + rule.set_filter(child->get_value()); } - if (has_child(r, "ElseFilter")) + if (r.has_child("ElseFilter")) { rule.set_else(true); } - if (has_child(r, "AlsoFilter")) + if (r.has_child("AlsoFilter")) { rule.set_also(true); } - optional min_scale = - get_opt_child(r, "MinScaleDenominator"); - if (min_scale) + child = r.get_opt_child("MinScaleDenominator"); + if (child) { - rule.set_min_scale(*min_scale); + rule.set_min_scale(child->get_value()); } - optional max_scale = - get_opt_child(r, "MaxScaleDenominator"); - if (max_scale) + child = r.get_opt_child("MaxScaleDenominator"); + if (child) { - rule.set_max_scale(*max_scale); + rule.set_max_scale(child->get_value()); } - ptree::const_iterator symIter = r.begin(); - ptree::const_iterator endSym = r.end(); + xml_node::const_iterator symIter = r.begin(); + xml_node::const_iterator endSym = r.end(); - for( ;symIter != endSym; ++symIter) + for(;symIter != endSym; ++symIter) { - ptree::value_type const& sym = *symIter; - if ( sym.first == "PointSymbolizer") + if (symIter->is("PointSymbolizer")) { - parse_point_symbolizer( rule, sym.second ); + parse_point_symbolizer(rule, *symIter); } - else if ( sym.first == "LinePatternSymbolizer") + else if (symIter->is("LinePatternSymbolizer")) { - parse_line_pattern_symbolizer( rule, sym.second ); + parse_line_pattern_symbolizer(rule, *symIter); } - else if ( sym.first == "PolygonPatternSymbolizer") + else if (symIter->is("PolygonPatternSymbolizer")) { - parse_polygon_pattern_symbolizer( rule, sym.second ); + parse_polygon_pattern_symbolizer(rule, *symIter); } - else if ( sym.first == "TextSymbolizer") + else if (symIter->is("TextSymbolizer")) { - parse_text_symbolizer( rule, sym.second ); + parse_text_symbolizer(rule, *symIter); } - else if ( sym.first == "ShieldSymbolizer") + else if (symIter->is("ShieldSymbolizer")) { - parse_shield_symbolizer( rule, sym.second ); + parse_shield_symbolizer(rule, *symIter); } - else if ( sym.first == "LineSymbolizer") + else if (symIter->is("LineSymbolizer")) { - parse_line_symbolizer( rule, sym.second ); + parse_line_symbolizer(rule, *symIter); } - else if ( sym.first == "PolygonSymbolizer") + else if (symIter->is("PolygonSymbolizer")) { - parse_polygon_symbolizer( rule, sym.second ); + parse_polygon_symbolizer(rule, *symIter); } - else if ( sym.first == "BuildingSymbolizer") + else if (symIter->is("BuildingSymbolizer")) { - parse_building_symbolizer( rule, sym.second ); + parse_building_symbolizer(rule, *symIter); } - else if ( sym.first == "RasterSymbolizer") + else if (symIter->is("RasterSymbolizer")) { - parse_raster_symbolizer( rule, sym.second ); + parse_raster_symbolizer(rule, *symIter); } - else if ( sym.first == "MarkersSymbolizer") + else if (symIter->is("MarkersSymbolizer")) { - parse_markers_symbolizer(rule, sym.second); - } - - else if ( sym.first != "MinScaleDenominator" && - sym.first != "MaxScaleDenominator" && - sym.first != "Filter" && - sym.first != "ElseFilter" && - sym.first != "AlsoFilter" && - sym.first != "" && - sym.first != "" ) - { - throw config_error(std::string("Unknown symbolizer '") + - sym.first + "'"); + parse_markers_symbolizer(rule, *symIter); } } - style.add_rule(rule); } catch (const config_error & ex) { - if ( ! name.empty() ) + if (!name.empty()) { - ex.append_context(std::string("in rule '") + name + "' in map '" + filename_ + "')"); + ex.append_context(std::string("in rule '") + name + "'", r); } throw; } } -void map_parser::parse_metawriter_in_symbolizer(symbolizer_base &sym, ptree const &pt) +void map_parser::parse_metawriter_in_symbolizer(symbolizer_base &sym, xml_node const &pt) { - optional writer = get_opt_attr(pt, "meta-writer"); + optional writer = pt.get_opt_attr("meta-writer"); if (!writer) return; - optional output = get_opt_attr(pt, "meta-output"); + optional output = pt.get_opt_attr("meta-output"); sym.add_metawriter(*writer, output); } -void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) { try { - std::stringstream s; - s << "file,base,allow-overlap,ignore-placement,opacity,placement,transform,meta-writer,meta-output"; + optional file = sym.get_opt_attr("file"); + optional base = sym.get_opt_attr("base"); + optional allow_overlap = sym.get_opt_attr("allow-overlap"); + optional ignore_placement = sym.get_opt_attr("ignore-placement"); + optional opacity = sym.get_opt_attr("opacity"); + optional transform_wkt = sym.get_opt_attr("transform"); - optional file = get_opt_attr(sym, "file"); - optional base = get_opt_attr(sym, "base"); - optional allow_overlap = - get_opt_attr(sym, "allow-overlap"); - optional ignore_placement = - get_opt_attr(sym, "ignore-placement"); - optional opacity = - get_opt_attr(sym, "opacity"); - - optional transform_wkt = get_opt_attr(sym, "transform"); + point_symbolizer symbol; + if (allow_overlap) + { + symbol.set_allow_overlap(* allow_overlap); + } + if (opacity) + { + symbol.set_opacity(* opacity); + } + if (ignore_placement) + { + symbol.set_ignore_placement(* ignore_placement); + } + point_placement_e placement = + sym.get_attr("placement", CENTROID_POINT_PLACEMENT); + symbol.set_point_placement(placement); if (file) { - ensure_attrs(sym, "PointSymbolizer", s.str()); try { - if( base ) + if(base) { std::map::const_iterator itr = file_sources_.find(*base); if (itr!=file_sources_.end()) @@ -986,23 +785,7 @@ void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym ) *file = ensure_relative_to_xml(file); - point_symbolizer symbol(parse_path(*file)); - - if (allow_overlap) - { - symbol.set_allow_overlap( * allow_overlap ); - } - if (opacity) - { - symbol.set_opacity( * opacity ); - } - if (ignore_placement) - { - symbol.set_ignore_placement( * ignore_placement ); - } - point_placement_e placement = - get_attr(sym, "placement", CENTROID_POINT_PLACEMENT); - symbol.set_point_placement( placement ); + symbol.set_filename(parse_path(*file)); if (transform_wkt) { @@ -1021,11 +804,8 @@ void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym ) tr.store_to(&matrix[0]); symbol.set_transform(matrix); } - - parse_metawriter_in_symbolizer(symbol, sym); - rule.append(symbol); } - catch (image_reader_exception const & ex ) + catch (image_reader_exception const & ex) { std::string msg("Failed to load image file '" + * file + "': " + ex.what()); @@ -1038,65 +818,29 @@ void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym ) std::clog << "### WARNING: " << msg << endl; } } - - } - else - { - ensure_attrs(sym, "PointSymbolizer", s.str()); - point_symbolizer symbol; - - if (allow_overlap) - { - symbol.set_allow_overlap( * allow_overlap ); - } - if (opacity) - { - symbol.set_opacity( * opacity ); - } - if (ignore_placement) - { - symbol.set_ignore_placement( * ignore_placement ); - } - point_placement_e placement = - get_attr(sym, "placement", CENTROID_POINT_PLACEMENT); - symbol.set_point_placement( placement ); - - parse_metawriter_in_symbolizer(symbol, sym); - rule.append(symbol); } + parse_metawriter_in_symbolizer(symbol, sym); + rule.append(symbol); } catch (const config_error & ex) { - ex.append_context("in PointSymbolizer"); + ex.append_context("in PointSymbolizer", sym); throw; } } -void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) { try { std::string filename(""); - optional file = get_opt_attr(sym, "file"); - optional base = get_opt_attr(sym, "base"); - optional transform_wkt = get_opt_attr(sym, "transform"); - - std::stringstream s; - //s << "file,opacity,spacing,max-error,allow-overlap,placement,"; - s << "file,base,transform,fill,opacity," - << "spacing,max-error,allow-overlap," - << "width,height,placement,marker-type," - << "stroke,stroke-width,stroke-opacity,stroke-linejoin," - << "stroke-linecap,stroke-dashoffset,stroke-dasharray," - // note: stroke-gamma intentionally left off here as markers do not support them - << "meta-writer,meta-output"; - ensure_attrs(sym, "MarkersSymbolizer", s.str()); + optional file = sym.get_opt_attr("file"); + optional base = sym.get_opt_attr("base"); + optional transform_wkt = sym.get_opt_attr("transform"); if (file) { - //s << "base,transform"; - //ensure_attrs(sym, "MarkersSymbolizer", s.str()); try { if (base) @@ -1123,15 +867,10 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) } } } - /*else - { - //s << "fill,marker-type,width,height"; - //ensure_attrs(sym, "MarkersSymbolizer", s.str()); - }*/ markers_symbolizer symbol(parse_path(filename)); - optional opacity = get_opt_attr(sym, "opacity"); - if (opacity) symbol.set_opacity( *opacity ); + optional opacity = sym.get_opt_attr("opacity"); + if (opacity) symbol.set_opacity(*opacity); if (transform_wkt) { @@ -1151,17 +890,19 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) symbol.set_transform(matrix); } - optional c = get_opt_color_attr(sym, "fill"); + optional c = sym.get_opt_attr("fill"); if (c) symbol.set_fill(*c); - optional spacing = get_opt_attr(sym, "spacing"); + optional spacing = sym.get_opt_attr("spacing"); if (spacing) symbol.set_spacing(*spacing); - optional max_error = get_opt_attr(sym, "max-error"); + optional max_error = sym.get_opt_attr("max-error"); if (max_error) symbol.set_max_error(*max_error); - optional allow_overlap = get_opt_attr(sym, "allow-overlap"); + optional allow_overlap = sym.get_opt_attr("allow-overlap"); + optional ignore_placement = sym.get_opt_attr("ignore-placement"); if (allow_overlap) symbol.set_allow_overlap(*allow_overlap); + if (ignore_placement) symbol.set_ignore_placement(*ignore_placement); - optional w = get_opt_attr(sym, "width"); - optional h = get_opt_attr(sym, "height"); + optional w = sym.get_opt_attr("width"); + optional h = sym.get_opt_attr("height"); if (w && h) { symbol.set_width(*w); @@ -1183,38 +924,37 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) parse_stroke(strk,sym); symbol.set_stroke(strk); - marker_placement_e placement = get_attr(sym, "placement", MARKER_LINE_PLACEMENT); - symbol.set_marker_placement( placement ); + marker_placement_e placement = sym.get_attr("placement", MARKER_LINE_PLACEMENT); + symbol.set_marker_placement(placement); marker_type_e dfl_marker_type = ARROW; if (placement == MARKER_POINT_PLACEMENT) dfl_marker_type = ELLIPSE; - marker_type_e marker_type = get_attr(sym, "marker-type", dfl_marker_type); - symbol.set_marker_type( marker_type ); + marker_type_e marker_type = sym.get_attr("marker-type", dfl_marker_type); + symbol.set_marker_type(marker_type); parse_metawriter_in_symbolizer(symbol, sym); rule.append(symbol); } catch (const config_error & ex) { - ex.append_context("in MarkersSymbolizer"); + ex.append_context("in MarkersSymbolizer", sym); throw; } } -void map_parser::parse_line_pattern_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_line_pattern_symbolizer(rule & rule, xml_node const & sym) { - ensure_attrs(sym, "LinePatternSymbolizer", "file,base,meta-writer,meta-output"); try { - std::string file = get_attr(sym, "file"); - optional base = get_opt_attr(sym, "base"); + std::string file = sym.get_attr("file"); + optional base = sym.get_opt_attr("base"); try { - if( base ) + if(base) { std::map::const_iterator itr = file_sources_.find(*base); if (itr!=file_sources_.end()) @@ -1230,7 +970,7 @@ void map_parser::parse_line_pattern_symbolizer( rule & rule, ptree const & sym ) parse_metawriter_in_symbolizer(symbol, sym); rule.append(symbol); } - catch (image_reader_exception const & ex ) + catch (image_reader_exception const & ex) { std::string msg("Failed to load image file '" + file + "': " + ex.what()); @@ -1246,23 +986,22 @@ void map_parser::parse_line_pattern_symbolizer( rule & rule, ptree const & sym ) } catch (const config_error & ex) { - ex.append_context("in LinePatternSymbolizer"); + ex.append_context("in LinePatternSymbolizer", sym); throw; } } -void map_parser::parse_polygon_pattern_symbolizer( rule & rule, - ptree const & sym ) +void map_parser::parse_polygon_pattern_symbolizer(rule & rule, + xml_node const & sym) { - ensure_attrs(sym, "PolygonPatternSymbolizer", "file,base,alignment,gamma,meta-writer,meta-output"); try { - std::string file = get_attr(sym, "file"); - optional base = get_opt_attr(sym, "base"); + std::string file = sym.get_attr("file"); + optional base = sym.get_opt_attr("base"); try { - if( base ) + if(base) { std::map::iterator itr = file_sources_.find(*base); if (itr!=file_sources_.end()) @@ -1276,21 +1015,21 @@ void map_parser::parse_polygon_pattern_symbolizer( rule & rule, polygon_pattern_symbolizer symbol(parse_path(file)); // pattern alignment - pattern_alignment_e p_alignment = get_attr(sym, "alignment",LOCAL_ALIGNMENT); + pattern_alignment_e p_alignment = sym.get_attr("alignment",LOCAL_ALIGNMENT); symbol.set_alignment(p_alignment); // gamma - optional gamma = get_opt_attr(sym, "gamma"); + optional gamma = sym.get_opt_attr("gamma"); if (gamma) symbol.set_gamma(*gamma); // gamma method - optional gamma_method = get_opt_attr(sym, "gamma-method"); + optional gamma_method = sym.get_opt_attr("gamma-method"); if (gamma_method) symbol.set_gamma_method(*gamma_method); parse_metawriter_in_symbolizer(symbol, sym); rule.append(symbol); } - catch (image_reader_exception const & ex ) + catch (image_reader_exception const & ex) { std::string msg("Failed to load image file '" + file + "': " + ex.what()); @@ -1306,41 +1045,28 @@ void map_parser::parse_polygon_pattern_symbolizer( rule & rule, } catch (const config_error & ex) { - ex.append_context("in PolygonPatternSymbolizer"); + ex.append_context("in PolygonPatternSymbolizer", sym); throw; } } -void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_text_symbolizer(rule & rule, xml_node const& sym) { - std::stringstream s_common; - s_common << "name,face-name,fontset-name,size,fill,orientation," - << "dx,dy,placement,vertical-alignment,halo-fill," - << "halo-radius,text-ratio,wrap-width,wrap-before," - << "wrap-character,text-transform,line-spacing," - << "label-position-tolerance,character-spacing," - << "spacing,minimum-distance,minimum-padding,minimum-path-length," - << "avoid-edges,allow-overlap,opacity,max-char-angle-delta," - << "horizontal-alignment,justify-alignment"; - - std::stringstream s_symbolizer; - s_symbolizer << s_common.str() << ",placements,placement-type," - << "meta-writer,meta-output"; - - ensure_attrs(sym, "TextSymbolizer", s_symbolizer.str()); try { text_placements_ptr placement_finder; - optional placement_type = get_opt_attr(sym, "placement-type"); + optional placement_type = sym.get_opt_attr("placement-type"); if (placement_type) { placement_finder = placements::registry::instance()->from_xml(*placement_type, sym, fontsets_); } else { - placement_finder = text_placements_ptr(boost::make_shared()); + placement_finder = boost::make_shared(); placement_finder->defaults.from_xml(sym, fontsets_); } if (strict_ && - !placement_finder->defaults.format.fontset.size()) + !placement_finder->defaults.format.fontset.size()) + { ensure_font_face(placement_finder->defaults.format.face_name); + } text_symbolizer text_symbol = text_symbolizer(placement_finder); parse_metawriter_in_symbolizer(text_symbol, sym); @@ -1348,46 +1074,32 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) } catch (const config_error & ex) { - ex.append_context("in TextSymbolizer"); + ex.append_context("in TextSymbolizer", sym); throw; } } -void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) { - std::string s_common( - "name,face-name,fontset-name,size,fill,orientation," - "dx,dy,placement,vertical-alignment,halo-fill," - "halo-radius,text-ratio,wrap-width,wrap-before," - "wrap-character,text-transform,line-spacing," - "label-position-tolerance,character-spacing," - "spacing,minimum-distance,minimum-padding,minimum-path-length," - "avoid-edges,allow-overlap,opacity,max-char-angle-delta," - "horizontal-alignment,justify-alignment"); - - std::string s_symbolizer(s_common + ",file,base," - "transform,shield-dx,shield-dy,text-opacity," - "unlock-image" - "placements,placement-type,meta-writer,meta-output"); - - ensure_attrs(sym, "ShieldSymbolizer", s_symbolizer); try { text_placements_ptr placement_finder; - optional placement_type = get_opt_attr(sym, "placement-type"); + optional placement_type = sym.get_opt_attr("placement-type"); if (placement_type) { placement_finder = placements::registry::instance()->from_xml(*placement_type, sym, fontsets_); } else { - placement_finder = text_placements_ptr(boost::make_shared()); + placement_finder = boost::make_shared(); } placement_finder->defaults.from_xml(sym, fontsets_); if (strict_ && - !placement_finder->defaults.format.fontset.size()) + !placement_finder->defaults.format.fontset.size()) + { ensure_font_face(placement_finder->defaults.format.face_name); + } shield_symbolizer shield_symbol = shield_symbolizer(placement_finder); /* Symbolizer specific attributes. */ - optional transform_wkt = get_opt_attr(sym, "transform"); + optional transform_wkt = sym.get_opt_attr("transform"); if (transform_wkt) { agg::trans_affine tr; @@ -1405,12 +1117,12 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) shield_symbol.set_transform(matrix); } // shield displacement - double shield_dx = get_attr(sym, "shield-dx", 0.0); - double shield_dy = get_attr(sym, "shield-dy", 0.0); + double shield_dx = sym.get_attr("shield-dx", 0.0); + double shield_dy = sym.get_attr("shield-dy", 0.0); shield_symbol.set_shield_displacement(shield_dx,shield_dy); // opacity - optional opacity = get_opt_attr(sym, "opacity"); + optional opacity = sym.get_opt_attr("opacity"); if (opacity) { shield_symbol.set_opacity(*opacity); @@ -1419,28 +1131,28 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) // text-opacity // TODO: Could be problematic because it is named opacity in TextSymbolizer but opacity has a diffrent meaning here. optional text_opacity = - get_opt_attr(sym, "text-opacity"); + sym.get_opt_attr("text-opacity"); if (text_opacity) { - shield_symbol.set_text_opacity( * text_opacity ); + shield_symbol.set_text_opacity(* text_opacity); } // unlock_image optional unlock_image = - get_opt_attr(sym, "unlock-image"); + sym.get_opt_attr("unlock-image"); if (unlock_image) { - shield_symbol.set_unlock_image( * unlock_image ); + shield_symbol.set_unlock_image(* unlock_image); } parse_metawriter_in_symbolizer(shield_symbol, sym); - std::string image_file = get_attr(sym, "file"); - optional base = get_opt_attr(sym, "base"); + std::string image_file = sym.get_attr("file"); + optional base = sym.get_opt_attr("base"); try { - if( base ) + if(base) { std::map::const_iterator itr = file_sources_.find(*base); if (itr!=file_sources_.end()) @@ -1452,7 +1164,7 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) image_file = ensure_relative_to_xml(image_file); shield_symbol.set_filename(parse_path(image_file)); } - catch (image_reader_exception const & ex ) + catch (image_reader_exception const & ex) { std::string msg("Failed to load image file '" + image_file + "': " + ex.what()); @@ -1469,95 +1181,78 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) } catch (const config_error & ex) { - ex.append_context("in ShieldSymbolizer"); + ex.append_context("in ShieldSymbolizer", sym); throw; } } -void map_parser::parse_stroke(stroke & strk, ptree const & sym) +void map_parser::parse_stroke(stroke & strk, xml_node const & sym) { // stroke color - optional c = get_opt_color_attr(sym, "stroke"); + optional c = sym.get_opt_attr("stroke"); if (c) strk.set_color(*c); // stroke-width - optional width = get_opt_attr(sym, "stroke-width"); + optional width = sym.get_opt_attr("stroke-width"); if (width) strk.set_width(*width); // stroke-opacity - optional opacity = get_opt_attr(sym, "stroke-opacity"); + optional opacity = sym.get_opt_attr("stroke-opacity"); if (opacity) strk.set_opacity(*opacity); // stroke-linejoin - optional line_join = get_opt_attr(sym, "stroke-linejoin"); + optional line_join = sym.get_opt_attr("stroke-linejoin"); if (line_join) strk.set_line_join(*line_join); // stroke-linecap - optional line_cap = get_opt_attr(sym, "stroke-linecap"); + optional line_cap = sym.get_opt_attr("stroke-linecap"); if (line_cap) strk.set_line_cap(*line_cap); // stroke-gamma - optional gamma = get_opt_attr(sym, "stroke-gamma"); + optional gamma = sym.get_opt_attr("stroke-gamma"); if (gamma) strk.set_gamma(*gamma); // stroke-gamma-method - optional gamma_method = get_opt_attr(sym, "stroke-gamma-method"); + optional gamma_method = sym.get_opt_attr("stroke-gamma-method"); if (gamma_method) strk.set_gamma_method(*gamma_method); // stroke-dashoffset - optional dash_offset = get_opt_attr(sym, "stroke-dashoffset"); + optional dash_offset = sym.get_opt_attr("stroke-dashoffset"); if (dash_offset) strk.set_dash_offset(*dash_offset); // stroke-dasharray - optional str = get_opt_attr(sym,"stroke-dasharray"); + optional str = sym.get_opt_attr("stroke-dasharray"); if (str) { - tokenizer<> tok (*str); std::vector dash_array; - tokenizer<>::iterator itr = tok.begin(); - for (; itr != tok.end(); ++itr) + if (util::parse_dasharray((*str).begin(),(*str).end(),dash_array)) { - try + if (!dash_array.empty()) { - double f = boost::lexical_cast(*itr); - dash_array.push_back(f); - } - catch ( boost::bad_lexical_cast &) - { - throw config_error(std::string("Failed to parse dasharray ") + - "'. Expected a " + - "list of floats but got '" + (*str) + "'"); - } - } - if (dash_array.size()) - { - size_t size = dash_array.size(); - if ( size % 2) - { - for (size_t i=0; i < size ;++i) + size_t size = dash_array.size(); + if (size % 2 == 1) + dash_array.insert(dash_array.end(),dash_array.begin(),dash_array.end()); + + std::vector::const_iterator pos = dash_array.begin(); + while (pos != dash_array.end()) { - dash_array.push_back(dash_array[i]); + if (*pos > 0.0 || *(pos+1) > 0.0) // avoid both dash and gap eq 0.0 + strk.add_dash(*pos,*(pos + 1)); + pos +=2; } - } - std::vector::const_iterator pos = dash_array.begin(); - while (pos != dash_array.end()) - { - strk.add_dash(*pos,*(pos + 1)); - pos +=2; - } + } + } + else + { + throw config_error(std::string("Failed to parse dasharray ") + + "'. Expected a " + + "list of floats or 'none' but got '" + (*str) + "'"); } } } -void map_parser::parse_line_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym) { - std::stringstream s; - s << "stroke,stroke-width,stroke-opacity,stroke-linejoin," - << "stroke-linecap,stroke-gamma,stroke-dash-offset,stroke-dasharray," - << "rasterizer," - << "meta-writer,meta-output"; - - ensure_attrs(sym, "LineSymbolizer", s.str()); try { stroke strk; @@ -1565,125 +1260,119 @@ void map_parser::parse_line_symbolizer( rule & rule, ptree const & sym ) line_symbolizer symbol = line_symbolizer(strk); // rasterizer method - line_rasterizer_e rasterizer = get_attr(sym, "rasterizer", RASTERIZER_FULL); - //optional rasterizer_method = get_opt_attr(sym, "full"); + line_rasterizer_e rasterizer = sym.get_attr("rasterizer", RASTERIZER_FULL); + //optional rasterizer_method = sym.get_opt_attr("full"); symbol.set_rasterizer(rasterizer); - + // smooth value + optional smooth = sym.get_opt_attr("smooth"); + if (smooth) symbol.set_smooth(*smooth); + // meta-writer parse_metawriter_in_symbolizer(symbol, sym); rule.append(symbol); } catch (const config_error & ex) { - ex.append_context("in LineSymbolizer"); + ex.append_context("in LineSymbolizer", sym); throw; } } -void map_parser::parse_polygon_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_polygon_symbolizer(rule & rule, xml_node const & sym) { - ensure_attrs(sym, "PolygonSymbolizer", "fill,fill-opacity,gamma,gamma-method,meta-writer,meta-output"); try { polygon_symbolizer poly_sym; // fill - optional fill = get_opt_color_attr(sym, "fill"); + optional fill = sym.get_opt_attr("fill"); if (fill) poly_sym.set_fill(*fill); // fill-opacity - optional opacity = get_opt_attr(sym, "fill-opacity"); + optional opacity = sym.get_opt_attr("fill-opacity"); if (opacity) poly_sym.set_opacity(*opacity); // gamma - optional gamma = get_opt_attr(sym, "gamma"); + optional gamma = sym.get_opt_attr("gamma"); if (gamma) poly_sym.set_gamma(*gamma); // gamma method - optional gamma_method = get_opt_attr(sym, "gamma-method"); + optional gamma_method = sym.get_opt_attr("gamma-method"); if (gamma_method) poly_sym.set_gamma_method(*gamma_method); + // smooth value + optional smooth = sym.get_opt_attr("smooth"); + if (smooth) poly_sym.set_smooth(*smooth); parse_metawriter_in_symbolizer(poly_sym, sym); rule.append(poly_sym); } catch (const config_error & ex) { - ex.append_context("in PolygonSymbolizer"); + ex.append_context("in PolygonSymbolizer", sym); throw; } } -void map_parser::parse_building_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_building_symbolizer(rule & rule, xml_node const & sym) { - ensure_attrs(sym, "PolygonSymbolizer", "fill,fill-opacity,height,meta-writer,meta-output"); try { building_symbolizer building_sym; // fill - optional fill = get_opt_color_attr(sym, "fill"); + optional fill = sym.get_opt_attr("fill"); if (fill) building_sym.set_fill(*fill); // fill-opacity - optional opacity = get_opt_attr(sym, "fill-opacity"); + optional opacity = sym.get_opt_attr("fill-opacity"); if (opacity) building_sym.set_opacity(*opacity); // height - optional height = get_opt_attr(sym, "height"); - if (height) building_sym.set_height(parse_expr(*height)); + optional height = sym.get_opt_attr("height"); + if (height) building_sym.set_height(*height); parse_metawriter_in_symbolizer(building_sym, sym); rule.append(building_sym); } catch (const config_error & ex) { - ex.append_context("in BuildingSymbolizer"); + ex.append_context("in BuildingSymbolizer", sym); throw; } } -void map_parser::parse_raster_symbolizer( rule & rule, ptree const & sym ) +void map_parser::parse_raster_symbolizer(rule & rule, xml_node const & sym) { - // no support for meta-writer,meta-output - ensure_attrs(sym, "RasterSymbolizer", "mode,scaling,opacity,filter-factor,mesh-size"); try { raster_symbolizer raster_sym; // mode - optional mode = get_opt_attr(sym, "mode"); + optional mode = sym.get_opt_attr("mode"); if (mode) raster_sym.set_mode(*mode); // scaling - optional scaling = get_opt_attr(sym, "scaling"); + optional scaling = sym.get_opt_attr("scaling"); if (scaling) raster_sym.set_scaling(*scaling); // opacity - optional opacity = get_opt_attr(sym, "opacity"); + optional opacity = sym.get_opt_attr("opacity"); if (opacity) raster_sym.set_opacity(*opacity); // filter factor - optional filter_factor = get_opt_attr(sym, "filter-factor"); + optional filter_factor = sym.get_opt_attr("filter-factor"); if (filter_factor) raster_sym.set_filter_factor(*filter_factor); // mesh-size - optional mesh_size = get_opt_attr(sym, "mesh-size"); + optional mesh_size = sym.get_opt_attr("mesh-size"); if (mesh_size) raster_sym.set_mesh_size(*mesh_size); - ptree::const_iterator cssIter = sym.begin(); - ptree::const_iterator endCss = sym.end(); + xml_node::const_iterator cssIter = sym.begin(); + xml_node::const_iterator endCss = sym.end(); for(; cssIter != endCss; ++cssIter) { - ptree::value_type const& css_tag = *cssIter; - - if (css_tag.first == "RasterColorizer") + if (cssIter->is("RasterColorizer")) { - raster_colorizer_ptr colorizer(new raster_colorizer()); + raster_colorizer_ptr colorizer = boost::make_shared(); raster_sym.set_colorizer(colorizer); - parse_raster_colorizer(colorizer, css_tag.second); - } - else if (css_tag.first != "" && - css_tag.first != "" ) - { - throw config_error(std::string("Unknown child node. ") + - "Expected 'RasterColorizer' but got '" + css_tag.first + "'"); + parse_raster_colorizer(colorizer, *cssIter); } } //Note: raster_symbolizer doesn't support metawriters @@ -1691,70 +1380,65 @@ void map_parser::parse_raster_symbolizer( rule & rule, ptree const & sym ) } catch (const config_error & ex) { - ex.append_context("in RasterSymbolizer"); + ex.append_context("in RasterSymbolizer", sym); throw; } } void map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc, - ptree const& node ) + xml_node const& node) { try { - ensure_attrs(node, "RasterColorizer", "default-mode,default-color,epsilon"); // mode colorizer_mode default_mode = - get_attr(node, "default-mode", COLORIZER_LINEAR); + node.get_attr("default-mode", COLORIZER_LINEAR); if(default_mode == COLORIZER_INHERIT) { throw config_error("RasterColorizer mode must not be INHERIT. "); } - rc->set_default_mode( default_mode ); + rc->set_default_mode(default_mode); // default colour - optional default_color = get_opt_color_attr(node, "default-color"); + optional default_color = node.get_opt_attr("default-color"); if (default_color) { - rc->set_default_color( *default_color ); + rc->set_default_color(*default_color); } // epsilon - optional eps = get_opt_attr(node, "epsilon"); + optional eps = node.get_opt_attr("epsilon"); if (eps) { if(*eps < 0) { throw config_error("RasterColorizer epsilon must be > 0. "); } - rc->set_epsilon( *eps ); + rc->set_epsilon(*eps); } - ptree::const_iterator stopIter = node.begin(); - ptree::const_iterator endStop = node.end(); + xml_node::const_iterator stopIter = node.begin(); + xml_node::const_iterator endStop = node.end(); float maximumValue = -std::numeric_limits::max(); for(; stopIter != endStop; ++stopIter) { - ptree::value_type const& stop_tag = *stopIter; - ptree const & stop = stopIter->second; - - if (stop_tag.first == "stop") + if (stopIter->is("stop")) { - ensure_attrs(stop_tag.second, "stop", "color,mode,value,label"); // colour is optional. - optional stopcolor = get_opt_color_attr(stop, "color"); + optional stopcolor = stopIter->get_opt_attr("color"); if (!stopcolor) { *stopcolor = *default_color; } // mode default to INHERIT colorizer_mode mode = - get_attr(stop, "mode", COLORIZER_INHERIT); + stopIter->get_attr("mode", COLORIZER_INHERIT); // value is required, and it must be bigger than the previous optional value = - get_opt_attr(stop, "value"); + stopIter->get_opt_attr("value"); if(!value) { throw config_error("stop tag missing value"); @@ -1766,7 +1450,7 @@ void map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc, maximumValue = *value; optional label = - get_opt_attr(stop, "label"); + stopIter->get_opt_attr("label"); //append the stop colorizer_stop tmpStop; @@ -1778,37 +1462,31 @@ void map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc, rc->add_stop(tmpStop); } - else if (stop_tag.first != "" && - stop_tag.first != "" ) - { - throw config_error(std::string("Unknown child node. ") + - "Expected 'stop' but got '" + stop_tag.first + "'"); - } } } catch (const config_error & ex) { - ex.append_context("in RasterColorizer"); + ex.append_context("in RasterColorizer", node); throw; } } -void map_parser::ensure_font_face( std::string const& face_name ) +void map_parser::ensure_font_face(std::string const& face_name) { - if ( ! font_manager_.get_face( face_name ) ) + if (! font_manager_.get_face(face_name)) { throw config_error("Failed to find font face '" + face_name + "'"); } } -std::string map_parser::ensure_relative_to_xml( boost::optional opt_path ) +std::string map_parser::ensure_relative_to_xml(boost::optional opt_path) { if (relative_to_xml_) { boost::filesystem::path xml_path = filename_; boost::filesystem::path rel_path = *opt_path; - if ( !rel_path.has_root_path() ) + if (!rel_path.has_root_path()) { #if (BOOST_FILESYSTEM_VERSION == 3) // TODO - normalize is now deprecated, use make_preferred? @@ -1828,44 +1506,45 @@ std::string map_parser::ensure_relative_to_xml( boost::optional opt return *opt_path; } -void map_parser::ensure_attrs(ptree const& sym, std::string name, std::string attrs) +void map_parser::find_unused_nodes(xml_node const& root) { - typedef ptree::key_type::value_type Ch; - optional attribs = sym.get_child_optional( boost::property_tree::xml_parser::xmlattr() ); - if (attribs) + std::stringstream error_message; + find_unused_nodes_recursive(root, error_message); + if (!error_message.str().empty()) { - std::set attr_set; - boost::split(attr_set, attrs, boost::is_any_of(",")); - std::ostringstream s(""); - s << "### " << name << " properties warning: "; - int missing = 0; - for (ptree::const_iterator it = attribs.get().begin(); it != attribs.get().end(); ++it) + throw config_error("The following nodes or attributes were not processed while parsing the xml file:" + error_message.str()); + } +} + +void map_parser::find_unused_nodes_recursive(xml_node const& node, std::stringstream &error_message) +{ + if (!node.processed()) + { + if (node.is_text()) { + error_message << "\n* text '" << node.text() << "'"; + } else { + error_message << "\n* node '" << node.name() << "' in line " << node.line(); + } + return; //All attributes and children are automatically unprocessed, too. + } + xml_node::attribute_map const& attr = node.get_attributes(); + xml_node::attribute_map::const_iterator aitr = attr.begin(); + xml_node::attribute_map::const_iterator aend = attr.end(); + for (;aitr!=aend; aitr++) + { + if (!aitr->second.processed) { - std::string name = it->first; - bool found = (attr_set.find(name) != attr_set.end()); - if (!found) - { - if (missing) - { - s << ","; - } - s << "'" << name << "'"; - ++missing; - } - } - if (missing) { - if (missing > 1) - { - s << " are"; - } - else - { - s << " is"; - } - s << " invalid, acceptable values are:\n'" << attrs << "'\n"; - std::clog << s.str(); + error_message << "\n* attribute '" << aitr->first << + "' with value '" << aitr->second.value << + "' in line " << node.line(); } } + xml_node::const_iterator itr = node.begin(); + xml_node::const_iterator end = node.end(); + for (; itr!=end; itr++) + { + find_unused_nodes_recursive(*itr, error_message); + } } } // end of namespace mapnik diff --git a/src/map.cpp b/src/map.cpp index f46437989..428c796c1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -29,6 +29,9 @@ #include #include +// boost +#include + // icu #include @@ -93,7 +96,6 @@ Map::Map(const Map& rhs) current_extent_(rhs.current_extent_), maximum_extent_(rhs.maximum_extent_), base_path_(rhs.base_path_), - extra_attr_(rhs.extra_attr_), extra_params_(rhs.extra_params_) {} Map& Map::operator=(const Map& rhs) @@ -112,7 +114,6 @@ Map& Map::operator=(const Map& rhs) aspectFixMode_=rhs.aspectFixMode_; maximum_extent_=rhs.maximum_extent_; base_path_=rhs.base_path_; - extra_attr_=rhs.extra_attr_; extra_params_=rhs.extra_params_; return *this; } @@ -396,7 +397,7 @@ void Map::zoom_all() std::vector::const_iterator end = layers_.end(); while (itr != end) { - if (itr->isActive()) + if (itr->active()) { std::string const& layer_srs = itr->srs(); projection proj1(layer_srs); @@ -451,54 +452,57 @@ void Map::zoom_to_box(const box2d &box) void Map::fixAspectRatio() { - double ratio1 = (double) width_ / (double) height_; - double ratio2 = current_extent_.width() / current_extent_.height(); - if (ratio1 == ratio2) return; - - switch(aspectFixMode_) + if (current_extent_.width() > 0 && current_extent_.height() > 0) { - case ADJUST_BBOX_HEIGHT: - current_extent_.height(current_extent_.width() / ratio1); - break; - case ADJUST_BBOX_WIDTH: - current_extent_.width(current_extent_.height() * ratio1); - break; - case ADJUST_CANVAS_HEIGHT: - height_ = int (width_ / ratio2 + 0.5); - break; - case ADJUST_CANVAS_WIDTH: - width_ = int (height_ * ratio2 + 0.5); - break; - case GROW_BBOX: - if (ratio2 > ratio1) + double ratio1 = static_cast(width_) / static_cast(height_); + double ratio2 = current_extent_.width() / current_extent_.height(); + if (ratio1 == ratio2) return; + + switch(aspectFixMode_) + { + case ADJUST_BBOX_HEIGHT: current_extent_.height(current_extent_.width() / ratio1); - else + break; + case ADJUST_BBOX_WIDTH: current_extent_.width(current_extent_.height() * ratio1); - break; - case SHRINK_BBOX: - if (ratio2 < ratio1) - current_extent_.height(current_extent_.width() / ratio1); - else - current_extent_.width(current_extent_.height() * ratio1); - break; - case GROW_CANVAS: - if (ratio2 > ratio1) - width_ = (int) (height_ * ratio2 + 0.5); - else + break; + case ADJUST_CANVAS_HEIGHT: height_ = int (width_ / ratio2 + 0.5); - break; - case SHRINK_CANVAS: - if (ratio2 > ratio1) - height_ = int (width_ / ratio2 + 0.5); - else - width_ = (int) (height_ * ratio2 + 0.5); - break; - default: - if (ratio2 > ratio1) - current_extent_.height(current_extent_.width() / ratio1); - else - current_extent_.width(current_extent_.height() * ratio1); - break; + break; + case ADJUST_CANVAS_WIDTH: + width_ = int (height_ * ratio2 + 0.5); + break; + case GROW_BBOX: + if (ratio2 > ratio1) + current_extent_.height(current_extent_.width() / ratio1); + else + current_extent_.width(current_extent_.height() * ratio1); + break; + case SHRINK_BBOX: + if (ratio2 < ratio1) + current_extent_.height(current_extent_.width() / ratio1); + else + current_extent_.width(current_extent_.height() * ratio1); + break; + case GROW_CANVAS: + if (ratio2 > ratio1) + width_ = static_cast(height_ * ratio2 + 0.5); + else + height_ = int (width_ / ratio2 + 0.5); + break; + case SHRINK_CANVAS: + if (ratio2 > ratio1) + height_ = int (width_ / ratio2 + 0.5); + else + width_ = static_cast(height_ * ratio2 + 0.5); + break; + default: + if (ratio2 > ratio1) + current_extent_.height(current_extent_.width() / ratio1); + else + current_extent_.width(current_extent_.height() * ratio1); + break; + } } } @@ -581,7 +585,8 @@ featureset_ptr Map::query_point(unsigned index, double x, double y) const #endif featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y)); if (fs) - return featureset_ptr(new filter_featureset(fs,hit_test_filter(x,y,tol))); + return boost::make_shared >(fs, + hit_test_filter(x,y,tol)); } } catch (...) @@ -626,7 +631,8 @@ featureset_ptr Map::query_map_point(unsigned index, double x, double y) const #endif featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y)); if (fs) - return featureset_ptr(new filter_featureset(fs,hit_test_filter(x,y,tol))); + return boost::make_shared >(fs, + hit_test_filter(x,y,tol)); } } catch (...) @@ -676,21 +682,6 @@ std::string Map::get_metawriter_property(std::string name) const return result; } -parameters const& Map::get_extra_attributes() const -{ - return extra_attr_; -} - -parameters& Map::get_extra_attributes() -{ - return extra_attr_; -} - -void Map::set_extra_attributes(parameters& attr) -{ - extra_attr_ = attr; -} - parameters const& Map::get_extra_parameters() const { return extra_params_; diff --git a/src/mapped_memory_cache.cpp b/src/mapped_memory_cache.cpp index c9ea8084b..7fc9adce8 100644 --- a/src/mapped_memory_cache.cpp +++ b/src/mapped_memory_cache.cpp @@ -29,13 +29,22 @@ #include #include #include +#include namespace mapnik { boost::unordered_map mapped_memory_cache::cache_; -bool mapped_memory_cache::insert (std::string const& uri, mapped_region_ptr mem) +void mapped_memory_cache::clear() +{ +#ifdef MAPNIK_THREADSAFE + mutex::scoped_lock lock(mutex_); +#endif + return cache_.clear(); +} + +bool mapped_memory_cache::insert(std::string const& uri, mapped_region_ptr mem) { #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); @@ -63,7 +72,7 @@ boost::optional mapped_memory_cache::find(std::string const& try { file_mapping mapping(uri.c_str(),read_only); - mapped_region_ptr region(new mapped_region(mapping,read_only)); + mapped_region_ptr region(boost::make_shared(mapping,read_only)); result.reset(region); diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index f5139699a..859be8bc0 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -23,11 +23,13 @@ //$Id$ // mapnik +#include #include #include #include -#include #include +#include +#include #include #include @@ -35,13 +37,22 @@ #include #include #include +#include namespace mapnik { boost::unordered_map marker_cache::cache_; -bool marker_cache::insert (std::string const& uri, marker_ptr path) +void marker_cache::clear() +{ +#ifdef MAPNIK_THREADSAFE + mutex::scoped_lock lock(mutex_); +#endif + return cache_.clear(); +} + +bool marker_cache::insert(std::string const& uri, marker_ptr path) { #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); @@ -72,7 +83,7 @@ boost::optional marker_cache::find(std::string const& uri, bool upda using namespace mapnik::svg; try { - path_ptr marker_path(new svg_storage_type); + path_ptr marker_path(boost::make_shared()); vertex_stl_adapter stl_storage(marker_path->source()); svg_path_adapter svg_path(stl_storage); svg_converter_type svg(svg_path, marker_path->attributes()); @@ -84,7 +95,7 @@ boost::optional marker_cache::find(std::string const& uri, bool upda svg.bounding_rect(&lox, &loy, &hix, &hiy); marker_path->set_bounding_box(lox,loy,hix,hiy); - marker_ptr mark(new marker(marker_path)); + marker_ptr mark(boost::make_shared(marker_path)); result.reset(mark); if (update_cache) { @@ -107,9 +118,9 @@ boost::optional marker_cache::find(std::string const& uri, bool upda unsigned width = reader->width(); unsigned height = reader->height(); BOOST_ASSERT(width > 0 && height > 0); - mapnik::image_ptr image(new mapnik::image_data_32(width,height)); + mapnik::image_ptr image(boost::make_shared(width,height)); reader->read(0,0,*image); - marker_ptr mark(new marker(image)); + marker_ptr mark(boost::make_shared(image)); result.reset(mark); if (update_cache) { diff --git a/src/markers_placement.cpp b/src/markers_placement.cpp index 9d5306be6..eb6c955f0 100644 --- a/src/markers_placement.cpp +++ b/src/markers_placement.cpp @@ -6,7 +6,7 @@ #include //round // agg #include "agg_basics.h" - +#include "agg_conv_clip_polyline.h" // stl #include @@ -226,7 +226,11 @@ void markers_placement::set_spacing_left(double sl, bool allo spacing_left_ = sl; } +typedef agg::conv_clip_polyline clipped_geometry_type; typedef coord_transform2 path_type; +typedef coord_transform2 clipped_path_type; + template class markers_placement; +template class markers_placement; } //ns mapnik diff --git a/src/markers_symbolizer.cpp b/src/markers_symbolizer.cpp index 02afffdd4..e640eac17 100644 --- a/src/markers_symbolizer.cpp +++ b/src/markers_symbolizer.cpp @@ -47,11 +47,12 @@ markers_symbolizer::markers_symbolizer() : symbolizer_with_image(path_expression_ptr(new path_expression)), symbolizer_base(), allow_overlap_(false), + ignore_placement_(false), fill_(color(0,0,255)), spacing_(100.0), max_error_(0.2), - width_(5.0), - height_(5.0), + width_(10.0), + height_(10.0), stroke_(), marker_p_(MARKER_LINE_PLACEMENT), marker_type_(ARROW) {} @@ -60,11 +61,12 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr filename) : symbolizer_with_image(filename), symbolizer_base(), allow_overlap_(false), + ignore_placement_(false), fill_(color(0,0,255)), spacing_(100.0), max_error_(0.2), - width_(5.0), - height_(5.0), + width_(10.0), + height_(10.0), stroke_(), marker_p_(MARKER_LINE_PLACEMENT), marker_type_(ARROW) {} @@ -73,6 +75,7 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) : symbolizer_with_image(rhs), symbolizer_base(rhs), allow_overlap_(rhs.allow_overlap_), + ignore_placement_(rhs.ignore_placement_), fill_(rhs.fill_), spacing_(rhs.spacing_), max_error_(rhs.max_error_), @@ -82,6 +85,16 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) marker_p_(rhs.marker_p_), marker_type_(rhs.marker_type_) {} +void markers_symbolizer::set_ignore_placement(bool ignore_placement) +{ + ignore_placement_ = ignore_placement; +} + +bool markers_symbolizer::get_ignore_placement() const +{ + return ignore_placement_; +} + void markers_symbolizer::set_allow_overlap(bool overlap) { allow_overlap_ = overlap; diff --git a/src/memory_datasource.cpp b/src/memory_datasource.cpp index 1e2edb189..ad87d871c 100644 --- a/src/memory_datasource.cpp +++ b/src/memory_datasource.cpp @@ -25,6 +25,10 @@ #include #include #include + +// boost +#include + // stl #include @@ -76,7 +80,7 @@ datasource::datasource_t memory_datasource::type() const featureset_ptr memory_datasource::features(const query& q) const { - return featureset_ptr(new memory_featureset(q.get_bbox(),*this)); + return boost::make_shared(q.get_bbox(),*this); } @@ -86,7 +90,7 @@ featureset_ptr memory_datasource::features_at_point(coord2d const& pt) const #ifdef MAPNIK_DEBUG std::clog << "box=" << box << ", pt x=" << pt.x << ", y=" << pt.y << "\n"; #endif - return featureset_ptr(new memory_featureset(box,*this)); + return boost::make_shared(box,*this); } box2d memory_datasource::envelope() const diff --git a/src/metawriter_factory.cpp b/src/metawriter_factory.cpp index d79201838..2c2a5973b 100644 --- a/src/metawriter_factory.cpp +++ b/src/metawriter_factory.cpp @@ -22,14 +22,15 @@ //$Id$ #include -#include - #include #include +#include +#include +#include +#include #include -using boost::property_tree::ptree; using boost::optional; using std::string; @@ -37,37 +38,40 @@ namespace mapnik { metawriter_ptr -metawriter_create(const boost::property_tree::ptree &pt) { +metawriter_create(xml_node const& pt) +{ metawriter_ptr writer; - string type = get_attr(pt, "type"); + string type = pt.get_attr("type"); - optional properties = get_opt_attr(pt, "default-output"); + optional properties = pt.get_opt_attr("default-output"); if (type == "json") { - string file = get_attr(pt, "file"); - metawriter_json_ptr json = metawriter_json_ptr(new metawriter_json(properties, parse_path(file))); - optional output_empty = get_opt_attr(pt, "output-empty"); + string file = pt.get_attr("file"); + metawriter_json_ptr json = boost::make_shared(properties, parse_path(file)); + optional output_empty = pt.get_opt_attr("output-empty"); if (output_empty) { json->set_output_empty(*output_empty); } - optional pixel_coordinates = get_opt_attr(pt, "pixel-coordinates"); + optional pixel_coordinates = pt.get_opt_attr("pixel-coordinates"); if (pixel_coordinates) { json->set_pixel_coordinates(*pixel_coordinates); } writer = json; } else if (type == "inmem") { - metawriter_inmem_ptr inmem = metawriter_inmem_ptr(new metawriter_inmem(properties)); + metawriter_inmem_ptr inmem = boost::make_shared(properties); writer = inmem; } else { - throw config_error(string("Unknown type '") + type + "'"); + throw config_error(string("Unknown type '") + type + "'", pt); } return writer; } void -metawriter_save(const metawriter_ptr &metawriter, ptree &metawriter_node, bool explicit_defaults) { +metawriter_save(const metawriter_ptr &metawriter, + boost::property_tree::ptree &metawriter_node, bool explicit_defaults) +{ metawriter_json *json = dynamic_cast(metawriter.get()); if (json) { diff --git a/src/palette.cpp b/src/palette.cpp index 29d4120d4..6125d8808 100644 --- a/src/palette.cpp +++ b/src/palette.cpp @@ -21,6 +21,7 @@ *****************************************************************************/ #include +#include namespace mapnik { diff --git a/src/parse_path.cpp b/src/parse_path.cpp index d538befa3..2c9fb9030 100644 --- a/src/parse_path.cpp +++ b/src/parse_path.cpp @@ -23,11 +23,13 @@ #include #include +#include + namespace mapnik { path_expression_ptr parse_path(std::string const & str) { - path_expression_ptr path(new path_expression) ; + path_expression_ptr path = boost::make_shared() ; path_expression_grammar g; std::string::const_iterator itr = str.begin(); diff --git a/src/placement_finder.cpp b/src/placement_finder.cpp index c9c2c6e1d..b7e797203 100644 --- a/src/placement_finder.cpp +++ b/src/placement_finder.cpp @@ -26,14 +26,11 @@ #include #include #include -#include #include #include -#include // agg #include "agg_path_length.h" -#include "agg_conv_clip_polyline.h" // boost #include @@ -270,9 +267,9 @@ void placement_finder::find_line_breaks() // wrap text at first wrap_char after (default) the wrap width or immediately before the current word if ((c == '\n') || (line_width > 0 && - ((line_width > wrap_at && !ci.format->wrap_before) || + ((line_width > wrap_at && !ci.format->wrap_before) || ((line_width + last_wrap_char_width + word_width) > wrap_at && ci.format->wrap_before)) ) - ) + ) { add_line(line_width, line_height, first_line); line_breaks_.push_back(last_wrap_char_pos); @@ -306,23 +303,47 @@ template void placement_finder::init_alignment() { valign_ = p.valign; - if (valign_ == V_AUTO) { + if (valign_ == V_AUTO) + { if (p.displacement.second > 0.0) + { valign_ = V_BOTTOM; - else if (p.displacement.second < 0.0) + } else if (p.displacement.second < 0.0) + { valign_ = V_TOP; - else + } else + { valign_ = V_MIDDLE; + } } halign_ = p.halign; - if (halign_ == H_AUTO) { + if (halign_ == H_AUTO) + { if (p.displacement.first > 0.0) + { halign_ = H_RIGHT; - else if (p.displacement.first < 0.0) + } else if (p.displacement.first < 0.0) + { halign_ = H_LEFT; - else + } else + { halign_ = H_MIDDLE; + } + } + + jalign_ = p.jalign; + if (jalign_ == J_AUTO) + { + if (p.displacement.first > 0.0) + { + jalign_ = J_LEFT; + } else if (p.displacement.first < 0.0) + { + jalign_ = J_RIGHT; + } else { + jalign_ = J_MIDDLE; + } } } @@ -385,11 +406,14 @@ void placement_finder::find_point_placement(double label_x, // set for upper left corner of text envelope for the first line, bottom left of first character y = string_height_ / 2.0 - line_height; + // RTL text is converted to a mirrored representation in get_string_info() + // so we have to fix line break order here + if (info_.get_rtl()) y = -y; // adjust for desired justification - if (p.jalign == J_LEFT) + if (jalign_ == J_LEFT) x = -(string_width_ / 2.0); - else if (p.jalign == J_RIGHT) + else if (jalign_ == J_RIGHT) x = (string_width_ / 2.0) - line_width; else /* J_MIDDLE */ x = -(line_width / 2.0); @@ -409,12 +433,18 @@ void placement_finder::find_point_placement(double label_x, line_width = line_sizes_[line_number].first; line_height= line_sizes_[line_number].second; - y -= line_height; // move position down to line start + if (info_.get_rtl()) + { + y += line_height; + } else + { + y -= line_height; // move position down to line start + } // reset to begining of line position - if (p.jalign == J_LEFT) + if (jalign_ == J_LEFT) x = -(string_width_ / 2.0); - else if (p.jalign == J_RIGHT) + else if (jalign_ == J_RIGHT) x = (string_width_ / 2.0) - line_width; else x = -(line_width / 2.0); @@ -438,9 +468,10 @@ void placement_finder::find_point_placement(double label_x, current_placement->center.y - dy - ci.ymax); // if there is an overlap with existing envelopes, then exit - no placement + if (!detector_.extent().intersects(e) || - (!p.allow_overlap && !detector_.has_point_placement(e, pi.get_actual_minimum_distance())) - ) + (!p.allow_overlap && + !detector_.has_point_placement(e, pi.get_actual_minimum_distance()))) { return; } @@ -623,19 +654,27 @@ void placement_finder::find_line_placements(PathT & shape_path) if (displacement != 0) { //Average the angle of all characters and then offset them all by that angle - //NOTE: This probably calculates a bad angle due to going around the circle, test this! double anglesum = 0; for (unsigned i = 0; i < current_placement->nodes_.size(); i++) { - anglesum += current_placement->nodes_[i].angle; + double angle = current_placement->nodes_[i].angle; + //Normalize angle in range -PI ... PI + while (angle > M_PI) { + angle -= 2*M_PI; + } + anglesum += angle; } anglesum /= current_placement->nodes_.size(); //Now it is angle average + double cosa = orientation * cos(anglesum); + double sina = orientation * sin(anglesum); //Offset all the characters by this angle for (unsigned i = 0; i < current_placement->nodes_.size(); i++) { - current_placement->nodes_[i].pos.x += pi.get_scale_factor() * displacement*cos(anglesum+M_PI/2); - current_placement->nodes_[i].pos.y += pi.get_scale_factor() * displacement*sin(anglesum+M_PI/2); + current_placement->nodes_[i].pos.x -= + pi.get_scale_factor() * displacement * sina; + current_placement->nodes_[i].pos.y += + pi.get_scale_factor() * displacement * cosa; } } @@ -675,10 +714,10 @@ void placement_finder::find_line_placements(PathT & shape_path) template std::auto_ptr placement_finder::get_placement_offset(std::vector const& path_positions, - std::vector const& path_distances, - int & orientation, - unsigned index, - double distance) + std::vector const& path_distances, + int & orientation, + unsigned index, + double distance) { //Check that the given distance is on the given index and find the correct index and distance if not while (distance < 0 && index > 1) @@ -718,10 +757,10 @@ std::auto_ptr placement_finder::get_placement_offset(std:: } std::auto_ptr current_placement( - new text_path((old_x + dx*distance/segment_length), - (old_y + dy*distance/segment_length) - ) - ); + new text_path((old_x + dx*distance/segment_length), + (old_y + dy*distance/segment_length) + ) + ); double angle = atan2(-dy, dx); @@ -830,7 +869,7 @@ std::auto_ptr placement_finder::get_placement_offset(std:: render_angle += M_PI; } current_placement->add_node(&ci, - render_x - current_placement->center.x, + render_x - current_placement->center.x, -render_y + current_placement->center.y, render_angle); @@ -870,7 +909,7 @@ std::auto_ptr placement_finder::get_placement_offset(std:: template bool placement_finder::test_placement(std::auto_ptr const& current_placement, - int orientation) + int orientation) { //Create and test envelopes bool status = true; @@ -907,7 +946,10 @@ bool placement_finder::test_placement(std::auto_ptr const& y - (cwidth*sina + ci.height()*cosa)); if (!detector_.extent().intersects(e) || - !detector_.has_placement(e, info_.get_string(), pi.get_actual_minimum_distance())) + (!p.allow_overlap && + !detector_.has_placement(e, info_.get_string(), pi.get_actual_minimum_distance()) + ) + ) { //std::clog << "No Intersects:" << !dimensions_.intersects(e) << ": " << e << " @ " << dimensions_ << std::endl; //std::clog << "No Placements:" << !detector_.has_placement(e, info.get_string(), p.minimum_distance) << std::endl; @@ -1014,10 +1056,9 @@ void placement_finder::clear_placements() while (!envelopes_.empty()) envelopes_.pop(); } -typedef coord_transform2 PathType; -typedef label_collision_detector4 DetectorType; - template class placement_finder; +template void placement_finder::find_point_placements(ClippedPathType &); +template void placement_finder::find_line_placements(ClippedPathType &); template void placement_finder::find_point_placements(PathType &); template void placement_finder::find_line_placements(PathType &); } // namespace diff --git a/src/polygon_symbolizer.cpp b/src/polygon_symbolizer.cpp index 7009e586c..7c783a12d 100644 --- a/src/polygon_symbolizer.cpp +++ b/src/polygon_symbolizer.cpp @@ -32,14 +32,16 @@ polygon_symbolizer::polygon_symbolizer() fill_(color(128,128,128)), opacity_(1.0), gamma_(1.0), - gamma_method_(GAMMA_POWER) {} + gamma_method_(GAMMA_POWER), + smooth_(0.0) {} polygon_symbolizer::polygon_symbolizer(color const& fill) : symbolizer_base(), fill_(fill), opacity_(1.0), gamma_(1.0), - gamma_method_(GAMMA_POWER) {} + gamma_method_(GAMMA_POWER), + smooth_(0.0) {} color const& polygon_symbolizer::get_fill() const { @@ -81,4 +83,14 @@ gamma_method_e polygon_symbolizer::get_gamma_method() const return gamma_method_; } +void polygon_symbolizer::set_smooth(double smooth) +{ + smooth_ = smooth; +} + +double polygon_symbolizer::smooth() const +{ + return smooth_; +} + } diff --git a/src/processed_text.cpp b/src/processed_text.cpp index 3a6949487..921e528c6 100644 --- a/src/processed_text.cpp +++ b/src/processed_text.cpp @@ -1,4 +1,28 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + #include +#include + namespace mapnik { @@ -43,7 +67,7 @@ string_info &processed_text::get_string_info() { if (!p.fontset.get_name().empty()) { - throw config_error("Unable to find specified font set '" + p.face_name + "'"); + throw config_error("Unable to find specified font set '" + p.fontset.get_name() + "'"); } else if (!p.face_name.empty()) { throw config_error("Unable to find specified font face '" + p.face_name + "'"); } else { diff --git a/src/proj_transform.cpp b/src/proj_transform.cpp index e6f0965c4..c52dfd7c6 100644 --- a/src/proj_transform.cpp +++ b/src/proj_transform.cpp @@ -102,8 +102,7 @@ bool proj_transform::forward (double * x, double * y , double * z, int point_cou } do { -// https://github.com/mapnik/mapnik/issues/1072 -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 mutex::scoped_lock lock(projection::mutex_); #endif if (pj_transform( source_.proj_, dest_.proj_, point_count, @@ -154,8 +153,7 @@ bool proj_transform::backward (double * x, double * y , double * z, int point_co } do { -// https://github.com/mapnik/mapnik/issues/1072 -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 mutex::scoped_lock lock(projection::mutex_); #endif diff --git a/src/projection.cpp b/src/projection.cpp index 66706edb6..5fc97e150 100644 --- a/src/projection.cpp +++ b/src/projection.cpp @@ -34,7 +34,7 @@ namespace mapnik { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 boost::mutex projection::mutex_; #endif @@ -84,7 +84,7 @@ std::string const& projection::params() const void projection::forward(double & x, double &y ) const { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 mutex::scoped_lock lock(mutex_); #endif projUV p; @@ -102,7 +102,7 @@ void projection::forward(double & x, double &y ) const void projection::inverse(double & x,double & y) const { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 mutex::scoped_lock lock(mutex_); #endif if (is_geographic_) @@ -120,7 +120,7 @@ void projection::inverse(double & x,double & y) const projection::~projection() { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 mutex::scoped_lock lock(mutex_); #endif if (proj_) pj_free(proj_); @@ -131,7 +131,7 @@ projection::~projection() void projection::init() { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 mutex::scoped_lock lock(mutex_); #endif #if PJ_VERSION >= 480 diff --git a/src/rapidxml_loader.cpp b/src/rapidxml_loader.cpp new file mode 100644 index 000000000..4a9293f54 --- /dev/null +++ b/src/rapidxml_loader.cpp @@ -0,0 +1,171 @@ + + +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifdef HAVE_LIBXML2 +#error HAVE_LIBXML2 defined but compiling rapidxml_loader.cpp! +#endif + +// mapnik +#include +#include +#include +#include + +// boost +#include +#include + +// stl +#include +#include + +using namespace std; +namespace rapidxml = boost::property_tree::detail::rapidxml; +namespace mapnik +{ +class rapidxml_loader : boost::noncopyable +{ +public: + rapidxml_loader(const char *encoding = NULL) : + filename_() + { + + } + + ~rapidxml_loader() + { + } + + void load(const std::string & filename, xml_node &node) + { + filename_ = filename; + std::basic_ifstream stream(filename.c_str()); + if (!stream) + { + throw config_error("Could not load map file", 0, filename); + } +// TODO: stream.imbue(loc); + load(stream, node); + } + + void load(std::basic_istream &stream, xml_node &node) + { + stream.unsetf(std::ios::skipws); + std::vector v(std::istreambuf_iterator(stream.rdbuf()), + std::istreambuf_iterator()); + if (!stream.good()) + { + throw config_error("Could not load map file", 0, filename_); + } + v.push_back(0); // zero-terminate + try + { + // Parse using appropriate flags + const int f_tws = rapidxml::parse_normalize_whitespace + | rapidxml::parse_trim_whitespace; + rapidxml::xml_document<> doc; + doc.parse(&v.front()); + + for (rapidxml::xml_node *child = doc.first_node(); + child; child = child->next_sibling()) + { + populate_tree(child, node); + } + } + catch (rapidxml::parse_error &e) + { + long line = static_cast( + std::count(&v.front(), e.where(), '\n') + 1); + throw config_error(e.what(), line, filename_); + } + } + + void load_string(const std::string & buffer, xml_node &node, std::string const & base_path ) + { + +// if (!base_path.empty()) +// { +// boost::filesystem::path path(base_path); +// if (!boost::filesystem::exists(path)) { +// throw config_error(string("Could not locate base_path '") + +// base_path + "': file or directory does not exist"); +// } +// } + + + load(buffer, node); + } +private: + void populate_tree(rapidxml::xml_node *cur_node, xml_node &node) + { + switch (cur_node->type()) + { + case rapidxml::node_element: + { + xml_node &new_node = node.add_child((char *)cur_node->name(), 0, false); + // Copy attributes + for (rapidxml::xml_attribute *attr = cur_node->first_attribute(); + attr; attr = attr->next_attribute()) + { + new_node.add_attribute(attr->name(), attr->value()); + } + + // Copy children + for (rapidxml::xml_node *child = cur_node->first_node(); + child; child = child->next_sibling()) + { + populate_tree(child, new_node); + } + } + break; + + // Data nodes + case rapidxml::node_data: + case rapidxml::node_cdata: + { + std::string trimmed = boost::algorithm::trim_copy(std::string(cur_node->value())); + if (trimmed.empty()) break; //Don't add empty text nodes + node.add_child(trimmed, 0, true); + } + break; + default: + break; + } + } +private: + std::string filename_; +}; + +void read_xml(std::string const & filename, xml_node &node) +{ + rapidxml_loader loader; + loader.load(filename, node); +} +void read_xml_string(std::string const & str, xml_node &node, std::string const & base_path) +{ + rapidxml_loader loader; + loader.load_string(str, node, base_path); +} + +} // end of namespace mapnik diff --git a/src/save_map.cpp b/src/save_map.cpp index 5a5fd50d4..c36554b23 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -91,6 +91,10 @@ public: { set_attr( sym_node, "rasterizer", sym.get_rasterizer() ); } + if ( sym.smooth() != dfl.smooth() || explicit_defaults_ ) + { + set_attr( sym_node, "smooth", sym.smooth() ); + } } void operator () ( line_pattern_symbolizer const& sym ) @@ -125,6 +129,10 @@ public: { set_attr( sym_node, "gamma-method", sym.get_gamma_method() ); } + if ( sym.smooth() != dfl.smooth() || explicit_defaults_ ) + { + set_attr( sym_node, "smooth", sym.smooth() ); + } add_metawriter_attributes(sym_node, sym); } @@ -265,6 +273,10 @@ public: { set_attr( sym_node, "allow-overlap", sym.get_allow_overlap() ); } + if (sym.get_ignore_placement() != dfl.get_ignore_placement() || explicit_defaults_) + { + set_attr( sym_node, "ignore-placement", sym.get_ignore_placement() ); + } if (sym.get_spacing() != dfl.get_spacing() || explicit_defaults_) { set_attr( sym_node, "spacing", sym.get_spacing() ); @@ -631,9 +643,9 @@ void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defau set_attr( layer_node, "srs", layer.srs() ); } - if ( !layer.isActive() || explicit_defaults ) + if ( !layer.active() || explicit_defaults ) { - set_attr/**/( layer_node, "status", layer.isActive() ); + set_attr/**/( layer_node, "status", layer.active() ); } if ( layer.clear_label_cache() || explicit_defaults ) @@ -641,19 +653,19 @@ void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defau set_attr/**/( layer_node, "clear-label-cache", layer.clear_label_cache() ); } - if ( layer.getMinZoom() ) + if ( layer.min_zoom() ) { - set_attr( layer_node, "minzoom", layer.getMinZoom() ); + set_attr( layer_node, "minzoom", layer.min_zoom() ); } - if ( layer.getMaxZoom() != std::numeric_limits::max() ) + if ( layer.max_zoom() != std::numeric_limits::max() ) { - set_attr( layer_node, "maxzoom", layer.getMaxZoom() ); + set_attr( layer_node, "maxzoom", layer.max_zoom() ); } - if ( layer.isQueryable() || explicit_defaults ) + if ( layer.queryable() || explicit_defaults ) { - set_attr( layer_node, "queryable", layer.isQueryable() ); + set_attr( layer_node, "queryable", layer.queryable() ); } if ( layer.cache_features() || explicit_defaults ) @@ -744,14 +756,6 @@ void serialize_map(ptree & pt, Map const & map, bool explicit_defaults) } } - parameters extra_attr = map.get_extra_attributes(); - parameters::const_iterator p_it = extra_attr.begin(); - parameters::const_iterator p_end = extra_attr.end(); - for (; p_it != p_end; ++p_it) - { - set_attr( map_node, p_it->first, p_it->second ); - } - serialize_parameters( map_node, map.get_extra_parameters()); Map::const_style_iterator it = map.styles().begin(); diff --git a/src/svg_parser.cpp b/src/svg_parser.cpp index 2107aa646..e62f45deb 100644 --- a/src/svg_parser.cpp +++ b/src/svg_parser.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "agg_ellipse.h" #include "agg_rounded_rect.h" @@ -225,10 +226,12 @@ void svg_parser::start_element(xmlTextReaderPtr reader) { parse_gradient_stop(reader); } +#ifdef MAPNIK_DEBUG else if (!xmlStrEqual(name, BAD_CAST "svg")) { std::clog << "notice: unhandled svg element: " << name << "\n"; } +#endif } void svg_parser::end_element(xmlTextReaderPtr reader) diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index 9672e95dc..cfcc83902 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -24,6 +24,7 @@ #include #include #include +#include "agg_conv_clip_polyline.h" namespace mapnik { @@ -50,8 +51,12 @@ bool text_symbolizer_helper::next_line_placement() geo_itr_ = geometries_to_process_.begin(); continue; //Reexecute size check } - typedef coord_transform2 path_type; - path_type path(t_, **geo_itr_, prj_trans_); + + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform2 path_type; + clipped_geometry_type clipped(**geo_itr_); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_, clipped, prj_trans_); finder_->clear_placements(); if (points_on_line_) { finder_->find_point_placements(path); @@ -136,9 +141,7 @@ void text_symbolizer_helper::initialize_geometries() largest_box_only = true; if (sym_.get_minimum_path_length() > 0) { - // TODO - find less costly method than fetching full envelope box2d gbox = t_.forward(geom.envelope(), prj_trans_); - if (gbox.width() < sym_.get_minimum_path_length()) { continue; @@ -162,10 +165,13 @@ template void text_symbolizer_helper::initialize_points() { label_placement_enum how_placed = placement_->properties.label_placement; - if (how_placed == LINE_PLACEMENT) { + if (how_placed == LINE_PLACEMENT) + { point_placement_ = false; return; - } else { + } + else + { point_placement_ = true; } @@ -188,14 +194,19 @@ void text_symbolizer_helper::initialize_points() t_.forward(&label_x, &label_y); points_.push_back(std::make_pair(label_x, label_y)); } - } else { + } + else + { if (how_placed == POINT_PLACEMENT) { geom.label_position(&label_x, &label_y); - } else if (how_placed == INTERIOR_PLACEMENT) + } + else if (how_placed == INTERIOR_PLACEMENT) { geom.label_interior_position(&label_x, &label_y); - } else { + } + else + { #ifdef MAPNIK_DEBUG std::cerr << "ERROR: Unknown placement type in initialize_points();\n"; #endif diff --git a/src/text_placements/dummy.cpp b/src/text_placements/dummy.cpp index 36c74597a..989fb542b 100644 --- a/src/text_placements/dummy.cpp +++ b/src/text_placements/dummy.cpp @@ -35,8 +35,7 @@ bool text_placement_info_dummy::next() text_placement_info_ptr text_placements_dummy::get_placement_info( double scale_factor) const { - return text_placement_info_ptr(boost::make_shared( - this, scale_factor)); + return boost::make_shared(this, scale_factor); } } //ns mapnik diff --git a/src/text_placements/list.cpp b/src/text_placements/list.cpp index a9bc7aa83..7aea6812d 100644 --- a/src/text_placements/list.cpp +++ b/src/text_placements/list.cpp @@ -20,9 +20,14 @@ * *****************************************************************************/ +//mapnik #include +#include + +//boost #include + namespace mapnik { @@ -58,8 +63,7 @@ text_symbolizer_properties & text_placements_list::get(unsigned i) text_placement_info_ptr text_placements_list::get_placement_info(double scale_factor) const { - return text_placement_info_ptr( - boost::make_shared(this, scale_factor)); + return boost::make_shared(this, scale_factor); } text_placements_list::text_placements_list() : text_placements(), list_(0) @@ -83,20 +87,19 @@ unsigned text_placements_list::size() const return list_.size(); } -text_placements_ptr text_placements_list::from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets) +text_placements_ptr text_placements_list::from_xml(xml_node const &xml, fontset_map const & fontsets) { using boost::property_tree::ptree; text_placements_list *list = new text_placements_list; text_placements_ptr ptr = text_placements_ptr(list); list->defaults.from_xml(xml, fontsets); - ptree::const_iterator itr = xml.begin(); - ptree::const_iterator end = xml.end(); + xml_node::const_iterator itr = xml.begin(); + xml_node::const_iterator end = xml.end(); for( ;itr != end; ++itr) { - if ((itr->first.find('<') != std::string::npos) || (itr->first != "Placement")) continue; -//TODO: ensure_attrs(symIter->second, "TextSymbolizer/Placement", s_common.str()); + if (itr->is_text() || !itr->is("Placement")) continue; text_symbolizer_properties &p = list->add(); - p.from_xml(itr->second, fontsets); + p.from_xml(*itr, fontsets); //TODO: if (strict_ && // !p.format.fontset.size()) // ensure_font_face(p.format.face_name); diff --git a/src/text_placements/registry.cpp b/src/text_placements/registry.cpp index 30668b78f..cf12b6213 100644 --- a/src/text_placements/registry.cpp +++ b/src/text_placements/registry.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include namespace mapnik { @@ -33,6 +35,7 @@ registry::registry() { register_name("simple", &text_placements_simple::from_xml); register_name("list", &text_placements_list::from_xml); + register_name("dummy", &text_placements_list::from_xml); } void registry::register_name(std::string name, from_xml_function_ptr ptr, bool overwrite) @@ -44,10 +47,10 @@ void registry::register_name(std::string name, from_xml_function_ptr ptr, bool o } } -text_placements_ptr registry::from_xml(std::string name, const boost::property_tree::ptree &xml, fontset_map const& fontsets) +text_placements_ptr registry::from_xml(std::string name, xml_node const& xml, fontset_map const& fontsets) { std::map::const_iterator itr = map_.find(name); - if (itr == map_.end()) throw config_error("Unknown placement-type '" + name + "'"); + if (itr == map_.end()) throw config_error("Unknown placement-type '" + name + "'", xml); return itr->second(xml, fontsets); } } //ns formatting diff --git a/src/text_placements/simple.cpp b/src/text_placements/simple.cpp index 598082e55..cefa199fa 100644 --- a/src/text_placements/simple.cpp +++ b/src/text_placements/simple.cpp @@ -23,6 +23,7 @@ // mapnik #include #include +#include // boost #include @@ -102,8 +103,7 @@ bool text_placement_info_simple::next_position_only() text_placement_info_ptr text_placements_simple::get_placement_info( double scale_factor) const { - return text_placement_info_ptr( - boost::make_shared(this, scale_factor)); + return boost::make_shared(this, scale_factor); } /** Position string: [POS][SIZE] @@ -144,10 +144,12 @@ void text_placements_simple::set_positions(std::string positions) (direction_name[push_back(phoenix::ref(direction_), _1)] % ',') >> *(',' >> qi::float_[push_back(phoenix::ref(text_sizes_), _1)]), space ); - if (first != last) { + if (first != last) + { std::cerr << "WARNING: Could not parse text_placement_simple placement string ('" << positions << "').\n"; } - if (direction_.size() == 0) { + if (direction_.size() == 0) + { std::cerr << "WARNING: text_placements_simple with no valid placements! ('"<< positions<<"')\n"; } } @@ -167,10 +169,10 @@ std::string text_placements_simple::get_positions() return positions_; //TODO: Build string from data in direction_ and text_sizes_ } -text_placements_ptr text_placements_simple::from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets) +text_placements_ptr text_placements_simple::from_xml(xml_node const &xml, fontset_map const & fontsets) { - text_placements_ptr ptr = text_placements_ptr(boost::make_shared( - get_attr(xml, "placements", "X"))); + text_placements_ptr ptr = boost::make_shared( + xml.get_attr("placements", "X")); ptr->defaults.from_xml(xml, fontsets); return ptr; } diff --git a/src/text_properties.cpp b/src/text_properties.cpp index 6b1e45ce8..89e4ee6cd 100644 --- a/src/text_properties.cpp +++ b/src/text_properties.cpp @@ -25,6 +25,11 @@ #include #include #include +#include +#include + +// boost +#include namespace mapnik { @@ -35,7 +40,7 @@ text_symbolizer_properties::text_symbolizer_properties() : displacement(0,0), label_placement(POINT_PLACEMENT), halign(H_AUTO), - jalign(J_MIDDLE), + jalign(J_AUTO), valign(V_AUTO), label_spacing(0), label_position_tolerance(0), @@ -76,45 +81,45 @@ formatting::node_ptr text_symbolizer_properties::format_tree() const return tree_; } -void text_symbolizer_properties::from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets) +void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const & fontsets) { - optional placement_ = get_opt_attr(sym, "placement"); + optional placement_ = sym.get_opt_attr("placement"); if (placement_) label_placement = *placement_; - optional valign_ = get_opt_attr(sym, "vertical-alignment"); + optional valign_ = sym.get_opt_attr("vertical-alignment"); if (valign_) valign = *valign_; - optional text_ratio_ = get_opt_attr(sym, "text-ratio"); + optional text_ratio_ = sym.get_opt_attr("text-ratio"); if (text_ratio_) text_ratio = *text_ratio_; - optional wrap_width_ = get_opt_attr(sym, "wrap-width"); + optional wrap_width_ = sym.get_opt_attr("wrap-width"); if (wrap_width_) wrap_width = *wrap_width_; - optional label_position_tolerance_ = get_opt_attr(sym, "label-position-tolerance"); + optional label_position_tolerance_ = sym.get_opt_attr("label-position-tolerance"); if (label_position_tolerance_) label_position_tolerance = *label_position_tolerance_; - optional spacing_ = get_opt_attr(sym, "spacing"); + optional spacing_ = sym.get_opt_attr("spacing"); if (spacing_) label_spacing = *spacing_; - optional minimum_distance_ = get_opt_attr(sym, "minimum-distance"); + optional minimum_distance_ = sym.get_opt_attr("minimum-distance"); if (minimum_distance_) minimum_distance = *minimum_distance_; - optional min_padding_ = get_opt_attr(sym, "minimum-padding"); + optional min_padding_ = sym.get_opt_attr("minimum-padding"); if (min_padding_) minimum_padding = *min_padding_; - optional min_path_length_ = get_opt_attr(sym, "minimum-path-length"); + optional min_path_length_ = sym.get_opt_attr("minimum-path-length"); if (min_path_length_) minimum_path_length = *min_path_length_; - optional avoid_edges_ = get_opt_attr(sym, "avoid-edges"); + optional avoid_edges_ = sym.get_opt_attr("avoid-edges"); if (avoid_edges_) avoid_edges = *avoid_edges_; - optional allow_overlap_ = get_opt_attr(sym, "allow-overlap"); + optional allow_overlap_ = sym.get_opt_attr("allow-overlap"); if (allow_overlap_) allow_overlap = *allow_overlap_; - optional halign_ = get_opt_attr(sym, "horizontal-alignment"); + optional halign_ = sym.get_opt_attr("horizontal-alignment"); if (halign_) halign = *halign_; - optional jalign_ = get_opt_attr(sym, "justify-alignment"); + optional jalign_ = sym.get_opt_attr("justify-alignment"); if (jalign_) jalign = *jalign_; /* Attributes needing special care */ - optional orientation_ = get_opt_attr(sym, "orientation"); + optional orientation_ = sym.get_opt_attr("orientation"); if (orientation_) orientation = parse_expression(*orientation_, "utf8"); - optional dx = get_opt_attr(sym, "dx"); + optional dx = sym.get_opt_attr("dx"); if (dx) displacement.first = *dx; - optional dy = get_opt_attr(sym, "dy"); + optional dy = sym.get_opt_attr("dy"); if (dy) displacement.second = *dy; - optional max_char_angle_delta_ = get_opt_attr(sym, "max-char-angle-delta"); + optional max_char_angle_delta_ = sym.get_opt_attr("max-char-angle-delta"); if (max_char_angle_delta_) max_char_angle_delta=(*max_char_angle_delta_)*(M_PI/180); - optional name_ = get_opt_attr(sym, "name"); + optional name_ = sym.get_opt_attr("name"); if (name_) { std::clog << "### WARNING: Using 'name' in TextSymbolizer/ShieldSymbolizer is deprecated!\n"; set_old_style_expression(parse_expression(*name_, "utf8")); @@ -218,7 +223,7 @@ void text_symbolizer_properties::add_expressions(expression_set &output) const void text_symbolizer_properties::set_old_style_expression(expression_ptr expr) { - tree_ = formatting::node_ptr(new formatting::text_node(expr)); + tree_ = boost::make_shared(expr); } char_properties::char_properties() : @@ -238,34 +243,34 @@ char_properties::char_properties() : } -void char_properties::from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets) +void char_properties::from_xml(xml_node const& sym, fontset_map const& fontsets) { - optional text_size_ = get_opt_attr(sym, "size"); + optional text_size_ = sym.get_opt_attr("size"); if (text_size_) text_size = *text_size_; - optional character_spacing_ = get_opt_attr(sym, "character-spacing"); + optional character_spacing_ = sym.get_opt_attr("character-spacing"); if (character_spacing_) character_spacing = *character_spacing_; - optional fill_ = get_opt_attr(sym, "fill"); + optional fill_ = sym.get_opt_attr("fill"); if (fill_) fill = *fill_; - optional halo_fill_ = get_opt_attr(sym, "halo-fill"); + optional halo_fill_ = sym.get_opt_attr("halo-fill"); if (halo_fill_) halo_fill = *halo_fill_; - optional halo_radius_ = get_opt_attr(sym, "halo-radius"); + optional halo_radius_ = sym.get_opt_attr("halo-radius"); if (halo_radius_) halo_radius = *halo_radius_; - optional wrap_before_ = get_opt_attr(sym, "wrap-before"); + optional wrap_before_ = sym.get_opt_attr("wrap-before"); if (wrap_before_) wrap_before = *wrap_before_; - optional tconvert_ = get_opt_attr(sym, "text-transform"); + optional tconvert_ = sym.get_opt_attr("text-transform"); if (tconvert_) text_transform = *tconvert_; - optional line_spacing_ = get_opt_attr(sym, "line-spacing"); + optional line_spacing_ = sym.get_opt_attr("line-spacing"); if (line_spacing_) line_spacing = *line_spacing_; - optional opacity_ = get_opt_attr(sym, "opacity"); + optional opacity_ = sym.get_opt_attr("opacity"); if (opacity_) text_opacity = *opacity_; - optional wrap_char_ = get_opt_attr(sym, "wrap-character"); + optional wrap_char_ = sym.get_opt_attr("wrap-character"); if (wrap_char_ && (*wrap_char_).size() > 0) wrap_char = ((*wrap_char_)[0]); - optional face_name_ = get_opt_attr(sym, "face-name"); + optional face_name_ = sym.get_opt_attr("face-name"); if (face_name_) { face_name = *face_name_; } - optional fontset_name_ = get_opt_attr(sym, "fontset-name"); + optional fontset_name_ = sym.get_opt_attr("fontset-name"); if (fontset_name_) { std::map::const_iterator itr = fontsets.find(*fontset_name_); if (itr != fontsets.end()) @@ -274,16 +279,16 @@ void char_properties::from_xml(boost::property_tree::ptree const &sym, fontset_m } else { - throw config_error("Unable to find any fontset named '" + *fontset_name_ + "'"); + throw config_error("Unable to find any fontset named '" + *fontset_name_ + "'", sym); } } if (!face_name.empty() && !fontset.get_name().empty()) { - throw config_error(std::string("Can't have both face-name and fontset-name")); + throw config_error("Can't have both face-name and fontset-name", sym); } if (face_name.empty() && fontset.get_name().empty()) { - throw config_error(std::string("Must have face-name or fontset-name")); + throw config_error("Must have face-name or fontset-name", sym); } } diff --git a/src/text_symbolizer.cpp b/src/text_symbolizer.cpp index c060e43d1..75e76849b 100644 --- a/src/text_symbolizer.cpp +++ b/src/text_symbolizer.cpp @@ -69,6 +69,7 @@ static const char * justify_alignment_strings[] = { "left", "center", "right", + "auto", "" }; diff --git a/src/xml_tree.cpp b/src/xml_tree.cpp new file mode 100644 index 000000000..36995166f --- /dev/null +++ b/src/xml_tree.cpp @@ -0,0 +1,483 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +//mapnik +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//boost +#include + +namespace mapnik +{ + +template +inline boost::optional fast_cast(xml_tree const& tree, std::string const& value) +{ + try + { + return boost::lexical_cast(value); + } + catch (boost::bad_lexical_cast const& ex) + { + return boost::optional(); + } +} + +template <> +inline boost::optional fast_cast(xml_tree const& tree, std::string const& value) +{ + int result; + if (mapnik::util::string2int(value, result)) + return boost::optional(result); + return boost::optional(); +} + +template <> +inline boost::optional fast_cast(xml_tree const& tree, std::string const& value) +{ + double result; + if (mapnik::util::string2double(value, result)) + return boost::optional(result); + return boost::optional(); +} + +template <> +inline boost::optional fast_cast(xml_tree const& tree, std::string const& value) +{ + float result; + if (mapnik::util::string2float(value, result)) + return boost::optional(result); + return boost::optional(); +} + +template <> +inline boost::optional fast_cast(xml_tree const& tree, std::string const& value) +{ + return value; +} + +template <> +inline boost::optional fast_cast(xml_tree const& tree, std::string const& value) +{ + mapnik::color c; + if (mapnik::color_factory::parse_from_string(c, value, tree.color_grammar)) + { + return c; + } + else + { + throw config_error("Failed to parse color '"+value+"'"); + } +} + +template <> +inline boost::optional fast_cast(xml_tree const& tree, std::string const& value) +{ + expression_ptr expr(boost::make_shared(true)); + if (expression_factory::parse_from_string(expr, value, tree.expr_grammar)) + { + return expr; + } else + { + throw mapnik::config_error("Failed to parse expression '" + value + "'"); + } +} + +/****************************************************************************/ + +class boolean; +template +struct name_trait +{ + static std::string name() + { + return ""; + } + // missing name_trait for type ... + // if you get here you are probably using a new type + // in the XML file. Just add a name trait for the new + // type below. + BOOST_STATIC_ASSERT( sizeof(T) == 0 ); +}; + +#define DEFINE_NAME_TRAIT( type, type_name ) \ + template <> \ + struct name_trait \ + { \ + static std::string name() { return std::string("type ") + type_name; } \ + }; + + +DEFINE_NAME_TRAIT( double, "double") +DEFINE_NAME_TRAIT( float, "float") +DEFINE_NAME_TRAIT( unsigned, "unsigned") +DEFINE_NAME_TRAIT( boolean, "boolean") +DEFINE_NAME_TRAIT( int, "integer" ) +DEFINE_NAME_TRAIT( std::string, "string" ) +DEFINE_NAME_TRAIT( color, "color" ) +DEFINE_NAME_TRAIT(expression_ptr, "expression_ptr" ) + +template +struct name_trait< mapnik::enumeration > +{ + typedef enumeration Enum; + + static std::string name() + { + std::string value_list("one of ["); + for (unsigned i = 0; i < Enum::MAX; ++i) + { + value_list += Enum::get_string( i ); + if ( i + 1 < Enum::MAX ) value_list += ", "; + } + value_list += "]"; + + return value_list; + } +}; + +/****************************************************************************/ + +xml_tree::xml_tree(std::string const& encoding) + : node_(*this, ""), + file_(), + tr_(encoding), + color_grammar(), + expr_grammar(tr_) +{ + node_.set_processed(true); //root node is always processed +} + +void xml_tree::set_filename(std::string fn) +{ + file_ = fn; +} + +std::string const& xml_tree::filename() const +{ + return file_; +} + +xml_node &xml_tree::root() +{ + return node_; +} + +/****************************************************************************/ +xml_attribute::xml_attribute(std::string const& value_) + : value(value_), processed(false) +{ + +} + +/****************************************************************************/ + +node_not_found::node_not_found(std::string node_name) + : node_name_(node_name) +{ + +} + +const char* node_not_found::what() const throw() +{ + return ("Node "+node_name_+ "not found").c_str(); +} + +node_not_found::~node_not_found() throw() +{ + +} + + +attribute_not_found::attribute_not_found( + std::string const& node_name, + std::string const& attribute_name) + : + node_name_(node_name), + attribute_name_(attribute_name) +{ + +} + +const char* attribute_not_found::what() const throw() +{ + return ("Attribute '" + attribute_name_ +"' not found in node '"+node_name_+ "'").c_str(); +} + +attribute_not_found::~attribute_not_found() throw() +{ + +} + +more_than_one_child::more_than_one_child(std::string const& node_name) + : node_name_(node_name) +{ + +} + +const char* more_than_one_child::what() const throw() +{ + return ("More than one child node in node '" + node_name_ +"'").c_str(); +} + +more_than_one_child::~more_than_one_child() throw() +{ + +} + +/****************************************************************************/ + +xml_node::xml_node(xml_tree &tree, std::string name, unsigned line, bool text_node) + : tree_(tree), + name_(name), + text_node_(text_node), + line_(line), + processed_(false) +{ + +} + +std::string xml_node::xml_text = ""; + +std::string const& xml_node::name() const +{ + if (!text_node_) + return name_; + else + return xml_text; +} + +std::string const& xml_node::text() const +{ + if (text_node_) + { + processed_ = true; + return name_; + } else + { + throw config_error("text() called on non-text node", *this); + } +} + +std::string const& xml_node::filename() const +{ + return tree_.filename(); +} + +bool xml_node::is_text() const +{ + return text_node_; +} + +bool xml_node::is(std::string const& name) const +{ + if (name_ == name) + { + processed_ = true; + return true; + } + return false; +} + +xml_node &xml_node::add_child(std::string const& name, unsigned line, bool text_node) +{ + children_.push_back(xml_node(tree_, name, line, text_node)); + return children_.back(); +} + +void xml_node::add_attribute(std::string const& name, std::string const& value) +{ + attributes_.insert(std::make_pair(name,xml_attribute(value))); +} + +xml_node::attribute_map const& xml_node::get_attributes() const +{ + return attributes_; +} + +void xml_node::set_processed(bool processed) const +{ + processed_ = processed; +} + +bool xml_node::processed() const +{ + return processed_; +} + +xml_node::const_iterator xml_node::begin() const +{ + return children_.begin(); +} + +xml_node::const_iterator xml_node::end() const +{ + return children_.end(); +} + +xml_node & xml_node::get_child(std::string const& name) +{ + std::list::iterator itr = children_.begin(); + std::list::iterator end = children_.end(); + for (; itr != end; itr++) + { + if (!(itr->text_node_) && itr->name_ == name) + { + itr->set_processed(true); + return *itr; + } + } + throw node_not_found(name); +} + +xml_node const& xml_node::get_child(std::string const& name) const +{ + xml_node const* node = get_opt_child(name); + if (!node) throw node_not_found(name); + return *node; +} + +xml_node const* xml_node::get_opt_child(std::string const& name) const +{ + const_iterator itr = children_.begin(); + const_iterator end = children_.end(); + for (; itr != end; itr++) + { + if (!(itr->text_node_) && itr->name_ == name) + { + itr->set_processed(true); + return &(*itr); + } + } + return 0; +} + +bool xml_node::has_child(std::string const& name) const +{ + return get_opt_child(name) != 0; +} + +template +boost::optional xml_node::get_opt_attr(std::string const& name) const +{ + std::map::const_iterator itr = attributes_.find(name); + if (itr == attributes_.end()) return boost::optional(); + itr->second.processed = true; + boost::optional result = fast_cast(tree_, itr->second.value); + if (!result) + { + throw config_error(std::string("Failed to parse attribute '") + + name + "'. Expected " + name_trait::name() + + " but got '" + itr->second.value + "'", *this); + } + return result; +} + +template +T xml_node::get_attr(std::string const& name, T const& default_value) const +{ + boost::optional value = get_opt_attr(name); + if (value) return *value; + return default_value; +} + +template +T xml_node::get_attr(std::string const& name) const +{ + boost::optional value = get_opt_attr(name); + if (value) return *value; + throw attribute_not_found(name_, name); +} + +std::string xml_node::get_text() const +{ + if (children_.size() == 0) + { + return ""; + } + if (children_.size() == 1) + { + return children_.front().text(); + } + throw more_than_one_child(name_); +} + + +template +T xml_node::get_value() const +{ + boost::optional result = fast_cast(tree_, get_text()); + if (!result) + { + throw config_error(std::string("Failed to parse value. Expected ") + + name_trait::name() + + " but got '" + get_text() + "'", *this); + } + return *result; +} + +unsigned xml_node::line() const +{ + return line_; +} + +#define compile_get_opt_attr(T) template boost::optional xml_node::get_opt_attr(std::string const&) const +#define compile_get_attr(T) template T xml_node::get_attr(std::string const&) const; template T xml_node::get_attr(std::string const&, T const&) const +#define compile_get_value(T) template T xml_node::get_value() const + +compile_get_opt_attr(boolean); +compile_get_opt_attr(std::string); +compile_get_opt_attr(unsigned); +compile_get_opt_attr(float); +compile_get_opt_attr(double); +compile_get_opt_attr(color); +compile_get_opt_attr(gamma_method_e); +compile_get_opt_attr(line_rasterizer_e); +compile_get_opt_attr(line_join_e); +compile_get_opt_attr(line_cap_e); +compile_get_opt_attr(text_transform_e); +compile_get_opt_attr(label_placement_e); +compile_get_opt_attr(vertical_alignment_e); +compile_get_opt_attr(horizontal_alignment_e); +compile_get_opt_attr(justify_alignment_e); +compile_get_opt_attr(expression_ptr); +compile_get_attr(std::string); +compile_get_attr(filter_mode_e); +compile_get_attr(point_placement_e); +compile_get_attr(marker_placement_e); +compile_get_attr(marker_type_e); +compile_get_attr(pattern_alignment_e); +compile_get_attr(line_rasterizer_e); +compile_get_attr(colorizer_mode); +compile_get_attr(double); +compile_get_value(int); +compile_get_value(double); +compile_get_value(expression_ptr); +} //ns mapnik diff --git a/tests/cpp_tests/build.py b/tests/cpp_tests/build.py index 11cd33f45..bcc31bc94 100644 --- a/tests/cpp_tests/build.py +++ b/tests/cpp_tests/build.py @@ -11,6 +11,8 @@ headers = env['CPPPATH'] libraries = copy(env['LIBMAPNIK_LIBS']) libraries.append('mapnik') +test_env.Append(CXXFLAGS='-g') + for cpp_test in glob.glob('*_test.cpp'): test_program = test_env.Program(cpp_test.replace('.cpp',''), [cpp_test], CPPPATH=headers, LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS']) Depends(test_program, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME'])) diff --git a/tests/cpp_tests/font_registration_test.cpp b/tests/cpp_tests/font_registration_test.cpp index 1906d896b..55715b9b1 100644 --- a/tests/cpp_tests/font_registration_test.cpp +++ b/tests/cpp_tests/font_registration_test.cpp @@ -6,8 +6,6 @@ using fs::path; namespace sys = boost::system; #include -//#include -//#include #include #include @@ -39,14 +37,23 @@ int main( int, char*[] ) // directories without fonts std::string src("src"); - // a legitimate directory will return true even it is does not - // successfully register a font... - BOOST_TEST( mapnik::freetype_engine::register_fonts(src , true ) ); - face_names = mapnik::freetype_engine::face_names(); - BOOST_TEST( face_names.size() == 0 ); - std::clog << "number of registered fonts: " << face_names.size() << std::endl; + // an empty directory will not return true + // we need to register at least one font and not fail on any + // to return true + BOOST_TEST( mapnik::freetype_engine::register_font(src) == false ); + BOOST_TEST( mapnik::freetype_engine::register_fonts(src, true) == false ); + BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 ); - // register unifont + // bogus, emtpy file that looks like font + BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/fake.ttf") == false ); + BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/fake.ttf") == false ); + BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 ); + + BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/intentionally-broken.ttf") == false ); + BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/intentionally-broken.ttf") == false ); + BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 ); + + // register unifont, since we know it sits in the root fonts/ dir BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir) ); face_names = mapnik::freetype_engine::face_names(); std::clog << "number of registered fonts: " << face_names.size() << std::endl; @@ -71,7 +78,7 @@ int main( int, char*[] ) BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir, true) ); face_names = mapnik::freetype_engine::face_names(); std::clog << "number of registered fonts: " << face_names.size() << std::endl; - BOOST_TEST( face_names.size() == 21 ); + BOOST_TEST( face_names.size() == 22 ); return ::boost::report_errors(); } diff --git a/tests/cpp_tests/params_test.cpp b/tests/cpp_tests/params_test.cpp new file mode 100644 index 000000000..86e702366 --- /dev/null +++ b/tests/cpp_tests/params_test.cpp @@ -0,0 +1,57 @@ + +#include +#include +#include +#include + +int main( int, char*[] ) +{ + + mapnik::parameters params; + + // true + params["bool"] = true; + BOOST_TEST( (params.get("bool") && *params.get("bool") == true)); + + params["bool"] = "true"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == true)); + + params["bool"] = 1; + BOOST_TEST( (params.get("bool") && *params.get("bool") == true)); + + params["bool"] = "1"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == true)); + + params["bool"] = "True"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == true)); + + params["bool"] = "on"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == true)); + + params["bool"] = "yes"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == true)); + + // false + params["bool"] = false; + BOOST_TEST( (params.get("bool") && *params.get("bool") == false) ); + + params["bool"] = "false"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == false) ); + + params["bool"] = 0; + BOOST_TEST( (params.get("bool") && *params.get("bool") == false)); + + params["bool"] = "0"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == false)); + + params["bool"] = "False"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == false)); + + params["bool"] = "off"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == false)); + + params["bool"] = "no"; + BOOST_TEST( (params.get("bool") && *params.get("bool") == false)); + + return ::boost::report_errors(); +} diff --git a/tests/data/fonts/fake.ttf b/tests/data/fonts/fake.ttf new file mode 100644 index 000000000..e69de29bb diff --git a/tests/data/fonts/intentionally-broken.ttf b/tests/data/fonts/intentionally-broken.ttf new file mode 100644 index 000000000..887230d76 Binary files /dev/null and b/tests/data/fonts/intentionally-broken.ttf differ diff --git a/tests/data/good_maps/extra_known_map_attributes.xml b/tests/data/good_maps/extra_known_map_attributes.xml index 38fa59661..0c88449a8 100644 --- a/tests/data/good_maps/extra_known_map_attributes.xml +++ b/tests/data/good_maps/extra_known_map_attributes.xml @@ -1,11 +1,13 @@ - + \ No newline at end of file diff --git a/tests/data/good_maps/rtl_text_map.xml b/tests/data/good_maps/rtl_text_map.xml index 3892c69af..38f46aca1 100644 --- a/tests/data/good_maps/rtl_text_map.xml +++ b/tests/data/good_maps/rtl_text_map.xml @@ -1,5 +1,7 @@ - + + + diff --git a/tests/python_tests/osm_test.py b/tests/python_tests/osm_test.py index ae063e6f3..91ad2a1ed 100644 --- a/tests/python_tests/osm_test.py +++ b/tests/python_tests/osm_test.py @@ -20,10 +20,10 @@ if 'osm' in mapnik.DatasourceCache.instance().plugin_names(): e = ds.envelope() # these are hardcoded in the plugin… ugh - assert_almost_equal(e.minx, -180.0) - assert_almost_equal(e.miny, -90.0) - assert_almost_equal(e.maxx, 180.0) - assert_almost_equal(e.maxy, 90) + eq_(e.minx >= -180.0,True) + eq_(e.miny >= -90.0,True) + eq_(e.maxx <= 180.0,True) + eq_(e.maxy <= 90,True) @raises(RuntimeError) def test_that_nonexistant_query_field_throws(**kwargs): diff --git a/tests/python_tests/parameters_test.py b/tests/python_tests/parameters_test.py index f4a774df9..7fcb483fb 100644 --- a/tests/python_tests/parameters_test.py +++ b/tests/python_tests/parameters_test.py @@ -24,6 +24,11 @@ def test_parameter(): eq_(p[0],'float') eq_(p[1],1.0777) + p = mapnik.Parameter('bool_string','True') + eq_(p[0],'bool_string') + eq_(p[1],'True') + eq_(bool(p[1]),True) + def test_parameters(): params = mapnik.Parameters() diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index 2bf8ec2d4..140f97c9d 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -57,6 +57,8 @@ def create_grid_map(width,height): s = mapnik.Style() r = mapnik.Rule() symb = mapnik.MarkersSymbolizer() + symb.width = 10 + symb.height = 10 symb.allow_overlap = True r.symbols.append(symb) diff --git a/tests/python_tests/render_test.py b/tests/python_tests/render_test.py index 131906a6d..cb1f19be7 100644 --- a/tests/python_tests/render_test.py +++ b/tests/python_tests/render_test.py @@ -146,6 +146,8 @@ def test_render_grid(): s = mapnik.Style() r = mapnik.Rule() symb = mapnik.MarkersSymbolizer() + symb.width = 10 + symb.height = 10 symb.allow_overlap = True r.symbols.append(symb) s.rules.append(r) diff --git a/tests/visual_tests/clean.sh b/tests/visual_tests/clean.sh index ba31ecae5..1278159f4 100755 --- a/tests/visual_tests/clean.sh +++ b/tests/visual_tests/clean.sh @@ -1,3 +1,3 @@ -rm -f *-agg.png -rm -f *-out.xml +rm -f images/*-agg.png +rm -f xml_output/*-out.xml diff --git a/tests/visual_tests/compare.py b/tests/visual_tests/compare.py index 21a627d99..46bba923e 100644 --- a/tests/visual_tests/compare.py +++ b/tests/visual_tests/compare.py @@ -1,4 +1,4 @@ -import math, operator +#import math, operator import Image import sys @@ -27,6 +27,10 @@ def compare(fn1, fn2): return -1 diff = 0 pixels = im1.size[0] * im1.size[1] + delta_pixels = im2.size[0] * im2.size[1] - pixels + if delta_pixels != 0: + errors.append((fn1, delta_pixels)) + return delta_pixels im1 = im1.getdata() im2 = im2.getdata() for i in range(3, pixels - 1, 3): @@ -38,9 +42,9 @@ def compare(fn1, fn2): def summary(): global errors + print "-"*80 + print "Summary:" if len(errors) != 0: - print "-"*80 - print "Summary:" for error in errors: if (error[1] is None): print "Could not verify %s: No reference image found!" % error[0] @@ -48,3 +52,7 @@ def summary(): print "%s failed: %d different pixels" % error print "-"*80 sys.exit(1) + else: + print 'No errors detected!' + print "-"*80 + sys.exit(0) diff --git a/tests/visual_tests/data/line-offset.osm b/tests/visual_tests/data/line-offset.osm new file mode 100644 index 000000000..9a568dc30 --- /dev/null +++ b/tests/visual_tests/data/line-offset.osm @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/visual_tests/lines.osm b/tests/visual_tests/data/lines.osm similarity index 100% rename from tests/visual_tests/lines.osm rename to tests/visual_tests/data/lines.osm diff --git a/tests/visual_tests/points.dbf b/tests/visual_tests/data/points.dbf similarity index 100% rename from tests/visual_tests/points.dbf rename to tests/visual_tests/data/points.dbf diff --git a/tests/visual_tests/points.osm b/tests/visual_tests/data/points.osm similarity index 100% rename from tests/visual_tests/points.osm rename to tests/visual_tests/data/points.osm diff --git a/tests/visual_tests/points.shp b/tests/visual_tests/data/points.shp similarity index 100% rename from tests/visual_tests/points.shp rename to tests/visual_tests/data/points.shp diff --git a/tests/visual_tests/expressionformat-500-reference.png b/tests/visual_tests/images/expressionformat-500-reference.png similarity index 100% rename from tests/visual_tests/expressionformat-500-reference.png rename to tests/visual_tests/images/expressionformat-500-reference.png diff --git a/tests/visual_tests/formating-500-reference.png b/tests/visual_tests/images/formating-500-reference.png similarity index 100% rename from tests/visual_tests/formating-500-reference.png rename to tests/visual_tests/images/formating-500-reference.png diff --git a/tests/visual_tests/formating-1-500-reference.png b/tests/visual_tests/images/formatting-1-500-reference.png similarity index 100% rename from tests/visual_tests/formating-1-500-reference.png rename to tests/visual_tests/images/formatting-1-500-reference.png diff --git a/tests/visual_tests/formating-2-500-reference.png b/tests/visual_tests/images/formatting-2-500-reference.png similarity index 100% rename from tests/visual_tests/formating-2-500-reference.png rename to tests/visual_tests/images/formatting-2-500-reference.png diff --git a/tests/visual_tests/formating-3-500-reference.png b/tests/visual_tests/images/formatting-3-500-reference.png similarity index 100% rename from tests/visual_tests/formating-3-500-reference.png rename to tests/visual_tests/images/formatting-3-500-reference.png diff --git a/tests/visual_tests/formating-4-500-reference.png b/tests/visual_tests/images/formatting-4-500-reference.png similarity index 100% rename from tests/visual_tests/formating-4-500-reference.png rename to tests/visual_tests/images/formatting-4-500-reference.png diff --git a/tests/visual_tests/images/jalign-auto-200-reference.png b/tests/visual_tests/images/jalign-auto-200-reference.png new file mode 100644 index 000000000..6acf39cdc Binary files /dev/null and b/tests/visual_tests/images/jalign-auto-200-reference.png differ diff --git a/tests/visual_tests/images/line-offset-900-reference.png b/tests/visual_tests/images/line-offset-900-reference.png new file mode 100644 index 000000000..37f3c4b6e Binary files /dev/null and b/tests/visual_tests/images/line-offset-900-reference.png differ diff --git a/tests/visual_tests/lines-1-200-reference.png b/tests/visual_tests/images/lines-1-200-reference.png similarity index 100% rename from tests/visual_tests/lines-1-200-reference.png rename to tests/visual_tests/images/lines-1-200-reference.png diff --git a/tests/visual_tests/lines-1-400-reference.png b/tests/visual_tests/images/lines-1-400-reference.png similarity index 100% rename from tests/visual_tests/lines-1-400-reference.png rename to tests/visual_tests/images/lines-1-400-reference.png diff --git a/tests/visual_tests/lines-1-600-reference.png b/tests/visual_tests/images/lines-1-600-reference.png similarity index 100% rename from tests/visual_tests/lines-1-600-reference.png rename to tests/visual_tests/images/lines-1-600-reference.png diff --git a/tests/visual_tests/lines-1-800-reference.png b/tests/visual_tests/images/lines-1-800-reference.png similarity index 100% rename from tests/visual_tests/lines-1-800-reference.png rename to tests/visual_tests/images/lines-1-800-reference.png diff --git a/tests/visual_tests/lines-2-200-reference.png b/tests/visual_tests/images/lines-2-200-reference.png similarity index 100% rename from tests/visual_tests/lines-2-200-reference.png rename to tests/visual_tests/images/lines-2-200-reference.png diff --git a/tests/visual_tests/lines-2-400-reference.png b/tests/visual_tests/images/lines-2-400-reference.png similarity index 100% rename from tests/visual_tests/lines-2-400-reference.png rename to tests/visual_tests/images/lines-2-400-reference.png diff --git a/tests/visual_tests/lines-2-600-reference.png b/tests/visual_tests/images/lines-2-600-reference.png similarity index 100% rename from tests/visual_tests/lines-2-600-reference.png rename to tests/visual_tests/images/lines-2-600-reference.png diff --git a/tests/visual_tests/lines-2-800-reference.png b/tests/visual_tests/images/lines-2-800-reference.png similarity index 100% rename from tests/visual_tests/lines-2-800-reference.png rename to tests/visual_tests/images/lines-2-800-reference.png diff --git a/tests/visual_tests/lines-3-200-reference.png b/tests/visual_tests/images/lines-3-200-reference.png similarity index 100% rename from tests/visual_tests/lines-3-200-reference.png rename to tests/visual_tests/images/lines-3-200-reference.png diff --git a/tests/visual_tests/lines-3-400-reference.png b/tests/visual_tests/images/lines-3-400-reference.png similarity index 100% rename from tests/visual_tests/lines-3-400-reference.png rename to tests/visual_tests/images/lines-3-400-reference.png diff --git a/tests/visual_tests/lines-3-600-reference.png b/tests/visual_tests/images/lines-3-600-reference.png similarity index 100% rename from tests/visual_tests/lines-3-600-reference.png rename to tests/visual_tests/images/lines-3-600-reference.png diff --git a/tests/visual_tests/lines-3-800-reference.png b/tests/visual_tests/images/lines-3-800-reference.png similarity index 100% rename from tests/visual_tests/lines-3-800-reference.png rename to tests/visual_tests/images/lines-3-800-reference.png diff --git a/tests/visual_tests/lines-shield-200-reference.png b/tests/visual_tests/images/lines-shield-200-reference.png similarity index 100% rename from tests/visual_tests/lines-shield-200-reference.png rename to tests/visual_tests/images/lines-shield-200-reference.png diff --git a/tests/visual_tests/lines-shield-400-reference.png b/tests/visual_tests/images/lines-shield-400-reference.png similarity index 100% rename from tests/visual_tests/lines-shield-400-reference.png rename to tests/visual_tests/images/lines-shield-400-reference.png diff --git a/tests/visual_tests/lines-shield-600-reference.png b/tests/visual_tests/images/lines-shield-600-reference.png similarity index 100% rename from tests/visual_tests/lines-shield-600-reference.png rename to tests/visual_tests/images/lines-shield-600-reference.png diff --git a/tests/visual_tests/lines-shield-800-reference.png b/tests/visual_tests/images/lines-shield-800-reference.png similarity index 100% rename from tests/visual_tests/lines-shield-800-reference.png rename to tests/visual_tests/images/lines-shield-800-reference.png diff --git a/tests/visual_tests/list-100-reference.png b/tests/visual_tests/images/list-100-reference.png similarity index 100% rename from tests/visual_tests/list-100-reference.png rename to tests/visual_tests/images/list-100-reference.png diff --git a/tests/visual_tests/list-150-reference.png b/tests/visual_tests/images/list-150-reference.png similarity index 100% rename from tests/visual_tests/list-150-reference.png rename to tests/visual_tests/images/list-150-reference.png diff --git a/tests/visual_tests/list-200-reference.png b/tests/visual_tests/images/list-200-reference.png similarity index 100% rename from tests/visual_tests/list-200-reference.png rename to tests/visual_tests/images/list-200-reference.png diff --git a/tests/visual_tests/list-250-reference.png b/tests/visual_tests/images/list-250-reference.png similarity index 100% rename from tests/visual_tests/list-250-reference.png rename to tests/visual_tests/images/list-250-reference.png diff --git a/tests/visual_tests/list-300-reference.png b/tests/visual_tests/images/list-300-reference.png similarity index 100% rename from tests/visual_tests/list-300-reference.png rename to tests/visual_tests/images/list-300-reference.png diff --git a/tests/visual_tests/list-400-reference.png b/tests/visual_tests/images/list-400-reference.png similarity index 100% rename from tests/visual_tests/list-400-reference.png rename to tests/visual_tests/images/list-400-reference.png diff --git a/tests/visual_tests/list-600-reference.png b/tests/visual_tests/images/list-600-reference.png similarity index 100% rename from tests/visual_tests/list-600-reference.png rename to tests/visual_tests/images/list-600-reference.png diff --git a/tests/visual_tests/list-800-reference.png b/tests/visual_tests/images/list-800-reference.png similarity index 100% rename from tests/visual_tests/list-800-reference.png rename to tests/visual_tests/images/list-800-reference.png diff --git a/tests/visual_tests/images/python-Format-reference.png b/tests/visual_tests/images/python-Format-reference.png new file mode 100644 index 000000000..1e0426a23 Binary files /dev/null and b/tests/visual_tests/images/python-Format-reference.png differ diff --git a/tests/visual_tests/python-IfElse-reference.png b/tests/visual_tests/images/python-IfElse-reference.png similarity index 100% rename from tests/visual_tests/python-IfElse-reference.png rename to tests/visual_tests/images/python-IfElse-reference.png diff --git a/tests/visual_tests/images/python-List-reference.png b/tests/visual_tests/images/python-List-reference.png new file mode 100644 index 000000000..21f6e4f58 Binary files /dev/null and b/tests/visual_tests/images/python-List-reference.png differ diff --git a/tests/visual_tests/python-MyText-reference.png b/tests/visual_tests/images/python-MyText-reference.png similarity index 100% rename from tests/visual_tests/python-MyText-reference.png rename to tests/visual_tests/images/python-MyText-reference.png diff --git a/tests/visual_tests/python-TextNode-reference.png b/tests/visual_tests/images/python-TextNode-reference.png similarity index 100% rename from tests/visual_tests/python-TextNode-reference.png rename to tests/visual_tests/images/python-TextNode-reference.png diff --git a/tests/visual_tests/images/rtl-point-200-reference.png b/tests/visual_tests/images/rtl-point-200-reference.png new file mode 100644 index 000000000..0d8979ed0 Binary files /dev/null and b/tests/visual_tests/images/rtl-point-200-reference.png differ diff --git a/tests/visual_tests/shieldsymbolizer-1-490-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-490-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-490-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-490-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-495-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-495-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-495-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-495-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-497-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-497-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-497-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-497-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-498-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-498-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-498-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-498-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-499-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-499-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-499-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-499-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-500-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-500-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-500-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-500-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-501-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-501-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-501-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-501-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-502-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-502-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-502-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-502-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-505-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-505-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-505-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-505-reference.png diff --git a/tests/visual_tests/shieldsymbolizer-1-510-reference.png b/tests/visual_tests/images/shieldsymbolizer-1-510-reference.png similarity index 100% rename from tests/visual_tests/shieldsymbolizer-1-510-reference.png rename to tests/visual_tests/images/shieldsymbolizer-1-510-reference.png diff --git a/tests/visual_tests/simple-100-reference.png b/tests/visual_tests/images/simple-100-reference.png similarity index 100% rename from tests/visual_tests/simple-100-reference.png rename to tests/visual_tests/images/simple-100-reference.png diff --git a/tests/visual_tests/simple-150-reference.png b/tests/visual_tests/images/simple-150-reference.png similarity index 100% rename from tests/visual_tests/simple-150-reference.png rename to tests/visual_tests/images/simple-150-reference.png diff --git a/tests/visual_tests/simple-200-reference.png b/tests/visual_tests/images/simple-200-reference.png similarity index 100% rename from tests/visual_tests/simple-200-reference.png rename to tests/visual_tests/images/simple-200-reference.png diff --git a/tests/visual_tests/simple-250-reference.png b/tests/visual_tests/images/simple-250-reference.png similarity index 100% rename from tests/visual_tests/simple-250-reference.png rename to tests/visual_tests/images/simple-250-reference.png diff --git a/tests/visual_tests/simple-300-reference.png b/tests/visual_tests/images/simple-300-reference.png similarity index 100% rename from tests/visual_tests/simple-300-reference.png rename to tests/visual_tests/images/simple-300-reference.png diff --git a/tests/visual_tests/simple-400-reference.png b/tests/visual_tests/images/simple-400-reference.png similarity index 100% rename from tests/visual_tests/simple-400-reference.png rename to tests/visual_tests/images/simple-400-reference.png diff --git a/tests/visual_tests/simple-600-reference.png b/tests/visual_tests/images/simple-600-reference.png similarity index 100% rename from tests/visual_tests/simple-600-reference.png rename to tests/visual_tests/images/simple-600-reference.png diff --git a/tests/visual_tests/simple-800-reference.png b/tests/visual_tests/images/simple-800-reference.png similarity index 100% rename from tests/visual_tests/simple-800-reference.png rename to tests/visual_tests/images/simple-800-reference.png diff --git a/tests/visual_tests/simple-E-500-reference.png b/tests/visual_tests/images/simple-E-500-reference.png similarity index 100% rename from tests/visual_tests/simple-E-500-reference.png rename to tests/visual_tests/images/simple-E-500-reference.png diff --git a/tests/visual_tests/simple-N-500-reference.png b/tests/visual_tests/images/simple-N-500-reference.png similarity index 100% rename from tests/visual_tests/simple-N-500-reference.png rename to tests/visual_tests/images/simple-N-500-reference.png diff --git a/tests/visual_tests/simple-NE-500-reference.png b/tests/visual_tests/images/simple-NE-500-reference.png similarity index 100% rename from tests/visual_tests/simple-NE-500-reference.png rename to tests/visual_tests/images/simple-NE-500-reference.png diff --git a/tests/visual_tests/simple-NW-500-reference.png b/tests/visual_tests/images/simple-NW-500-reference.png similarity index 100% rename from tests/visual_tests/simple-NW-500-reference.png rename to tests/visual_tests/images/simple-NW-500-reference.png diff --git a/tests/visual_tests/simple-S-500-reference.png b/tests/visual_tests/images/simple-S-500-reference.png similarity index 100% rename from tests/visual_tests/simple-S-500-reference.png rename to tests/visual_tests/images/simple-S-500-reference.png diff --git a/tests/visual_tests/simple-SE-500-reference.png b/tests/visual_tests/images/simple-SE-500-reference.png similarity index 100% rename from tests/visual_tests/simple-SE-500-reference.png rename to tests/visual_tests/images/simple-SE-500-reference.png diff --git a/tests/visual_tests/simple-SW-500-reference.png b/tests/visual_tests/images/simple-SW-500-reference.png similarity index 100% rename from tests/visual_tests/simple-SW-500-reference.png rename to tests/visual_tests/images/simple-SW-500-reference.png diff --git a/tests/visual_tests/simple-W-500-reference.png b/tests/visual_tests/images/simple-W-500-reference.png similarity index 100% rename from tests/visual_tests/simple-W-500-reference.png rename to tests/visual_tests/images/simple-W-500-reference.png diff --git a/tests/visual_tests/expressionformat.xml b/tests/visual_tests/styles/expressionformat.xml similarity index 90% rename from tests/visual_tests/expressionformat.xml rename to tests/visual_tests/styles/expressionformat.xml index 3c7b74b03..5c66ab54c 100644 --- a/tests/visual_tests/expressionformat.xml +++ b/tests/visual_tests/styles/expressionformat.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/formating.xml b/tests/visual_tests/styles/formating.xml similarity index 91% rename from tests/visual_tests/formating.xml rename to tests/visual_tests/styles/formating.xml index d59c7b8da..acef45dd7 100644 --- a/tests/visual_tests/formating.xml +++ b/tests/visual_tests/styles/formating.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/formating-1.xml b/tests/visual_tests/styles/formatting-1.xml similarity index 91% rename from tests/visual_tests/formating-1.xml rename to tests/visual_tests/styles/formatting-1.xml index 75158e8b5..a044f662c 100644 --- a/tests/visual_tests/formating-1.xml +++ b/tests/visual_tests/styles/formatting-1.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/formating-2.xml b/tests/visual_tests/styles/formatting-2.xml similarity index 91% rename from tests/visual_tests/formating-2.xml rename to tests/visual_tests/styles/formatting-2.xml index 4fda094db..285646515 100644 --- a/tests/visual_tests/formating-2.xml +++ b/tests/visual_tests/styles/formatting-2.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/formating-3.xml b/tests/visual_tests/styles/formatting-3.xml similarity index 91% rename from tests/visual_tests/formating-3.xml rename to tests/visual_tests/styles/formatting-3.xml index 1e1bbd048..159ef880c 100644 --- a/tests/visual_tests/formating-3.xml +++ b/tests/visual_tests/styles/formatting-3.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/formating-4.xml b/tests/visual_tests/styles/formatting-4.xml similarity index 89% rename from tests/visual_tests/formating-4.xml rename to tests/visual_tests/styles/formatting-4.xml index 746f38d02..551cd09d5 100644 --- a/tests/visual_tests/formating-4.xml +++ b/tests/visual_tests/styles/formatting-4.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/styles/jalign-auto.xml b/tests/visual_tests/styles/jalign-auto.xml new file mode 100644 index 000000000..8956751e5 --- /dev/null +++ b/tests/visual_tests/styles/jalign-auto.xml @@ -0,0 +1,30 @@ + + + + + + My Style + + shape + ../data/points.shp + + + + + + diff --git a/tests/visual_tests/styles/line-offset.xml b/tests/visual_tests/styles/line-offset.xml new file mode 100644 index 000000000..ed738555d --- /dev/null +++ b/tests/visual_tests/styles/line-offset.xml @@ -0,0 +1,29 @@ + + + + + My Style + + osm + ../data/line-offset.osm + + + + + \ No newline at end of file diff --git a/tests/visual_tests/lines-1.xml b/tests/visual_tests/styles/lines-1.xml similarity index 89% rename from tests/visual_tests/lines-1.xml rename to tests/visual_tests/styles/lines-1.xml index 7df2294c7..5b8fe6a58 100644 --- a/tests/visual_tests/lines-1.xml +++ b/tests/visual_tests/styles/lines-1.xml @@ -6,7 +6,7 @@ My Style osm - lines.osm + ../data/lines.osm diff --git a/tests/visual_tests/lines-2.xml b/tests/visual_tests/styles/lines-2.xml similarity index 90% rename from tests/visual_tests/lines-2.xml rename to tests/visual_tests/styles/lines-2.xml index 1c77a3115..9b32abb73 100644 --- a/tests/visual_tests/lines-2.xml +++ b/tests/visual_tests/styles/lines-2.xml @@ -6,7 +6,7 @@ My Style osm - lines.osm + ../data/lines.osm diff --git a/tests/visual_tests/lines-3.xml b/tests/visual_tests/styles/lines-3.xml similarity index 90% rename from tests/visual_tests/lines-3.xml rename to tests/visual_tests/styles/lines-3.xml index ef37dc51c..13f5cc332 100644 --- a/tests/visual_tests/lines-3.xml +++ b/tests/visual_tests/styles/lines-3.xml @@ -6,7 +6,7 @@ My Style osm - lines.osm + ../data/lines.osm diff --git a/tests/visual_tests/lines-shield.xml b/tests/visual_tests/styles/lines-shield.xml similarity index 76% rename from tests/visual_tests/lines-shield.xml rename to tests/visual_tests/styles/lines-shield.xml index 05a0f4fd2..4402411a7 100644 --- a/tests/visual_tests/lines-shield.xml +++ b/tests/visual_tests/styles/lines-shield.xml @@ -6,14 +6,14 @@ My Style osm - lines.osm + ../data/lines.osm diff --git a/tests/visual_tests/list.xml b/tests/visual_tests/styles/list.xml similarity index 85% rename from tests/visual_tests/list.xml rename to tests/visual_tests/styles/list.xml index 93ef3726d..e146ded22 100644 --- a/tests/visual_tests/list.xml +++ b/tests/visual_tests/styles/list.xml @@ -7,9 +7,9 @@ + ../data/points.osm--> shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/styles/rtl-point.xml b/tests/visual_tests/styles/rtl-point.xml new file mode 100644 index 000000000..54edac854 --- /dev/null +++ b/tests/visual_tests/styles/rtl-point.xml @@ -0,0 +1,25 @@ + + + + + + My Style + + + shape + ../data/points.shp + + + + + + diff --git a/tests/visual_tests/shieldsymbolizer-1.xml b/tests/visual_tests/styles/shieldsymbolizer-1.xml similarity index 55% rename from tests/visual_tests/shieldsymbolizer-1.xml rename to tests/visual_tests/styles/shieldsymbolizer-1.xml index 6f780d888..329343461 100644 --- a/tests/visual_tests/shieldsymbolizer-1.xml +++ b/tests/visual_tests/styles/shieldsymbolizer-1.xml @@ -1,58 +1,58 @@ - + My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple-E.xml b/tests/visual_tests/styles/simple-E.xml similarity index 90% rename from tests/visual_tests/simple-E.xml rename to tests/visual_tests/styles/simple-E.xml index 31e11acaa..9a0668bd0 100644 --- a/tests/visual_tests/simple-E.xml +++ b/tests/visual_tests/styles/simple-E.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple-N.xml b/tests/visual_tests/styles/simple-N.xml similarity index 90% rename from tests/visual_tests/simple-N.xml rename to tests/visual_tests/styles/simple-N.xml index 919e0d2b6..74265ec5a 100644 --- a/tests/visual_tests/simple-N.xml +++ b/tests/visual_tests/styles/simple-N.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple-NE.xml b/tests/visual_tests/styles/simple-NE.xml similarity index 90% rename from tests/visual_tests/simple-NE.xml rename to tests/visual_tests/styles/simple-NE.xml index 74c6a5d09..df1095195 100644 --- a/tests/visual_tests/simple-NE.xml +++ b/tests/visual_tests/styles/simple-NE.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple-NW.xml b/tests/visual_tests/styles/simple-NW.xml similarity index 90% rename from tests/visual_tests/simple-NW.xml rename to tests/visual_tests/styles/simple-NW.xml index 5e80dc607..120e26fcb 100644 --- a/tests/visual_tests/simple-NW.xml +++ b/tests/visual_tests/styles/simple-NW.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple-S.xml b/tests/visual_tests/styles/simple-S.xml similarity index 90% rename from tests/visual_tests/simple-S.xml rename to tests/visual_tests/styles/simple-S.xml index 1ada1baca..e738ab8b4 100644 --- a/tests/visual_tests/simple-S.xml +++ b/tests/visual_tests/styles/simple-S.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple-SE.xml b/tests/visual_tests/styles/simple-SE.xml similarity index 90% rename from tests/visual_tests/simple-SE.xml rename to tests/visual_tests/styles/simple-SE.xml index c8ee4f6d5..ae43761b0 100644 --- a/tests/visual_tests/simple-SE.xml +++ b/tests/visual_tests/styles/simple-SE.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple-SW.xml b/tests/visual_tests/styles/simple-SW.xml similarity index 90% rename from tests/visual_tests/simple-SW.xml rename to tests/visual_tests/styles/simple-SW.xml index 641452d4b..7b206417c 100644 --- a/tests/visual_tests/simple-SW.xml +++ b/tests/visual_tests/styles/simple-SW.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple-W.xml b/tests/visual_tests/styles/simple-W.xml similarity index 90% rename from tests/visual_tests/simple-W.xml rename to tests/visual_tests/styles/simple-W.xml index 012dc4375..cd0708a7a 100644 --- a/tests/visual_tests/simple-W.xml +++ b/tests/visual_tests/styles/simple-W.xml @@ -6,7 +6,7 @@ My Style shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/simple.xml b/tests/visual_tests/styles/simple.xml similarity index 77% rename from tests/visual_tests/simple.xml rename to tests/visual_tests/styles/simple.xml index cc008f598..61bb07748 100644 --- a/tests/visual_tests/simple.xml +++ b/tests/visual_tests/styles/simple.xml @@ -5,12 +5,8 @@ My Style - shape - points.shp + ../data/points.shp diff --git a/tests/visual_tests/test.py b/tests/visual_tests/test.py index b7509fd73..29716e6bd 100755 --- a/tests/visual_tests/test.py +++ b/tests/visual_tests/test.py @@ -2,45 +2,62 @@ # -*- coding: utf-8 -*- import mapnik -import cairo import sys import os.path from compare import compare, summary -dirname = os.path.dirname(sys.argv[0]) -files = [ - ("list", 800, 600, 400, 300, 250, 200, 150, 100), - ("simple", 800, 600, 400, 300, 250, 200, 150, 100), - ("lines-1", (800, 800), (600, 600), (400, 400), (200, 200)), - ("lines-2", (800, 800), (600, 600), (400, 400), (200, 200)), - ("lines-3", (800, 800), (600, 600), (400, 400), (200, 200)), - ("lines-shield", (800, 800), (600, 600), (400, 400), (200, 200)), - ("simple-E", 500), - ("simple-NE", 500), - ("simple-NW", 500), - ("simple-N", 500), - ("simple-SE", 500), - ("simple-SW", 500), - ("simple-S", 500), - ("simple-W", 500), - ("formating-1", 500), - ("formating-2", 500), - ("formating-3", 500), - ("formating-4", 500), - ("shieldsymbolizer-1", 490, 495, 497, 498, 499, 500, 501, 502, 505, 510), - ("expressionformat", 500)] +defaults = { + 'sizes': [(500, 100)], + 'bbox': mapnik.Box2d(-0.05, -0.01, 0.95, 0.01) +} -def render(filename, width, height=100): +sizes_many_in_big_range = [(800, 100), (600, 100), (400, 100), + (300, 100), (250, 100), (150, 100), (100, 100)] + +sizes_few_square = [(800, 800), (600, 600), (400, 400), (200, 200)] +sizes_many_in_small_range = [(490, 100), (495, 100), (497, 100), (498, 100), + (499, 100), (500, 100), (501, 100), (502, 100), (505, 100), (510, 100)] + +dirname = os.path.dirname(__file__) + +files = [ + {'name': "list", 'sizes': sizes_many_in_big_range}, + {'name': "simple", 'sizes': sizes_many_in_big_range}, + {'name': "lines-1", 'sizes': sizes_few_square}, + {'name': "lines-2", 'sizes': sizes_few_square}, + {'name': "lines-3", 'sizes': sizes_few_square}, + {'name': "lines-shield", 'sizes': sizes_few_square}, + {'name': "simple-E"}, + {'name': "simple-NE"}, + {'name': "simple-NW"}, + {'name': "simple-N"}, + {'name': "simple-SE"}, + {'name': "simple-SW"}, + {'name': "simple-S"}, + {'name': "simple-W"}, + {'name': "formatting-1"}, + {'name': "formatting-2"}, + {'name': "formatting-3"}, + {'name': "formatting-4"}, + {'name': "expressionformat"}, + {'name': "shieldsymbolizer-1", 'sizes': sizes_many_in_small_range}, + {'name': "rtl-point", 'sizes': [(200, 200)]}, + {'name': "jalign-auto", 'sizes': [(200, 200)]}, + {'name': "line-offset", 'sizes':[(900, 250)], + 'bbox': mapnik.Box2d(-5.192, 50.189, -5.174, 50.195)} + ] + +def render(filename, width, height, bbox): print "-"*80 print "Rendering style \"%s\" with size %dx%d ... " % (filename, width, height) print "-"*80 - width = int(width) - height = int(height) m = mapnik.Map(width, height) - mapnik.load_map(m, os.path.join(dirname, "%s.xml" % filename), False) - bbox = mapnik.Box2d(-0.05, -0.01, 0.95, 0.01) - m.zoom_to_box(bbox) - basefn = '%s-%d' % (filename, width) + mapnik.load_map(m, os.path.join(dirname, "styles", "%s.xml" % filename), False) + if bbox is not None: + m.zoom_to_box(bbox) + else: + m.zoom_all() + basefn = os.path.join(dirname, "images", '%s-%d' % (filename, width)) mapnik.render_to_file(m, basefn+'-agg.png') diff = compare(basefn + '-agg.png', basefn + '-reference.png') if diff > 0: @@ -51,16 +68,15 @@ def render(filename, width, height=100): return m if len(sys.argv) == 2: - files = [(sys.argv[1], 500)] + files = [(sys.argv[1], (500, 500))] elif len(sys.argv) > 2: files = [sys.argv[1:]] for f in files: - for width in f[1:]: - if isinstance(width, tuple): - m = render(f[0], width[0], width[1]) - else: - m = render(f[0], width) - mapnik.save_map(m, "%s-out.xml" % f[0]) + config = dict(defaults) + config.update(f) + for size in config['sizes']: + m = render(config['name'], size[0], size[1], config['bbox']) + mapnik.save_map(m, os.path.join(dirname, 'xml_output', "%s-out.xml" % config['name'])) summary() diff --git a/tests/visual_tests/test_python.py b/tests/visual_tests/test_python.py index e45ab6e55..9648a8626 100755 --- a/tests/visual_tests/test_python.py +++ b/tests/visual_tests/test_python.py @@ -1,6 +1,10 @@ #!/usr/bin/env python import mapnik import sys +import os.path +from compare import compare, summary + +dirname = os.path.dirname(__file__) class MyText(mapnik.FormattingNode): def __init__(self): @@ -67,7 +71,7 @@ m.append_style('Style', style) layer = mapnik.Layer('Layer') -layer.datasource = mapnik.Shapefile(file="points.shp") +layer.datasource = mapnik.Shapefile(file=os.path.join(dirname,"data/points.shp")) layer.styles.append('Style') m.layers.append(layer) @@ -95,4 +99,9 @@ format_trees = [ for format_tree in format_trees: text.placements.defaults.format_tree = format_tree[1] - mapnik.render_to_file(m, 'python-%s.png' % format_tree[0], 'png') + mapnik.render_to_file(m, os.path.join(dirname,"images", 'python-%s.png' % format_tree[0]), 'png') + compare(os.path.join(dirname,"images", 'python-%s.png' % format_tree[0]), + os.path.join(dirname,"images", 'python-%s-reference.png' % format_tree[0]) + ) + +summary() diff --git a/tests/visual_tests/xml_output/.gitignore b/tests/visual_tests/xml_output/.gitignore new file mode 100644 index 000000000..6722cd96e --- /dev/null +++ b/tests/visual_tests/xml_output/.gitignore @@ -0,0 +1 @@ +*.xml diff --git a/utils/performance/mapnik-speed-check b/utils/performance/mapnik-speed-check index 581676c72..44cf0bc84 100755 --- a/utils/performance/mapnik-speed-check +++ b/utils/performance/mapnik-speed-check @@ -39,6 +39,11 @@ def f_(set): if __name__=='__main__': # if passed, set up bbox + + #test_ = "load()" + test_ = "render()" + init(stylesheet) + if len(sys.argv) == 4: bbox = sys.argv[3] if ',' in bbox: @@ -47,10 +52,6 @@ if __name__=='__main__': parts = bbox.split(' ') env = mapnik.Box2d(*map(float,parts)) m.zoom_to_box(env) - - #test_ = "load()" - test_ = "render()" - init(stylesheet) # load once - making sure mmap'd shapefiles are loaded eval(test_) diff --git a/utils/xml/mapnik2.dtd b/utils/xml/mapnik.dtd similarity index 100% rename from utils/xml/mapnik2.dtd rename to utils/xml/mapnik.dtd