diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index d273e81c3..91e73b2e6 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -28,117 +28,192 @@ namespace mapnik { -template -void agg_renderer::process(text_symbolizer const& sym, - Feature const& feature, - proj_transform const& prj_trans) +struct largest_bbox_comp +{ + bool operator() (geometry_type const* g0, geometry_type const* g1) const + { + box2d b0 = g0->envelope(); + box2d b1 = g1->envelope(); + return b0.width()*b0.height() < b1.width()*b1.height(); + } + +}; + +typedef boost::tuple point_type; +typedef std::vector label_points_type; + +void get_label_points(label_points_type & labels, + Feature const& feature, + text_symbolizer const& sym, + proj_transform const& prj_trans, + CoordTransform const& t + ) { - // Use a boost::ptr_vector here instread of std::vector? std::vector geometries_to_process; + unsigned num_geom = feature.num_geometries(); for (unsigned i=0; i 0) { // TODO - find less costly method than fetching full envelope - box2d gbox = t_.forward(geom.envelope(),prj_trans); + box2d gbox = t.forward(geom.envelope(),prj_trans); if (gbox.width() < sym.get_minimum_path_length()) { continue; } } - // TODO - calculate length here as well - geometries_to_process.push_back(const_cast(&geom)); + geometries_to_process.push_back(const_cast(&geom)); } - if (!geometries_to_process.size() > 0) - return; // early return to avoid significant overhead of rendering setup + vector::const_iterator largest = std::max_element(geometries_to_process.begin(), + geometries_to_process.end(), + largest_bbox_comp()); + if (largest != geometries_to_process.end()) + { + double z=0.0; + double label_x,label_y; + if (sym.get_label_placement() == POINT_PLACEMENT) + (*largest)->label_position(&label_x, &label_y); + else if (sym.get_label_placement() == INTERIOR_PLACEMENT) + (*largest)->label_interior_position(&label_x, &label_y); + else // default to bbox center + { + box2d box = (*largest)->envelope(); + coord2d c = box.center(); + label_x = c.x; + label_y = c.y; + } + prj_trans.backward(label_x,label_y, z); + t.forward(&label_x,&label_y); + + labels.push_back(boost::make_tuple(label_x,label_y)); + } + + /* + std::sort(geometries_to_process.begin(), geometries_to_process.end(), largest_bbox_first()); + BOOST_FOREACH( geometry_type * g, geometries_to_process) + { + double z=0.0; + double label_x,label_y; + if (sym.get_label_placement() == POINT_PLACEMENT) + g->label_position(&label_x, &label_y); + else + g->label_interior_position(&label_x, &label_y); + prj_trans.backward(label_x,label_y, z); + t.forward(&label_x,&label_y); + + labels.push_back(boost::make_tuple(label_x,label_y)); + } + */ +} +template +void agg_renderer::process(text_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + label_points_type labels; + get_label_points(labels, feature, sym, prj_trans, t_); + + if (labels.size() == 0) return; + typedef coord_transform2 path_type; +////////////////////////////////////////////////////////////////////// + + expression_ptr name_expr = sym.get_name(); + if (!name_expr) return; + value_type result = boost::apply_visitor(evaluate(feature),*name_expr); + UnicodeString text = result.to_unicode(); + + if ( sym.get_text_transform() == UPPERCASE) + { + text = text.toUpper(); + } + else if ( sym.get_text_transform() == LOWERCASE) + { + text = text.toLower(); + } + else if ( sym.get_text_transform() == CAPITALIZE) + { + text = text.toTitle(0); + } + + if ( text.length() <= 0 ) return; + color const& fill = sym.get_fill(); + + face_set_ptr faces; + + if (sym.get_fontset().size() > 0) + { + faces = font_manager_.get_face_set(sym.get_fontset()); + } + else + { + faces = font_manager_.get_face_set(sym.get_face_name()); + } + + stroker_ptr strk = font_manager_.get_stroker(); + if (!(faces->size() > 0 && strk)) + { + throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'"); + } + +///////////////////////// +////////////// renderer + text_renderer ren(pixmap_, faces, *strk); + ren.set_fill(fill); + ren.set_halo_fill(sym.get_halo_fill()); + ren.set_halo_radius(sym.get_halo_radius() * scale_factor_); + ren.set_opacity(sym.get_text_opacity()); + +///////////////////////// + +////// + box2d dims(0,0,width_,height_); + placement_finder finder(*detector_,dims); + + +/////////// + bool placement_found = false; text_placement_info_ptr placement_options = sym.get_placement_options()->get_placement_info(); while (!placement_found && placement_options->next()) { - expression_ptr name_expr = sym.get_name(); - if (!name_expr) return; - value_type result = boost::apply_visitor(evaluate(feature),*name_expr); - UnicodeString text = result.to_unicode(); - - if ( sym.get_text_transform() == UPPERCASE) - { - text = text.toUpper(); - } - else if ( sym.get_text_transform() == LOWERCASE) - { - text = text.toLower(); - } - else if ( sym.get_text_transform() == CAPITALIZE) - { - text = text.toTitle(NULL); - } - - if ( text.length() <= 0 ) continue; - color const& fill = sym.get_fill(); - - face_set_ptr faces; - - if (sym.get_fontset().size() > 0) - { - faces = font_manager_.get_face_set(sym.get_fontset()); - } - else - { - faces = font_manager_.get_face_set(sym.get_face_name()); - } - - stroker_ptr strk = font_manager_.get_stroker(); - if (!(faces->size() > 0 && strk)) - { - throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'"); - } - text_renderer ren(pixmap_, faces, *strk); ren.set_character_size(placement_options->text_size * scale_factor_); - ren.set_fill(fill); - ren.set_halo_fill(sym.get_halo_fill()); - ren.set_halo_radius(sym.get_halo_radius() * scale_factor_); - ren.set_opacity(sym.get_text_opacity()); - - box2d dims(0,0,width_,height_); - placement_finder finder(*detector_,dims); - - string_info info(text); + string_info info(text); faces->get_string_info(info); metawriter_with_properties writer = sym.get_metawriter(); - BOOST_FOREACH( geometry_type * geom, geometries_to_process ) + //BOOST_FOREACH( geometry_type * geom, geometries_to_process ) + BOOST_FOREACH (point_type const& pt, labels) { - while (!placement_found && placement_options->next_position_only()) + //while (!placement_found && placement_options->next_position_only()) { placement text_placement(info, sym, scale_factor_); text_placement.avoid_edges = sym.get_avoid_edges(); if (writer.first) text_placement.collect_extents =true; // needed for inmem metawriter - if (sym.get_label_placement() == POINT_PLACEMENT || - sym.get_label_placement() == INTERIOR_PLACEMENT) + //if (sym.get_label_placement() == POINT_PLACEMENT || + // sym.get_label_placement() == INTERIOR_PLACEMENT) { - double label_x=0.0; - double label_y=0.0; - double z=0.0; - if (sym.get_label_placement() == POINT_PLACEMENT) - geom->label_position(&label_x, &label_y); - else - geom->label_interior_position(&label_x, &label_y); - prj_trans.backward(label_x,label_y, z); - t_.forward(&label_x,&label_y); - + //double label_x=0.0; + //double label_y=0.0; + //double z=0.0; + //if (sym.get_label_placement() == POINT_PLACEMENT) + // geom->label_position(&label_x, &label_y); + //else + // geom->label_interior_position(&label_x, &label_y); + //prj_trans.backward(label_x,label_y, z); + //t_.forward(&label_x,&label_y); + + double angle = 0.0; expression_ptr angle_expr = sym.get_orientation(); if (angle_expr) @@ -148,17 +223,18 @@ void agg_renderer::process(text_symbolizer const& sym, angle = result.to_double(); } - finder.find_point_placement(text_placement, placement_options, label_x,label_y, + finder.find_point_placement(text_placement, placement_options, boost::get<0>(pt),boost::get<1>(pt), angle, sym.get_line_spacing(), sym.get_character_spacing()); finder.update_detector(text_placement); } - else if ( geom->num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT) - { - path_type path(t_,*geom,prj_trans); - finder.find_line_placements(text_placement, placement_options, path); - } - + + //else if ( geom->num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT) + // { + // path_type path(t_,*geom,prj_trans); + // finder.find_line_placements(text_placement, placement_options, path); + // } + if (!text_placement.placements.size()) continue; placement_found = true;