void placement_finder<DetectorT>::find_point_placements(T & shape_path) { unsigned cmd; double new_x = 0.0; double new_y = 0.0; double old_x = 0.0; double old_y = 0.0; bool first = true; double total_distance = get_total_distance<T>(shape_path); shape_path.rewind(0); if (distance == 0) //Point data, not a line { double x, y; shape_path.vertex(&x,&y); find_point_placement(x, y); return; } if (total_distance < p.minimum_path_length) return; int num_labels = 1; if (p.label_spacing > 0) num_labels = static_cast<int> (floor(total_distance / pi.get_actual_label_spacing())); if (p.force_odd_labels && num_labels % 2 == 0) num_labels--; if (num_labels <= 0) num_labels = 1; //Read out the tolerance // No tolreance if not given (old behaviour) double tolerance_delta, tolerance; if (p.label_position_tolerance > 0) { tolerance = p.label_position_tolerance; tolerance_delta = std::max ( 1.0, p.label_position_tolerance/100.0 ); } else { tolerance = 0.0; tolerance_delta = 1.0; } double distance = 0.0; // distance from last label double spacing = total_distance / num_labels; if (tolerance > spacing) tolerance = spacing; double target_distance = (spacing - tolerance) / 2; // first label should be placed at half the spacing double diff = 0.0; while (!agg::is_stop(cmd = shape_path.vertex(&new_x,&new_y))) //For each node in the shape { if (first || agg::is_move_to(cmd)) //Don't do any processing if it is the first node { first = false; } else { //Add the length of this segment to the total we have saved up double segment_length = std::sqrt(std::pow(old_x-new_x,2) + std::pow(old_y-new_y,2)); //Pythagoras distance += segment_length; //While we have enough distance to place text in while (distance > (target_distance + diff)) { //Try place at the specified place double new_weight = (segment_length - (distance - target_distance - diff))/segment_length; if (find_point_placement(old_x + (new_x-old_x)*new_weight, old_y + (new_y-old_y)*new_weight)) { distance -= target_distance; //Consume the spacing gap we have used up target_distance = spacing; //Need to reset the target_distance as it is spacing/2 for the first label. diff = 0.0; } else { diff += tolerance_delta; if (diff > tolerance) { distance -= target_distance; target_distance = spacing; diff = 0.0; } } } } old_x = new_x; old_y = new_y; } }
bool placement_finder::find_line_placements(T & path, bool points) { if (!layouts_.line_count()) return true; //TODO vertex_cache pp(path); bool success = false; while (pp.next_subpath()) { if (points) { if (pp.length() <= 0.001) { success = find_point_placement(pp.current_position()) || success; continue; } } else { if ((pp.length() < text_props_->minimum_path_length * scale_factor_) || (pp.length() <= 0.001) // Clipping removed whole geometry || (pp.length() < layouts_.width())) { continue; } } double spacing = get_spacing(pp.length(), points ? 0. : layouts_.width()); //horizontal_alignment_e halign = layouts_.back()->horizontal_alignment(); // halign == H_LEFT -> don't move if (horizontal_alignment_ == H_MIDDLE || horizontal_alignment_ == H_AUTO || horizontal_alignment_ == H_ADJUST) { if (!pp.forward(spacing / 2.0)) continue; } else if (horizontal_alignment_ == H_RIGHT) { if (!pp.forward(pp.length())) continue; } if (move_dx_ != 0.0) path_move_dx(pp, move_dx_); do { tolerance_iterator tolerance_offset(text_props_->label_position_tolerance * scale_factor_, spacing); //TODO: Handle halign while (tolerance_offset.next()) { vertex_cache::scoped_state state(pp); if (pp.move(tolerance_offset.get()) && ((points && find_point_placement(pp.current_position())) || (!points && single_line_placement(pp, text_props_->upright)))) { success = true; break; } } } while (pp.forward(spacing)); } return success; }