Revert previous fix for #89 and add a new improved fix that enhances the

value class to have a proper null type and do comparisions SQL style so
that null is neither equal nor not equal to other things.
This commit is contained in:
Tom Hughes 2008-04-12 15:22:27 +00:00
parent a27bde741e
commit 4483d59797
5 changed files with 259 additions and 178 deletions

View file

@ -47,6 +47,11 @@ namespace boost { namespace python {
{ {
return ::PyUnicode_FromWideChar((wchar_t*)s.getBuffer(),implicit_cast<ssize_t>(s.length())); return ::PyUnicode_FromWideChar((wchar_t*)s.getBuffer(),implicit_cast<ssize_t>(s.length()));
} }
PyObject * operator() (mapnik::value_null const& s) const
{
return NULL;
}
}; };
struct mapnik_value_to_python struct mapnik_value_to_python

View file

@ -120,11 +120,6 @@ namespace mapnik {
return props_.end(); return props_.end();
} }
bool exists(const std::string &k) const
{
return props_.find(k) != props_.end();
}
std::string to_string() const std::string to_string() const
{ {
std::stringstream ss; std::stringstream ss;

View file

@ -39,14 +39,18 @@
namespace mapnik { namespace mapnik {
typedef boost::variant<bool,int,double,UnicodeString> value_base; struct value_null
{
};
typedef boost::variant<value_null,bool,int,double,UnicodeString> value_base;
namespace impl { namespace impl {
struct equals struct equals
: public boost::static_visitor<bool> : public boost::static_visitor<bool>
{ {
template <typename T, typename U> template <typename T, typename U>
bool operator() (const T &, const U & ) const bool operator() (const T &, const U &) const
{ {
return false; return false;
} }
@ -72,19 +76,73 @@ namespace mapnik {
{ {
return lhs == rhs; return lhs == rhs;
} }
bool operator() (value_null, value_null) const
{
return false;
}
}; };
struct not_equals
: public boost::static_visitor<bool>
{
template <typename T, typename U>
bool operator() (const T &, const U &) const
{
return true;
}
template <typename T>
bool operator() (T lhs, T rhs) const
{
return lhs != rhs;
}
bool operator() (int lhs, double rhs) const
{
return lhs != rhs;
}
bool operator() (double lhs, int rhs) const
{
return lhs != rhs;
}
bool operator() (UnicodeString const& lhs,
UnicodeString const& rhs) const
{
return lhs != rhs;
}
bool operator() (value_null, value_null) const
{
return false;
}
template <typename T>
bool operator() (value_null, const T &) const
{
return false;
}
template <typename T>
bool operator() (const T &, value_null) const
{
return false;
}
};
struct greater_than struct greater_than
: public boost::static_visitor<bool> : public boost::static_visitor<bool>
{ {
template <typename T, typename U> template <typename T, typename U>
bool operator()( const T &, const U & ) const bool operator()(const T &, const U &) const
{ {
return false; return false;
} }
template <typename T> template <typename T>
bool operator()( T lhs, T rhs ) const bool operator()(T lhs, T rhs) const
{ {
return lhs > rhs; return lhs > rhs;
} }
@ -103,13 +161,18 @@ namespace mapnik {
{ {
return lhs > rhs; return lhs > rhs;
} }
bool operator() (value_null, value_null) const
{
return false;
}
}; };
struct greater_or_equal struct greater_or_equal
: public boost::static_visitor<bool> : public boost::static_visitor<bool>
{ {
template <typename T, typename U> template <typename T, typename U>
bool operator()( const T &, const U & ) const bool operator()(const T &, const U &) const
{ {
return false; return false;
} }
@ -130,23 +193,28 @@ namespace mapnik {
return lhs >= rhs; return lhs >= rhs;
} }
bool operator() (UnicodeString const& lhs, UnicodeString const& rhs ) const bool operator() (UnicodeString const& lhs, UnicodeString const& rhs) const
{ {
return lhs >= rhs; return lhs >= rhs;
} }
bool operator() (value_null, value_null) const
{
return false;
}
}; };
struct less_than struct less_than
: public boost::static_visitor<bool> : public boost::static_visitor<bool>
{ {
template <typename T, typename U> template <typename T, typename U>
bool operator()( const T &, const U & ) const bool operator()(const T &, const U &) const
{ {
return false; return false;
} }
template <typename T> template <typename T>
bool operator()( T lhs,T rhs) const bool operator()(T lhs, T rhs) const
{ {
return lhs < rhs; return lhs < rhs;
} }
@ -161,24 +229,29 @@ namespace mapnik {
return lhs < rhs; return lhs < rhs;
} }
bool operator()( UnicodeString const& lhs, bool operator()(UnicodeString const& lhs,
UnicodeString const& rhs ) const UnicodeString const& rhs ) const
{ {
return lhs < rhs; return lhs < rhs;
} }
bool operator() (value_null, value_null) const
{
return false;
}
}; };
struct less_or_equal struct less_or_equal
: public boost::static_visitor<bool> : public boost::static_visitor<bool>
{ {
template <typename T, typename U> template <typename T, typename U>
bool operator()( const T &, const U & ) const bool operator()(const T &, const U &) const
{ {
return false; return false;
} }
template <typename T> template <typename T>
bool operator()(T lhs, T rhs ) const bool operator()(T lhs, T rhs) const
{ {
return lhs <= rhs; return lhs <= rhs;
} }
@ -194,11 +267,16 @@ namespace mapnik {
} }
template <typename T> template <typename T>
bool operator()( UnicodeString const& lhs, bool operator()(UnicodeString const& lhs,
UnicodeString const& rhs ) const UnicodeString const& rhs ) const
{ {
return lhs <= rhs; return lhs <= rhs;
} }
bool operator() (value_null, value_null) const
{
return false;
}
}; };
template <typename V> template <typename V>
@ -386,7 +464,12 @@ namespace mapnik {
ss << std::setprecision(16) << val; ss << std::setprecision(16) << val;
return ss.str(); return ss.str();
} }
};
std::string operator() (value_null const& val) const
{
return "";
}
};
struct to_unicode : public boost::static_visitor<UnicodeString> struct to_unicode : public boost::static_visitor<UnicodeString>
{ {
@ -411,6 +494,11 @@ namespace mapnik {
out << std::setprecision(16) << val; out << std::setprecision(16) << val;
return UnicodeString(out.str().c_str()); return UnicodeString(out.str().c_str());
} }
UnicodeString operator() (value_null const& val) const
{
return UnicodeString("");
}
}; };
struct to_expression_string : public boost::static_visitor<std::string> struct to_expression_string : public boost::static_visitor<std::string>
@ -455,9 +543,14 @@ namespace mapnik {
ss << std::setprecision(16) << val; ss << std::setprecision(16) << val;
return ss.str(); return ss.str();
} }
std::string operator() (value_null const& val) const
{
return "null";
}
}; };
} }
class value class value
{ {
value_base base_; value_base base_;
@ -468,7 +561,7 @@ namespace mapnik {
public: public:
value () value ()
: base_(0) {} : base_(value_null()) {}
template <typename T> value(T _val_) template <typename T> value(T _val_)
: base_(_val_) {} : base_(_val_) {}
@ -480,7 +573,7 @@ namespace mapnik {
bool operator!=(value const& other) const bool operator!=(value const& other) const
{ {
return !(boost::apply_visitor(impl::equals(),base_,other.base_)); return boost::apply_visitor(impl::not_equals(),base_,other.base_);
} }
bool operator>(value const& other) const bool operator>(value const& other) const

View file

@ -456,52 +456,49 @@ namespace mapnik
proj_transform const& prj_trans) proj_transform const& prj_trans)
{ {
typedef coord_transform2<CoordTransform,geometry2d> path_type; typedef coord_transform2<CoordTransform,geometry2d> path_type;
if (feature.exists(sym.get_name())) UnicodeString text = feature[sym.get_name()].to_unicode();
boost::shared_ptr<ImageData32> const& data = sym.get_image();
if (text.length() > 0 && data)
{ {
UnicodeString text = feature[sym.get_name()].to_unicode(); face_ptr face = font_manager_.get_face(sym.get_face_name());
boost::shared_ptr<ImageData32> const& data = sym.get_image(); if (face)
if (text.length() > 0 && data)
{ {
face_ptr face = font_manager_.get_face(sym.get_face_name()); text_renderer<mapnik::Image32> ren(pixmap_,face);
if (face) ren.set_pixel_size(sym.get_text_size());
ren.set_fill(sym.get_fill());
string_info info(text);
face->get_string_info(info);
placement_finder<label_collision_detector4> finder(detector_);
unsigned num_geom = feature.num_geometries();
for (unsigned i=0;i<num_geom;++i)
{ {
text_renderer<mapnik::Image32> ren(pixmap_,face); geometry2d const& geom = feature.get_geometry(i);
ren.set_pixel_size(sym.get_text_size()); if (geom.num_points() > 0) // don't bother with empty geometries
ren.set_fill(sym.get_fill()); {
path_type path(t_,geom,prj_trans);
string_info info(text); placement text_placement(info, sym);
face->get_string_info(info); text_placement.avoid_edges = sym.get_avoid_edges();
finder.find_point_placements<path_type>(text_placement,path);
placement_finder<label_collision_detector4> finder(detector_);
unsigned num_geom = feature.num_geometries();
for (unsigned i=0;i<num_geom;++i)
{
geometry2d const& geom = feature.get_geometry(i);
if (geom.num_points() > 0) // don't bother with empty geometries
{
path_type path(t_,geom,prj_trans);
placement text_placement(info, sym);
text_placement.avoid_edges = sym.get_avoid_edges();
finder.find_point_placements<path_type>(text_placement,path);
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii) for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
{ {
int w = data->width(); int w = data->width();
int h = data->height(); int h = data->height();
double x = text_placement.placements[ii].starting_x; double x = text_placement.placements[ii].starting_x;
double y = text_placement.placements[ii].starting_y; double y = text_placement.placements[ii].starting_y;
int px=int(x - (w/2)); int px=int(x - (w/2));
int py=int(y - (h/2)); int py=int(y - (h/2));
pixmap_.set_rectangle_alpha(px,py,*data); pixmap_.set_rectangle_alpha(px,py,*data);
Envelope<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]); Envelope<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
ren.render(x,y); ren.render(x,y);
}
} }
} }
} }
@ -668,61 +665,58 @@ namespace mapnik
proj_transform const& prj_trans) proj_transform const& prj_trans)
{ {
typedef coord_transform2<CoordTransform,geometry2d> path_type; typedef coord_transform2<CoordTransform,geometry2d> path_type;
if (feature.exists(sym.get_name())) UnicodeString text = feature[sym.get_name()].to_unicode();
if ( text.length() > 0 )
{ {
UnicodeString text = feature[sym.get_name()].to_unicode(); Color const& fill = sym.get_fill();
if ( text.length() > 0 ) face_ptr face = font_manager_.get_face(sym.get_face_name());
if (face)
{ {
Color const& fill = sym.get_fill(); text_renderer<mapnik::Image32> ren(pixmap_,face);
face_ptr face = font_manager_.get_face(sym.get_face_name()); ren.set_pixel_size(sym.get_text_size());
if (face) ren.set_fill(fill);
ren.set_halo_fill(sym.get_halo_fill());
ren.set_halo_radius(sym.get_halo_radius());
placement_finder<label_collision_detector4> finder(detector_);
string_info info(text);
face->get_string_info(info);
unsigned num_geom = feature.num_geometries();
for (unsigned i=0;i<num_geom;++i)
{ {
text_renderer<mapnik::Image32> ren(pixmap_,face); geometry2d const& geom = feature.get_geometry(i);
ren.set_pixel_size(sym.get_text_size()); if (geom.num_points() > 0) // don't bother with empty geometries
ren.set_fill(fill);
ren.set_halo_fill(sym.get_halo_fill());
ren.set_halo_radius(sym.get_halo_radius());
placement_finder<label_collision_detector4> finder(detector_);
string_info info(text);
face->get_string_info(info);
unsigned num_geom = feature.num_geometries();
for (unsigned i=0;i<num_geom;++i)
{ {
geometry2d const& geom = feature.get_geometry(i); path_type path(t_,geom,prj_trans);
if (geom.num_points() > 0) // don't bother with empty geometries placement text_placement(info,sym);
if (sym.get_label_placement() == POINT_PLACEMENT)
{ {
path_type path(t_,geom,prj_trans); double label_x, label_y, z=0.0;
placement text_placement(info,sym); geom.label_position(&label_x, &label_y);
if (sym.get_label_placement() == POINT_PLACEMENT) prj_trans.backward(label_x,label_y, z);
{ t_.forward(&label_x,&label_y);
double label_x, label_y, z=0.0; finder.find_point_placement(text_placement,label_x,label_y);
geom.label_position(&label_x, &label_y); }
prj_trans.backward(label_x,label_y, z); else //LINE_PLACEMENT
t_.forward(&label_x,&label_y); {
finder.find_point_placement(text_placement,label_x,label_y); finder.find_line_placements<path_type>(text_placement,path);
} }
else //LINE_PLACEMENT
{
finder.find_line_placements<path_type>(text_placement,path);
}
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii) for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii)
{ {
double x = text_placement.placements[ii].starting_x; double x = text_placement.placements[ii].starting_x;
double y = text_placement.placements[ii].starting_y; double y = text_placement.placements[ii].starting_y;
Envelope<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]); Envelope<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
ren.render(x,y); ren.render(x,y);
}
} }
} }
} }
else }
{ else
throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'"); {
} throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'");
} }
} }
} }

View file

@ -750,47 +750,44 @@ namespace mapnik
{ {
typedef coord_transform2<CoordTransform,geometry2d> path_type; typedef coord_transform2<CoordTransform,geometry2d> path_type;
if (feature.exists(sym.get_name())) UnicodeString text = feature[sym.get_name()].to_unicode();
boost::shared_ptr<ImageData32> const& data = sym.get_image();
if (text.length() > 0 && data)
{ {
UnicodeString text = feature[sym.get_name()].to_unicode(); cairo_face_ptr face = face_manager_.get_face(sym.get_face_name());
boost::shared_ptr<ImageData32> const& data = sym.get_image();
if (text.length() > 0 && data) if (face)
{ {
cairo_face_ptr face = face_manager_.get_face(sym.get_face_name()); cairo_context context(context_);
if (face) context.set_font_face(face);
string_info info(text);
face->get_string_info(sym.get_text_size(), info);
placement_finder<label_collision_detector4> finder(detector_);
for (unsigned i = 0; i < feature.num_geometries(); ++i)
{ {
cairo_context context(context_); geometry2d const& geom = feature.get_geometry(i);
context.set_font_face(face); if (geom.num_points() > 0) // don't bother with empty geometries
string_info info(text);
face->get_string_info(sym.get_text_size(), info);
placement_finder<label_collision_detector4> finder(detector_);
for (unsigned i = 0; i < feature.num_geometries(); ++i)
{ {
geometry2d const& geom = feature.get_geometry(i); path_type path(t_, geom, prj_trans);
placement text_placement(info, sym);
if (geom.num_points() > 0) // don't bother with empty geometries text_placement.avoid_edges = sym.get_avoid_edges();
finder.find_point_placements<path_type>(text_placement, path);
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
{ {
path_type path(t_, geom, prj_trans); double shield_x = text_placement.placements[ii].starting_x - data->width() / 2;
placement text_placement(info, sym); double shield_y = text_placement.placements[ii].starting_y - data->height() / 2;
text_placement.avoid_edges = sym.get_avoid_edges(); context.add_image(shield_x, shield_y, *data);
finder.find_point_placements<path_type>(text_placement, path); context.add_text(sym, text_placement.placements[ii], face);
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
{
double shield_x = text_placement.placements[ii].starting_x - data->width() / 2;
double shield_y = text_placement.placements[ii].starting_y - data->height() / 2;
context.add_image(shield_x, shield_y, *data);
context.add_text(sym, text_placement.placements[ii], face);
}
} }
} }
} }
@ -927,60 +924,57 @@ namespace mapnik
{ {
typedef coord_transform2<CoordTransform,geometry2d> path_type; typedef coord_transform2<CoordTransform,geometry2d> path_type;
if (feature.exists(sym.get_name())) UnicodeString text = feature[sym.get_name()].to_unicode();
if (text.length() > 0)
{ {
UnicodeString text = feature[sym.get_name()].to_unicode(); cairo_face_ptr face = face_manager_.get_face(sym.get_face_name());
if (text.length() > 0) if (face)
{ {
cairo_face_ptr face = face_manager_.get_face(sym.get_face_name()); cairo_context context(context_);
if (face) context.set_font_face(face);
string_info info(text);
face->get_string_info(sym.get_text_size(), info);
placement_finder<label_collision_detector4> finder(detector_);
for (unsigned i = 0; i < feature.num_geometries(); ++i)
{ {
cairo_context context(context_); geometry2d const& geom = feature.get_geometry(i);
context.set_font_face(face); if (geom.num_points() > 0) // don't bother with empty geometries
string_info info(text);
face->get_string_info(sym.get_text_size(), info);
placement_finder<label_collision_detector4> finder(detector_);
for (unsigned i = 0; i < feature.num_geometries(); ++i)
{ {
geometry2d const& geom = feature.get_geometry(i); path_type path(t_, geom, prj_trans);
placement text_placement(info, sym);
if (geom.num_points() > 0) // don't bother with empty geometries if (sym.get_label_placement() == POINT_PLACEMENT)
{ {
path_type path(t_, geom, prj_trans); double label_x, label_y, z = 0.0;
placement text_placement(info, sym);
if (sym.get_label_placement() == POINT_PLACEMENT) geom.label_position(&label_x, &label_y);
{ prj_trans.backward(label_x, label_y, z);
double label_x, label_y, z = 0.0; t_.forward(&label_x, &label_y);
finder.find_point_placement(text_placement, label_x, label_y);
}
else //LINE_PLACEMENT
{
finder.find_line_placements<path_type>(text_placement, path);
}
geom.label_position(&label_x, &label_y); for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii)
prj_trans.backward(label_x, label_y, z); {
t_.forward(&label_x, &label_y); context.add_text(sym, text_placement.placements[ii], face);
finder.find_point_placement(text_placement, label_x, label_y);
}
else //LINE_PLACEMENT
{
finder.find_line_placements<path_type>(text_placement, path);
}
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii)
{
context.add_text(sym, text_placement.placements[ii], face);
}
} }
} }
} }
else }
{ else
throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'"); {
} throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'");
} }
} }
} }