Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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";
        }
    }
}
Пример #4
0
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);
            }
        }
    }
}
Пример #5
0
 /** 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;
 }
Пример #6
0
    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\":";
    }
Пример #7
0
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();
}
Пример #8
0
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;
}
Пример #9
0
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;
    }
}
Пример #10
0
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;
}
Пример #11
0
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);
        }
    }
}
Пример #12
0
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();
}
Пример #13
0
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);
}
Пример #14
0
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!";
        }
    }
Пример #15
0
 void copy_text_ptr(T & sym) const
 {
     boost::ignore_unused_variable_warning(sym);
     MAPNIK_LOG_WARN(rule) << "rule: deep copying TextSymbolizers is broken!";
 }
Пример #16
0
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);
        }
    }
}
Пример #17
0
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";
}
Пример #18
0
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;
    }
}
Пример #19
0
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;
}