<commit_before>#ifndef __MAPNIK_VECTOR_PROCESSOR_H__
#define __MAPNIK_VECTOR_PROCESSOR_H__

#include <mapnik/map.hpp>
#include <mapnik/request.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/query.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/scale_denominator.hpp>
#include <mapnik/attribute_descriptor.hpp>
#include <mapnik/feature_layer_desc.hpp>
#include <mapnik/config.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/version.hpp>
#include <mapnik/noncopyable.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/raster.hpp>
#include <mapnik/warp.hpp>

// agg
#ifdef CONV_CLIPPER
#include "agg_path_storage.h"
#include "agg_conv_clipper.h"
#else
#include "agg_conv_clip_polygon.h"
#endif

#include "agg_conv_clip_polyline.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"

#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

#include <iostream>
#include <string>
#include <stdexcept>

#include "mapnik3x_compatibility.hpp"
#include MAPNIK_MAKE_SHARED_INCLUDE
#include MAPNIK_SHARED_INCLUDE

namespace mapnik { namespace vector {

/*
  This processor combines concepts from mapnik's
  feature_style_processor and agg_renderer. It
  differs in that here we only process layers in
  isolation of their styles, and because of this we need
  options for clipping and simplification, for example,
  that would normally come from a style's symbolizers
*/

    template <typename T>
    class processor : private mapnik::noncopyable
    {
    public:
        typedef T backend_type;
    private:
        backend_type & backend_;
        mapnik::Map const& m_;
        mapnik::request const& m_req_;
        double scale_factor_;
        mapnik::CoordTransform t_;
        unsigned tolerance_;
        bool painted_;
    public:
        processor(T & backend,
                  mapnik::Map const& map,
                  mapnik::request const& m_req,
                  double scale_factor=1.0,
                  unsigned offset_x=0,
                  unsigned offset_y=0,
                  unsigned tolerance=1)
            : backend_(backend),
              m_(map),
              m_req_(m_req),
              scale_factor_(scale_factor),
              t_(m_req.width(),m_req.height(),m_req.extent(),offset_x,offset_y),
              tolerance_(tolerance),
              painted_(false) {}

        void apply(double scale_denom=0.0)
        {
            mapnik::projection proj(m_.srs(),true);
            if (scale_denom <= 0.0)
            {
                scale_denom = mapnik::scale_denominator(m_req_.scale(),proj.is_geographic());
            }
            scale_denom *= scale_factor_;
            BOOST_FOREACH ( mapnik::layer const& lay, m_.layers() )
            {
                if (lay.visible(scale_denom))
                {
                    apply_to_layer(lay,
                                   proj,
                                   m_req_.scale(),
                                   scale_denom,
                                   m_req_.width(),
                                   m_req_.height(),
                                   m_req_.extent(),
                                   m_req_.buffer_size());
                }
            }
        }

        bool painted() const
        {
            return painted_;
        }

        void apply_to_layer(mapnik::layer const& lay,
                            mapnik::projection const& proj0,
                            double scale,
                            double scale_denom,
                            unsigned width,
                            unsigned height,
                            box2d<double> const& extent,
                            int buffer_size)
        {
            mapnik::datasource_ptr ds = lay.datasource();
            if (!ds)
            {
                return;
            }
            mapnik::projection proj1(lay.srs(),true);
            mapnik::proj_transform prj_trans(proj0,proj1);
            box2d<double> query_ext = extent; // unbuffered
            box2d<double> buffered_query_ext(query_ext);  // buffered
            double buffer_padding = 2.0 * scale;
            boost::optional<int> layer_buffer_size = lay.buffer_size();
            if (layer_buffer_size) // if layer overrides buffer size, use this value to compute buffered extent
            {
                buffer_padding *= *layer_buffer_size;
            }
            else
            {
                buffer_padding *= buffer_size;
            }
            buffered_query_ext.width(query_ext.width() + buffer_padding);
            buffered_query_ext.height(query_ext.height() + buffer_padding);
            // clip buffered extent by maximum extent, if supplied
            boost::optional<box2d<double> > const& maximum_extent = m_.maximum_extent();
            if (maximum_extent)
            {
                buffered_query_ext.clip(*maximum_extent);
            }
            mapnik::box2d<double> layer_ext = lay.envelope();
            bool fw_success = false;
            bool early_return = false;
            // first, try intersection of map extent forward projected into layer srs
            if (prj_trans.forward(buffered_query_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext))
            {
                fw_success = true;
                layer_ext.clip(buffered_query_ext);
            }
            // if no intersection and projections are also equal, early return
            else if (prj_trans.equal())
            {
                early_return = true;
            }
            // next try intersection of layer extent back projected into map srs
            else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext))
            {
                layer_ext.clip(buffered_query_ext);
                // forward project layer extent back into native projection
                if (! prj_trans.forward(layer_ext, PROJ_ENVELOPE_POINTS))
                {
                    std::cerr << "feature_style_processor: Layer=" << lay.name()
                              << " extent=" << layer_ext << " in map projection "
                              << " did not reproject properly back to layer projection";
                }
            }
            else
            {
                // if no intersection then nothing to do for layer
                early_return = true;
            }
            if (early_return)
            {
                return;
            }

            // if we've got this far, now prepare the unbuffered extent
            // which is used as a bbox for clipping geometries
            if (maximum_extent)
            {
                query_ext.clip(*maximum_extent);
            }
            mapnik::box2d<double> layer_ext2 = lay.envelope();
            if (fw_success)
            {
                if (prj_trans.forward(query_ext, PROJ_ENVELOPE_POINTS))
                {
                    layer_ext2.clip(query_ext);
                }
            }
            else
            {
                if (prj_trans.backward(layer_ext2, PROJ_ENVELOPE_POINTS))
                {
                    layer_ext2.clip(query_ext);
                    prj_trans.forward(layer_ext2, PROJ_ENVELOPE_POINTS);
                }
            }
            double qw = query_ext.width()>0 ? query_ext.width() : 1;
            double qh = query_ext.height()>0 ? query_ext.height() : 1;
            mapnik::query::resolution_type res(width/qw,
                                               height/qh);
            mapnik::query q(layer_ext,res,scale_denom,extent);
            mapnik::layer_descriptor lay_desc = ds->get_descriptor();
            BOOST_FOREACH(mapnik::attribute_descriptor const& desc, lay_desc.get_descriptors())
            {
                q.add_property_name(desc.get_name());
            }
            mapnik::featureset_ptr features = ds->features(q);
            if (!features)
            {
                return;
            }
            mapnik::feature_ptr feature = features->next();
            if (feature) {
                backend_.start_tile_layer(lay.name());
                raster_ptr const& source = feature->get_raster();
                if (source)
                {
                    box2d<double> target_ext = box2d<double>(source->ext_);
                    prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS);
                    box2d<double> ext = t_.forward(target_ext);
                    int start_x = static_cast<int>(std::floor(ext.minx()+.5));
                    int start_y = static_cast<int>(std::floor(ext.miny()+.5));
                    int end_x = static_cast<int>(std::floor(ext.maxx()+.5));
                    int end_y = static_cast<int>(std::floor(ext.maxy()+.5));
                    int raster_width = end_x - start_x;
                    int raster_height = end_y - start_y;
                    if (raster_width > 0 && raster_height > 0)
                    {
                        raster target(target_ext, raster_width, raster_height);
                        if (!source->premultiplied_alpha_)
                        {
                            agg::rendering_buffer buffer(source->data_.getBytes(),
                                                         source->data_.width(),
                                                         source->data_.height(),
                                                         source->data_.width() * 4);
                            agg::pixfmt_rgba32 pixf(buffer);
                            pixf.premultiply();
                        }
                        if (!prj_trans.equal())
                        {
                            double offset_x = ext.minx() - start_x;
                            double offset_y = ext.miny() - start_y;
                            reproject_and_scale_raster(target, *source, prj_trans,
                                             offset_x, offset_y,
                                             width,
                                             2.0,
                                             SCALING_BILINEAR);
                        }
                        else
                        {
                            double image_ratio_x = ext.width() / source->data_.width();
                            double image_ratio_y = ext.height() / source->data_.height();
                            scale_image_agg<image_data_32>(target.data_,
                                                           source->data_,
                                                           SCALING_BILINEAR,
                                                           image_ratio_x,
                                                           image_ratio_y,
                                                           0.0,
                                                           0.0,
                                                           2.0);
                        }
                        mapnik::image_data_32 im_tile(width,height);
                        composite(im_tile, target.data_,
                                  src_over, 1,
                                  start_x, start_y, false);
                        agg::rendering_buffer buffer(im_tile.getBytes(),
                                                     im_tile.width(),
                                                     im_tile.height(),
                                                     im_tile.width() * 4);
                        agg::pixfmt_rgba32 pixf(buffer);
                        pixf.demultiply();
                        backend_.start_tile_feature(*feature);
                        backend_.add_tile_feature_raster(mapnik::save_to_string(im_tile,"jpeg"));
                    }
                    backend_.stop_tile_layer();
                    return;
                }
                // vector pathway
                while (feature)
                {
                    boost::ptr_vector<mapnik::geometry_type> & paths = feature->paths();
                    if (paths.empty()) {
                        feature = features->next();
                        continue;
                    }
                    backend_.start_tile_feature(*feature);
                    BOOST_FOREACH( mapnik::geometry_type & geom, paths)
                    {
                        mapnik::box2d<double> geom_box = geom.envelope();
                        if (!geom_box.intersects(buffered_query_ext))
                        {
                            continue;
                        }
                        if (handle_geometry(geom,
                                            prj_trans,
                                            buffered_query_ext) > 0)
                        {
                            painted_ = true;
                        }
                    }
                    backend_.stop_tile_feature();
                    feature = features->next();
                }
                backend_.stop_tile_layer();
            }
        }

        unsigned handle_geometry(mapnik::geometry_type & geom,
                                 mapnik::proj_transform const& prj_trans,
                                 mapnik::box2d<double> const& buffered_query_ext)
        {
            unsigned path_count = 0;
            switch (geom.type())
            {
            case MAPNIK_POINT:
            {
                if (geom.size() > 0)
                {
                    typedef mapnik::coord_transform<mapnik::CoordTransform,
                        mapnik::geometry_type> path_type;
                    path_type path(t_, geom, prj_trans);
                    path_count = backend_.add_path(path, tolerance_, geom.type());
                }
                break;
            }
            case MAPNIK_LINESTRING:
            {
                if (geom.size() > 1)
                {
                    typedef agg::conv_clip_polyline<mapnik::geometry_type> line_clipper;
                    line_clipper clipped(geom);
                    clipped.clip_box(
                        buffered_query_ext.minx(),
                        buffered_query_ext.miny(),
                        buffered_query_ext.maxx(),
                        buffered_query_ext.maxy());
                    typedef mapnik::coord_transform<mapnik::CoordTransform, line_clipper> path_type;
                    path_type path(t_, clipped, prj_trans);
                    path_count = backend_.add_path(path, tolerance_, geom.type());
                }
                break;
            }
            case MAPNIK_POLYGON:
            {
                if (geom.size() > 2)
                {
#ifdef CONV_CLIPPER
                    agg::path_storage ps;
                    ps.move_to(buffered_query_ext.minx(), buffered_query_ext.miny());
                    ps.line_to(buffered_query_ext.minx(), buffered_query_ext.maxy());
                    ps.line_to(buffered_query_ext.maxx(), buffered_query_ext.maxy());
                    ps.line_to(buffered_query_ext.maxx(), buffered_query_ext.miny());
                    ps.close_polygon();
                    typedef agg::conv_clipper<mapnik::geometry_type, agg::path_storage> poly_clipper;
                    poly_clipper clipped(geom,ps,
                                         agg::clipper_and,
                                         agg::clipper_non_zero,
                                         agg::clipper_non_zero,
                                         1);
                    //clipped.rewind(0);
#else
                    typedef agg::conv_clip_polygon<mapnik::geometry_type> poly_clipper;
                    poly_clipper clipped(geom);
                    clipped.clip_box(
                        buffered_query_ext.minx(),
                        buffered_query_ext.miny(),
                        buffered_query_ext.maxx(),
                        buffered_query_ext.maxy());
#endif
                    typedef mapnik::coord_transform<mapnik::CoordTransform, poly_clipper> path_type;
                    path_type path(t_, clipped, prj_trans);
                    path_count = backend_.add_path(path, tolerance_, geom.type());
                }
                break;
            }
            case MAPNIK_UNKNOWN:
            default:
            {
                throw std::runtime_error("unhandled geometry type");
                break;
            }
            }
            return path_count;
        }
    };

    }} // end ns

#endif // __MAPNIK_VECTOR_TILE_PROCESSOR_H__
<commit_msg>support both mapnik 3.x and 2.3.x<commit_after>#ifndef __MAPNIK_VECTOR_PROCESSOR_H__
#define __MAPNIK_VECTOR_PROCESSOR_H__

#include <mapnik/map.hpp>
#include <mapnik/request.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/query.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/scale_denominator.hpp>
#include <mapnik/attribute_descriptor.hpp>
#include <mapnik/feature_layer_desc.hpp>
#include <mapnik/config.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/version.hpp>
#include <mapnik/noncopyable.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/raster.hpp>
#include <mapnik/warp.hpp>
#include <mapnik/version.hpp>

// agg
#ifdef CONV_CLIPPER
#include "agg_path_storage.h"
#include "agg_conv_clipper.h"
#else
#include "agg_conv_clip_polygon.h"
#endif

#include "agg_conv_clip_polyline.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"

#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

#include <iostream>
#include <string>
#include <stdexcept>

#include "mapnik3x_compatibility.hpp"
#include MAPNIK_MAKE_SHARED_INCLUDE
#include MAPNIK_SHARED_INCLUDE

namespace mapnik { namespace vector {

/*
  This processor combines concepts from mapnik's
  feature_style_processor and agg_renderer. It
  differs in that here we only process layers in
  isolation of their styles, and because of this we need
  options for clipping and simplification, for example,
  that would normally come from a style's symbolizers
*/

    template <typename T>
    class processor : private mapnik::noncopyable
    {
    public:
        typedef T backend_type;
    private:
        backend_type & backend_;
        mapnik::Map const& m_;
        mapnik::request const& m_req_;
        double scale_factor_;
        mapnik::CoordTransform t_;
        unsigned tolerance_;
        bool painted_;
    public:
        processor(T & backend,
                  mapnik::Map const& map,
                  mapnik::request const& m_req,
                  double scale_factor=1.0,
                  unsigned offset_x=0,
                  unsigned offset_y=0,
                  unsigned tolerance=1)
            : backend_(backend),
              m_(map),
              m_req_(m_req),
              scale_factor_(scale_factor),
              t_(m_req.width(),m_req.height(),m_req.extent(),offset_x,offset_y),
              tolerance_(tolerance),
              painted_(false) {}

        void apply(double scale_denom=0.0)
        {
            mapnik::projection proj(m_.srs(),true);
            if (scale_denom <= 0.0)
            {
                scale_denom = mapnik::scale_denominator(m_req_.scale(),proj.is_geographic());
            }
            scale_denom *= scale_factor_;
            BOOST_FOREACH ( mapnik::layer const& lay, m_.layers() )
            {
                if (lay.visible(scale_denom))
                {
                    apply_to_layer(lay,
                                   proj,
                                   m_req_.scale(),
                                   scale_denom,
                                   m_req_.width(),
                                   m_req_.height(),
                                   m_req_.extent(),
                                   m_req_.buffer_size());
                }
            }
        }

        bool painted() const
        {
            return painted_;
        }

        void apply_to_layer(mapnik::layer const& lay,
                            mapnik::projection const& proj0,
                            double scale,
                            double scale_denom,
                            unsigned width,
                            unsigned height,
                            box2d<double> const& extent,
                            int buffer_size)
        {
            mapnik::datasource_ptr ds = lay.datasource();
            if (!ds)
            {
                return;
            }
            mapnik::projection proj1(lay.srs(),true);
            mapnik::proj_transform prj_trans(proj0,proj1);
            box2d<double> query_ext = extent; // unbuffered
            box2d<double> buffered_query_ext(query_ext);  // buffered
            double buffer_padding = 2.0 * scale;
            boost::optional<int> layer_buffer_size = lay.buffer_size();
            if (layer_buffer_size) // if layer overrides buffer size, use this value to compute buffered extent
            {
                buffer_padding *= *layer_buffer_size;
            }
            else
            {
                buffer_padding *= buffer_size;
            }
            buffered_query_ext.width(query_ext.width() + buffer_padding);
            buffered_query_ext.height(query_ext.height() + buffer_padding);
            // clip buffered extent by maximum extent, if supplied
            boost::optional<box2d<double> > const& maximum_extent = m_.maximum_extent();
            if (maximum_extent)
            {
                buffered_query_ext.clip(*maximum_extent);
            }
            mapnik::box2d<double> layer_ext = lay.envelope();
            bool fw_success = false;
            bool early_return = false;
            // first, try intersection of map extent forward projected into layer srs
            if (prj_trans.forward(buffered_query_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext))
            {
                fw_success = true;
                layer_ext.clip(buffered_query_ext);
            }
            // if no intersection and projections are also equal, early return
            else if (prj_trans.equal())
            {
                early_return = true;
            }
            // next try intersection of layer extent back projected into map srs
            else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext))
            {
                layer_ext.clip(buffered_query_ext);
                // forward project layer extent back into native projection
                if (! prj_trans.forward(layer_ext, PROJ_ENVELOPE_POINTS))
                {
                    std::cerr << "feature_style_processor: Layer=" << lay.name()
                              << " extent=" << layer_ext << " in map projection "
                              << " did not reproject properly back to layer projection";
                }
            }
            else
            {
                // if no intersection then nothing to do for layer
                early_return = true;
            }
            if (early_return)
            {
                return;
            }

            // if we've got this far, now prepare the unbuffered extent
            // which is used as a bbox for clipping geometries
            if (maximum_extent)
            {
                query_ext.clip(*maximum_extent);
            }
            mapnik::box2d<double> layer_ext2 = lay.envelope();
            if (fw_success)
            {
                if (prj_trans.forward(query_ext, PROJ_ENVELOPE_POINTS))
                {
                    layer_ext2.clip(query_ext);
                }
            }
            else
            {
                if (prj_trans.backward(layer_ext2, PROJ_ENVELOPE_POINTS))
                {
                    layer_ext2.clip(query_ext);
                    prj_trans.forward(layer_ext2, PROJ_ENVELOPE_POINTS);
                }
            }
            double qw = query_ext.width()>0 ? query_ext.width() : 1;
            double qh = query_ext.height()>0 ? query_ext.height() : 1;
            mapnik::query::resolution_type res(width/qw,
                                               height/qh);
            mapnik::query q(layer_ext,res,scale_denom,extent);
            mapnik::layer_descriptor lay_desc = ds->get_descriptor();
            BOOST_FOREACH(mapnik::attribute_descriptor const& desc, lay_desc.get_descriptors())
            {
                q.add_property_name(desc.get_name());
            }
            mapnik::featureset_ptr features = ds->features(q);
            if (!features)
            {
                return;
            }
            mapnik::feature_ptr feature = features->next();
            if (feature) {
                backend_.start_tile_layer(lay.name());
                raster_ptr const& source = feature->get_raster();
                if (source)
                {
                    box2d<double> target_ext = box2d<double>(source->ext_);
                    prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS);
                    box2d<double> ext = t_.forward(target_ext);
                    int start_x = static_cast<int>(std::floor(ext.minx()+.5));
                    int start_y = static_cast<int>(std::floor(ext.miny()+.5));
                    int end_x = static_cast<int>(std::floor(ext.maxx()+.5));
                    int end_y = static_cast<int>(std::floor(ext.maxy()+.5));
                    int raster_width = end_x - start_x;
                    int raster_height = end_y - start_y;
                    if (raster_width > 0 && raster_height > 0)
                    {
                        #if MAPNIK_VERSION >= 300000
                        raster target(target_ext, raster_width, raster_height, source->get_filter_factor());
                        #else
                        raster target(target_ext, raster_width, raster_height);
                        #endif
                        if (!source->premultiplied_alpha_)
                        {
                            agg::rendering_buffer buffer(source->data_.getBytes(),
                                                         source->data_.width(),
                                                         source->data_.height(),
                                                         source->data_.width() * 4);
                            agg::pixfmt_rgba32 pixf(buffer);
                            pixf.premultiply();
                        }
                        if (!prj_trans.equal())
                        {
                            double offset_x = ext.minx() - start_x;
                            double offset_y = ext.miny() - start_y;
                            #if MAPNIK_VERSION >= 300000
                            reproject_and_scale_raster(target, *source, prj_trans,
                                             offset_x, offset_y,
                                             width,
                                             SCALING_BILINEAR);
                            #else
                            reproject_and_scale_raster(target, *source, prj_trans,
                                             offset_x, offset_y,
                                             width,
                                             2.0,
                                             SCALING_BILINEAR);
                            #endif
                        }
                        else
                        {
                            double image_ratio_x = ext.width() / source->data_.width();
                            double image_ratio_y = ext.height() / source->data_.height();
                            #if MAPNIK_VERSION >= 300000
                            scale_image_agg<image_data_32>(target.data_,
                                                           source->data_,
                                                           SCALING_BILINEAR,
                                                           image_ratio_x,
                                                           image_ratio_y,
                                                           0.0,
                                                           0.0,
                                                           source->get_filter_factor());
                            #else
                            scale_image_agg<image_data_32>(target.data_,
                                                           source->data_,
                                                           SCALING_BILINEAR,
                                                           image_ratio_x,
                                                           image_ratio_y,
                                                           0.0,
                                                           0.0,
                                                           2.0);
                            #endif
                        }
                        mapnik::image_data_32 im_tile(width,height);
                        composite(im_tile, target.data_,
                                  src_over, 1,
                                  start_x, start_y, false);
                        agg::rendering_buffer buffer(im_tile.getBytes(),
                                                     im_tile.width(),
                                                     im_tile.height(),
                                                     im_tile.width() * 4);
                        agg::pixfmt_rgba32 pixf(buffer);
                        pixf.demultiply();
                        backend_.start_tile_feature(*feature);
                        backend_.add_tile_feature_raster(mapnik::save_to_string(im_tile,"jpeg"));
                    }
                    backend_.stop_tile_layer();
                    return;
                }
                // vector pathway
                while (feature)
                {
                    boost::ptr_vector<mapnik::geometry_type> & paths = feature->paths();
                    if (paths.empty()) {
                        feature = features->next();
                        continue;
                    }
                    backend_.start_tile_feature(*feature);
                    BOOST_FOREACH( mapnik::geometry_type & geom, paths)
                    {
                        mapnik::box2d<double> geom_box = geom.envelope();
                        if (!geom_box.intersects(buffered_query_ext))
                        {
                            continue;
                        }
                        if (handle_geometry(geom,
                                            prj_trans,
                                            buffered_query_ext) > 0)
                        {
                            painted_ = true;
                        }
                    }
                    backend_.stop_tile_feature();
                    feature = features->next();
                }
                backend_.stop_tile_layer();
            }
        }

        unsigned handle_geometry(mapnik::geometry_type & geom,
                                 mapnik::proj_transform const& prj_trans,
                                 mapnik::box2d<double> const& buffered_query_ext)
        {
            unsigned path_count = 0;
            switch (geom.type())
            {
            case MAPNIK_POINT:
            {
                if (geom.size() > 0)
                {
                    typedef mapnik::coord_transform<mapnik::CoordTransform,
                        mapnik::geometry_type> path_type;
                    path_type path(t_, geom, prj_trans);
                    path_count = backend_.add_path(path, tolerance_, geom.type());
                }
                break;
            }
            case MAPNIK_LINESTRING:
            {
                if (geom.size() > 1)
                {
                    typedef agg::conv_clip_polyline<mapnik::geometry_type> line_clipper;
                    line_clipper clipped(geom);
                    clipped.clip_box(
                        buffered_query_ext.minx(),
                        buffered_query_ext.miny(),
                        buffered_query_ext.maxx(),
                        buffered_query_ext.maxy());
                    typedef mapnik::coord_transform<mapnik::CoordTransform, line_clipper> path_type;
                    path_type path(t_, clipped, prj_trans);
                    path_count = backend_.add_path(path, tolerance_, geom.type());
                }
                break;
            }
            case MAPNIK_POLYGON:
            {
                if (geom.size() > 2)
                {
#ifdef CONV_CLIPPER
                    agg::path_storage ps;
                    ps.move_to(buffered_query_ext.minx(), buffered_query_ext.miny());
                    ps.line_to(buffered_query_ext.minx(), buffered_query_ext.maxy());
                    ps.line_to(buffered_query_ext.maxx(), buffered_query_ext.maxy());
                    ps.line_to(buffered_query_ext.maxx(), buffered_query_ext.miny());
                    ps.close_polygon();
                    typedef agg::conv_clipper<mapnik::geometry_type, agg::path_storage> poly_clipper;
                    poly_clipper clipped(geom,ps,
                                         agg::clipper_and,
                                         agg::clipper_non_zero,
                                         agg::clipper_non_zero,
                                         1);
                    //clipped.rewind(0);
#else
                    typedef agg::conv_clip_polygon<mapnik::geometry_type> poly_clipper;
                    poly_clipper clipped(geom);
                    clipped.clip_box(
                        buffered_query_ext.minx(),
                        buffered_query_ext.miny(),
                        buffered_query_ext.maxx(),
                        buffered_query_ext.maxy());
#endif
                    typedef mapnik::coord_transform<mapnik::CoordTransform, poly_clipper> path_type;
                    path_type path(t_, clipped, prj_trans);
                    path_count = backend_.add_path(path, tolerance_, geom.type());
                }
                break;
            }
            case MAPNIK_UNKNOWN:
            default:
            {
                throw std::runtime_error("unhandled geometry type");
                break;
            }
            }
            return path_count;
        }
    };

    }} // end ns

#endif // __MAPNIK_VECTOR_TILE_PROCESSOR_H__
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/pacing/include/paced_sender.h"

#include <assert.h>

#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace_event.h"

namespace {
// Time limit in milliseconds between packet bursts.
const int kMinPacketLimitMs = 5;

// Upper cap on process interval, in case process has not been called in a long
// time.
const int kMaxIntervalTimeMs = 30;

// Max time that the first packet in the queue can sit in the queue if no
// packets are sent, regardless of buffer state. In practice only in effect at
// low bitrates (less than 320 kbits/s).
const int kMaxQueueTimeWithoutSendingMs = 30;

// Max padding bytes per second.
const int kMaxPaddingKbps = 800;

}  // namespace

namespace webrtc {

namespace paced_sender {
struct Packet {
  Packet(uint32_t ssrc, uint16_t seq_number, int64_t capture_time_ms,
         int length_in_bytes)
      : ssrc_(ssrc),
        sequence_number_(seq_number),
        capture_time_ms_(capture_time_ms),
        bytes_(length_in_bytes) {
  }
  uint32_t ssrc_;
  uint16_t sequence_number_;
  int64_t capture_time_ms_;
  int bytes_;
};

// STL list style class which prevents duplicates in the list.
class PacketList {
 public:
  PacketList() {};

  bool empty() const {
    return packet_list_.empty();
  }

  Packet front() const {
    return packet_list_.front();
  }

  void pop_front() {
    Packet& packet = packet_list_.front();
    uint16_t sequence_number = packet.sequence_number_;
    packet_list_.pop_front();
    sequence_number_set_.erase(sequence_number);
  }

  void push_back(const Packet& packet) {
    if (sequence_number_set_.find(packet.sequence_number_) ==
        sequence_number_set_.end()) {
      // Don't insert duplicates.
      packet_list_.push_back(packet);
      sequence_number_set_.insert(packet.sequence_number_);
    }
  }

 private:
  std::list<Packet> packet_list_;
  std::set<uint16_t> sequence_number_set_;
};

class IntervalBudget {
 public:
  explicit IntervalBudget(int initial_target_rate_kbps)
      : target_rate_kbps_(initial_target_rate_kbps),
        bytes_remaining_(0) {}

  void set_target_rate_kbps(int target_rate_kbps) {
    target_rate_kbps_ = target_rate_kbps;
  }

  void IncreaseBudget(int delta_time_ms) {
    int bytes = target_rate_kbps_ * delta_time_ms / 8;
    if (bytes_remaining_ < 0) {
      // We overused last interval, compensate this interval.
      bytes_remaining_ = bytes_remaining_ + bytes;
    } else {
      // If we underused last interval we can't use it this interval.
      bytes_remaining_ = bytes;
    }
  }

  void UseBudget(int bytes) {
    bytes_remaining_ = std::max(bytes_remaining_ - bytes,
                                -100 * target_rate_kbps_ / 8);
  }

  int bytes_remaining() const { return bytes_remaining_; }

 private:
  int target_rate_kbps_;
  int bytes_remaining_;
};
}  // namespace paced_sender

PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps,
                         float pace_multiplier)
    : callback_(callback),
      pace_multiplier_(pace_multiplier),
      enabled_(false),
      paused_(false),
      critsect_(CriticalSectionWrapper::CreateCriticalSection()),
      media_budget_(new paced_sender::IntervalBudget(
          pace_multiplier_ * target_bitrate_kbps)),
      padding_budget_(new paced_sender::IntervalBudget(kMaxPaddingKbps)),
      // No padding until UpdateBitrate is called.
      pad_up_to_bitrate_budget_(new paced_sender::IntervalBudget(0)),
      time_last_update_(TickTime::Now()),
      capture_time_ms_last_queued_(0),
      capture_time_ms_last_sent_(0),
      high_priority_packets_(new paced_sender::PacketList),
      normal_priority_packets_(new paced_sender::PacketList),
      low_priority_packets_(new paced_sender::PacketList) {
  UpdateBytesPerInterval(kMinPacketLimitMs);
}

PacedSender::~PacedSender() {
}

void PacedSender::Pause() {
  CriticalSectionScoped cs(critsect_.get());
  paused_ = true;
}

void PacedSender::Resume() {
  CriticalSectionScoped cs(critsect_.get());
  paused_ = false;
}

void PacedSender::SetStatus(bool enable) {
  CriticalSectionScoped cs(critsect_.get());
  enabled_ = enable;
}

bool PacedSender::Enabled() const {
  CriticalSectionScoped cs(critsect_.get());
  return enabled_;
}

void PacedSender::UpdateBitrate(int target_bitrate_kbps,
                                int pad_up_to_bitrate_kbps) {
  CriticalSectionScoped cs(critsect_.get());
  media_budget_->set_target_rate_kbps(pace_multiplier_ * target_bitrate_kbps);
  pad_up_to_bitrate_budget_->set_target_rate_kbps(pad_up_to_bitrate_kbps);
}

bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
    uint16_t sequence_number, int64_t capture_time_ms, int bytes) {
  CriticalSectionScoped cs(critsect_.get());

  if (!enabled_) {
    UpdateMediaBytesSent(bytes);
    return true;  // We can send now.
  }
  if (capture_time_ms < 0) {
    capture_time_ms = TickTime::MillisecondTimestamp();
  }
  if (priority != kHighPriority &&
      capture_time_ms > capture_time_ms_last_queued_) {
    capture_time_ms_last_queued_ = capture_time_ms;
    TRACE_EVENT_ASYNC_BEGIN1("webrtc_rtp", "PacedSend", capture_time_ms,
                             "capture_time_ms", capture_time_ms);
  }
  paced_sender::PacketList* packet_list = NULL;
  switch (priority) {
    case kHighPriority:
      packet_list = high_priority_packets_.get();
      break;
    case kNormalPriority:
      packet_list = normal_priority_packets_.get();
      break;
    case kLowPriority:
      packet_list = low_priority_packets_.get();
      break;
  }
  packet_list->push_back(paced_sender::Packet(ssrc, sequence_number,
                                              capture_time_ms, bytes));
  return false;
}

int PacedSender::QueueInMs() const {
  CriticalSectionScoped cs(critsect_.get());
  int64_t now_ms = TickTime::MillisecondTimestamp();
  int64_t oldest_packet_capture_time = now_ms;
  if (!high_priority_packets_->empty()) {
    oldest_packet_capture_time = std::min(
        oldest_packet_capture_time,
        high_priority_packets_->front().capture_time_ms_);
  }
  if (!normal_priority_packets_->empty()) {
    oldest_packet_capture_time = std::min(
        oldest_packet_capture_time,
        normal_priority_packets_->front().capture_time_ms_);
  }
  if (!low_priority_packets_->empty()) {
    oldest_packet_capture_time = std::min(
        oldest_packet_capture_time,
        low_priority_packets_->front().capture_time_ms_);
  }
  return now_ms - oldest_packet_capture_time;
}

int32_t PacedSender::TimeUntilNextProcess() {
  CriticalSectionScoped cs(critsect_.get());
  int64_t elapsed_time_ms =
      (TickTime::Now() - time_last_update_).Milliseconds();
  if (elapsed_time_ms <= 0) {
    return kMinPacketLimitMs;
  }
  if (elapsed_time_ms >= kMinPacketLimitMs) {
    return 0;
  }
  return kMinPacketLimitMs - elapsed_time_ms;
}

int32_t PacedSender::Process() {
  TickTime now = TickTime::Now();
  CriticalSectionScoped cs(critsect_.get());
  int elapsed_time_ms = (now - time_last_update_).Milliseconds();
  time_last_update_ = now;
  if (!paused_) {
    if (elapsed_time_ms > 0) {
      uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
      UpdateBytesPerInterval(delta_time_ms);
    }
    uint32_t ssrc;
    uint16_t sequence_number;
    int64_t capture_time_ms;
    paced_sender::PacketList* packet_list;
    while (ShouldSendNextPacket(&packet_list)) {
      GetNextPacketFromList(packet_list, &ssrc, &sequence_number,
                            &capture_time_ms);
      critsect_->Leave();

      const bool success = callback_->TimeToSendPacket(ssrc, sequence_number,
                                                       capture_time_ms);
      // If packet cannt be sent then keep it in packet list and exit early.
      // There's no need to send more packets.
      if (!success) {
        return 0;
      }

      critsect_->Enter();
      packet_list->pop_front();
      const bool last_packet = packet_list->empty() ||
          packet_list->front().capture_time_ms_ > capture_time_ms;
      if (packet_list != high_priority_packets_.get()) {
        if (capture_time_ms > capture_time_ms_last_sent_) {
          capture_time_ms_last_sent_ = capture_time_ms;
        } else if (capture_time_ms == capture_time_ms_last_sent_ &&
                   last_packet) {
          TRACE_EVENT_ASYNC_END0("webrtc_rtp", "PacedSend", capture_time_ms);
        }
      }
    }
    if (high_priority_packets_->empty() &&
        normal_priority_packets_->empty() &&
        low_priority_packets_->empty() &&
        padding_budget_->bytes_remaining() > 0 &&
        pad_up_to_bitrate_budget_->bytes_remaining() > 0) {
      int padding_needed = std::min(
          padding_budget_->bytes_remaining(),
          pad_up_to_bitrate_budget_->bytes_remaining());
      critsect_->Leave();
      int bytes_sent = callback_->TimeToSendPadding(padding_needed);
      critsect_->Enter();
      media_budget_->UseBudget(bytes_sent);
      padding_budget_->UseBudget(bytes_sent);
      pad_up_to_bitrate_budget_->UseBudget(bytes_sent);
    }
  }
  return 0;
}

// MUST have critsect_ when calling.
void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
  media_budget_->IncreaseBudget(delta_time_ms);
  padding_budget_->IncreaseBudget(delta_time_ms);
  pad_up_to_bitrate_budget_->IncreaseBudget(delta_time_ms);
}

// MUST have critsect_ when calling.
bool PacedSender::ShouldSendNextPacket(paced_sender::PacketList** packet_list) {
  if (media_budget_->bytes_remaining() <= 0) {
    // All bytes consumed for this interval.
    // Check if we have not sent in a too long time.
    if ((TickTime::Now() - time_last_send_).Milliseconds() >
        kMaxQueueTimeWithoutSendingMs) {
      if (!high_priority_packets_->empty()) {
        *packet_list = high_priority_packets_.get();
        return true;
      }
      if (!normal_priority_packets_->empty()) {
        *packet_list = normal_priority_packets_.get();
        return true;
      }
    }
    return false;
  }
  if (!high_priority_packets_->empty()) {
    *packet_list = high_priority_packets_.get();
    return true;
  }
  if (!normal_priority_packets_->empty()) {
    *packet_list = normal_priority_packets_.get();
    return true;
  }
  if (!low_priority_packets_->empty()) {
    *packet_list = low_priority_packets_.get();
    return true;
  }
  return false;
}

void PacedSender::GetNextPacketFromList(paced_sender::PacketList* packets,
    uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms) {
  paced_sender::Packet packet = packets->front();
  UpdateMediaBytesSent(packet.bytes_);
  *sequence_number = packet.sequence_number_;
  *ssrc = packet.ssrc_;
  *capture_time_ms = packet.capture_time_ms_;
}

// MUST have critsect_ when calling.
void PacedSender::UpdateMediaBytesSent(int num_bytes) {
  time_last_send_ = TickTime::Now();
  media_budget_->UseBudget(num_bytes);
  pad_up_to_bitrate_budget_->UseBudget(num_bytes);
}

}  // namespace webrtc
<commit_msg>Fix memory bot failure<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/pacing/include/paced_sender.h"

#include <assert.h>

#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace_event.h"

namespace {
// Time limit in milliseconds between packet bursts.
const int kMinPacketLimitMs = 5;

// Upper cap on process interval, in case process has not been called in a long
// time.
const int kMaxIntervalTimeMs = 30;

// Max time that the first packet in the queue can sit in the queue if no
// packets are sent, regardless of buffer state. In practice only in effect at
// low bitrates (less than 320 kbits/s).
const int kMaxQueueTimeWithoutSendingMs = 30;

// Max padding bytes per second.
const int kMaxPaddingKbps = 800;

}  // namespace

namespace webrtc {

namespace paced_sender {
struct Packet {
  Packet(uint32_t ssrc, uint16_t seq_number, int64_t capture_time_ms,
         int length_in_bytes)
      : ssrc_(ssrc),
        sequence_number_(seq_number),
        capture_time_ms_(capture_time_ms),
        bytes_(length_in_bytes) {
  }
  uint32_t ssrc_;
  uint16_t sequence_number_;
  int64_t capture_time_ms_;
  int bytes_;
};

// STL list style class which prevents duplicates in the list.
class PacketList {
 public:
  PacketList() {};

  bool empty() const {
    return packet_list_.empty();
  }

  Packet front() const {
    return packet_list_.front();
  }

  void pop_front() {
    Packet& packet = packet_list_.front();
    uint16_t sequence_number = packet.sequence_number_;
    packet_list_.pop_front();
    sequence_number_set_.erase(sequence_number);
  }

  void push_back(const Packet& packet) {
    if (sequence_number_set_.find(packet.sequence_number_) ==
        sequence_number_set_.end()) {
      // Don't insert duplicates.
      packet_list_.push_back(packet);
      sequence_number_set_.insert(packet.sequence_number_);
    }
  }

 private:
  std::list<Packet> packet_list_;
  std::set<uint16_t> sequence_number_set_;
};

class IntervalBudget {
 public:
  explicit IntervalBudget(int initial_target_rate_kbps)
      : target_rate_kbps_(initial_target_rate_kbps),
        bytes_remaining_(0) {}

  void set_target_rate_kbps(int target_rate_kbps) {
    target_rate_kbps_ = target_rate_kbps;
  }

  void IncreaseBudget(int delta_time_ms) {
    int bytes = target_rate_kbps_ * delta_time_ms / 8;
    if (bytes_remaining_ < 0) {
      // We overused last interval, compensate this interval.
      bytes_remaining_ = bytes_remaining_ + bytes;
    } else {
      // If we underused last interval we can't use it this interval.
      bytes_remaining_ = bytes;
    }
  }

  void UseBudget(int bytes) {
    bytes_remaining_ = std::max(bytes_remaining_ - bytes,
                                -100 * target_rate_kbps_ / 8);
  }

  int bytes_remaining() const { return bytes_remaining_; }

 private:
  int target_rate_kbps_;
  int bytes_remaining_;
};
}  // namespace paced_sender

PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps,
                         float pace_multiplier)
    : callback_(callback),
      pace_multiplier_(pace_multiplier),
      enabled_(false),
      paused_(false),
      critsect_(CriticalSectionWrapper::CreateCriticalSection()),
      media_budget_(new paced_sender::IntervalBudget(
          pace_multiplier_ * target_bitrate_kbps)),
      padding_budget_(new paced_sender::IntervalBudget(kMaxPaddingKbps)),
      // No padding until UpdateBitrate is called.
      pad_up_to_bitrate_budget_(new paced_sender::IntervalBudget(0)),
      time_last_update_(TickTime::Now()),
      capture_time_ms_last_queued_(0),
      capture_time_ms_last_sent_(0),
      high_priority_packets_(new paced_sender::PacketList),
      normal_priority_packets_(new paced_sender::PacketList),
      low_priority_packets_(new paced_sender::PacketList) {
  UpdateBytesPerInterval(kMinPacketLimitMs);
}

PacedSender::~PacedSender() {
}

void PacedSender::Pause() {
  CriticalSectionScoped cs(critsect_.get());
  paused_ = true;
}

void PacedSender::Resume() {
  CriticalSectionScoped cs(critsect_.get());
  paused_ = false;
}

void PacedSender::SetStatus(bool enable) {
  CriticalSectionScoped cs(critsect_.get());
  enabled_ = enable;
}

bool PacedSender::Enabled() const {
  CriticalSectionScoped cs(critsect_.get());
  return enabled_;
}

void PacedSender::UpdateBitrate(int target_bitrate_kbps,
                                int pad_up_to_bitrate_kbps) {
  CriticalSectionScoped cs(critsect_.get());
  media_budget_->set_target_rate_kbps(pace_multiplier_ * target_bitrate_kbps);
  pad_up_to_bitrate_budget_->set_target_rate_kbps(pad_up_to_bitrate_kbps);
}

bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
    uint16_t sequence_number, int64_t capture_time_ms, int bytes) {
  CriticalSectionScoped cs(critsect_.get());

  if (!enabled_) {
    UpdateMediaBytesSent(bytes);
    return true;  // We can send now.
  }
  if (capture_time_ms < 0) {
    capture_time_ms = TickTime::MillisecondTimestamp();
  }
  if (priority != kHighPriority &&
      capture_time_ms > capture_time_ms_last_queued_) {
    capture_time_ms_last_queued_ = capture_time_ms;
    TRACE_EVENT_ASYNC_BEGIN1("webrtc_rtp", "PacedSend", capture_time_ms,
                             "capture_time_ms", capture_time_ms);
  }
  paced_sender::PacketList* packet_list = NULL;
  switch (priority) {
    case kHighPriority:
      packet_list = high_priority_packets_.get();
      break;
    case kNormalPriority:
      packet_list = normal_priority_packets_.get();
      break;
    case kLowPriority:
      packet_list = low_priority_packets_.get();
      break;
  }
  packet_list->push_back(paced_sender::Packet(ssrc, sequence_number,
                                              capture_time_ms, bytes));
  return false;
}

int PacedSender::QueueInMs() const {
  CriticalSectionScoped cs(critsect_.get());
  int64_t now_ms = TickTime::MillisecondTimestamp();
  int64_t oldest_packet_capture_time = now_ms;
  if (!high_priority_packets_->empty()) {
    oldest_packet_capture_time = std::min(
        oldest_packet_capture_time,
        high_priority_packets_->front().capture_time_ms_);
  }
  if (!normal_priority_packets_->empty()) {
    oldest_packet_capture_time = std::min(
        oldest_packet_capture_time,
        normal_priority_packets_->front().capture_time_ms_);
  }
  if (!low_priority_packets_->empty()) {
    oldest_packet_capture_time = std::min(
        oldest_packet_capture_time,
        low_priority_packets_->front().capture_time_ms_);
  }
  return now_ms - oldest_packet_capture_time;
}

int32_t PacedSender::TimeUntilNextProcess() {
  CriticalSectionScoped cs(critsect_.get());
  int64_t elapsed_time_ms =
      (TickTime::Now() - time_last_update_).Milliseconds();
  if (elapsed_time_ms <= 0) {
    return kMinPacketLimitMs;
  }
  if (elapsed_time_ms >= kMinPacketLimitMs) {
    return 0;
  }
  return kMinPacketLimitMs - elapsed_time_ms;
}

int32_t PacedSender::Process() {
  TickTime now = TickTime::Now();
  CriticalSectionScoped cs(critsect_.get());
  int elapsed_time_ms = (now - time_last_update_).Milliseconds();
  time_last_update_ = now;
  if (!paused_) {
    if (elapsed_time_ms > 0) {
      uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
      UpdateBytesPerInterval(delta_time_ms);
    }
    uint32_t ssrc;
    uint16_t sequence_number;
    int64_t capture_time_ms;
    paced_sender::PacketList* packet_list;
    while (ShouldSendNextPacket(&packet_list)) {
      GetNextPacketFromList(packet_list, &ssrc, &sequence_number,
                            &capture_time_ms);
      critsect_->Leave();

      const bool success = callback_->TimeToSendPacket(ssrc, sequence_number,
                                                       capture_time_ms);
      critsect_->Enter();
      // If packet cannt be sent then keep it in packet list and exit early.
      // There's no need to send more packets.
      if (!success) {
        return 0;
      }
      packet_list->pop_front();
      const bool last_packet = packet_list->empty() ||
          packet_list->front().capture_time_ms_ > capture_time_ms;
      if (packet_list != high_priority_packets_.get()) {
        if (capture_time_ms > capture_time_ms_last_sent_) {
          capture_time_ms_last_sent_ = capture_time_ms;
        } else if (capture_time_ms == capture_time_ms_last_sent_ &&
                   last_packet) {
          TRACE_EVENT_ASYNC_END0("webrtc_rtp", "PacedSend", capture_time_ms);
        }
      }
    }
    if (high_priority_packets_->empty() &&
        normal_priority_packets_->empty() &&
        low_priority_packets_->empty() &&
        padding_budget_->bytes_remaining() > 0 &&
        pad_up_to_bitrate_budget_->bytes_remaining() > 0) {
      int padding_needed = std::min(
          padding_budget_->bytes_remaining(),
          pad_up_to_bitrate_budget_->bytes_remaining());
      critsect_->Leave();
      int bytes_sent = callback_->TimeToSendPadding(padding_needed);
      critsect_->Enter();
      media_budget_->UseBudget(bytes_sent);
      padding_budget_->UseBudget(bytes_sent);
      pad_up_to_bitrate_budget_->UseBudget(bytes_sent);
    }
  }
  return 0;
}

// MUST have critsect_ when calling.
void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
  media_budget_->IncreaseBudget(delta_time_ms);
  padding_budget_->IncreaseBudget(delta_time_ms);
  pad_up_to_bitrate_budget_->IncreaseBudget(delta_time_ms);
}

// MUST have critsect_ when calling.
bool PacedSender::ShouldSendNextPacket(paced_sender::PacketList** packet_list) {
  if (media_budget_->bytes_remaining() <= 0) {
    // All bytes consumed for this interval.
    // Check if we have not sent in a too long time.
    if ((TickTime::Now() - time_last_send_).Milliseconds() >
        kMaxQueueTimeWithoutSendingMs) {
      if (!high_priority_packets_->empty()) {
        *packet_list = high_priority_packets_.get();
        return true;
      }
      if (!normal_priority_packets_->empty()) {
        *packet_list = normal_priority_packets_.get();
        return true;
      }
    }
    return false;
  }
  if (!high_priority_packets_->empty()) {
    *packet_list = high_priority_packets_.get();
    return true;
  }
  if (!normal_priority_packets_->empty()) {
    *packet_list = normal_priority_packets_.get();
    return true;
  }
  if (!low_priority_packets_->empty()) {
    *packet_list = low_priority_packets_.get();
    return true;
  }
  return false;
}

void PacedSender::GetNextPacketFromList(paced_sender::PacketList* packets,
    uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms) {
  paced_sender::Packet packet = packets->front();
  UpdateMediaBytesSent(packet.bytes_);
  *sequence_number = packet.sequence_number_;
  *ssrc = packet.ssrc_;
  *capture_time_ms = packet.capture_time_ms_;
}

// MUST have critsect_ when calling.
void PacedSender::UpdateMediaBytesSent(int num_bytes) {
  time_last_send_ = TickTime::Now();
  media_budget_->UseBudget(num_bytes);
  pad_up_to_bitrate_budget_->UseBudget(num_bytes);
}

}  // namespace webrtc
<|endoftext|>


<commit_before>#include "mainframe.hpp"
#include "constants.hpp"
#include "menubar.hpp"
#include "notebook.hpp"
#include "preferences/preferencespagepaths.hpp"

MainFrame::MainFrame(Settings *settings)
    : wxFrame(NULL, wxID_ANY, PROGRAM_NAME, wxDefaultPosition, wxSize(WINDOW_WIDTH, WINDOW_HEIGHT))
{
    m_preferencesEditor = NULL;
    m_settings = settings;

    CreateStatusBar();
    SetStatusText("Welcome");

    MenuBar *menuBar = new MenuBar();
    menuBar->Bind(wxEVT_MENU, &MainFrame::OnMenuBarItemClicked, this);
    SetMenuBar(menuBar);

    wxPanel *notebookPanel = new wxPanel(this);
    wxBoxSizer *notebookPanelSizer = new wxBoxSizer(wxVERTICAL);
    m_notebook = new Notebook(notebookPanel, *this);
    m_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &MainFrame::OnNotebookPageChanged, this);

    m_displayFrame = new DisplayFrame(this);
    m_displayFrame->Show();
    // When the frame is closed, we want to update menu bar.
    m_displayFrame->Bind(wxEVT_CLOSE_WINDOW, &MenuBar::OnFrameClosed, menuBar);
    // When a checkbox belonging to this frame gets (un)checked, we want to update what is being drawn in the current workspace.
    m_displayFrame->Bind(wxEVT_CHECKBOX, &MainFrame::OnDisplayFrameCheckBoxClicked, this);

    m_paletteFrame = new PaletteFrame(this);
    m_paletteFrame->Show();
    m_paletteFrame->Bind(wxEVT_CLOSE_WINDOW, &MenuBar::OnFrameClosed, menuBar);

    m_toolbarFrame = new ToolbarFrame(this, [&](int toolId) { m_notebook->OnToolSelected(toolId); });
    m_toolbarFrame->Show();
    m_toolbarFrame->Bind(wxEVT_CLOSE_WINDOW, &MenuBar::OnFrameClosed, menuBar);

    notebookPanelSizer->Add(m_notebook, 1, wxEXPAND);
    notebookPanel->SetSizer(notebookPanelSizer);
    AddWorkspace(m_settings->GetSoldatPath() + "maps/test.pms");
}

MainFrame::~MainFrame()
{
    // Fix for segmentation fault after closing the program with at least 2 tabs opened.
    m_notebook->Unbind(wxEVT_NOTEBOOK_PAGE_CHANGED, &MainFrame::OnNotebookPageChanged, this);

    if (m_preferencesEditor)
    {
        m_preferencesEditor->Dismiss();
    }
}

void MainFrame::AddWorkspace(wxString mapPath)
{
    try
    {
        m_notebook->AddWorkspace(*m_settings, mapPath);
    }
    catch (const std::runtime_error& error)
    {
        wxMessageBox(error.what(), "Workspace construction failed.");
        Close(true);

        return;
    }
}

void MainFrame::OnBackgroundColorChanged(wxColourPickerEvent &event)
{
    m_notebook->SetBackgroundColors(m_mapSettingsDialog->GetBackgroundBottomColor(),
                                    m_mapSettingsDialog->GetBackgroundTopColor());
}

void MainFrame::OnDisplayFrameCheckBoxClicked(wxCommandEvent &event)
{
    int displaySetting = event.GetId();
    bool isChecked = event.IsChecked();

    m_notebook->SetCurrentDisplaySetting(displaySetting, isChecked);
}

void MainFrame::OnMenuBarItemClicked(wxCommandEvent &event)
{
    wxWindowID menuBarItemId = event.GetId();

    switch (menuBarItemId)
    {
        case ID_MENU_FILE_NEW:
            AddWorkspace(wxEmptyString);
            break;

        case ID_MENU_FILE_OPEN_COMPILED:
            {
                wxString path = wxFileSelector(wxT("Open PMS file"), wxEmptyString,
                                wxEmptyString, wxEmptyString, wxT("*.pms"), wxFD_FILE_MUST_EXIST);
                if (!path.IsEmpty())
                {
                    AddWorkspace(path);
                }
            }
            break;

        case ID_MENU_FILE_SAVE_AS_PMS:
            {
                wxString path = wxFileSelector(wxT("Save as PMS"), m_settings->GetSoldatPath() + "maps/",
                    wxEmptyString, wxT(".pms"), wxT(".pms"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
                if (!path.IsEmpty())
                {
                    m_notebook->SaveCurrentMapAsPMS(path);
                }
            }
            break;

        case ID_MENU_EDIT_SELECT_ALL:
            m_notebook->SelectAll();
            break;

        case ID_MENU_EDIT_MAP_SETTINGS:
            {
                m_mapSettingsDialog = new MapSettingsDialog(this, m_notebook->GetCurrentMap(),
                                                            m_settings->GetSoldatPath());
                m_mapSettingsDialog->GetBackgroundBottomColorPicker()->Bind(wxEVT_COLOURPICKER_CHANGED,
                    &MainFrame::OnBackgroundColorChanged, this);
                m_mapSettingsDialog->GetBackgroundTopColorPicker()->Bind(wxEVT_COLOURPICKER_CHANGED,
                    &MainFrame::OnBackgroundColorChanged, this);
                m_mapSettingsDialog->GetTextureChoice()->Bind(wxEVT_CHOICE,
                    &MainFrame::OnPolygonsTextureChanged, this);
                m_mapSettingsDialog->ShowModal();
            }
            break;

        case ID_MENU_EDIT_PREFERENCES:
            m_preferencesEditor = new wxPreferencesEditor();
            m_preferencesEditor->AddPage(new PreferencesPagePaths(m_settings));
            m_preferencesEditor->Show(this);
            break;

        case ID_MENU_WINDOWS_SHOW_ALL:
            ShowAllMiniFrames(true);
            break;

        case ID_MENU_WINDOWS_HIDE_ALL:
            ShowAllMiniFrames(false);
            break;

        case ID_MENU_WINDOWS_DISPLAY:
            m_displayFrame->ToggleVisibility();
            break;

        case ID_MENU_WINDOWS_PALETTE:
            m_paletteFrame->ToggleVisibility();
            break;

        case ID_MENU_WINDOWS_TOOLBAR:
            m_toolbarFrame->ToggleVisibility();
            break;
    }

    // Pass the event to following event handler.
    event.Skip();
}

void MainFrame::OnNotebookPageChanged(wxBookCtrlEvent &event)
{
    m_displayFrame->UpdateCheckBoxes(m_notebook->GetCurrentDisplaySettings());
    event.Skip();
}

void MainFrame::OnPolygonsTextureChanged(wxCommandEvent &event)
{
    wxString textureFilename = event.GetString();
    m_notebook->SetPolygonsTexture(textureFilename);
}

void MainFrame::ShowAllMiniFrames(bool show)
{
    m_displayFrame->Show(show);
    m_paletteFrame->Show(show);
    m_toolbarFrame->Show(show);
}
<commit_msg>Fixed extension wildcard for Save as PMS file selector<commit_after>#include "mainframe.hpp"
#include "constants.hpp"
#include "menubar.hpp"
#include "notebook.hpp"
#include "preferences/preferencespagepaths.hpp"

MainFrame::MainFrame(Settings *settings)
    : wxFrame(NULL, wxID_ANY, PROGRAM_NAME, wxDefaultPosition, wxSize(WINDOW_WIDTH, WINDOW_HEIGHT))
{
    m_preferencesEditor = NULL;
    m_settings = settings;

    CreateStatusBar();
    SetStatusText("Welcome");

    MenuBar *menuBar = new MenuBar();
    menuBar->Bind(wxEVT_MENU, &MainFrame::OnMenuBarItemClicked, this);
    SetMenuBar(menuBar);

    wxPanel *notebookPanel = new wxPanel(this);
    wxBoxSizer *notebookPanelSizer = new wxBoxSizer(wxVERTICAL);
    m_notebook = new Notebook(notebookPanel, *this);
    m_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &MainFrame::OnNotebookPageChanged, this);

    m_displayFrame = new DisplayFrame(this);
    m_displayFrame->Show();
    // When the frame is closed, we want to update menu bar.
    m_displayFrame->Bind(wxEVT_CLOSE_WINDOW, &MenuBar::OnFrameClosed, menuBar);
    // When a checkbox belonging to this frame gets (un)checked, we want to update what is being drawn in the current workspace.
    m_displayFrame->Bind(wxEVT_CHECKBOX, &MainFrame::OnDisplayFrameCheckBoxClicked, this);

    m_paletteFrame = new PaletteFrame(this);
    m_paletteFrame->Show();
    m_paletteFrame->Bind(wxEVT_CLOSE_WINDOW, &MenuBar::OnFrameClosed, menuBar);

    m_toolbarFrame = new ToolbarFrame(this, [&](int toolId) { m_notebook->OnToolSelected(toolId); });
    m_toolbarFrame->Show();
    m_toolbarFrame->Bind(wxEVT_CLOSE_WINDOW, &MenuBar::OnFrameClosed, menuBar);

    notebookPanelSizer->Add(m_notebook, 1, wxEXPAND);
    notebookPanel->SetSizer(notebookPanelSizer);
    AddWorkspace(m_settings->GetSoldatPath() + "maps/test.pms");
}

MainFrame::~MainFrame()
{
    // Fix for segmentation fault after closing the program with at least 2 tabs opened.
    m_notebook->Unbind(wxEVT_NOTEBOOK_PAGE_CHANGED, &MainFrame::OnNotebookPageChanged, this);

    if (m_preferencesEditor)
    {
        m_preferencesEditor->Dismiss();
    }
}

void MainFrame::AddWorkspace(wxString mapPath)
{
    try
    {
        m_notebook->AddWorkspace(*m_settings, mapPath);
    }
    catch (const std::runtime_error& error)
    {
        wxMessageBox(error.what(), "Workspace construction failed.");
        Close(true);

        return;
    }
}

void MainFrame::OnBackgroundColorChanged(wxColourPickerEvent &event)
{
    m_notebook->SetBackgroundColors(m_mapSettingsDialog->GetBackgroundBottomColor(),
                                    m_mapSettingsDialog->GetBackgroundTopColor());
}

void MainFrame::OnDisplayFrameCheckBoxClicked(wxCommandEvent &event)
{
    int displaySetting = event.GetId();
    bool isChecked = event.IsChecked();

    m_notebook->SetCurrentDisplaySetting(displaySetting, isChecked);
}

void MainFrame::OnMenuBarItemClicked(wxCommandEvent &event)
{
    wxWindowID menuBarItemId = event.GetId();

    switch (menuBarItemId)
    {
        case ID_MENU_FILE_NEW:
            AddWorkspace(wxEmptyString);
            break;

        case ID_MENU_FILE_OPEN_COMPILED:
            {
                wxString path = wxFileSelector(wxT("Open PMS file"), wxEmptyString,
                                wxEmptyString, wxEmptyString, wxT("*.pms"), wxFD_FILE_MUST_EXIST);
                if (!path.IsEmpty())
                {
                    AddWorkspace(path);
                }
            }
            break;

        case ID_MENU_FILE_SAVE_AS_PMS:
            {
                wxString path = wxFileSelector(wxT("Save as PMS"), m_settings->GetSoldatPath() + "maps/",
                    wxEmptyString, wxT(".pms"), wxT("*.pms"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
                if (!path.IsEmpty())
                {
                    m_notebook->SaveCurrentMapAsPMS(path);
                }
            }
            break;

        case ID_MENU_EDIT_SELECT_ALL:
            m_notebook->SelectAll();
            break;

        case ID_MENU_EDIT_MAP_SETTINGS:
            {
                m_mapSettingsDialog = new MapSettingsDialog(this, m_notebook->GetCurrentMap(),
                                                            m_settings->GetSoldatPath());
                m_mapSettingsDialog->GetBackgroundBottomColorPicker()->Bind(wxEVT_COLOURPICKER_CHANGED,
                    &MainFrame::OnBackgroundColorChanged, this);
                m_mapSettingsDialog->GetBackgroundTopColorPicker()->Bind(wxEVT_COLOURPICKER_CHANGED,
                    &MainFrame::OnBackgroundColorChanged, this);
                m_mapSettingsDialog->GetTextureChoice()->Bind(wxEVT_CHOICE,
                    &MainFrame::OnPolygonsTextureChanged, this);
                m_mapSettingsDialog->ShowModal();
            }
            break;

        case ID_MENU_EDIT_PREFERENCES:
            m_preferencesEditor = new wxPreferencesEditor();
            m_preferencesEditor->AddPage(new PreferencesPagePaths(m_settings));
            m_preferencesEditor->Show(this);
            break;

        case ID_MENU_WINDOWS_SHOW_ALL:
            ShowAllMiniFrames(true);
            break;

        case ID_MENU_WINDOWS_HIDE_ALL:
            ShowAllMiniFrames(false);
            break;

        case ID_MENU_WINDOWS_DISPLAY:
            m_displayFrame->ToggleVisibility();
            break;

        case ID_MENU_WINDOWS_PALETTE:
            m_paletteFrame->ToggleVisibility();
            break;

        case ID_MENU_WINDOWS_TOOLBAR:
            m_toolbarFrame->ToggleVisibility();
            break;
    }

    // Pass the event to following event handler.
    event.Skip();
}

void MainFrame::OnNotebookPageChanged(wxBookCtrlEvent &event)
{
    m_displayFrame->UpdateCheckBoxes(m_notebook->GetCurrentDisplaySettings());
    event.Skip();
}

void MainFrame::OnPolygonsTextureChanged(wxCommandEvent &event)
{
    wxString textureFilename = event.GetString();
    m_notebook->SetPolygonsTexture(textureFilename);
}

void MainFrame::ShowAllMiniFrames(bool show)
{
    m_displayFrame->Show(show);
    m_paletteFrame->Show(show);
    m_toolbarFrame->Show(show);
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
   This file is part of BayesOptimization, an efficient C++ library for
   Bayesian optimization.

   Copyright (C) 2011 Ruben Martinez-Cantin <rmcantin@unizar.es>

   BayesOptimization is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   BayesOptimization is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with BayesOptimization.  If not, see <http://www.gnu.org/licenses/>.
-----------------------------------------------------------------------------
*/

#ifndef  _CRITERIA_HPP_
#define  _CRITERIA_HPP_

#include <algorithm>

#include "ctypes.h"
#include "specialtypes.hpp"
#include "randgen.hpp"

class Criteria
{
public:

  Criteria():
    mtRandom(100u)
  {
    criterium = c_ei;
    resetAnnealValues();
    resetHedgeValues();
    eta = 1;
    use_annealing = false;
  }

  virtual ~Criteria(){}

  inline void resetHedgeValues()
  { g_ei = 0;  g_lcb = 0;  g_poi = 0; }

  inline void resetAnnealValues()
  { n_calls = 0; g = 1; beta = 1; epsilon = 0.01; }

  inline void setCriterium(criterium_name c)
  { criterium = c; }
  inline void setAnnealing(bool anneal)
  { use_annealing = anneal; }

  inline double evaluate(NonParametricProcess &gp, const vectord &query)
  {
    n_calls++;
    if (use_annealing) updateCoolingScheme(query.size());

    double yPred, sPred, yMin = gp.getValueAtMinimum();
    gp.prediction(query,yPred,sPred);
    double yStar;

     switch (criterium)
      {
      case c_ei: return gp.negativeExpectedImprovement(yPred,sPred,yMin,g);
      case c_lcb: return gp.lowerConfidenceBound(yPred,sPred,beta);
      case c_poi: return gp.negativeProbabilityOfImprovement(yPred,sPred,yMin,epsilon);
      case c_greedyAOptimality: return sPred;
      case c_expectedReturn: return yPred;
      case c_optimisticSampling:
	yStar = gp.sample_query(query,mtRandom);
	return std::min(yPred,yStar);
      case c_gp_hedge:
      default: std::cout << "Error in criterium" << std::endl; return 0.0;
      }

  }

  double abs_max(double a, double b)
  { return (std::abs(a)<std::abs(b)) ? b:a; }

  /**
   * Update the accumulated rewards for the GP-Hedge algorithm. See References
   * for a detailled explanation
   *
   * @param r_ei   Reward of the Expected Improvement algorithm
   * @param r_lcb  Reward of the Lower Confidence Bound algorithm
   * @param r_poi  Reward of the Probability of Improvement algorithm
   *
   * @return name of the selected algorithm.
   */
  criterium_name update_hedge(double l_ei, double l_lcb, double l_poi)
  {
    randFloat sample( mtRandom, realUniformDist(0,1) );

    double max_g = std::max(g_ei,std::max(g_lcb,g_poi));
    double min_g = std::min(g_ei,std::min(g_lcb,g_poi));
    double rang_g = max_g - min_g;

    //g_ei += min_g; g_lcb += min_g; g_poi += min_g;
    //g_ei /= rang_g; g_lcb /= rang_g; g_poi /= rang_g;

    eta = sqrt(2*log(3)/rang_g);

    // To avoid overflow
    double offset = min_g;//abs_max(g_ei,abs_max(g_lcb,g_poi));

    std::cout << offset << "," << std::endl;

    double p_ei = exp(eta*(g_ei - offset));
    double p_lcb = exp(eta*(g_lcb - offset));
    double p_poi = exp(eta*(g_poi - offset));
    double sum_p = p_ei + p_lcb + p_poi;

    std::cout << p_ei << "," << p_lcb << "," << p_poi << "," << std::endl;

    // Compute probabilities of choosing action
    p_ei  /= sum_p; p_lcb /= sum_p; p_poi /= sum_p;

    // Update accumulated rewards for next time
    g_ei -= l_ei; g_lcb -= l_lcb; g_poi -= l_poi;

    std::cout << l_ei << "," << l_lcb << "," << l_poi << "," << std::endl;
    std::cout << g_ei << "," << g_lcb << "," << g_poi << "," << std::endl;
    std::cout << p_ei << "," << p_lcb << "," << p_poi << "," << std::endl;

    double u = sample();

    if (u < p_ei)
      return c_ei;
    else if (u < p_lcb+p_ei)
      return c_lcb;
    else
    return c_poi;
  }

protected:

  /**
   * Updates the parameters that can be used for annealing
   *
   * @param ndims # of imput dimensions.
   */
  inline void updateCoolingScheme(size_t ndims)
  {
    double coef = 5;

    if (n_calls%10)
      g = std::max(1,static_cast<int>(round(g/2.0)));
    beta = sqrt(2*log(n_calls*n_calls)*(ndims+1) + log(ndims)*ndims*coef);
  }

protected:

  criterium_name criterium;
  randEngine mtRandom;
  unsigned int n_calls, g;

  double beta, epsilon, eta;
  double g_poi,g_lcb,g_ei;
  bool use_annealing;

};

#endif
<commit_msg>Solved issues with hedge algorithm<commit_after>/*
-----------------------------------------------------------------------------
   This file is part of BayesOptimization, an efficient C++ library for
   Bayesian optimization.

   Copyright (C) 2011 Ruben Martinez-Cantin <rmcantin@unizar.es>

   BayesOptimization is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   BayesOptimization is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with BayesOptimization.  If not, see <http://www.gnu.org/licenses/>.
-----------------------------------------------------------------------------
*/

#ifndef  _CRITERIA_HPP_
#define  _CRITERIA_HPP_

#include <algorithm>

#include "ctypes.h"
#include "specialtypes.hpp"
#include "randgen.hpp"

class Criteria
{
public:

  Criteria():
    mtRandom(100u)
  {
    criterium = c_ei;
    resetAnnealValues();
    resetHedgeValues();
    eta = 1;
    use_annealing = false;
  }

  virtual ~Criteria(){}

  inline void resetHedgeValues()
  { g_ei = 0;  g_lcb = 0;  g_poi = 0; }

  inline void resetAnnealValues()
  { n_calls = 0; g = 1; beta = 1; epsilon = 0.01; }

  inline void setCriterium(criterium_name c)
  { criterium = c; }
  inline void setAnnealing(bool anneal)
  { use_annealing = anneal; }

  inline double evaluate(NonParametricProcess &gp, const vectord &query)
  {
    n_calls++;
    if (use_annealing) updateCoolingScheme(query.size());

    double yPred, sPred, yMin = gp.getValueAtMinimum();
    gp.prediction(query,yPred,sPred);
    double yStar;

     switch (criterium)
      {
      case c_ei: return gp.negativeExpectedImprovement(yPred,sPred,yMin,g);
      case c_lcb: return gp.lowerConfidenceBound(yPred,sPred,beta);
      case c_poi: return gp.negativeProbabilityOfImprovement(yPred,sPred,yMin,epsilon);
      case c_greedyAOptimality: return sPred;
      case c_expectedReturn: return yPred;
      case c_optimisticSampling:
	yStar = gp.sample_query(query,mtRandom);
	return std::min(yPred,yStar);
      case c_gp_hedge:
      default: std::cout << "Error in criterium" << std::endl; return 0.0;
      }

  }

  double abs_max(double a, double b)
  { return (std::abs(a)<std::abs(b)) ? b:a; }

  /**
   * Update the accumulated rewards for the GP-Hedge algorithm. See References
   * for a detailled explanation. Although it has been carefully implemented to
   * avoid overflow or underflow it may still suffer from it if the predictions
   * of the GP produce very large numbers.
   *
   * @param l_ei   Loss of the Expected Improvement algorithm
   * @param l_lcb  Loss of the Lower Confidence Bound algorithm
   * @param l_poi  Loss of the Probability of Improvement algorithm
   *
   * @return name of the selected algorithm.
   */
  criterium_name update_hedge(double l_ei, double l_lcb, double l_poi)
  {
    // TODO: Vectorize the function to support an arbitrary number of criteria.
    randFloat sample( mtRandom, realUniformDist(0,1) );

    double max_g = std::max(g_ei,std::max(g_lcb,g_poi));
    double min_g = std::min(g_ei,std::min(g_lcb,g_poi));

    double max_l = std::max(l_ei,std::max(l_lcb,l_poi));
    l_ei += max_l; l_lcb += max_l; l_poi += max_l;        // We just care about the differences

    eta = sqrt(2*log(3)/max_g);                           // Optimal eta according to Shapire

    // To avoid overflow
    double offset = min_g;
    g_ei -= offset; g_lcb -= offset; g_poi -= offset;

    std::cout << offset << "," << std::endl;

    double p_ei = exp(eta*g_ei);
    double p_lcb = exp(eta*g_lcb);
    double p_poi = exp(eta*g_poi);
    double sum_p = p_ei + p_lcb + p_poi;

    std::cout << p_ei << "," << p_lcb << "," << p_poi << "," << std::endl;

    // Compute probabilities of choosing action
    p_ei  /= sum_p; p_lcb /= sum_p; p_poi /= sum_p;

    // Update accumulated rewards for next time
    g_ei -= l_ei; g_lcb -= l_lcb; g_poi -= l_poi;

    std::cout << l_ei << "," << l_lcb << "," << l_poi << "," << std::endl;
    std::cout << g_ei << "," << g_lcb << "," << g_poi << "," << std::endl;
    std::cout << p_ei << "," << p_lcb << "," << p_poi << "," << std::endl;

    double u = sample();

    if (u < p_ei)
      return c_ei;
    else if (u < p_lcb+p_ei)
      return c_lcb;
    else
    return c_poi;
  }

protected:

  /**
   * Updates the parameters that can be used for annealing
   *
   * @param ndims # of imput dimensions.
   */
  inline void updateCoolingScheme(size_t ndims)
  {
    double coef = 5;

    if (n_calls%10)
      g = std::max(1,static_cast<int>(round(g/2.0)));
    beta = sqrt(2*log(n_calls*n_calls)*(ndims+1) + log(ndims)*ndims*coef);
  }

protected:

  criterium_name criterium;
  randEngine mtRandom;
  unsigned int n_calls, g;

  double beta, epsilon, eta;
  double g_poi,g_lcb,g_ei;
  bool use_annealing;

};

#endif
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2012 by the fifechan team                               *
 *   http://fifechan.github.com/fifechan                                   *
 *   This file is part of fifechan.                                        *
 *                                                                         *
 *   fifechan is free software; you can redistribute it and/or             *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessn and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessn a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of Guichan nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef FCN_FIFECHAN_HPP
#define FCN_FIFECAHN_HPP

#include <fifechan/actionevent.hpp>
#include <fifechan/actionlistener.hpp>
#include <fifechan/cliprectangle.hpp>
#include <fifechan/color.hpp>
#include <fifechan/containerevent.hpp>
#include <fifechan/containerlistener.hpp>
#include <fifechan/deathlistener.hpp>
#include <fifechan/event.hpp>
#include <fifechan/exception.hpp>
#include <fifechan/focushandler.hpp>
#include <fifechan/focuslistener.hpp>
#include <fifechan/font.hpp>
#include <fifechan/genericinput.hpp>
#include <fifechan/graphics.hpp>
#include <fifechan/gui.hpp>
#include <fifechan/image.hpp>
#include <fifechan/imagefont.hpp>
#include <fifechan/imageloader.hpp>
#include <fifechan/input.hpp>
#include <fifechan/inputevent.hpp>
#include <fifechan/key.hpp>
#include <fifechan/keyevent.hpp>
#include <fifechan/keyinput.hpp>
#include <fifechan/keylistener.hpp>
#include <fifechan/listmodel.hpp>
#include <fifechan/mouseevent.hpp>
#include <fifechan/mouseinput.hpp>
#include <fifechan/mouselistener.hpp>
#include <fifechan/rectangle.hpp>
#include <fifechan/selectionevent.hpp>
#include <fifechan/selectionlistener.hpp>
#include <fifechan/widget.hpp>
#include <fifechan/widgetlistener.hpp>
#include <fifechan/widgets/button.hpp>
#include <fifechan/widgets/checkbox.hpp>
#include <fifechan/widgets/container.hpp>
#include <fifechan/widgets/dropdown.hpp>
#include <fifechan/widgets/icon.hpp>
#include <fifechan/widgets/iconprogressbar.hpp>
#include <fifechan/widgets/imagebutton.hpp>
#include <fifechan/widgets/label.hpp>
#include <fifechan/widgets/listbox.hpp>
#include <fifechan/widgets/passwordfield.hpp>
#include <fifechan/widgets/scrollarea.hpp>
#include <fifechan/widgets/slider.hpp>
#include <fifechan/widgets/radiobutton.hpp>
#include <fifechan/widgets/tab.hpp>
#include <fifechan/widgets/tabbedarea.hpp>
#include <fifechan/widgets/textbox.hpp>
#include <fifechan/widgets/textfield.hpp>
#include <fifechan/widgets/window.hpp>

#include "fifechan/platform.hpp"

class Widget;

extern "C"
{
    /**
     * Gets the the version of Guichan. As it is a C function
     * it can be used to check for Guichan with autotools.
     *
     * @return the version of Guichan.
     */
    FCN_CORE_DECLSPEC extern const char* fcnFifechanVersion();
}

#endif // end FCN_FIFECHAN_HPP
<commit_msg>Fix typo.<commit_after>/***************************************************************************
 *   Copyright (C) 2012 by the fifechan team                               *
 *   http://fifechan.github.com/fifechan                                   *
 *   This file is part of fifechan.                                        *
 *                                                                         *
 *   fifechan is free software; you can redistribute it and/or             *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessén a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of Guichan nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef FCN_FIFECHAN_HPP
#define FCN_FIFECHAN_HPP

#include <fifechan/actionevent.hpp>
#include <fifechan/actionlistener.hpp>
#include <fifechan/cliprectangle.hpp>
#include <fifechan/color.hpp>
#include <fifechan/containerevent.hpp>
#include <fifechan/containerlistener.hpp>
#include <fifechan/deathlistener.hpp>
#include <fifechan/event.hpp>
#include <fifechan/exception.hpp>
#include <fifechan/focushandler.hpp>
#include <fifechan/focuslistener.hpp>
#include <fifechan/font.hpp>
#include <fifechan/genericinput.hpp>
#include <fifechan/graphics.hpp>
#include <fifechan/gui.hpp>
#include <fifechan/image.hpp>
#include <fifechan/imagefont.hpp>
#include <fifechan/imageloader.hpp>
#include <fifechan/input.hpp>
#include <fifechan/inputevent.hpp>
#include <fifechan/key.hpp>
#include <fifechan/keyevent.hpp>
#include <fifechan/keyinput.hpp>
#include <fifechan/keylistener.hpp>
#include <fifechan/listmodel.hpp>
#include <fifechan/mouseevent.hpp>
#include <fifechan/mouseinput.hpp>
#include <fifechan/mouselistener.hpp>
#include <fifechan/rectangle.hpp>
#include <fifechan/selectionevent.hpp>
#include <fifechan/selectionlistener.hpp>
#include <fifechan/widget.hpp>
#include <fifechan/widgetlistener.hpp>
#include <fifechan/widgets/button.hpp>
#include <fifechan/widgets/checkbox.hpp>
#include <fifechan/widgets/container.hpp>
#include <fifechan/widgets/dropdown.hpp>
#include <fifechan/widgets/icon.hpp>
#include <fifechan/widgets/iconprogressbar.hpp>
#include <fifechan/widgets/imagebutton.hpp>
#include <fifechan/widgets/label.hpp>
#include <fifechan/widgets/listbox.hpp>
#include <fifechan/widgets/passwordfield.hpp>
#include <fifechan/widgets/scrollarea.hpp>
#include <fifechan/widgets/slider.hpp>
#include <fifechan/widgets/radiobutton.hpp>
#include <fifechan/widgets/tab.hpp>
#include <fifechan/widgets/tabbedarea.hpp>
#include <fifechan/widgets/textbox.hpp>
#include <fifechan/widgets/textfield.hpp>
#include <fifechan/widgets/window.hpp>

#include "fifechan/platform.hpp"

class Widget;

extern "C"
{
    /**
     * Gets the the version of Guichan. As it is a C function
     * it can be used to check for Guichan with autotools.
     *
     * @return the version of Guichan.
     */
    FCN_CORE_DECLSPEC extern const char* fcnFifechanVersion();
}

#endif // end FCN_FIFECHAN_HPP
<|endoftext|>