add 'interior' placement option to text_symbolizr - patch from Toby Collet - closes #709

This commit is contained in:
Dane Springmeyer 2011-02-01 08:13:08 +00:00
parent 4b076272fe
commit e803b1c2ec
7 changed files with 91 additions and 8 deletions

View file

@ -165,6 +165,7 @@ void export_text_symbolizer()
.value("LINE_PLACEMENT",LINE_PLACEMENT)
.value("POINT_PLACEMENT",POINT_PLACEMENT)
.value("VERTEX_PLACEMENT",VERTEX_PLACEMENT)
.value("INTERIOR_PLACEMENT",INTERIOR_PLACEMENT)
;
enumeration_<vertical_alignment_e>("vertical_alignment")
.value("TOP",TOP)

View file

@ -105,6 +105,75 @@ public:
}
return result;
}
void label_interior_position(double *x, double *y) const
{
// start with the default label position
label_position(x,y);
unsigned size = cont_.size();
// if we are not a polygon, or the default is within the polygon we are done
if (size < 3 || hit_test(*x,*y,0))
return;
// otherwise we find a horizontal line across the polygon and then return the
// center of the widest intersection between the polygon and the line.
std::vector<double> intersections; // only need to store the X as we know the y
double x0, y0;
rewind(0);
unsigned command = vertex(&x0, &y0);
double x1,y1;
while (SEG_END != (command=vertex(&x1, &y1)))
{
if (command != SEG_MOVETO)
{
// if the segments overlap
if (y0==y1)
{
if (y0==*y)
{
double xi = (x0+x1)/2.0;
intersections.push_back(xi);
}
}
// if the path segment crosses the bisector
else if ((y0 <= *y && y1 >= *y) ||
(y0 >= *y && y1 <= *y))
{
// then calculate the intersection
double xi = x0;
if (x0 != x1)
{
double m = (y1-y0)/(x1-x0);
double c = y0 - m*x0;
xi = (*y-c)/m;
}
intersections.push_back(xi);
}
}
x0 = x1;
y0 = y1;
}
// no intersections we just return the default
if (intersections.empty())
return;
x0=intersections[0];
double max_width = 0;
for (unsigned ii = 1; ii < intersections.size(); ++ii)
{
double x1=intersections[ii];
double xc=(x0+x1)/2.0;
double width = fabs(x1-x0);
if (width > max_width && hit_test(xc,*y,0))
{
*x=xc;
max_width = width;
}
}
}
void label_position(double *x, double *y) const
{
unsigned size = cont_.size();

View file

@ -45,6 +45,7 @@ enum label_placement_enum {
POINT_PLACEMENT,
LINE_PLACEMENT,
VERTEX_PLACEMENT,
INTERIOR_PLACEMENT,
label_placement_enum_MAX
};

View file

@ -121,7 +121,7 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
path_type path(t_,geom,prj_trans);
label_placement_enum how_placed = sym.get_label_placement();
if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT)
if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT || how_placed == INTERIOR_PLACEMENT)
{
// for every vertex, try and place a shield/text
geom.rewind(0);
@ -138,6 +138,8 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
if( how_placed == VERTEX_PLACEMENT )
geom.vertex(&label_x,&label_y); // by vertex
else if( how_placed == INTERIOR_PLACEMENT )
geom.label_interior_position(&label_x,&label_y);
else
geom.label_position(&label_x, &label_y); // by middle of line or by point
prj_trans.backward(label_x,label_y, z);

View file

@ -95,10 +95,14 @@ void agg_renderer<T>::process(text_symbolizer const& sym,
{
placement text_placement(info,sym,scale_factor_);
text_placement.avoid_edges = sym.get_avoid_edges();
if (sym.get_label_placement() == POINT_PLACEMENT)
if (sym.get_label_placement() == POINT_PLACEMENT ||
sym.get_label_placement() == INTERIOR_PLACEMENT)
{
double label_x, label_y, z=0.0;
geom.label_position(&label_x, &label_y);
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);

View file

@ -1141,7 +1141,7 @@ void cairo_renderer_base::process(shield_symbolizer const& sym,
path_type path(t_, geom, prj_trans);
label_placement_enum how_placed = sym.get_label_placement();
if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT)
if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT || how_placed == INTERIOR_PLACEMENT)
{
// for every vertex, try and place a shield/text
geom.rewind(0);
@ -1158,6 +1158,8 @@ void cairo_renderer_base::process(shield_symbolizer const& sym,
if( how_placed == VERTEX_PLACEMENT )
geom.vertex(&label_x,&label_y); // by vertex
else if( how_placed == INTERIOR_PLACEMENT )
geom.label_interior_position(&label_x,&label_y);
else
geom.label_position(&label_x, &label_y); // by middle of line or by point
prj_trans.backward(label_x,label_y, z);
@ -1550,11 +1552,14 @@ void cairo_renderer_base::process(text_symbolizer const& sym,
path_type path(t_, geom, prj_trans);
placement text_placement(info, sym, 1.0);
if (sym.get_label_placement() == POINT_PLACEMENT)
if (sym.get_label_placement() == POINT_PLACEMENT ||
sym.get_label_placement() == INTERIOR_PLACEMENT)
{
double label_x, label_y, z = 0.0;
geom.label_position(&label_x, &label_y);
double label_x, label_y, 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);

View file

@ -34,6 +34,7 @@ static const char * label_placement_strings[] = {
"point",
"line",
"vertex",
"interior",
""
};