Beispiel #1
0
void envelope_points(std::vector< coord<double,2> > & coords, box2d<double>& env, int points)
{
    double width = env.width();
    double height = env.height();

    int steps;

    if (points <= 4) {
        steps = 0;
    } else {
        steps = static_cast<int>(std::ceil((points - 4) / 4.0));
    }

    steps += 1;
    double xstep = width / steps;
    double ystep = height / steps;

    for (int i=0; i<=steps; i++) {
        coords.push_back(coord<double,2>(env.minx() + i * xstep, env.miny()));
        coords.push_back(coord<double,2>(env.minx() + i * xstep, env.maxy()));

    }
    for (int i=1; i<steps; i++) {
        coords.push_back(coord<double,2>(env.minx(), env.miny() + i * ystep));
        coords.push_back(coord<double,2>(env.maxx(), env.miny() + i * ystep));
    }
}
    bool has_placement(box2d<double> const& box, double margin, mapnik::value_unicode_string const& text, double repeat_distance)
    {
        // Don't bother with any of the repeat checking unless the repeat distance is greater than the margin
        if (repeat_distance <= margin) {
            return has_placement(box, margin);
        }

        box2d<double> repeat_box(box.minx() - repeat_distance, box.miny() - repeat_distance,
                                 box.maxx() + repeat_distance, box.maxy() + repeat_distance);

        box2d<double> const& margin_box = (margin > 0
                                               ? box2d<double>(box.minx() - margin, box.miny() - margin,
                                                               box.maxx() + margin, box.maxy() + margin)
                                               : box);

        tree_t::query_iterator tree_itr = tree_.query_in_box(repeat_box);
        tree_t::query_iterator tree_end = tree_.query_end();

        for ( ;tree_itr != tree_end; ++tree_itr)
        {
            if (tree_itr->get().box.intersects(margin_box) || (text == tree_itr->get().text && tree_itr->get().box.intersects(repeat_box)))
            {
                return false;
            }
        }

        return true;
    }
    bool has_placement(box2d<double> const& box, double minimum_distance, mapnik::value_unicode_string const& text, double repeat_distance)
    {
        box2d<double> const& minimum_box = (minimum_distance > 0
                                               ? box2d<double>(box.minx() - minimum_distance, box.miny() - minimum_distance,
                                                               box.maxx() + minimum_distance, box.maxy() + minimum_distance)
                                               : box);

        box2d<double> const& repeat_box = (repeat_distance > 0
                                               ? box2d<double>(box.minx() - repeat_distance, box.miny() - repeat_distance,
                                                               box.maxx() + repeat_distance, box.maxy() + repeat_distance)
                                               : box);

        tree_t::query_iterator itr = tree_.query_in_box(repeat_distance > minimum_distance ? repeat_box : minimum_box);
        tree_t::query_iterator end = tree_.query_end();

        for ( ;itr != end; ++itr)
        {
            if (itr->box.intersects(minimum_box) || (text == itr->text && itr->box.intersects(repeat_box)))
            {
                return false;
            }
        }

        return true;
    }
 inline box2d<double> transform(box2d<double>& box) const
 {
     int x_offset = int(std::floor(box.minx() / tile_size_));
     int y_offset = int(std::floor(box.miny() / tile_size_));
     box2d<double> rem(x_offset * tile_size_,
                       y_offset * tile_size_,
                       x_offset * tile_size_,
                       y_offset * tile_size_);
     box.init(box.minx() - rem.minx(),
              box.miny() - rem.miny(),
              box.maxx() - rem.maxx(),
              box.maxy() - rem.maxy());
     return rem;
 }
    tiled_multi_file_policy(std::string const& file_pattern,
                            std::string const& format,
                            unsigned tile_size,
                            box2d<double> extent,
                            box2d<double> bbox,
                            unsigned width,
                            unsigned height,
                            unsigned tile_stride)
      : image_width_(width),
        image_height_(height),
        tile_size_(tile_size),
        tile_stride_(tile_stride)
    {
        double lox = extent.minx();
        double loy = extent.miny();
   
        //int max_x = int(std::ceil(double(width) / double(tile_size)));
        //int max_y = int(std::ceil(double(height) / double(tile_size)));

        double pixel_x = extent.width() / double(width);
        double pixel_y = extent.height() / double(height);

#ifdef MAPNIK_DEBUG 
        std::clog << "Raster Plugin: PIXEL SIZE("<< pixel_x << "," << pixel_y << ")" << std::endl;
#endif

        // intersection of query with extent => new query
        box2d<double> e = bbox.intersect(extent);
      
        const int x_min = int(std::floor((e.minx() - lox) / (tile_size * pixel_x)));
        const int y_min = int(std::floor((e.miny() - loy) / (tile_size * pixel_y)));
        const int x_max = int(std::ceil((e.maxx() - lox) / (tile_size * pixel_x)));
        const int y_max = int(std::ceil((e.maxy() - loy) / (tile_size * pixel_y)));

        for (int x = x_min; x < x_max; ++x)
        {
            for (int y = y_min; y < y_max; ++y)
            {
                // x0, y0, x1, y1 => projection-space image coordinates.
                double x0 = lox + x*tile_size*pixel_x;
                double y0 = loy + y*tile_size*pixel_y;
                double x1 = x0 + tile_size*pixel_x;
                double y1 = y0 + tile_size*pixel_y;
            
                // check if it intersects the query
                if (e.intersects(box2d<double>(x0,y0,x1,y1)))
                {
                    // tile_box => intersection of tile with query in projection-space.
                    box2d<double> tile_box = e.intersect(box2d<double>(x0,y0,x1,y1));
                    std::string file = interpolate(file_pattern, x, y);
                    raster_info info(file,format,tile_box,tile_size,tile_size);
                    infos_.push_back(info);
                }
            }
        }
#ifdef MAPNIK_DEBUG 
        std::clog << "Raster Plugin: INFO SIZE=" << infos_.size() << " " << file_pattern << std::endl;
#endif
    }
 inline box2d<double> backward(box2d<double> const& e) const
 {
     double x0 = e.minx();
     double y0 = e.miny();
     double x1 = e.maxx();
     double y1 = e.maxy();
     backward(&x0, &y0);
     backward(&x1, &y1);
     return box2d<double>(x0, y0, x1, y1);
 }
Beispiel #7
0
std::string occi_datasource::sql_bbox(box2d<double> const& env) const
{
    std::ostringstream b;
    b << std::setprecision(16);
    b << "MDSYS.SDO_GEOMETRY(" << SDO_GTYPE_2DPOLYGON << "," << srid_ << ",NULL,";
    b << " MDSYS.SDO_ELEM_INFO_ARRAY(1," << SDO_ETYPE_POLYGON << "," << SDO_INTERPRETATION_RECTANGLE << "),";
    b << " MDSYS.SDO_ORDINATE_ARRAY(";
    b << env.minx() << "," << env.miny() << ", ";
    b << env.maxx() << "," << env.maxy() << "))";
    return b.str();
}
std::string postgis_datasource::sql_bbox(box2d<double> const& env) const
{
    std::ostringstream b;
    if (srid_ > 0)
        b << "SetSRID(";
    b << "'BOX3D(";
    b << std::setprecision(16);
    b << env.minx() << " " << env.miny() << ",";
    b << env.maxx() << " " << env.maxy() << ")'::box3d";
    if (srid_ > 0)
        b << ", " << srid_ << ")";
    return b.str();
}
 inline box2d<double> backward(box2d<double> const& e,
                               proj_transform const& prj_trans) const
 {
     double x0 = e.minx();
     double y0 = e.miny();
     double x1 = e.maxx();
     double y1 = e.maxy();
     double z = 0.0;
     backward(&x0, &y0);
     prj_trans.forward(x0, y0, z);
     backward(&x1, &y1);
     prj_trans.forward(x1, y1, z);
     return box2d<double>(x0, y0, x1, y1);
 }
Beispiel #10
0
    void split_box(box2d<double> const& node_extent,box2d<double> * ext)
    {
        double width=node_extent.width();
        double height=node_extent.height();

        double lox=node_extent.minx();
        double loy=node_extent.miny();
        double hix=node_extent.maxx();
        double hiy=node_extent.maxy();

        ext[0]=box2d<double>(lox,loy,lox + width * ratio_,loy + height * ratio_);
        ext[1]=box2d<double>(hix - width * ratio_,loy,hix,loy + height * ratio_);
        ext[2]=box2d<double>(lox,hiy - height*ratio_,lox + width * ratio_,hiy);
        ext[3]=box2d<double>(hix - width * ratio_,hiy - height*ratio_,hix,hiy);
    }
Beispiel #11
0
void agg_renderer<T0,T1>::debug_draw_box(R& buf, box2d<double> const& box,
                                     double x, double y, double angle)
{
    using pixfmt = agg::pixfmt_rgba32_pre;
    using renderer_base = agg::renderer_base<pixfmt>;
    using renderer_type = agg::renderer_scanline_aa_solid<renderer_base>;

    agg::scanline_p8 sl_line;
    pixfmt pixf(buf);
    renderer_base renb(pixf);
    renderer_type ren(renb);

    // compute tranformation matrix
    agg::trans_affine tr = agg::trans_affine_rotation(angle).translate(x, y);
    // prepare path
    agg::path_storage pbox;
    pbox.start_new_path();
    pbox.move_to(box.minx(), box.miny());
    pbox.line_to(box.maxx(), box.miny());
    pbox.line_to(box.maxx(), box.maxy());
    pbox.line_to(box.minx(), box.maxy());
    pbox.line_to(box.minx(), box.miny());

    // prepare stroke with applied transformation
    using conv_transform = agg::conv_transform<agg::path_storage>;
    using conv_stroke = agg::conv_stroke<conv_transform>;
    conv_transform tbox(pbox, tr);
    conv_stroke sbox(tbox);
    sbox.generator().width(1.0 * common_.scale_factor_);

    // render the outline
    ras_ptr->reset();
    ras_ptr->add_path(sbox);
    ren.color(agg::rgba8_pre(0x33, 0x33, 0xff, 0xcc)); // blue is fine
    agg::render_scanlines(*ras_ptr, sl_line, ren);
}
    bool has_placement(box2d<double> const& box, mapnik::value_unicode_string const& text, double distance)
    {
        box2d<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);
        tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
        tree_t::query_iterator end = tree_.query_end();

        for ( ;itr != end; ++itr)
        {
            if (itr->box.intersects(box) || (text == itr->text && itr->box.intersects(bigger_box)))
            {
                return false;
            }
        }

        return true;
    }
    bool has_point_placement(box2d<double> const& box, double distance)
    {
        box2d<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);
        tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
        tree_t::query_iterator end = tree_.query_end();

        for ( ;itr != end; ++itr)
        {
            if (itr->box.intersects(bigger_box))
            {
                return false;
            }
        }

        return true;
    }
Beispiel #14
0
bool proj_transform::backward (box2d<double> & box) const
{
    if (is_source_equal_dest_)
        return true;

    double minx = box.minx();
    double miny = box.miny();
    double maxx = box.maxx();
    double maxy = box.maxy();
    double z = 0.0;
    if (!backward(minx,miny,z))
        return false;
    if (!backward(maxx,maxy,z))
        return false;
    box.init(minx,miny,maxx,maxy);
    return true;
}
Beispiel #15
0
 /** Rotates the size_ box and translates the position. */
 box2d<double> perform_transform(double angle, double dx, double dy)
 {
     double x1 = size_.minx();
     double x2 = size_.maxx();
     double y1 = size_.miny();
     double y2 = size_.maxy();
     agg::trans_affine tr = tr_ * agg::trans_affine_rotation(angle).translate(dx, dy);
     double xA = x1, yA = y1, xB = x2, yB = y1, xC = x2, yC = y2, xD = x1, yD = y2;
     tr.transform(&xA, &yA);
     tr.transform(&xB, &yB);
     tr.transform(&xC, &yC);
     tr.transform(&xD, &yD);
     box2d<double> result(xA, yA, xC, yC);
     result.expand_to_include(xB, yB);
     result.expand_to_include(xD, yD);
     return result;
 }
void draw_rect(image_32 &pixmap, box2d<double> const& box)
{
    double x0 = box.minx();
    double x1 = box.maxx();
    double y0 = box.miny();
    double y1 = box.maxy();
    unsigned color1 = 0xff0000ff;
    for (double x=x0; x<x1; x++)
    {
        pixmap.setPixel(x, y0, color1);
        pixmap.setPixel(x, y1, color1);
    }
    for (double y=y0; y<y1; y++)
    {
        pixmap.setPixel(x0, y, color1);
        pixmap.setPixel(x1, y, color1);
    }
}
    tiled_file_policy(std::string const& file,
                      std::string const& format,
                      unsigned tile_size,
                      box2d<double> extent,
                      box2d<double> bbox,
                      unsigned width,
                      unsigned height)
    {
        double lox = extent.minx();
        double loy = extent.miny();
   
        int max_x = int(std::ceil(double(width) / double(tile_size)));
        int max_y = int(std::ceil(double(height) / double(tile_size)));

        double pixel_x = extent.width() / double(width);
        double pixel_y = extent.height() / double(height);

#ifdef MAPNIK_DEBUG 
        std::clog << "Raster Plugin: PIXEL SIZE("<< pixel_x << "," << pixel_y << ")" << std::endl;
#endif

        box2d<double> e = bbox.intersect(extent);
      
        for (int x = 0; x < max_x; ++x)
        {
            for (int y = 0; y < max_y; ++y)
            {
                double x0 = lox + x * tile_size * pixel_x;
                double y0 = loy + y * tile_size * pixel_y;
                double x1 = x0 + tile_size * pixel_x;
                double y1 = y0 + tile_size * pixel_y;
            
                if (e.intersects(box2d<double>(x0, y0, x1, y1)))
                {
                    box2d<double> tile_box = e.intersect(box2d<double>(x0,y0,x1,y1));
                    raster_info info(file,format,tile_box,tile_size,tile_size);
                    infos_.push_back(info);
                }
            }
        }
#ifdef MAPNIK_DEBUG 
        std::clog << "Raster Plugin: INFO SIZE=" << infos_.size() << " " << file << std::endl;
#endif
    }
    bool has_placement(box2d<double> const& box, double margin)
    {
        box2d<double> const& margin_box = (margin > 0
                                               ? box2d<double>(box.minx() - margin, box.miny() - margin,
                                                               box.maxx() + margin, box.maxy() + margin)
                                               : box);

        tree_t::query_iterator tree_itr = tree_.query_in_box(margin_box);
        tree_t::query_iterator tree_end = tree_.query_end();

        for (;tree_itr != tree_end; ++tree_itr)
        {
            if (tree_itr->get().box.intersects(margin_box))
            {
                return false;
            }
        }
        return true;
    }
    bool has_placement(box2d<double> const& box, double minimum_distance)
    {
        box2d<double> const& minimum_box = (minimum_distance > 0
                                               ? box2d<double>(box.minx() - minimum_distance, box.miny() - minimum_distance,
                                                               box.maxx() + minimum_distance, box.maxy() + minimum_distance)
                                               : box);

        tree_t::query_iterator itr = tree_.query_in_box(minimum_box);
        tree_t::query_iterator end = tree_.query_end();

        for (;itr != end; ++itr)
        {
            if (itr->box.intersects(minimum_box))
            {
                return false;
            }
        }
        return true;
    }
Beispiel #20
0
void cairo_context::set_gradient(cairo_gradient const& pattern, const box2d<double> &bbox)
{
    cairo_pattern_t * gradient = pattern.gradient();
    double bx1=bbox.minx();
    double by1=bbox.miny();
    double bx2=bbox.maxx();
    double by2=bbox.maxy();
    if (pattern.units() != USER_SPACE_ON_USE)
    {
        if (pattern.units() == OBJECT_BOUNDING_BOX)
        {
            cairo_path_extents(cairo_.get(), &bx1, &by1, &bx2, &by2);
        }
        cairo_matrix_t cairo_matrix;
        cairo_pattern_get_matrix(gradient, &cairo_matrix);
        cairo_matrix_scale(&cairo_matrix,1.0/(bx2-bx1),1.0/(by2-by1));
        cairo_matrix_translate(&cairo_matrix, -bx1,-by1);
        cairo_pattern_set_matrix(gradient, &cairo_matrix);
    }
    cairo_set_source(cairo_.get(), const_cast<cairo_pattern_t*>(gradient));
    check_object_status_and_throw_exception(*this);
}
Beispiel #21
0
    void render_gradient(Rasterizer& ras,
                         Scanline& sl,
                         Renderer& ren,
                         const gradient &grad,
                         agg::trans_affine const& mtx,
                         double opacity,
                         const box2d<double> &symbol_bbox,
                         const box2d<double> &path_bbox)
    {
        typedef agg::gamma_lut<agg::int8u, agg::int8u> gamma_lut_type;
        typedef agg::gradient_lut<agg::color_interpolator<agg::rgba8>, 1024> color_func_type;
        typedef agg::span_interpolator_linear<> interpolator_type;
        typedef agg::span_allocator<agg::rgba8> span_allocator_type;

        span_allocator_type             m_alloc;
        color_func_type                 m_gradient_lut;
        gamma_lut_type                  m_gamma_lut;

        double x1,x2,y1,y2,radius;
        grad.get_control_points(x1,y1,x2,y2,radius);

        m_gradient_lut.remove_all();
        BOOST_FOREACH ( mapnik::stop_pair const& st, grad.get_stop_array() )
        {
            mapnik::color const& stop_color = st.second;
            unsigned r = stop_color.red();
            unsigned g = stop_color.green();
            unsigned b = stop_color.blue();
            unsigned a = stop_color.alpha();
            //MAPNIK_LOG_DEBUG(svg_renderer) << "svg_renderer: r=" << r << ",g=" << g << ",b=" << b << ",a=" << a;
            m_gradient_lut.add_color(st.first, agg::rgba8(r, g, b, int(a * opacity)));
        }
        m_gradient_lut.build_lut();

        agg::trans_affine transform = mtx;
        transform.invert();
        agg::trans_affine tr;
        tr = grad.get_transform();
        tr.invert();
        transform *= tr;

        if (grad.get_units() != USER_SPACE_ON_USE)
        {
            double bx1=symbol_bbox.minx();
            double by1=symbol_bbox.miny();
            double bx2=symbol_bbox.maxx();
            double by2=symbol_bbox.maxy();

            if (grad.get_units() == OBJECT_BOUNDING_BOX)
            {
                bx1=path_bbox.minx();
                by1=path_bbox.miny();
                bx2=path_bbox.maxx();
                by2=path_bbox.maxy();
            }

            transform.translate(-bx1,-by1);
            transform.scale(1.0/(bx2-bx1),1.0/(by2-by1));
        }


        if (grad.get_gradient_type() == RADIAL)
        {
            typedef agg::gradient_radial_focus gradient_adaptor_type;
            typedef agg::span_gradient<agg::rgba8,
                interpolator_type,
                gradient_adaptor_type,
                color_func_type> span_gradient_type;

            // the agg radial gradient assumes it is centred on 0
            transform.translate(-x2,-y2);

            // scale everything up since agg turns things into integers a bit too soon
            int scaleup=255;
            radius*=scaleup;
            x1*=scaleup;
            y1*=scaleup;
            x2*=scaleup;
            y2*=scaleup;

            transform.scale(scaleup,scaleup);
            interpolator_type     span_interpolator(transform);
            gradient_adaptor_type gradient_adaptor(radius,(x1-x2),(y1-y2));

            span_gradient_type    span_gradient(span_interpolator,
                                                gradient_adaptor,
                                                m_gradient_lut,
                                                0, radius);

            render_scanlines_aa(ras, sl, ren, m_alloc, span_gradient);
        }
        else
        {
            typedef linear_gradient_from_segment gradient_adaptor_type;
            typedef agg::span_gradient<agg::rgba8,
                interpolator_type,
                gradient_adaptor_type,
                color_func_type> span_gradient_type;

            // scale everything up since agg turns things into integers a bit too soon
            int scaleup=255;
            x1*=scaleup;
            y1*=scaleup;
            x2*=scaleup;
            y2*=scaleup;

            transform.scale(scaleup,scaleup);

            interpolator_type     span_interpolator(transform);
            gradient_adaptor_type gradient_adaptor(x1,y1,x2,y2);

            span_gradient_type    span_gradient(span_interpolator,
                                                gradient_adaptor,
                                                m_gradient_lut,
                                                0, scaleup);

            render_scanlines_aa(ras, sl, ren, m_alloc, span_gradient);
        }
    }
Beispiel #22
0
 static boost::python::tuple
 getinitargs(const box2d<double>& e)
 {
     using namespace boost::python;
     return boost::python::make_tuple(e.minx(),e.miny(),e.maxx(),e.maxy());
 }
    void render_gradient(Rasterizer& ras,
                         Scanline& sl,
                         Renderer& ren,
                         gradient const& grad,
                         agg::trans_affine const& mtx,
                         double opacity,
                         box2d<double> const& symbol_bbox,
                         curved_trans_type & curved_trans,
                         unsigned path_id)
    {
        using gamma_lut_type = agg::gamma_lut<agg::int8u, agg::int8u>;
        using color_func_type = agg::gradient_lut<agg::color_interpolator<agg::rgba8>, 1024>;
        using interpolator_type = agg::span_interpolator_linear<>;
        using span_allocator_type = agg::span_allocator<agg::rgba8>;

        span_allocator_type             m_alloc;
        color_func_type                 m_gradient_lut;
        gamma_lut_type                  m_gamma_lut;

        double x1,x2,y1,y2,radius;
        grad.get_control_points(x1,y1,x2,y2,radius);

        m_gradient_lut.remove_all();
        for ( mapnik::stop_pair const& st : grad.get_stop_array() )
        {
            mapnik::color const& stop_color = st.second;
            unsigned r = stop_color.red();
            unsigned g = stop_color.green();
            unsigned b = stop_color.blue();
            unsigned a = stop_color.alpha();
            m_gradient_lut.add_color(st.first, agg::rgba8_pre(r, g, b, int(a * opacity)));
        }
        if (m_gradient_lut.build_lut())
        {
            agg::trans_affine transform = mtx;
            transform.invert();
            agg::trans_affine tr;
            tr = grad.get_transform();
            tr.invert();
            transform *= tr;

            if (grad.get_units() != USER_SPACE_ON_USE)
            {
                double bx1=symbol_bbox.minx();
                double by1=symbol_bbox.miny();
                double bx2=symbol_bbox.maxx();
                double by2=symbol_bbox.maxy();

                if (grad.get_units() == OBJECT_BOUNDING_BOX)
                {
                    bounding_rect_single(curved_trans, path_id, &bx1, &by1, &bx2, &by2);
                }

                transform.translate(-bx1,-by1);
                transform.scale(1.0/(bx2-bx1),1.0/(by2-by1));
            }

            if (grad.get_gradient_type() == RADIAL)
            {
                using gradient_adaptor_type = agg::gradient_radial_focus;
                using span_gradient_type = agg::span_gradient<agg::rgba8,
                                                              interpolator_type,
                                                              gradient_adaptor_type,
                                                              color_func_type>;

                // the agg radial gradient assumes it is centred on 0
                transform.translate(-x2,-y2);

                // scale everything up since agg turns things into integers a bit too soon
                int scaleup=255;
                radius *= scaleup;
                x1 *= scaleup;
                y1 *= scaleup;
                x2 *= scaleup;
                y2 *= scaleup;

                transform.scale(scaleup,scaleup);
                interpolator_type     span_interpolator(transform);
                gradient_adaptor_type gradient_adaptor(radius,(x1-x2),(y1-y2));

                span_gradient_type    span_gradient(span_interpolator,
                                                    gradient_adaptor,
                                                    m_gradient_lut,
                                                    0, radius);

                render_scanlines_aa(ras, sl, ren, m_alloc, span_gradient);
            }
            else
            {
                using gradient_adaptor_type = linear_gradient_from_segment;
                using span_gradient_type = agg::span_gradient<agg::rgba8,
                                                              interpolator_type,
                                                              gradient_adaptor_type,
                                                              color_func_type>;
                // scale everything up since agg turns things into integers a bit too soon
                int scaleup=255;
                x1 *= scaleup;
                y1 *= scaleup;
                x2 *= scaleup;
                y2 *= scaleup;

                transform.scale(scaleup,scaleup);

                interpolator_type     span_interpolator(transform);
                gradient_adaptor_type gradient_adaptor(x1,y1,x2,y2);

                span_gradient_type    span_gradient(span_interpolator,
                                                    gradient_adaptor,
                                                    m_gradient_lut,
                                                    0, scaleup);

                render_scanlines_aa(ras, sl, ren, m_alloc, span_gradient);
            }
        }
    }
 inline void forward(double *x, double *y) const
 {
     *x = (*x - extent_.minx()) * sx_ - (offset_x_ - offset_);
     *y = (extent_.maxy() - *y) * sy_ - (offset_y_ - offset_);
 }
 inline void backward(double *x, double *y) const
 {
     *x = extent_.minx() + (*x + (offset_x_ - offset_)) / sx_;
     *y = extent_.maxy() - (*y + (offset_y_ - offset_)) / sy_;
 }