fix viewBox
coordinate system logic + apply transform in <use>
element
This commit is contained in:
parent
3fbce913d0
commit
3edcd4afa2
1 changed files with 47 additions and 14 deletions
|
@ -61,8 +61,8 @@ struct viewbox
|
||||||
{
|
{
|
||||||
double x0;
|
double x0;
|
||||||
double y0;
|
double y0;
|
||||||
double x1;
|
double width;
|
||||||
double y1;
|
double height;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -70,8 +70,8 @@ BOOST_FUSION_ADAPT_STRUCT (
|
||||||
mapnik::svg::viewbox,
|
mapnik::svg::viewbox,
|
||||||
(double, x0)
|
(double, x0)
|
||||||
(double, y0)
|
(double, y0)
|
||||||
(double, x1)
|
(double, width)
|
||||||
(double, y1)
|
(double, height)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -368,24 +368,31 @@ void parse_element(svg_parser & parser, char const* name, rapidxml::xml_node<cha
|
||||||
switch (name_to_int(name))
|
switch (name_to_int(name))
|
||||||
{
|
{
|
||||||
case name_to_int("path"):
|
case name_to_int("path"):
|
||||||
|
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||||
parse_path(parser, node);
|
parse_path(parser, node);
|
||||||
break;
|
break;
|
||||||
case name_to_int("polygon"):
|
case name_to_int("polygon"):
|
||||||
|
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||||
parse_polygon(parser, node);
|
parse_polygon(parser, node);
|
||||||
break;
|
break;
|
||||||
case name_to_int("polyline"):
|
case name_to_int("polyline"):
|
||||||
|
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||||
parse_polyline(parser, node);
|
parse_polyline(parser, node);
|
||||||
break;
|
break;
|
||||||
case name_to_int("line"):
|
case name_to_int("line"):
|
||||||
|
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||||
parse_line(parser, node);
|
parse_line(parser, node);
|
||||||
break;
|
break;
|
||||||
case name_to_int("rect"):
|
case name_to_int("rect"):
|
||||||
|
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||||
parse_rect(parser, node);
|
parse_rect(parser, node);
|
||||||
break;
|
break;
|
||||||
case name_to_int("circle"):
|
case name_to_int("circle"):
|
||||||
|
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||||
parse_circle(parser, node);
|
parse_circle(parser, node);
|
||||||
break;
|
break;
|
||||||
case name_to_int("ellipse"):
|
case name_to_int("ellipse"):
|
||||||
|
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||||
parse_ellipse(parser, node);
|
parse_ellipse(parser, node);
|
||||||
break;
|
break;
|
||||||
case name_to_int("svg"):
|
case name_to_int("svg"):
|
||||||
|
@ -615,28 +622,49 @@ void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
{
|
{
|
||||||
height = parse_svg_value(parser.err_handler(), height_attr->value(), has_percent_height);
|
height = parse_svg_value(parser.err_handler(), height_attr->value(), has_percent_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const* viewbox_attr = node->first_attribute("viewBox");
|
auto const* viewbox_attr = node->first_attribute("viewBox");
|
||||||
if (viewbox_attr)
|
if (viewbox_attr)
|
||||||
{
|
{
|
||||||
has_viewbox = parse_viewbox(parser.err_handler(), viewbox_attr->value(), vbox);
|
has_viewbox = parse_viewbox(parser.err_handler(), viewbox_attr->value(), vbox);
|
||||||
}
|
if (width > 0 && height > 0 && vbox.width > 0 && vbox.height > 0)
|
||||||
|
{
|
||||||
|
agg::trans_affine t{};
|
||||||
|
double sx = width / vbox.width;
|
||||||
|
double sy = height / vbox.height;
|
||||||
|
double scale = std::min(sx, sy);
|
||||||
|
// xMidYMid (the default)
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
double ratio1 = vbox.width / vbox.height;
|
||||||
|
double ratio2 = width / height;
|
||||||
|
|
||||||
|
if (ratio1 > ratio2)
|
||||||
|
{
|
||||||
|
t = agg::trans_affine_translation(0, -0.5 * (vbox.height - height / scale)) * t;
|
||||||
|
}
|
||||||
|
else if (ratio2 > ratio1)
|
||||||
|
{
|
||||||
|
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale), 0) * t;
|
||||||
|
}
|
||||||
|
t = agg::trans_affine_translation(-vbox.x0, -vbox.y0) * t;
|
||||||
|
parser.viewbox_tr_ = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (has_percent_width && !has_percent_height && has_viewbox)
|
if (has_percent_width && !has_percent_height && has_viewbox)
|
||||||
{
|
{
|
||||||
aspect_ratio = vbox.x1 / vbox.y1;
|
aspect_ratio = vbox.width / vbox.height;
|
||||||
width = aspect_ratio * height;
|
width = aspect_ratio * height;
|
||||||
}
|
}
|
||||||
else if (!has_percent_width && has_percent_height && has_viewbox)
|
else if (!has_percent_width && has_percent_height && has_viewbox)
|
||||||
{
|
{
|
||||||
aspect_ratio = vbox.x1 / vbox.y1;
|
aspect_ratio = vbox.width/vbox.height;
|
||||||
height = height / aspect_ratio;
|
height = height / aspect_ratio;
|
||||||
}
|
}
|
||||||
else if (has_percent_width && has_percent_height && has_viewbox)
|
else if (has_percent_width && has_percent_height && has_viewbox)
|
||||||
{
|
{
|
||||||
width = vbox.x1;
|
width = vbox.width;
|
||||||
height = vbox.y1;
|
height = vbox.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.path_.set_dimensions(width, height);
|
parser.path_.set_dimensions(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,26 +729,31 @@ void parse_use(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
w = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
w = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
||||||
|
if (percent) w *= parser.path_.width();
|
||||||
}
|
}
|
||||||
attr = node->first_attribute("height");
|
attr = node->first_attribute("height");
|
||||||
if (attr)
|
if (attr)
|
||||||
{
|
{
|
||||||
h = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
h = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
||||||
|
if (percent) h *= parser.path_.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
agg::trans_affine t{};
|
agg::trans_affine t{};
|
||||||
if (w != 0.0 && h != 0.0)
|
|
||||||
|
if (!node->first_attribute("transform") && w != 0.0 && h != 0.0)
|
||||||
{
|
{
|
||||||
if(w < 0.0)
|
if (w < 0.0)
|
||||||
{
|
{
|
||||||
parser.err_handler().on_error("parse_use: Invalid width");
|
parser.err_handler().on_error("parse_use: Invalid width");
|
||||||
}
|
}
|
||||||
else if(h < 0.0)
|
else if (h < 0.0)
|
||||||
{
|
{
|
||||||
parser.err_handler().on_error("parse_use: Invalid height");
|
parser.err_handler().on_error("parse_use: Invalid height");
|
||||||
}
|
}
|
||||||
double scale = std::min(double(w/parser.path_.width()), double(h/parser.path_.height()));
|
double scale = std::min(double(w / parser.path_.width()), double(h / parser.path_.height()));
|
||||||
t *= agg::trans_affine_scaling(scale);
|
t *= agg::trans_affine_scaling(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
t *= agg::trans_affine_translation(x, y);
|
t *= agg::trans_affine_translation(x, y);
|
||||||
parser.path_.transform().premultiply(t);
|
parser.path_.transform().premultiply(t);
|
||||||
traverse_tree(parser, base_node);
|
traverse_tree(parser, base_node);
|
||||||
|
|
Loading…
Add table
Reference in a new issue