mapnik::raster_ptr pgraster_wkb_reader::read_rgba(mapnik::box2d<double> const& bbox, uint16_t width, uint16_t height) { mapnik::image_rgba8 im(width, height, true, true); // Start with plain white (ABGR or RGBA depending on endiannes) im.set(0xffffffff); uint8_t nodataval; for (int bn=0; bn<numBands_; ++bn) { uint8_t type = read_uint8(&ptr_); int pixtype = BANDTYPE_PIXTYPE(type); int offline = BANDTYPE_IS_OFFDB(type) ? 1 : 0; int hasnodata = BANDTYPE_HAS_NODATA(type) ? 1 : 0; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: band " << bn << " type:" << pixtype << " offline:" << offline << " hasnodata:" << hasnodata; if ( offline ) { MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band " << bn << " unsupported"; continue; } if ( pixtype > PT_8BUI || pixtype < PT_8BSI ) { MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: band " << bn << " type " << type << " unsupported"; continue; } uint8_t tmp = read_uint8(&ptr_); if ( ! bn ) nodataval = tmp; else if ( tmp != nodataval ) { MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: band " << bn << " nodataval " << tmp << " != band 0 nodataval " << nodataval; } int ps = 4; // sizeof(image::pixel_type) uint8_t * image_data = im.bytes(); for (int y=0; y<height_; ++y) { for (int x=0; x<width_; ++x) { uint8_t val = read_uint8(&ptr_); // y * width_ * ps is the row (ps is pixel size) // x * ps is the column int off = y * width_ * ps + x * ps; // Pixel space is RGBA image_data[off+bn] = val; } } } mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(bbox, im, 1.0); raster->set_nodata(0xffffffff); return raster; }
bool placement_finder::next_position() { if (info_.next()) { // parent layout, has top-level ownership of a new evaluated_format_properties_ptr (TODO is this good enough to stay in scope???) // but does not take ownership of the text_symbolizer_properties (info_.properties) text_layout_ptr layout = std::make_shared<text_layout>(font_manager_, feature_, attr_, scale_factor_, info_.properties, info_.properties.layout_defaults, info_.properties.format_tree()); // TODO: why is this call needed? // https://github.com/mapnik/mapnik/issues/2525 text_props_ = evaluate_text_properties(info_.properties,feature_,attr_); // Note: this clear call is needed when multiple placements are tried // like with placement-type="simple|list" if (!layouts_.empty()) layouts_.clear(); // Note: multiple layouts_ may result from this add() call layouts_.add(layout); layouts_.layout(); // cache a few values for use elsewhere in placement finder move_dx_ = layout->displacement().x; horizontal_alignment_ = layout->horizontal_alignment(); return true; } MAPNIK_LOG_WARN(placement_finder) << "next_position() called while last call already returned false!\n"; return false; }
font_library::font_library() : library_(nullptr), memory_(new FT_MemoryRec_) { memory_->alloc = _Alloc_Func; memory_->free = _Free_Func; memory_->realloc = _Realloc_Func; FT_Error error = FT_New_Library(&*memory_, &library_); if (error) throw std::runtime_error("can not initialize FreeType2 library"); FT_Add_Default_Modules(library_); #if ((FREETYPE_MAJOR*1000 + FREETYPE_MINOR)*1000 >= 2008000) FT_Set_Default_Properties(library_); #endif if (!std::getenv("FREETYPE_PROPERTIES") && version() >= compact_version(2, 7, 0)) { FT_UInt interpreter_version = 35; error = FT_Property_Set(library_, "truetype", "interpreter-version", &interpreter_version ); if (error) { MAPNIK_LOG_WARN(font_library) << "FreeType: Error setting interpreter-version=35"; } } }
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, markers_symbolizer const& sym) { std::size_t geom_count = feature.paths().size(); if (geom_count == 1) { converter.apply(feature.paths()[0]); } else if (geom_count > 1) { marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum>(sym, keys::markers_multipolicy, feature, vars, MARKER_EACH_MULTI); marker_placement_enum placement = get<marker_placement_enum>(sym, keys::markers_placement_type, feature, vars, MARKER_POINT_PLACEMENT); if (placement == MARKER_POINT_PLACEMENT && multi_policy == MARKER_WHOLE_MULTI) { double x, y; if (label::centroid_geoms(feature.paths().begin(), feature.paths().end(), x, y)) { geometry_type pt(geometry_type::types::Point); pt.move_to(x, y); // unset any clipping since we're now dealing with a point converter.template unset<clip_poly_tag>(); converter.apply(pt); } } else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) && multi_policy == MARKER_LARGEST_MULTI) { // Only apply to path with largest envelope area // TODO: consider using true area for polygon types double maxarea = 0; geometry_type const* largest = 0; for (geometry_type const& geom : feature.paths()) { const box2d<double>& env = geom.envelope(); double area = env.width() * env.height(); if (area > maxarea) { maxarea = area; largest = &geom; } } if (largest) { converter.apply(*largest); } } else { if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT) { MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'"; } for (geometry_type const& path : feature.paths()) { converter.apply(path); } } } }
/** Set spacing_left_, adjusts error_ and performs sanity checks. */ void set_spacing_left(double sl, bool allow_negative=false) { double delta_error = sl - spacing_left_; if (!allow_negative && delta_error < 0) { MAPNIK_LOG_WARN(markers_placement) << "Unexpected negative error in markers_placement. Please file a bug report."; return; } #ifdef MAPNIK_DEBUG if (delta_error == 0.0) { MAPNIK_LOG_WARN(markers_placement) << "Not moving at all in set_spacing_left()! Please file a bug report."; } #endif error_ += delta_error; spacing_left_ = sl; }
inline void write_feature_header(std::string type) { if (count_ == STOPPED) { MAPNIK_LOG_WARN(metawrite_json) << "Metawriter: instance not started before using it."; } if (count_ == HEADER_NOT_WRITTEN) write_header(); if (count_++) *f_ << ",\n"; *f_ << "{ \"type\": \"Feature\",\n \"geometry\": { \"type\": \"" << type << "\",\n \"coordinates\":"; }
mapnik::raster_ptr pgraster_wkb_reader::read_grayscale(mapnik::box2d<double> const& bbox, uint16_t width, uint16_t height) { uint8_t type = read_uint8(&ptr_); int pixtype = BANDTYPE_PIXTYPE(type); int offline = BANDTYPE_IS_OFFDB(type) ? 1 : 0; int hasnodata = BANDTYPE_HAS_NODATA(type) ? 1 : 0; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: band type:" << pixtype << " offline:" << offline << " hasnodata:" << hasnodata; if ( offline ) { MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band " " unsupported"; return mapnik::raster_ptr(); } switch (pixtype) { case PT_1BB: case PT_2BUI: case PT_4BUI: // all <8BPP values are wrote in full bytes anyway case PT_8BSI: // mapnik does not support signed anyway case PT_8BUI: return read_grayscale_band(bbox, width_, height_, hasnodata, std::bind(read_uint8, &ptr_)); break; case PT_16BSI: // mapnik does not support signed anyway case PT_16BUI: return read_grayscale_band(bbox, width_, height_, hasnodata, std::bind(read_uint16, &ptr_, endian_)); break; case PT_32BSI: // mapnik does not support signed anyway case PT_32BUI: return read_grayscale_band(bbox, width_, height_, hasnodata, std::bind(read_uint32, &ptr_, endian_)); break; default: std::ostringstream err; err << "pgraster_wkb_reader: grayscale band type " << pixtype << " unsupported"; //MAPNIK_LOG_WARN(pgraster) << err.str(); throw mapnik::datasource_exception(err.str()); } return mapnik::raster_ptr(); }
bool placement_finder::next_position() { if (info_.next()) { text_layout_ptr layout = std::make_shared<text_layout>(font_manager_, scale_factor_, info_.properties.layout_defaults); layout->evaluate_properties(feature_, attr_); move_dx_ = layout->displacement().x; info_.properties.process(*layout, feature_, attr_); layouts_.clear(); // FIXME !!!! layouts_.add(layout); layouts_.layout(); horizontal_alignment_ = layout->horizontal_alignment(); return true; } MAPNIK_LOG_WARN(placement_finder) << "next_position() called while last call already returned false!\n"; return false; }
mapnik::geometry::geometry<double> ogr_converter::convert_geometry(OGRGeometry* ogr_geom) { // NOTE: wkbFlatten macro in ogr flattens 2.5d types into base 2d type switch (wkbFlatten(ogr_geom->getGeometryType())) { case wkbPoint: return convert_point(static_cast<OGRPoint*>(ogr_geom)); break; case wkbMultiPoint: return convert_multipoint(static_cast<OGRMultiPoint*>(ogr_geom)); break; case wkbLinearRing: return convert_linestring(static_cast<OGRLinearRing*>(ogr_geom)); break; case wkbLineString: return convert_linestring(static_cast<OGRLineString*>(ogr_geom)); break; case wkbMultiLineString: return convert_multilinestring(static_cast<OGRMultiLineString*>(ogr_geom)); break; case wkbPolygon: return convert_polygon(static_cast<OGRPolygon*>(ogr_geom)); break; case wkbMultiPolygon: return convert_multipolygon(static_cast<OGRMultiPolygon*>(ogr_geom)); break; case wkbGeometryCollection: return convert_collection(static_cast<OGRGeometryCollection*>(ogr_geom)); break; case wkbNone: case wkbUnknown: default: { MAPNIK_LOG_WARN(ogr) << "ogr_converter: unknown <ogr> geometry_type=" << wkbFlatten(ogr_geom->getGeometryType()); } return mapnik::geometry::geometry<double>(); break; } }
bool placement_finder::next_position() { if (info_.next()) { text_layout_ptr layout = std::make_shared<text_layout>(font_manager_, scale_factor_, info_.properties.layout_defaults); layout->evaluate_properties(feature_, attr_); move_dx_ = layout->displacement().x; // TODO: this call is needed (text-bug1533) ?? // https://github.com/mapnik/mapnik/issues/2525 text_props_ = evaluate_text_properties(info_.properties,feature_,attr_); info_.properties.process(*layout, feature_, attr_); // Note: this clear call is needed when multiple placements are tried // like with placement-type="simple|list" if (!layouts_.empty()) layouts_.clear(); // Note: multiple layouts_ may result from this add() call layouts_.add(layout); layouts_.layout(); horizontal_alignment_ = layout->horizontal_alignment(); return true; } MAPNIK_LOG_WARN(placement_finder) << "next_position() called while last call already returned false!\n"; return false; }
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, symbolizer_base const& sym) { using vertex_converter_type = Converter; using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type>; using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>; auto const& geom = feature.get_geometry(); geometry::geometry_types type = geometry::geometry_type(geom); if (type == geometry::geometry_types::Point || type == geometry::geometry_types::LineString || type == geometry::geometry_types::Polygon) { apply_vertex_converter_type apply(converter); mapnik::util::apply_visitor(vertex_processor_type(apply), geom); } else { marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars); marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars); if (placement == MARKER_POINT_PLACEMENT && multi_policy == MARKER_WHOLE_MULTI) { geometry::point<double> pt; // test if centroid is contained by bounding box if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y)) { // unset any clipping since we're now dealing with a point converter.template unset<clip_poly_tag>(); geometry::point_vertex_adapter<double> va(pt); converter.apply(va); } } else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) && multi_policy == MARKER_LARGEST_MULTI) { // Only apply to path with largest envelope area // TODO: consider using true area for polygon types if (type == geometry::geometry_types::MultiPolygon) { geometry::multi_polygon<double> const& multi_poly = mapnik::util::get<geometry::multi_polygon<double> >(geom); double maxarea = 0; geometry::polygon<double> const* largest = 0; for (geometry::polygon<double> const& poly : multi_poly) { box2d<double> bbox = geometry::envelope(poly); geometry::polygon_vertex_adapter<double> va(poly); double area = bbox.width() * bbox.height(); if (area > maxarea) { maxarea = area; largest = &poly; } } if (largest) { geometry::polygon_vertex_adapter<double> va(*largest); converter.apply(va); } } else { MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue"; } } else { if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT) { MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'"; } apply_vertex_converter_type apply(converter); mapnik::util::apply_visitor(vertex_processor_type(apply), geom); } } }
mapnik::raster_ptr pgraster_wkb_reader::get_raster() { /* Read endianness */ endian_ = *ptr_; ptr_ += 1; /* Read version of protocol */ uint16_t version = read_uint16(&ptr_, endian_); if (version != 0) { MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: WKB version " << version << " unsupported"; return mapnik::raster_ptr(); } numBands_ = read_uint16(&ptr_, endian_); double scaleX = read_float64(&ptr_, endian_); double scaleY = read_float64(&ptr_, endian_); double ipX = read_float64(&ptr_, endian_); double ipY = read_float64(&ptr_, endian_); double skewX = read_float64(&ptr_, endian_); double skewY = read_float64(&ptr_, endian_); int32_t srid = read_int32(&ptr_, endian_); width_ = read_uint16(&ptr_, endian_); height_ = read_uint16(&ptr_, endian_); MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: numBands=" << numBands_; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: scaleX=" << scaleX; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: scaleY=" << scaleY; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: ipX=" << ipX; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: ipY=" << ipY; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: skewX=" << skewX; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: skewY=" << skewY; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: srid=" << srid; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: size=" << width_ << "x" << height_; // this is for color interpretation MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: bandno=" << bandno_; if ( skewX || skewY ) { MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: raster rotation is not supported"; return mapnik::raster_ptr(); } mapnik::box2d<double> ext(ipX,ipY,ipX+(width_*scaleX),ipY+(height_*scaleY)); MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: Raster extent=" << ext; if ( bandno_ ) { if ( bandno_ != 1 ) { MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: " "reading bands other than 1st as indexed is unsupported"; return mapnik::raster_ptr(); } MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: requested band " << bandno_; return read_indexed(ext, width_, height_); } else { switch (numBands_) { case 1: return read_grayscale(ext, width_, height_); break; case 3: case 4: return read_rgba(ext, width_, height_); break; default: std::ostringstream err; err << "pgraster_wkb_reader: raster with " << numBands_ << " bands is not supported, specify a band number"; //MAPNIK_LOG_WARN(pgraster) << err.str(); throw mapnik::datasource_exception(err.str()); return mapnik::raster_ptr(); } } return mapnik::raster_ptr(); }
void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const & fontsets) { optional<label_placement_e> placement_ = sym.get_opt_attr<label_placement_e>("placement"); if (placement_) label_placement = *placement_; optional<vertical_alignment_e> valign_ = sym.get_opt_attr<vertical_alignment_e>("vertical-alignment"); if (valign_) valign = *valign_; optional<double> text_ratio_ = sym.get_opt_attr<double>("text-ratio"); if (text_ratio_) text_ratio = *text_ratio_; optional<double> wrap_width_ = sym.get_opt_attr<double>("wrap-width"); if (wrap_width_) wrap_width = *wrap_width_; optional<boolean> wrap_before_ = sym.get_opt_attr<boolean>("wrap-before"); if (wrap_before_) wrap_before = *wrap_before_; optional<double> label_position_tolerance_ = sym.get_opt_attr<double>("label-position-tolerance"); if (label_position_tolerance_) label_position_tolerance = *label_position_tolerance_; optional<double> spacing_ = sym.get_opt_attr<double>("spacing"); if (spacing_) label_spacing = *spacing_; else { // https://github.com/mapnik/mapnik/issues/1427 spacing_ = sym.get_opt_attr<double>("label-spacing"); if (spacing_) label_spacing = *spacing_; } optional<double> minimum_distance_ = sym.get_opt_attr<double>("minimum-distance"); if (minimum_distance_) minimum_distance = *minimum_distance_; optional<double> min_padding_ = sym.get_opt_attr<double>("minimum-padding"); if (min_padding_) minimum_padding = *min_padding_; optional<double> min_path_length_ = sym.get_opt_attr<double>("minimum-path-length"); if (min_path_length_) minimum_path_length = *min_path_length_; optional<boolean> avoid_edges_ = sym.get_opt_attr<boolean>("avoid-edges"); if (avoid_edges_) avoid_edges = *avoid_edges_; optional<boolean> allow_overlap_ = sym.get_opt_attr<boolean>("allow-overlap"); if (allow_overlap_) allow_overlap = *allow_overlap_; optional<boolean> largest_bbox_only_ = sym.get_opt_attr<boolean>("largest-bbox-only"); if (largest_bbox_only_) largest_bbox_only = *largest_bbox_only_; optional<horizontal_alignment_e> halign_ = sym.get_opt_attr<horizontal_alignment_e>("horizontal-alignment"); if (halign_) halign = *halign_; optional<justify_alignment_e> jalign_ = sym.get_opt_attr<justify_alignment_e>("justify-alignment"); if (jalign_) jalign = *jalign_; optional<expression_ptr> orientation_ = sym.get_opt_attr<expression_ptr>("orientation"); if (orientation_) orientation = *orientation_; optional<boolean> rotate_displacement_ = sym.get_opt_attr<boolean>("rotate-displacement"); if (rotate_displacement_) rotate_displacement = *rotate_displacement_; optional<text_upright_e> upright_ = sym.get_opt_attr<text_upright_e>("upright"); if (upright_) upright = *upright_; optional<double> dx = sym.get_opt_attr<double>("dx"); if (dx) displacement.x = *dx; optional<double> dy = sym.get_opt_attr<double>("dy"); if (dy) displacement.y = *dy; optional<double> max_char_angle_delta_ = sym.get_opt_attr<double>("max-char-angle-delta"); if (max_char_angle_delta_) max_char_angle_delta=(*max_char_angle_delta_)*(M_PI/180); optional<expression_ptr> name_ = sym.get_opt_attr<expression_ptr>("name"); if (name_) { MAPNIK_LOG_WARN(text_placements) << "Using 'name' in TextSymbolizer/ShieldSymbolizer is deprecated!"; set_old_style_expression(*name_); } format->from_xml(sym, fontsets); formatting::node_ptr n(formatting::node::from_xml(sym)); if (n) set_format_tree(n); }
text_layout::text_layout(face_manager_freetype & font_manager, feature_impl const& feature, attributes const& attrs, double scale_factor, text_symbolizer_properties const& properties, text_layout_properties const& layout_defaults, formatting::node_ptr tree) : font_manager_(font_manager), scale_factor_(scale_factor), itemizer_(), width_map_(), width_(0.0), height_(0.0), glyphs_count_(0), lines_(), layout_properties_(layout_defaults), properties_(properties), format_(std::make_unique<detail::evaluated_format_properties>()) { double dx = util::apply_visitor(extract_value<value_double>(feature,attrs), layout_properties_.dx); double dy = util::apply_visitor(extract_value<value_double>(feature,attrs), layout_properties_.dy); displacement_ = evaluate_displacement(dx,dy, layout_properties_.dir); std::string wrap_str = util::apply_visitor(extract_value<std::string>(feature,attrs), layout_properties_.wrap_char); if (!wrap_str.empty()) wrap_char_ = wrap_str[0]; wrap_width_ = util::apply_visitor(extract_value<value_double>(feature,attrs), layout_properties_.wrap_width); double angle = util::apply_visitor(extract_value<value_double>(feature,attrs), layout_properties_.orientation); orientation_.init(angle * M_PI/ 180.0); wrap_before_ = util::apply_visitor(extract_value<value_bool>(feature,attrs), layout_properties_.wrap_before); repeat_wrap_char_ = util::apply_visitor(extract_value<value_bool>(feature,attrs), layout_properties_.repeat_wrap_char); rotate_displacement_ = util::apply_visitor(extract_value<value_bool>(feature,attrs), layout_properties_.rotate_displacement); valign_ = util::apply_visitor(extract_value<vertical_alignment_enum>(feature,attrs),layout_properties_.valign); halign_ = util::apply_visitor(extract_value<horizontal_alignment_enum>(feature,attrs),layout_properties_.halign); jalign_ = util::apply_visitor(extract_value<justify_alignment_enum>(feature,attrs),layout_properties_.jalign); // Takes a feature and produces formatted text as output. if (tree) { format_properties const& format_defaults = properties_.format_defaults; format_->text_size = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.text_size); format_->character_spacing = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.character_spacing); format_->line_spacing = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.line_spacing); format_->text_opacity = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.text_opacity); format_->halo_opacity = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.halo_opacity); format_->halo_radius = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.halo_radius); format_->fill = util::apply_visitor(extract_value<color>(feature,attrs), format_defaults.fill); format_->halo_fill = util::apply_visitor(extract_value<color>(feature,attrs), format_defaults.halo_fill); format_->text_transform = util::apply_visitor(extract_value<text_transform_enum>(feature,attrs), format_defaults.text_transform); format_->face_name = format_defaults.face_name; format_->fontset = format_defaults.fontset; format_->ff_settings = util::apply_visitor(extract_value<font_feature_settings>(feature,attrs), format_defaults.ff_settings); // Turn off ligatures if character_spacing > 0. if (format_->character_spacing > .0 && format_->ff_settings.count() == 0) { format_->ff_settings.append(font_feature_liga_off); } tree->apply(format_, feature, attrs, *this); } else { MAPNIK_LOG_WARN(text_properties) << "text_symbolizer_properties can't produce text: No formatting tree!"; } }
void copy_text_ptr(T & sym) const { boost::ignore_unused_variable_warning(sym); MAPNIK_LOG_WARN(rule) << "rule: deep copying TextSymbolizers is broken!"; }
void render_point_symbolizer(point_symbolizer const &sym, mapnik::feature_impl &feature, proj_transform const &prj_trans, RendererType &common, F render_marker) { std::string filename = get<std::string,keys::file>(sym,feature, common.vars_); std::shared_ptr<mapnik::marker const> mark = filename.empty() ? std::make_shared<mapnik::marker const>(mapnik::marker_rgba8()) : marker_cache::instance().find(filename, true); if (!mark->is<mapnik::marker_null>()) { value_double opacity = get<value_double,keys::opacity>(sym, feature, common.vars_); value_bool allow_overlap = get<value_bool, keys::allow_overlap>(sym, feature, common.vars_); value_bool ignore_placement = get<value_bool, keys::ignore_placement>(sym, feature, common.vars_); point_placement_enum placement= get<point_placement_enum, keys::point_placement_type>(sym, feature, common.vars_); box2d<double> const& bbox = mark->bounding_box(); coord2d center = bbox.center(); agg::trans_affine tr; auto image_transform = get_optional<transform_type>(sym, keys::image_transform); if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform, common.scale_factor_); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine recenter_tr = recenter * tr; box2d<double> label_ext = bbox * recenter_tr * agg::trans_affine_scaling(common.scale_factor_); mapnik::geometry::geometry<double> const& geometry = feature.get_geometry(); mapnik::geometry::point<double> pt; geometry::geometry_types type = geometry::geometry_type(geometry); if (placement == CENTROID_POINT_PLACEMENT || type == geometry::geometry_types::Point || type == geometry::geometry_types::MultiPoint) { if (!geometry::centroid(geometry, pt)) return; } else if (type == mapnik::geometry::geometry_types::Polygon) { auto const& poly = mapnik::util::get<geometry::polygon<double> >(geometry); geometry::polygon_vertex_adapter<double> va(poly); if (!label::interior_position(va ,pt.x, pt.y)) return; } else { MAPNIK_LOG_WARN(point_symbolizer) << "TODO: unhandled geometry type for point symbolizer"; return; } double x = pt.x; double y = pt.y; double z = 0; prj_trans.backward(x,y,z); common.t_.forward(&x,&y); label_ext.re_center(x,y); if (allow_overlap || common.detector_->has_placement(label_ext)) { render_marker(pixel_position(x, y), *mark, tr, opacity); if (!ignore_placement) common.detector_->insert(label_ext); } } }
void grid_renderer<T>::process(raster_symbolizer const&, mapnik::feature_impl &, proj_transform const&) { MAPNIK_LOG_WARN(grid_renderer) << "grid_renderer: raster_symbolizer is not yet supported"; }
bool markers_placement<Locator, Detector>::get_point( double & x, double & y, double & angle, bool add_to_detector) { if (done_) return false; unsigned cmd; /* This functions starts at the position of the previous marker, walks along the path, counting how far it has to go in spacing_left. If one marker can't be placed at the position it should go to it is moved a bit. The error is compensated for in the next call to this function. error > 0: Marker too near to the end of the path. error = 0: Perfect position. error < 0: Marker too near to the beginning of the path. */ if (marker_nr_++ == 0) { //First marker spacing_left_ = spacing_ / 2; } else { spacing_left_ = spacing_; } spacing_left_ -= error_; error_ = 0; //Loop exits when a position is found or when no more segments are available while (true) { //Do not place markers too close to the beginning of a segment if (spacing_left_ < marker_width_/2) { set_spacing_left(marker_width_/2); //Only moves forward } //Error for this marker is too large. Skip to the next position. if (abs(error_) > max_error_ * spacing_) { if (error_ > spacing_) { error_ = 0; //Avoid moving backwards MAPNIK_LOG_WARN(markers_placement) << "Extremely large error in markers_placement. Please file a bug report."; } spacing_left_ += spacing_ - error_; error_ = 0; } double dx = next_x - last_x; double dy = next_y - last_y; double segment_length = std::sqrt(dx * dx + dy * dy); if (segment_length <= spacing_left_) { //Segment is to short to place marker. Find next segment spacing_left_ -= segment_length; last_x = next_x; last_y = next_y; while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y))) { //Skip over "move" commands last_x = next_x; last_y = next_y; } if (agg::is_stop(cmd)) { done_ = true; return false; } continue; //Try again } /* At this point we know the following things: - segment_length > spacing_left - error is small enough - at least half a marker fits into this segment */ //Check if marker really fits in this segment if (segment_length < marker_width_) { //Segment to short => Skip this segment set_spacing_left(segment_length + marker_width_/2); //Only moves forward continue; } else if (segment_length - spacing_left_ < marker_width_/2) { //Segment is long enough, but we are to close to the end //Note: This function moves backwards. This could lead to an infinite // loop when another function adds a positive offset. Therefore we // only move backwards when there is no offset if (error_ == 0) { set_spacing_left(segment_length - marker_width_/2, true); } else { //Skip this segment set_spacing_left(segment_length + marker_width_/2); //Only moves forward } continue; //Force checking of max_error constraint } angle = atan2(dy, dx); x = last_x + dx * (spacing_left_ / segment_length); y = last_y + dy * (spacing_left_ / segment_length); box2d<double> box = perform_transform(angle, x, y); if (!allow_overlap_ && !detector_.has_placement(box)) { //10.0 is the approxmiate number of positions tried and choosen arbitrarily set_spacing_left(spacing_left_ + spacing_ * max_error_ / 10.0); //Only moves forward continue; } if (add_to_detector) detector_.insert(box); last_x = x; last_y = y; return true; } }
bool freetype_engine::register_font_impl(std::string const& file_name, font_library & library, freetype_engine::font_file_mapping_type & font_file_mapping) { MAPNIK_LOG_DEBUG(font_engine_freetype) << "registering: " << file_name; mapnik::util::file file(file_name); if (!file) return false; FT_Face face = 0; FT_Open_Args args; FT_StreamRec streamRec; memset(&args, 0, sizeof(args)); memset(&streamRec, 0, sizeof(streamRec)); streamRec.base = 0; streamRec.pos = 0; streamRec.size = file.size(); streamRec.descriptor.pointer = file.get(); streamRec.read = ft_read_cb; streamRec.close = nullptr; args.flags = FT_OPEN_STREAM; args.stream = &streamRec; 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 < num_faces; ++i ) { // if face is null then this is the first face FT_Error error = FT_Open_Face(library.get(), &args, i, &face); if (error) break; // store num_faces locally, after FT_Done_Face it can not be accessed any more if (num_faces == 0) 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) { std::string name = std::string(face->family_name) + " " + std::string(face->style_name); // skip fonts with leading . in the name if (!boost::algorithm::starts_with(name,".")) { // http://stackoverflow.com/a/24795559/2333354 auto range = font_file_mapping.equal_range(name); if (range.first == range.second) // the key was previously absent; insert a pair { font_file_mapping.emplace_hint(range.first, name, std::make_pair(i,file_name)); } else // the key was present, replace the associated value { /* some action with value range.first->second about to be overwritten here */ MAPNIK_LOG_WARN(font_engine_freetype) << "registering new " << name << " at '" << file_name << "'"; range.first->second = std::make_pair(i,file_name); // replace value } success = true; } } else { std::ostringstream s; 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"; MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str(); } if (face) FT_Done_Face(face); } return success; }