<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_GEOMETRY_HPP
#define MAPNIK_GEOMETRY_HPP

// mapnik
#include <mapnik/vertex_vector.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/geom_util.hpp>

// boost
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

namespace mapnik {

enum eGeomType {
    Point = 1,
    LineString,
    Polygon,
    MultiPoint,
    MultiLineString,
    MultiPolygon
};

template <typename T, template <typename> class Container=vertex_vector>
class geometry
{
public:
    typedef T vertex_type;
    typedef typename vertex_type::type value_type;
    typedef Container<vertex_type> container_type;
private:
    container_type cont_;
    eGeomType type_;
    mutable unsigned itr_;
public:

    geometry(eGeomType type)
        : type_(type),
          itr_(0)
    {}

    eGeomType type() const
    {
        return type_;
    }

    box2d<double> envelope() const
    {
        box2d<double> result;
        double x(0);
        double y(0);
        rewind(0);
        for (unsigned i=0;i<num_points();++i)
        {
            vertex(&x,&y);
            if (i==0)
            {
                result.init(x,y,x,y);
            }
            else
            {
                result.expand_to_include(x,y);
            }
        }
        return result;
    }

    void label_interior_position(double *x, double *y) const
    {
        // start with the default label position
        label_position(x,y);
        unsigned size = cont_.size();
        // if we are not a polygon, or the default is within the polygon we are done
        if (size < 3 || hit_test(*x,*y,0))
            return;

        // otherwise we find a horizontal line across the polygon and then return the
        // center of the widest intersection between the polygon and the line.

        std::vector<double> intersections; // only need to store the X as we know the y

        double x0=0;
        double y0=0;
        rewind(0);
        unsigned command = vertex(&x0, &y0);
        double x1,y1;
        while (SEG_END != (command=vertex(&x1, &y1)))
        {
            if (command != SEG_MOVETO)
            {
                // if the segments overlap
                if (y0==y1)
                {
                    if (y0==*y)
                    {
                        double xi = (x0+x1)/2.0;
                        intersections.push_back(xi);
                    }
                }
                // if the path segment crosses the bisector
                else if ((y0 <= *y && y1 >= *y) ||
                        (y0 >= *y && y1 <= *y))
                {
                    // then calculate the intersection
                    double xi = x0;
                    if (x0 != x1)
                    {
                        double m = (y1-y0)/(x1-x0);
                        double c = y0 - m*x0;
                        xi = (*y-c)/m;
                    }

                    intersections.push_back(xi);
                }
            }
            x0 = x1;
            y0 = y1;
        }
        // no intersections we just return the default
        if (intersections.empty())
            return;
        x0=intersections[0];
        double max_width = 0;
        for (unsigned ii = 1; ii < intersections.size(); ++ii)
        {
            double x1=intersections[ii];
            double xc=(x0+x1)/2.0;
            double width = fabs(x1-x0);
            if (width > max_width && hit_test(xc,*y,0))
            {
                *x=xc;
                max_width = width;
            }
        }
    }

    /* center of gravity centroid
      - best visually but does not work with multipolygons
    */
    void label_position(double *x, double *y) const
    {
        if (type_ == LineString || type_ == MultiLineString)
        {
            middle_point(x,y);
            return;
        }

        unsigned size = cont_.size();
        if (size < 3)
        {
            cont_.get_vertex(0,x,y);
            return;
        }

        double ai;
        double atmp = 0;
        double xtmp = 0;
        double ytmp = 0;
        double x0 =0;
        double y0 =0;
        double x1 =0;
        double y1 =0;
        double ox =0;
        double oy =0;

        unsigned i;

        // Use first point as origin to improve numerical accuracy
        cont_.get_vertex(0,&ox,&oy);

        for (i = 0; i < size-1; i++)
        {
            cont_.get_vertex(i,&x0,&y0);
            cont_.get_vertex(i+1,&x1,&y1);

            x0 -= ox; y0 -= oy;
            x1 -= ox; y1 -= oy;

            ai = x0 * y1 - x1 * y0;
            atmp += ai;
            xtmp += (x1 + x0) * ai;
            ytmp += (y1 + y0) * ai;
        }
        if (atmp != 0)
        {
            *x = (xtmp/(3*atmp)) + ox;
            *y = (ytmp/(3*atmp)) + oy;
            return;
        }
        *x=x0;
        *y=y0;
    }

    /* center of bounding box centroid */
    void label_position2(double *x, double *y) const
    {

        box2d<double> box = envelope();
        *x = box.center().x;
        *y = box.center().y;
    }

    /* summarized distance centroid */
    void label_position3(double *x, double *y) const
    {
        if (type_ == LineString || type_ == MultiLineString)
        {
            middle_point(x,y);
            return;
        }

        unsigned i = 0;
        double l = 0.0;
        double tl = 0.0;
        double cx = 0.0;
        double cy = 0.0;
        double x0 = 0.0;
        double y0 = 0.0;
        double x1 = 0.0;
        double y1 = 0.0;
        unsigned size = cont_.size();
        for (i = 0; i < size-1; i++)
        {
            cont_.get_vertex(i,&x0,&y0);
            cont_.get_vertex(i+1,&x1,&y1);
            l = distance(x0,y0,x1,y1);
            cx += l * (x1 + x0)/2;
            cy += l * (y1 + y0)/2;
            tl += l;
        }
        *x = cx / tl;
        *y = cy / tl;
    }

    void middle_point(double *x, double *y) const
    {
        // calculate mid point on path
        double x0=0;
        double y0=0;
        double x1=0;
        double y1=0;

        unsigned size = cont_.size();
        if (size == 1)
        {
            cont_.get_vertex(0,x,y);
        }
        else if (size == 2)
        {
            cont_.get_vertex(0,&x0,&y0);
            cont_.get_vertex(1,&x1,&y1);
            *x = 0.5 * (x1 + x0);
            *y = 0.5 * (y1 + y0);
        }
        else
        {
            double len=0.0;
            for (unsigned pos = 1; pos < size; ++pos)
            {
                cont_.get_vertex(pos-1,&x0,&y0);
                cont_.get_vertex(pos,&x1,&y1);
                double dx = x1 - x0;
                double dy = y1 - y0;
                len += std::sqrt(dx * dx + dy * dy);
            }
            double midlen = 0.5 * len;
            double dist = 0.0;
            for (unsigned pos = 1; pos < size;++pos)
            {
                cont_.get_vertex(pos-1,&x0,&y0);
                cont_.get_vertex(pos,&x1,&y1);
                double dx = x1 - x0;
                double dy = y1 - y0;
                double seg_len = std::sqrt(dx * dx + dy * dy);
                if (( dist + seg_len) >= midlen)
                {
                    double r = (midlen - dist)/seg_len;
                    *x = x0 + (x1 - x0) * r;
                    *y = y0 + (y1 - y0) * r;
                    break;
                }
                dist += seg_len;
            }
        }
    }

    void push_vertex(value_type x, value_type y, CommandType c)
    {
        cont_.push_back(x,y,c);
    }

    void line_to(value_type x,value_type y)
    {
        push_vertex(x,y,SEG_LINETO);
    }

    void move_to(value_type x,value_type y)
    {
        push_vertex(x,y,SEG_MOVETO);
    }

    unsigned num_points() const
    {
        return cont_.size();
    }

    unsigned vertex(double* x, double* y) const
    {
        return cont_.get_vertex(itr_++,x,y);
    }

    unsigned get_vertex(unsigned pos, double* x, double* y) const
    {
        return cont_.get_vertex(pos, x, y);
    }

    void rewind(unsigned ) const
    {
        itr_=0;
    }

    bool hit_test(value_type x, value_type y, double tol) const
    {
        if (cont_.size() == 1) {
            // Handle points
            double x0, y0;
            cont_.get_vertex(0, &x0, &y0);
            return distance(x, y, x0, y0) <= fabs(tol);
        } else if (cont_.size() > 1) {
            bool inside=false;
            double x0=0;
            double y0=0;
            rewind(0);
            vertex(&x0, &y0);

            unsigned command;
            double x1,y1;
            while (SEG_END != (command=vertex(&x1, &y1)))
            {
                if (command == SEG_MOVETO)
                {
                    x0 = x1;
                    y0 = y1;
                    continue;
                }
                if ((((y1 <= y) && (y < y0)) ||
                     ((y0 <= y) && (y < y1))) &&
                    ( x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1))
                    inside=!inside;
                x0=x1;
                y0=y1;
            }
            return inside;
        }
        return false;
    }

    void set_capacity(size_t size)
    {
        cont_.set_capacity(size);
    }
};

typedef geometry<vertex2d,vertex_vector> geometry_type;
typedef boost::shared_ptr<geometry_type> geometry_ptr;
typedef boost::ptr_vector<geometry_type> geometry_containter;

}

#endif // MAPNIK_GEOMETRY_HPP
<commit_msg>cleanup typedefs, changed template params: vertex_type -> coord_type<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_GEOMETRY_HPP
#define MAPNIK_GEOMETRY_HPP

// mapnik
#include <mapnik/vertex_vector.hpp>
#include <mapnik/geom_util.hpp>

// boost
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

namespace mapnik {

enum eGeomType {
    Point = 1,
    LineString,
    Polygon,
    MultiPoint,
    MultiLineString,
    MultiPolygon
};

template <typename T, template <typename> class Container=vertex_vector>
class geometry
{
public:
    typedef T coord_type;
    typedef Container<coord_type> container_type;
    typedef typename container_type::value_type value_type;

private:
    container_type cont_;
    eGeomType type_;
    mutable unsigned itr_;
public:

    geometry(eGeomType type)
        : type_(type),
          itr_(0)
    {}

    eGeomType type() const
    {
        return type_;
    }

    container_type const& data() const
    {
        return cont_;
    }

    box2d<double> envelope() const
    {
        box2d<double> result;
        double x(0);
        double y(0);
        rewind(0);
        for (unsigned i=0;i<num_points();++i)
        {
            vertex(&x,&y);
            if (i==0)
            {
                result.init(x,y,x,y);
            }
            else
            {
                result.expand_to_include(x,y);
            }
        }
        return result;
    }

    void label_interior_position(double *x, double *y) const
    {
        // start with the default label position
        label_position(x,y);
        unsigned size = cont_.size();
        // if we are not a polygon, or the default is within the polygon we are done
        if (size < 3 || hit_test(*x,*y,0))
            return;

        // otherwise we find a horizontal line across the polygon and then return the
        // center of the widest intersection between the polygon and the line.

        std::vector<double> intersections; // only need to store the X as we know the y

        double x0=0;
        double y0=0;
        rewind(0);
        unsigned command = vertex(&x0, &y0);
        double x1,y1;
        while (SEG_END != (command=vertex(&x1, &y1)))
        {
            if (command != SEG_MOVETO)
            {
                // if the segments overlap
                if (y0==y1)
                {
                    if (y0==*y)
                    {
                        double xi = (x0+x1)/2.0;
                        intersections.push_back(xi);
                    }
                }
                // if the path segment crosses the bisector
                else if ((y0 <= *y && y1 >= *y) ||
                        (y0 >= *y && y1 <= *y))
                {
                    // then calculate the intersection
                    double xi = x0;
                    if (x0 != x1)
                    {
                        double m = (y1-y0)/(x1-x0);
                        double c = y0 - m*x0;
                        xi = (*y-c)/m;
                    }

                    intersections.push_back(xi);
                }
            }
            x0 = x1;
            y0 = y1;
        }
        // no intersections we just return the default
        if (intersections.empty())
            return;
        x0=intersections[0];
        double max_width = 0;
        for (unsigned ii = 1; ii < intersections.size(); ++ii)
        {
            double x1=intersections[ii];
            double xc=(x0+x1)/2.0;
            double width = fabs(x1-x0);
            if (width > max_width && hit_test(xc,*y,0))
            {
                *x=xc;
                max_width = width;
            }
        }
    }

    /* center of gravity centroid
      - best visually but does not work with multipolygons
    */
    void label_position(double *x, double *y) const
    {
        if (type_ == LineString || type_ == MultiLineString)
        {
            middle_point(x,y);
            return;
        }

        unsigned size = cont_.size();
        if (size < 3)
        {
            cont_.get_vertex(0,x,y);
            return;
        }

        double ai;
        double atmp = 0;
        double xtmp = 0;
        double ytmp = 0;
        double x0 =0;
        double y0 =0;
        double x1 =0;
        double y1 =0;
        double ox =0;
        double oy =0;

        unsigned i;

        // Use first point as origin to improve numerical accuracy
        cont_.get_vertex(0,&ox,&oy);

        for (i = 0; i < size-1; i++)
        {
            cont_.get_vertex(i,&x0,&y0);
            cont_.get_vertex(i+1,&x1,&y1);

            x0 -= ox; y0 -= oy;
            x1 -= ox; y1 -= oy;

            ai = x0 * y1 - x1 * y0;
            atmp += ai;
            xtmp += (x1 + x0) * ai;
            ytmp += (y1 + y0) * ai;
        }
        if (atmp != 0)
        {
            *x = (xtmp/(3*atmp)) + ox;
            *y = (ytmp/(3*atmp)) + oy;
            return;
        }
        *x=x0;
        *y=y0;
    }

    /* center of bounding box centroid */
    void label_position2(double *x, double *y) const
    {

        box2d<double> box = envelope();
        *x = box.center().x;
        *y = box.center().y;
    }

    /* summarized distance centroid */
    void label_position3(double *x, double *y) const
    {
        if (type_ == LineString || type_ == MultiLineString)
        {
            middle_point(x,y);
            return;
        }

        unsigned i = 0;
        double l = 0.0;
        double tl = 0.0;
        double cx = 0.0;
        double cy = 0.0;
        double x0 = 0.0;
        double y0 = 0.0;
        double x1 = 0.0;
        double y1 = 0.0;
        unsigned size = cont_.size();
        for (i = 0; i < size-1; i++)
        {
            cont_.get_vertex(i,&x0,&y0);
            cont_.get_vertex(i+1,&x1,&y1);
            l = distance(x0,y0,x1,y1);
            cx += l * (x1 + x0)/2;
            cy += l * (y1 + y0)/2;
            tl += l;
        }
        *x = cx / tl;
        *y = cy / tl;
    }

    void middle_point(double *x, double *y) const
    {
        // calculate mid point on path
        double x0=0;
        double y0=0;
        double x1=0;
        double y1=0;

        unsigned size = cont_.size();
        if (size == 1)
        {
            cont_.get_vertex(0,x,y);
        }
        else if (size == 2)
        {
            cont_.get_vertex(0,&x0,&y0);
            cont_.get_vertex(1,&x1,&y1);
            *x = 0.5 * (x1 + x0);
            *y = 0.5 * (y1 + y0);
        }
        else
        {
            double len=0.0;
            for (unsigned pos = 1; pos < size; ++pos)
            {
                cont_.get_vertex(pos-1,&x0,&y0);
                cont_.get_vertex(pos,&x1,&y1);
                double dx = x1 - x0;
                double dy = y1 - y0;
                len += std::sqrt(dx * dx + dy * dy);
            }
            double midlen = 0.5 * len;
            double dist = 0.0;
            for (unsigned pos = 1; pos < size;++pos)
            {
                cont_.get_vertex(pos-1,&x0,&y0);
                cont_.get_vertex(pos,&x1,&y1);
                double dx = x1 - x0;
                double dy = y1 - y0;
                double seg_len = std::sqrt(dx * dx + dy * dy);
                if (( dist + seg_len) >= midlen)
                {
                    double r = (midlen - dist)/seg_len;
                    *x = x0 + (x1 - x0) * r;
                    *y = y0 + (y1 - y0) * r;
                    break;
                }
                dist += seg_len;
            }
        }
    }

    void push_vertex(coord_type x, coord_type y, CommandType c)
    {
        cont_.push_back(x,y,c);
    }

    void line_to(coord_type x,coord_type y)
    {
        push_vertex(x,y,SEG_LINETO);
    }

    void move_to(coord_type x,coord_type y)
    {
        push_vertex(x,y,SEG_MOVETO);
    }

    unsigned num_points() const
    {
        return cont_.size();
    }

    unsigned vertex(double* x, double* y) const
    {
        return cont_.get_vertex(itr_++,x,y);
    }

    unsigned get_vertex(unsigned pos, double* x, double* y) const
    {
        return cont_.get_vertex(pos, x, y);
    }

    void rewind(unsigned ) const
    {
        itr_=0;
    }

    bool hit_test(coord_type x, coord_type y, double tol) const
    {
        if (cont_.size() == 1) {
            // Handle points
            double x0, y0;
            cont_.get_vertex(0, &x0, &y0);
            return distance(x, y, x0, y0) <= fabs(tol);
        } else if (cont_.size() > 1) {
            bool inside=false;
            double x0=0;
            double y0=0;
            rewind(0);
            vertex(&x0, &y0);

            unsigned command;
            double x1,y1;
            while (SEG_END != (command=vertex(&x1, &y1)))
            {
                if (command == SEG_MOVETO)
                {
                    x0 = x1;
                    y0 = y1;
                    continue;
                }
                if ((((y1 <= y) && (y < y0)) ||
                     ((y0 <= y) && (y < y1))) &&
                    ( x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1))
                    inside=!inside;
                x0=x1;
                y0=y1;
            }
            return inside;
        }
        return false;
    }

    void set_capacity(size_t size)
    {
        cont_.set_capacity(size);
    }
};

typedef geometry<double,vertex_vector> geometry_type;
typedef boost::shared_ptr<geometry_type> geometry_ptr;
typedef boost::ptr_vector<geometry_type> geometry_containter;

}

#endif // MAPNIK_GEOMETRY_HPP
<|endoftext|>


<commit_before>#pragma once
/*
* Covariant Mozart Utility Library: Switcher
*
* This program 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
* any later version.
*
* This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2016 Michael Lee(李登淳)
* Email: China-LDC@outlook.com
* Github: https://github.com/mikecovlee
* Website: http://ldc.atd3.cn
*
* Version: 17.1.0
*/
#include "./base.hpp"
#include "./any.hpp"
#include "./function.hpp"
#include "./tuple.hpp"
#include <deque>

namespace cov {
	class switcher final {
	public:
		typedef cov::function<void()> case_type;
	private:
		std::deque<cov::tuple<cov::any,cov::function<void()>>> mCases;
		cov::function<void()> mDefault;
		const cov::any mCondition;
	public:
		switcher()=delete;
		switcher(const cov::any& val):mCondition(val) {}
		switcher(switcher&&) noexcept=delete;
		switcher(const switcher&)=delete;
		~switcher()=default;
		void add_case(const cov::any& head,const case_type& body)
		{
			if(object::show_warning&&head.type()!=mCondition.type())
				throw cov::warning("W0001");
			bool exsist=false;
			for(auto& it:mCases) {
				if(it.get<0>()==head) {
					exsist=true;
					if(object::show_warning)
						throw cov::warning("W0002");
					else
						it.get<1>()=body;
					break;
				}
			}
			if(!exsist)
				mCases.push_back(tuple<cov::any,cov::function<void()>>(head,body));
		}
		void add_default(const case_type& body)
		{
			if(mDefault.callable()&&object::show_warning)
				throw cov::warning("W0002");
			mDefault=body;
		}
		void perform()
		{
			for(auto& it:mCases) {
				if(it.get<0>()==mCondition&&it.get<1>().callable()) {
					it.get<1>().call();
					return;
				}
			}
			if(mDefault.callable())
				mDefault.call();
		}
	};
	class switcher_stack final {
		std::deque<switcher*> mStack;
	public:
		switcher_stack()=default;
		switcher_stack(switcher_stack&&) noexcept=delete;
		switcher_stack(const switcher_stack&)=delete;
		~switcher_stack()
		{
			for(auto&it:mStack)
				delete it;
		}
		switcher& top()
		{
			return *mStack.front();
		}
		void push(const cov::any& val)
		{
			mStack.push_front(new switcher(val));
		}
		void pop()
		{
			delete mStack.front();
			mStack.pop_front();
		}
	};
	switcher_stack cov_switchers;
}

#define CovSwitch(obj) cov::cov_switchers.push(obj);
#define EndCovSwitch cov::cov_switchers.top().perform();cov::cov_switchers.pop();
#define CovCase(obj) cov::cov_switchers.top().add_case(obj,[&]{
#define CovDefault cov::cov_switchers.top().add_default([&]{
#define EndCovCase });<commit_msg>更新Mozart版本：改善性能<commit_after>#pragma once
/*
* Covariant Mozart Utility Library: Switcher
*
* This program 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
* any later version.
*
* This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2016 Michael Lee(李登淳)
* Email: China-LDC@outlook.com
* Github: https://github.com/mikecovlee
* Website: http://ldc.atd3.cn
*
* Version: 17.4.1
*/
#include "./base.hpp"
#include "./any.hpp"
#include "./function.hpp"
#include "./tuple.hpp"
#include <unordered_map>
#include <forward_list>

namespace cov {
	class switcher final {
	public:
		typedef cov::function<void()> case_type;
	private:
		std::unordered_map<cov::any,cov::function<void()>> mCases;
		cov::function<void()> mDefault;
		const cov::any mCondition;
	public:
		switcher()=delete;
		switcher(const cov::any& val):mCondition(val) {}
		switcher(switcher&&) noexcept=delete;
		switcher(const switcher&)=delete;
		~switcher()=default;
		void add_case(const cov::any& head,const case_type& body)
		{
			if(object::show_warning&&head.type()!=mCondition.type())
				throw cov::warning("W0001");
			if(mCases.count(head)==0)
				mCases.emplace(head,body);
			else if(object::show_warning)
				throw cov::warning("W0002");
		}
		void add_default(const case_type& body)
		{
			if(mDefault.callable()&&object::show_warning)
				throw cov::warning("W0002");
			mDefault=body;
		}
		void perform()
		{
			if(mCases.count(mCondition)>0&&mCases.at(mCondition).callable())
				mCases.at(mCondition)();
			else if(mDefault.callable())
				mDefault.call();
		}
	};
	class switcher_stack final {
		std::forward_list<switcher*> mStack;
	public:
		switcher_stack()=default;
		switcher_stack(switcher_stack&&) noexcept=delete;
		switcher_stack(const switcher_stack&)=delete;
		~switcher_stack()
		{
			for(auto&it:mStack)
				delete it;
		}
		switcher& top()
		{
			return *mStack.front();
		}
		void push(const cov::any& val)
		{
			mStack.push_front(new switcher(val));
		}
		void pop()
		{
			delete mStack.front();
			mStack.pop_front();
		}
	};
	switcher_stack cov_switchers;
}

#define CovSwitch(obj) cov::cov_switchers.push(obj);
#define EndCovSwitch cov::cov_switchers.top().perform();cov::cov_switchers.pop();
#define CovCase(obj) cov::cov_switchers.top().add_case(obj,[&]{
#define CovDefault cov::cov_switchers.top().add_default([&]{
#define EndCovCase });
<|endoftext|>


<commit_before>#include <phypp.hpp>

int phypp_main(int argc, char* argv[]) {
    if (argc < 2) {
        print("usage: make_shifts <ob_filter> [options]");
        return 0;
    }

    vec1u exclude;
    std::string helper;

    read_args(argc-1, argv+1, arg_list(exclude, helper));

    if (helper.empty()) {
        error("please provide the name of (one of) the helper target you used to "
            "calibrate the shifts (helper=...)");
        return 1;
    }

    helper = tolower(helper);

    std::string scis = argv[1];

    vec1d cent_ra, cent_dec;
    ascii::read_table("centroid_helper.txt", 0, cent_ra, cent_dec);

    vec1u ids = uindgen(cent_ra.size())+1;
    vec1u idex = where(is_any_of(ids, exclude));
    inplace_remove(ids, idex);
    inplace_remove(cent_ra, idex);
    inplace_remove(cent_dec, idex);

    std::ofstream cmb("combine.sof");

    vec1d shx, shy;

    vec1d x0, y0;
    bool first_line = true;
    uint_t nexp = 0;

    for (uint_t i : range(ids)) {
        std::string dir = scis+align_right(strn(ids[i]), 2, '0')+"/";
        print(dir);

        vec1s files = dir+file::list_files(dir+"sci_reconstructed*-sci.fits");
        if (files.empty()) {
            files = dir+file::list_files(dir+"SCI_RECONSTRUCTED*-sci.fits");
        }
        inplace_sort(files);

        // Find out which exposures contain the helper target from which the
        // shifts were calibrated
        vec1u ignore;
        for (uint_t k : range(files)) {
            std::string f = files[k];
            fits::generic_file fcubes(f);

            vec1s arms(24);
            bool badfile = false;
            for (uint_t u : range(24)) {
                if (!fcubes.read_keyword("ESO OCS ARM"+strn(u+1)+" NAME", arms[u])) {
                    note("ignoring invalid file '", f, "'");
                    note("missing keyword 'ESO OCS ARM"+strn(u+1)+" NAME'");
                    ignore.push_back(k);
                    badfile = true;
                    break;
                }
            }

            if (badfile) continue;

            arms = tolower(trim(arms));

            vec1u ida = where(arms == helper);
            if (ida.empty()) {
                ignore.push_back(k);
            } else if (x0.empty()) {
                // Get astrometry of IFUs from first exposure
                // NB: assumes the rotation is the same for all exposures,
                // which is anyway what kmos_combine does later on.
                fcubes.reach_hdu(ida[0]+1);
                astro::ad2xy(astro::wcs(fcubes.read_header()), cent_ra, cent_dec, x0, y0);
            }
        }

        inplace_remove(files, ignore);

        if (files.empty()) {
            warning("folder ", dir, " does not contain any usable file");
            continue;
        }

        for (std::string f : files) {
            cmb << f << " COMMAND_LINE\n";
            ++nexp;
        }

        double dox = x0[0] - x0[i], doy = y0[0] - y0[i];

        if (first_line) {
            // Ommit first line which has, by definition, no offset
            first_line = false;
        } else {
            shx.push_back(dox);
            shy.push_back(doy);
        }

        if (file::exists(dir+"helpers/shifts.txt")) {
            vec1d tx, ty;
            ascii::read_table(dir+"helpers/shifts.txt", 0, tx, ty);
            for (uint_t j : range(tx)) {
                shx.push_back(dox+tx[j]);
                shy.push_back(doy+ty[j]);
            }
        }
    }

    note("found ", nexp, " exposures");

    cmb.close();

    auto truncate_decimals = vectorize_lambda([](double v, uint_t nd) {
        return long(v*e10(nd))/e10(nd);
    });

    shx = truncate_decimals(shx, 2);
    shy = truncate_decimals(shy, 2);

    ascii::write_table("shifts.txt", 10, shx, shy);

    return 0;
}
<commit_msg>Added error message<commit_after>#include <phypp.hpp>

int phypp_main(int argc, char* argv[]) {
    if (argc < 2) {
        print("usage: make_shifts <ob_filter> [options]");
        return 0;
    }

    vec1u exclude;
    std::string helper;

    read_args(argc-1, argv+1, arg_list(exclude, helper));

    if (helper.empty()) {
        error("please provide the name of (one of) the helper target you used to "
            "calibrate the shifts (helper=...)");
        return 1;
    }

    helper = tolower(helper);

    std::string scis = argv[1];

    vec1d cent_ra, cent_dec;
    ascii::read_table("centroid_helper.txt", 0, cent_ra, cent_dec);

    vec1u ids = uindgen(cent_ra.size())+1;
    vec1u idex = where(is_any_of(ids, exclude));
    inplace_remove(ids, idex);
    inplace_remove(cent_ra, idex);
    inplace_remove(cent_dec, idex);

    std::ofstream cmb("combine.sof");

    vec1d shx, shy;

    vec1d x0, y0;
    bool first_line = true;
    uint_t nexp = 0;

    for (uint_t i : range(ids)) {
        std::string dir = scis+align_right(strn(ids[i]), 2, '0')+"/";
        print(dir);

        vec1s files = dir+file::list_files(dir+"sci_reconstructed*-sci.fits");
        if (files.empty()) {
            files = dir+file::list_files(dir+"SCI_RECONSTRUCTED*-sci.fits");
        }
        inplace_sort(files);

        // Find out which exposures contain the helper target from which the
        // shifts were calibrated
        vec1u ignore;
        for (uint_t k : range(files)) {
            std::string f = files[k];
            fits::generic_file fcubes(f);

            vec1s arms(24);
            bool badfile = false;
            for (uint_t u : range(24)) {
                if (!fcubes.read_keyword("ESO OCS ARM"+strn(u+1)+" NAME", arms[u])) {
                    note("ignoring invalid file '", f, "'");
                    note("missing keyword 'ESO OCS ARM"+strn(u+1)+" NAME'");
                    ignore.push_back(k);
                    badfile = true;
                    break;
                }
            }

            if (badfile) continue;

            arms = tolower(trim(arms));

            vec1u ida = where(arms == helper);
            if (ida.empty()) {
                ignore.push_back(k);
            } else if (x0.empty()) {
                // Get astrometry of IFUs from first exposure
                // NB: assumes the rotation is the same for all exposures,
                // which is anyway what kmos_combine does later on.
                fcubes.reach_hdu(ida[0]+1);
                astro::ad2xy(astro::wcs(fcubes.read_header()), cent_ra, cent_dec, x0, y0);
            }
        }

        inplace_remove(files, ignore);

        if (files.empty()) {
            warning("folder ", dir, " does not contain any usable file");
            continue;
        }

        for (std::string f : files) {
            cmb << f << " COMMAND_LINE\n";
            ++nexp;
        }

        double dox = x0[0] - x0[i], doy = y0[0] - y0[i];

        if (first_line) {
            // Ommit first line which has, by definition, no offset
            first_line = false;
        } else {
            shx.push_back(dox);
            shy.push_back(doy);
        }

        if (file::exists(dir+"helpers/shifts.txt")) {
            vec1d tx, ty;
            ascii::read_table(dir+"helpers/shifts.txt", 0, tx, ty);
            for (uint_t j : range(tx)) {
                shx.push_back(dox+tx[j]);
                shy.push_back(doy+ty[j]);
            }
        } else {
            warning("could not find dither in ", dir, "helpers/shifts.txt");
        }
    }

    note("found ", nexp, " exposures");

    cmb.close();

    auto truncate_decimals = vectorize_lambda([](double v, uint_t nd) {
        return long(v*e10(nd))/e10(nd);
    });

    shx = truncate_decimals(shx, 2);
    shy = truncate_decimals(shy, 2);

    ascii::write_table("shifts.txt", 10, shx, shy);

    return 0;
}
<|endoftext|>


<commit_before>// Copyright 2015 Bulat Ziganshin
// Released to public domain

#include <amp.h>
#include <iostream>
#include "timer.h"

int main()
{
    static const unsigned DATASIZE = 1<<25;
    static const unsigned BIN      = 1<<4;   // count low 4-bit freqs for every byte
    static const unsigned CHUNK_CNT= 1<<8;   // split data into 256 blocks and calculate histogram for each one separately
    static const unsigned CHUNK    = DATASIZE/CHUNK_CNT;         // 128k
    static const unsigned ITER     = CHUNK/sizeof(unsigned);     //  32k
    static const unsigned STRIDE   = 128;   // how many elements to process by the single thread

    std::vector<unsigned> inbuf(CHUNK_CNT*ITER);
    std::vector<unsigned> outbuf(CHUNK_CNT*BIN);

    concurrency::array_view<unsigned, 2> srcdata(CHUNK_CNT, ITER, inbuf);
    concurrency::array_view<unsigned, 2> histogram(CHUNK_CNT, BIN, outbuf);
    srcdata.discard_data();
    histogram.discard_data();

    concurrency::parallel_for_each (srcdata.extent, [=](concurrency::index<2> idx) restrict(amp)
    {
        srcdata[idx] = (srcdata.extent[1]*idx[0]+idx[1]) * 1234567890;
    });
    srcdata.synchronize();

    Timer t;
    t.Start();

    concurrency::extent<2>  data_extent (srcdata.extent[0], srcdata.extent[1]/STRIDE);
    static const unsigned TILE = 256, TILE1 = 64, TILE0 = TILE/TILE1;  // single tile processes TILE0 blocks and TILE1 independent parts in every block

    const uint64_t DATASET = uint64_t(10)<<30;
    std::cout << "Measuring on " << (DATASET>>30) << " GB dataset";

    for (int i=0; i<DATASET/DATASIZE; i++)
        concurrency::parallel_for_each (data_extent.tile<TILE0,TILE1>(), [=](concurrency::tiled_index<TILE0,TILE1> idx) restrict(amp)
        {
            tile_static unsigned freq[BIN*TILE];
            unsigned loc_idx = idx.local[0]*TILE0+idx.local[1];
            for (int i=0; i<BIN; i++)
                freq[i*TILE+loc_idx] = 0;
            idx.barrier.wait_with_tile_static_memory_fence();

            for (int i=0; i<STRIDE; i++)
            {
                unsigned x = srcdata (idx.global[0], i*(ITER/STRIDE)+idx.global[1]);
                freq[( x      % BIN)*TILE+loc_idx]++;
                freq[((x>> 8) % BIN)*TILE+loc_idx]++;
                freq[((x>>16) % BIN)*TILE+loc_idx]++;
                freq[((x>>24) % BIN)*TILE+loc_idx]++;
            }
            idx.barrier.wait_with_tile_static_memory_fence();

            unsigned sum = 0;
            for (int i=0; i<BIN; i++)
                sum += freq [loc_idx*BIN + i];   // assume TILE1 >= BIN
            concurrency::atomic_fetch_add (&histogram(idx.global[0], (loc_idx*BIN)/TILE),  sum);
        });

    histogram.synchronize();
    t.Stop();
    std::cout << ": " << t.Elapsed() << " milliseconds\n";

    return 0;
}
<commit_msg>Histogram16: further style edits<commit_after>// Copyright 2015 Bulat Ziganshin
// Released to public domain

#include <amp.h>
#include <stdio.h>
#include "timer.h"

int main()
{
    static const unsigned DATASIZE = 1<<25;
    static const unsigned BINS     = 1<<4;   // count low 4-bit freqs for every byte
    static const unsigned CHUNK_CNT= 1<<8;   // split data into 256 blocks and calculate histogram for each one separately
    static const unsigned CHUNK    = DATASIZE/CHUNK_CNT;         // 128k
    static const unsigned ITER     = CHUNK/sizeof(unsigned);     //  32k
    static const unsigned STRIDE   = 128;   // how many elements to process by the single thread

    std::vector<unsigned> inbuf(CHUNK_CNT*ITER);
    std::vector<unsigned> outbuf(CHUNK_CNT*BINS);

    concurrency::array_view<unsigned, 2> srcdata(CHUNK_CNT, ITER, inbuf);
    concurrency::array_view<unsigned, 2> histogram(CHUNK_CNT, BINS, outbuf);
    srcdata.discard_data();
    histogram.discard_data();

    // fill with pseudo-random data
    concurrency::parallel_for_each (srcdata.extent, [=](concurrency::index<2> idx) restrict(amp)
    {
        srcdata[idx] = (srcdata.extent[1]*idx[0]+idx[1]) * 1234567891;
    });
    srcdata.synchronize();

    const uint64_t DATASET = uint64_t(10)<<30;
    printf("Measuring on %d GiB random data", int(DATASET>>30));
    Timer t;  t.Start();

    for (int i=0; i<DATASET/DATASIZE; i++)
    {
        concurrency::extent<2>  data_extent (srcdata.extent[0], srcdata.extent[1]/STRIDE);
        static const unsigned TILE = 256, TILE1 = 64, TILE0 = TILE/TILE1;  // single tile processes TILE0 blocks and TILE1 independent parts in every block

        concurrency::parallel_for_each (data_extent.tile<TILE0,TILE1>(), [=](concurrency::tiled_index<TILE0,TILE1> idx) restrict(amp)
        {
            tile_static unsigned freq[BINS*TILE];
            unsigned loc_idx = idx.local[0]*TILE1+idx.local[1];
            for (int i=0; i<BINS; i++)
                freq[i*TILE+loc_idx] = 0;
            //idx.barrier.wait_with_tile_static_memory_fence();   // may improve performance

            for (int i=0; i<STRIDE; i++)
            {
                #define count(bin)  (freq[(bin)*TILE+loc_idx]++)
                unsigned x = srcdata (idx.global[0], i*(ITER/STRIDE)+idx.global[1]);
                count( x      % BINS);
                count((x>> 8) % BINS);
                count((x>>16) % BINS);
                count((x>>24) % BINS);
                #undef count
            }
            idx.barrier.wait_with_tile_static_memory_fence();

            // We update only sum per thread, that's correct only if TILE1 >= BINS
            unsigned sum = 0;
            for (int i=0; i<BINS; i++)
                sum += freq [loc_idx*BINS + i];
            concurrency::atomic_fetch_add (&histogram(idx.global[0], (loc_idx*BINS)/TILE),  sum);
        });
    }

    histogram.synchronize();
    t.Stop();  auto speed = DATASET/(t.Elapsed()/1000);
    printf(": %.3lf milliseconds = %.3lf GB/s = %.3lf GiB/s\n", t.Elapsed(), speed/1e9, speed/(1<<30));
    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <cassert>
#include <tudocomp/def.hpp>
#include <tudocomp/util/View.hpp>

namespace tdc {

/// \brief Contains a literal and its location in the input.
///
/// This structure is used by encoders to get a glimpse at the literals it will
/// receive. The encoder is given a stream of literals and their occurences in
/// the compressed text. This information can be used to initialize data
/// structures that can be used for efficient encoding, e.g. a Huffman tree
/// or a k-mer dictionary.
struct Literal {
    /// The literal.
    uliteral_t c;

    /// The position of the literal in the input.
    len_t pos;
};

class LiteralIterator {
    /// \brief Tests whether there are more literals in the stream.
    /// \return \e true if there are more literals in the stream, \e false
    ///         otherwise.
    inline bool has_next() const { return false; }

    /// \brief Yields the next literal from the stream.
    /// \return The next literal from the stream.
    inline Literal next() { assert(false); return Literal{0, 0}; }
};

/// \brief An empty literal iterator that yields no literals whatsoever.
class NoLiterals : LiteralIterator {
};

/// \brief A literal iterator that yields every character from a \ref View.
class ViewLiterals : LiteralIterator {
private:
    View m_view;
    len_t m_index;

public:
    /// \brief Constructor.
    ///
    /// \param view The view to iterate over.
    inline ViewLiterals(View view) : m_view(view), m_index(0) {
    }

    /// \brief Tests whether there are more literals in the stream.
    /// \return \e true if there are more literals in the stream, \e false
    ///         otherwise.
    inline bool has_next() const {
        return m_index < m_view.size();
    }

    /// \brief Yields the next literal from the stream.
    /// \return The next literal from the stream.
    inline Literal next() {
        assert(has_next());

        auto i = m_index++;
        return Literal { uliteral_t(m_view[i]), i };
    }
};

}

<commit_msg>Fix LiteralIterator functions not being public<commit_after>#pragma once

#include <cassert>
#include <tudocomp/def.hpp>
#include <tudocomp/util/View.hpp>

namespace tdc {

/// \brief Contains a literal and its location in the input.
///
/// This structure is used by encoders to get a glimpse at the literals it will
/// receive. The encoder is given a stream of literals and their occurences in
/// the compressed text. This information can be used to initialize data
/// structures that can be used for efficient encoding, e.g. a Huffman tree
/// or a k-mer dictionary.
struct Literal {
    /// The literal.
    uliteral_t c;

    /// The position of the literal in the input.
    len_t pos;
};

class LiteralIterator {
public:
    /// \brief Tests whether there are more literals in the stream.
    /// \return \e true if there are more literals in the stream, \e false
    ///         otherwise.
    inline bool has_next() const { return false; }

    /// \brief Yields the next literal from the stream.
    /// \return The next literal from the stream.
    inline Literal next() { assert(false); return Literal{0, 0}; }
};

/// \brief An empty literal iterator that yields no literals whatsoever.
class NoLiterals : LiteralIterator {
};

/// \brief A literal iterator that yields every character from a \ref View.
class ViewLiterals : LiteralIterator {
private:
    View m_view;
    len_t m_index;

public:
    /// \brief Constructor.
    ///
    /// \param view The view to iterate over.
    inline ViewLiterals(View view) : m_view(view), m_index(0) {
    }

    /// \brief Tests whether there are more literals in the stream.
    /// \return \e true if there are more literals in the stream, \e false
    ///         otherwise.
    inline bool has_next() const {
        return m_index < m_view.size();
    }

    /// \brief Yields the next literal from the stream.
    /// \return The next literal from the stream.
    inline Literal next() {
        assert(has_next());

        auto i = m_index++;
        return Literal { uliteral_t(m_view[i]), i };
    }
};

}

<|endoftext|>


<commit_before>#include "feature_covering.hpp"
#include "cell_coverer.hpp"
#include "cell_id.hpp"
#include "feature.hpp"
#include "scales.hpp"

#include "../geometry/covering_utils.hpp"

#include "../base/base.hpp"
#include "../base/stl_add.hpp"

#include "../std/algorithm.hpp"
#include "../std/bind.hpp"
#include "../std/vector.hpp"

namespace
{

// This class should only be used with covering::CoverObject()!
class FeatureIntersector
{
public:
  struct Trg
  {
    m2::PointD m_A, m_B, m_C;
    Trg(m2::PointD const & a, m2::PointD const & b, m2::PointD const & c)
      : m_A(a), m_B(b), m_C(c) {}
  };

  vector<m2::PointD> m_Polyline;
  vector<Trg> m_Trg;

  // Note:
  // 1. Here we don't need to differentiate between CELL_OBJECT_INTERSECT and OBJECT_INSIDE_CELL.
  // 2. We can return CELL_OBJECT_INTERSECT instead of CELL_INSIDE_OBJECT - it's just
  //    a performance penalty.
  covering::CellObjectIntersection operator() (RectId const & cell) const
  {
    for (size_t i = 0; i < m_Trg.size(); ++i)
    {
      covering::CellObjectIntersection const res =
          covering::IntersectCellWithTriangle(cell, m_Trg[i].m_A, m_Trg[i].m_B, m_Trg[i].m_C);
      switch (res)
      {
      case covering::CELL_OBJECT_NO_INTERSECTION:
        break;
      case covering::CELL_INSIDE_OBJECT:
        return covering::CELL_INSIDE_OBJECT;
      case covering::CELL_OBJECT_INTERSECT:
      case covering::OBJECT_INSIDE_CELL:
        return covering::CELL_OBJECT_INTERSECT;
      }
    }
    for (size_t i = 1; i < m_Polyline.size(); ++i)
    {
      covering::CellObjectIntersection const res =
          covering::IntersectCellWithLine(cell, m_Polyline[i], m_Polyline[i-1]);
      switch (res)
      {
      case covering::CELL_OBJECT_NO_INTERSECTION:
        break;
      case covering::CELL_INSIDE_OBJECT:
        ASSERT(false, (cell, i, m_Polyline));
        return covering::CELL_OBJECT_INTERSECT;
      case covering::CELL_OBJECT_INTERSECT:
      case covering::OBJECT_INSIDE_CELL:
        return covering::CELL_OBJECT_INTERSECT;
      }
    }
    return covering::CELL_OBJECT_NO_INTERSECTION;
  }

  typedef CellIdConverter<MercatorBounds, RectId> CellIdConverterType;

  static m2::PointD ConvertPoint(double x, double y)
  {
    return m2::PointD(CellIdConverterType::XToCellIdX(x),
                      CellIdConverterType::YToCellIdY(y));
  }

  void operator() (pair<double, double> const & pt)
  {
    m_Polyline.push_back(ConvertPoint(pt.first, pt.second));
  }

  void operator() (m2::PointD const & a, m2::PointD const & b, m2::PointD const & c)
  {
    m_Trg.push_back(Trg(ConvertPoint(a.x, a.y),
                        ConvertPoint(b.x, b.y),
                        ConvertPoint(c.x, c.y)));
  }
};

}

namespace covering
{

vector<int64_t> CoverFeature(FeatureType const & f, int cellDepth, uint64_t cellPenaltyArea)
{
  FeatureIntersector featureIntersector;
  f.ForEachPointRef(featureIntersector, -1);
  f.ForEachTriangleRef(featureIntersector, -1);

  CHECK(!featureIntersector.m_Trg.empty() || !featureIntersector.m_Polyline.empty(), \
        (f.DebugString(-1)));

  if (featureIntersector.m_Trg.empty() && featureIntersector.m_Polyline.size() == 1)
  {
    m2::PointD pt = featureIntersector.m_Polyline[0];
    return vector<int64_t>(
          1, RectId::FromXY(static_cast<uint32_t>(pt.x), static_cast<uint32_t>(pt.y),
                            RectId::DEPTH_LEVELS - 1).ToInt64(cellDepth));
  }

  vector<RectId> cells;
  covering::CoverObject(featureIntersector, cellPenaltyArea, cells, cellDepth, RectId::Root());

  vector<int64_t> res(cells.size());
  for (size_t i = 0; i < cells.size(); ++i)
    res[i] = cells[i].ToInt64(cellDepth);

  return res;
}

void SortAndMergeIntervals(IntervalsT v, IntervalsT & res)
{
#ifdef DEBUG
  ASSERT ( res.empty(), () );
  for (size_t i = 0; i < v.size(); ++i)
    ASSERT_LESS(v[i].first, v[i].second, (i));
#endif

  sort(v.begin(), v.end());

  res.reserve(v.size());
  for (size_t i = 0; i < v.size(); ++i)
  {
    if (i == 0 || res.back().second < v[i].first)
      res.push_back(v[i]);
    else
      res.back().second = max(res.back().second, v[i].second);
  }
}

IntervalsT SortAndMergeIntervals(IntervalsT const & v)
{
  IntervalsT res;
  SortAndMergeIntervals(v, res);
  return res;
}

void AppendLowerLevels(RectId id, int cellDepth, IntervalsT & intervals)
{
  int64_t idInt64 = id.ToInt64(cellDepth);
  intervals.push_back(make_pair(idInt64, idInt64 + id.SubTreeSize(cellDepth)));
  while (id.Level() > 0)
  {
    id = id.Parent();
    idInt64 = id.ToInt64(cellDepth);
    intervals.push_back(make_pair(idInt64, idInt64 + 1));
  }
}

void CoverViewportAndAppendLowerLevels(m2::RectD const & r, int cellDepth, IntervalsT & res)
{
  vector<RectId> ids;
  CoverRect<MercatorBounds, RectId>(r.minX(), r.minY(), r.maxX(), r.maxY(), 8, cellDepth, ids);

  IntervalsT intervals;
  intervals.reserve(ids.size() * 4);

  for (size_t i = 0; i < ids.size(); ++i)
    AppendLowerLevels(ids[i], cellDepth, intervals);

  SortAndMergeIntervals(intervals, res);
}

RectId GetRectIdAsIs(m2::RectD const & r)
{
  double const eps = MercatorBounds::GetCellID2PointAbsEpsilon();

  return CellIdConverter<MercatorBounds, RectId>::Cover2PointsWithCell(
    MercatorBounds::ClampX(r.minX() + eps),
    MercatorBounds::ClampY(r.minY() + eps),
    MercatorBounds::ClampX(r.maxX() - eps),
    MercatorBounds::ClampY(r.maxY() - eps));
}

int GetCodingDepth(int scale)
{
  int const delta = scales::GetUpperScale() - scale;
  ASSERT_GREATER_OR_EQUAL ( delta, 0, () );

  return (RectId::DEPTH_LEVELS - delta);
}

IntervalsT const & CoveringGetter::Get(int scale)
{
  int const cellDepth = GetCodingDepth(scale);
  int const ind = (cellDepth == RectId::DEPTH_LEVELS ? 0 : 1);

  if (m_res[ind].empty())
  {
    switch (m_mode)
    {
    case 0:
      CoverViewportAndAppendLowerLevels(m_rect, cellDepth, m_res[ind]);
      break;

    case 1:
      AppendLowerLevels(GetRectIdAsIs(m_rect), cellDepth, m_res[ind]);
      break;

    case 2:
      m_res[ind].push_back(IntervalsT::value_type(0, static_cast<int64_t>((1ULL << 63) - 1)));
      break;
    }
  }

  return m_res[ind];
}

}
<commit_msg>Fix rect covering for tiling drawing. Take into account index cell depth.<commit_after>#include "feature_covering.hpp"
#include "cell_coverer.hpp"
#include "cell_id.hpp"
#include "feature.hpp"
#include "scales.hpp"

#include "../geometry/covering_utils.hpp"

#include "../base/base.hpp"
#include "../base/stl_add.hpp"

#include "../std/algorithm.hpp"
#include "../std/bind.hpp"
#include "../std/vector.hpp"

namespace
{

// This class should only be used with covering::CoverObject()!
class FeatureIntersector
{
public:
  struct Trg
  {
    m2::PointD m_A, m_B, m_C;
    Trg(m2::PointD const & a, m2::PointD const & b, m2::PointD const & c)
      : m_A(a), m_B(b), m_C(c) {}
  };

  vector<m2::PointD> m_Polyline;
  vector<Trg> m_Trg;

  // Note:
  // 1. Here we don't need to differentiate between CELL_OBJECT_INTERSECT and OBJECT_INSIDE_CELL.
  // 2. We can return CELL_OBJECT_INTERSECT instead of CELL_INSIDE_OBJECT - it's just
  //    a performance penalty.
  covering::CellObjectIntersection operator() (RectId const & cell) const
  {
    for (size_t i = 0; i < m_Trg.size(); ++i)
    {
      covering::CellObjectIntersection const res =
          covering::IntersectCellWithTriangle(cell, m_Trg[i].m_A, m_Trg[i].m_B, m_Trg[i].m_C);
      switch (res)
      {
      case covering::CELL_OBJECT_NO_INTERSECTION:
        break;
      case covering::CELL_INSIDE_OBJECT:
        return covering::CELL_INSIDE_OBJECT;
      case covering::CELL_OBJECT_INTERSECT:
      case covering::OBJECT_INSIDE_CELL:
        return covering::CELL_OBJECT_INTERSECT;
      }
    }
    for (size_t i = 1; i < m_Polyline.size(); ++i)
    {
      covering::CellObjectIntersection const res =
          covering::IntersectCellWithLine(cell, m_Polyline[i], m_Polyline[i-1]);
      switch (res)
      {
      case covering::CELL_OBJECT_NO_INTERSECTION:
        break;
      case covering::CELL_INSIDE_OBJECT:
        ASSERT(false, (cell, i, m_Polyline));
        return covering::CELL_OBJECT_INTERSECT;
      case covering::CELL_OBJECT_INTERSECT:
      case covering::OBJECT_INSIDE_CELL:
        return covering::CELL_OBJECT_INTERSECT;
      }
    }
    return covering::CELL_OBJECT_NO_INTERSECTION;
  }

  typedef CellIdConverter<MercatorBounds, RectId> CellIdConverterType;

  static m2::PointD ConvertPoint(double x, double y)
  {
    return m2::PointD(CellIdConverterType::XToCellIdX(x),
                      CellIdConverterType::YToCellIdY(y));
  }

  void operator() (pair<double, double> const & pt)
  {
    m_Polyline.push_back(ConvertPoint(pt.first, pt.second));
  }

  void operator() (m2::PointD const & a, m2::PointD const & b, m2::PointD const & c)
  {
    m_Trg.push_back(Trg(ConvertPoint(a.x, a.y),
                        ConvertPoint(b.x, b.y),
                        ConvertPoint(c.x, c.y)));
  }
};

}

namespace covering
{

vector<int64_t> CoverFeature(FeatureType const & f, int cellDepth, uint64_t cellPenaltyArea)
{
  FeatureIntersector featureIntersector;
  f.ForEachPointRef(featureIntersector, -1);
  f.ForEachTriangleRef(featureIntersector, -1);

  CHECK(!featureIntersector.m_Trg.empty() || !featureIntersector.m_Polyline.empty(), \
        (f.DebugString(-1)));

  if (featureIntersector.m_Trg.empty() && featureIntersector.m_Polyline.size() == 1)
  {
    m2::PointD pt = featureIntersector.m_Polyline[0];
    return vector<int64_t>(
          1, RectId::FromXY(static_cast<uint32_t>(pt.x), static_cast<uint32_t>(pt.y),
                            RectId::DEPTH_LEVELS - 1).ToInt64(cellDepth));
  }

  vector<RectId> cells;
  covering::CoverObject(featureIntersector, cellPenaltyArea, cells, cellDepth, RectId::Root());

  vector<int64_t> res(cells.size());
  for (size_t i = 0; i < cells.size(); ++i)
    res[i] = cells[i].ToInt64(cellDepth);

  return res;
}

void SortAndMergeIntervals(IntervalsT v, IntervalsT & res)
{
#ifdef DEBUG
  ASSERT ( res.empty(), () );
  for (size_t i = 0; i < v.size(); ++i)
    ASSERT_LESS(v[i].first, v[i].second, (i));
#endif

  sort(v.begin(), v.end());

  res.reserve(v.size());
  for (size_t i = 0; i < v.size(); ++i)
  {
    if (i == 0 || res.back().second < v[i].first)
      res.push_back(v[i]);
    else
      res.back().second = max(res.back().second, v[i].second);
  }
}

IntervalsT SortAndMergeIntervals(IntervalsT const & v)
{
  IntervalsT res;
  SortAndMergeIntervals(v, res);
  return res;
}

void AppendLowerLevels(RectId id, int cellDepth, IntervalsT & intervals)
{
  int64_t idInt64 = id.ToInt64(cellDepth);
  intervals.push_back(make_pair(idInt64, idInt64 + id.SubTreeSize(cellDepth)));
  while (id.Level() > 0)
  {
    id = id.Parent();
    idInt64 = id.ToInt64(cellDepth);
    intervals.push_back(make_pair(idInt64, idInt64 + 1));
  }
}

void CoverViewportAndAppendLowerLevels(m2::RectD const & r, int cellDepth, IntervalsT & res)
{
  vector<RectId> ids;
  CoverRect<MercatorBounds, RectId>(r.minX(), r.minY(), r.maxX(), r.maxY(), 8, cellDepth, ids);

  IntervalsT intervals;
  intervals.reserve(ids.size() * 4);

  for (size_t i = 0; i < ids.size(); ++i)
    AppendLowerLevels(ids[i], cellDepth, intervals);

  SortAndMergeIntervals(intervals, res);
}

RectId GetRectIdAsIs(m2::RectD const & r)
{
  double const eps = MercatorBounds::GetCellID2PointAbsEpsilon();

  return CellIdConverter<MercatorBounds, RectId>::Cover2PointsWithCell(
    MercatorBounds::ClampX(r.minX() + eps),
    MercatorBounds::ClampY(r.minY() + eps),
    MercatorBounds::ClampX(r.maxX() - eps),
    MercatorBounds::ClampY(r.maxY() - eps));
}

int GetCodingDepth(int scale)
{
  int const delta = scales::GetUpperScale() - scale;
  ASSERT_GREATER_OR_EQUAL ( delta, 0, () );

  return (RectId::DEPTH_LEVELS - delta);
}

IntervalsT const & CoveringGetter::Get(int scale)
{
  int const cellDepth = GetCodingDepth(scale);
  int const ind = (cellDepth == RectId::DEPTH_LEVELS ? 0 : 1);

  if (m_res[ind].empty())
  {
    switch (m_mode)
    {
    case 0:
      CoverViewportAndAppendLowerLevels(m_rect, cellDepth, m_res[ind]);
      break;

    case 1:
    {
      RectId id = GetRectIdAsIs(m_rect);
      while (id.Level() >= cellDepth)
        id = id.Parent();
      AppendLowerLevels(id, cellDepth, m_res[ind]);
      break;
    }

    case 2:
      m_res[ind].push_back(IntervalsT::value_type(0, static_cast<int64_t>((1ULL << 63) - 1)));
      break;
    }
  }

  return m_res[ind];
}

}
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_font.h"

#include "mugen_item.h"
#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"
#include "mugen_util.h"
#include "globals.h"
#include "util/funcs.h"

// If you use this, please delete the item after you use it, this isn't java ok
static MugenItemContent *getOpts( const std::string &opt ){
    std::string contentHolder = "";
    MugenItemContent *temp = new MugenItemContent();
    const char * ignored = " \r\n";
    Global::debug(1) << "Parsing string to ItemContent: " << opt << endl;
    for( unsigned int i = 0; i < opt.size(); ++i ){
	if( opt[i] == ';' )break;
	if( opt[i] == ' ' ){
	    if( !contentHolder.empty() ) *temp << contentHolder;
	    Global::debug(1) << "Got content: " << contentHolder << endl;
	    contentHolder = "";
	}
	//Start grabbing our item
	else if (! strchr(ignored, opt[i])){
		contentHolder += opt[i];
	}
    }
    if( !contentHolder.empty() ){
	*temp << contentHolder;
	Global::debug(1) << "Got content: " << contentHolder << endl;
    }
    return temp;
}

MugenFont::MugenFont( const string & file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( std::string(Util::getDataPath() + "mugen/font/" + file).c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = file;

    load();
}

MugenFont::MugenFont( const char * file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( std::string(Util::getDataPath() + "mugen/font/" + file).c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = string( file );

    load();
}

MugenFont::MugenFont( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;
}

MugenFont::~MugenFont(){
    if(bmp){
	delete bmp;
    }
}

MugenFont & MugenFont::operator=( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;

    return *this;
}

// Implement Font stuff
void MugenFont::setSize( const int x, const int y ){
    // We don't change sizes
    if  ( (x < 0 || y < 0) && type!=Fixed ){
	return;
    }
}
const int MugenFont::getSizeX() const{
    return width;
}
const int MugenFont::getSizeY() const{
    return height;
}

const int MugenFont::textLength( const char * text ) const{
    std::string str(text);
    int size =0;
    for (unsigned int i = 0; i < str.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(str[i]);
	if (loc!=positions.end()){
	   size+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character assume regular width and skip to the next character
	    size+=width + spacingx;
	}
    }
    return size;
}

const int MugenFont::getHeight( const string & str ) const{
    // What? I guess this is for freetype?
    return getHeight();
}

const int MugenFont::getHeight() const{
    return height;
}

void MugenFont::printf( int x, int y, int color, const Bitmap & work, const string & str, int marker, ... ) const{
    // Va list
    char buf[512];
    va_list ap;

    va_start(ap, marker);
    vsnprintf(buf, sizeof(buf), str.c_str(), ap);
    va_end(ap);

    const std::string newstr(buf);

    int workoffsetx = 0;
    for (unsigned int i = 0; i < newstr.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(newstr[i]);
	if (loc!=positions.end()){
	    Bitmap character = Bitmap::temporaryBitmap( loc->second.width + spacingx, height + spacingy);
	    bmp->Blit( loc->second.startx, 0, loc->second.width + spacingx, height + spacingy,0,0, character );
	    character.draw( x + workoffsetx, y, work);
	    workoffsetx+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character draw nothing, assume width, and skip to the next character
	    workoffsetx+=width + spacingx;
	}
    }
}

void MugenFont::load(){

    /* 16 skips the header stuff */
    int location = 16;
    // Lets go ahead and skip the crap -> (Elecbyte signature and version) start at the 16th byte
    ifile.seekg(location,ios::beg);
    unsigned long pcxlocation;
    unsigned long pcxsize;
    unsigned long txtlocation;
    unsigned long txtsize;
    unsigned char *pcx;

    ifile.read( (char *)&pcxlocation, sizeof(unsigned long) );
    ifile.read( (char *)&pcxsize, sizeof(unsigned long) );
    ifile.read( (char *)&txtlocation, sizeof(unsigned long) );
    ifile.read( (char *)&txtsize, sizeof(unsigned long) );
    Global::debug(1) << "PCX Location: " << pcxlocation << " | PCX Size: " << pcxsize << endl;
    Global::debug(1) << "TXT Location: " << txtlocation << " | TXT Actual location: " << pcxlocation + pcxsize << " | TXT Size: " << txtsize << endl;

    // Get the pcx load our bitmap
    ifile.seekg(pcxlocation,ios::beg);
    pcx = new unsigned char[pcxsize];
    ifile.read((char *)pcx, pcxsize);

    bmp = new Bitmap(Bitmap::memoryPCX((unsigned char*) pcx, pcxsize));

    delete [] pcx;

    // Get the text
    ifile.seekg(pcxlocation+pcxsize, ios::beg);
    std::vector<std::string> ourText;
    while( !ifile.eof() ){
	std::string line;
	getline( ifile, line );
	ourText.push_back(line);
    }

    std::vector< MugenSection * > collection = MugenUtil::configReader( ourText );

    for( unsigned int i = 0; i < collection.size(); ++i ){
	const std::string &head = collection[i]->getHeader();
	if( head == "Def" ){
	    while( collection[i]->hasItems() ){
		MugenItemContent *content = collection[i]->getNext();
		const MugenItem *item = content->getNext();
		std::string itemhead = item->query();
		MugenUtil::removeSpaces(itemhead);
		// This is so we don't have any problems with crap like Name, NaMe, naMe or whatever
		MugenUtil::fixCase( itemhead );
		if ( itemhead.find("size")!=std::string::npos ){
		    *content->getNext() >> width;
		    *content->getNext() >> height;
		} else if ( itemhead.find("spacing")!=std::string::npos ){
		    *content->getNext() >> spacingx;
		    *content->getNext() >> spacingy;
		} else if ( itemhead.find("colors")!=std::string::npos ){
		    *content->getNext() >> colors;
		} else if ( itemhead.find("offset")!=std::string::npos ){
		    *content->getNext() >> offsetx;
		    *content->getNext() >> offsety;
		} else if ( itemhead.find("type")!=std::string::npos ){
		    std::string temp;
		    *content->getNext() >> temp;
		    MugenUtil::removeSpaces(temp);
		    MugenUtil::fixCase(temp);
		    if (temp == "variable")type = Variable;
		    else if (temp == "fixed")type = Fixed;
		    Global::debug(1) << "Type: " << temp << endl;
		} //else throw MugenException( "Unhandled option in Info Section: " + itemhead );
	    }
	    Global::debug(1) << "Size X: " << width << ", Size Y: " << height << ", Spacing X: " << spacingx << ", Spacing Y: " << spacingy << ", Colors: " << colors << ", Offset X: " << offsetx << ", Offset Y: " << offsety << endl;
	}
	if( head == "Map" ){
	    bool beginParse = false;
	    int locationx = 0;
	    for (std::vector<std::string>::iterator l = ourText.begin(); l != ourText.end(); ++l){
		std::string line = *l;
		if (!beginParse){
		    if (line.find("[Map]")==std::string::npos){
			continue;
		    } else{
			beginParse = true;
			continue;
		    }
		}
		MugenItemContent *opt = getOpts(line);
		std::string character;
		int startx = locationx * width;
		int chrwidth = width;
		*opt->getNext() >> character;
		if( character != "empty" ) {
		    if (character == "0x5b") character = "[";
		    else if (character == "0x3b") character = ";";
		    if (type != Fixed){
			// get other two
			*opt->getNext() >> startx;
			*opt->getNext() >> chrwidth;
		    }
		    delete opt;
		    FontLocation loc;
		    loc.startx = startx;
		    loc.width = chrwidth;
		    char code = character[0];
		    Global::debug(1) << "Storing Character: " << code << " | startx: " << loc.startx << " | width: " << loc.width << endl;
		    positions[code] = loc;
		}
		++locationx;
	    }
	}
    }

    // Time to get rid of collection
    for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
        if(*i)delete (*i);
    }

    ifile.close();

}

<commit_msg>Corrected deletion of MugenItemContent<commit_after>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_font.h"

#include "mugen_item.h"
#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"
#include "mugen_util.h"
#include "globals.h"
#include "util/funcs.h"

// If you use this, please delete the item after you use it, this isn't java ok
static MugenItemContent *getOpts( const std::string &opt ){
    std::string contentHolder = "";
    MugenItemContent *temp = new MugenItemContent();
    const char * ignored = " \r\n";
    Global::debug(1) << "Parsing string to ItemContent: " << opt << endl;
    for( unsigned int i = 0; i < opt.size(); ++i ){
	if( opt[i] == ';' )break;
	if( opt[i] == ' ' ){
	    if( !contentHolder.empty() ) *temp << contentHolder;
	    Global::debug(1) << "Got content: " << contentHolder << endl;
	    contentHolder = "";
	}
	//Start grabbing our item
	else if (! strchr(ignored, opt[i])){
		contentHolder += opt[i];
	}
    }
    if( !contentHolder.empty() ){
	*temp << contentHolder;
	Global::debug(1) << "Got content: " << contentHolder << endl;
    }
    return temp;
}

MugenFont::MugenFont( const string & file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( std::string(Util::getDataPath() + "mugen/font/" + file).c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = file;

    load();
}

MugenFont::MugenFont( const char * file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( std::string(Util::getDataPath() + "mugen/font/" + file).c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = string( file );

    load();
}

MugenFont::MugenFont( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;
}

MugenFont::~MugenFont(){
    if(bmp){
	delete bmp;
    }
}

MugenFont & MugenFont::operator=( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;

    return *this;
}

// Implement Font stuff
void MugenFont::setSize( const int x, const int y ){
    // We don't change sizes
    if  ( (x < 0 || y < 0) && type!=Fixed ){
	return;
    }
}
const int MugenFont::getSizeX() const{
    return width;
}
const int MugenFont::getSizeY() const{
    return height;
}

const int MugenFont::textLength( const char * text ) const{
    std::string str(text);
    int size =0;
    for (unsigned int i = 0; i < str.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(str[i]);
	if (loc!=positions.end()){
	   size+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character assume regular width and skip to the next character
	    size+=width + spacingx;
	}
    }
    return size;
}

const int MugenFont::getHeight( const string & str ) const{
    // What? I guess this is for freetype?
    return getHeight();
}

const int MugenFont::getHeight() const{
    return height;
}

void MugenFont::printf( int x, int y, int color, const Bitmap & work, const string & str, int marker, ... ) const{
    // Va list
    char buf[512];
    va_list ap;

    va_start(ap, marker);
    vsnprintf(buf, sizeof(buf), str.c_str(), ap);
    va_end(ap);

    const std::string newstr(buf);

    int workoffsetx = 0;
    for (unsigned int i = 0; i < newstr.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(newstr[i]);
	if (loc!=positions.end()){
	    Bitmap character = Bitmap::temporaryBitmap( loc->second.width + spacingx, height + spacingy);
	    bmp->Blit( loc->second.startx, 0, loc->second.width + spacingx, height + spacingy,0,0, character );
	    character.draw( x + workoffsetx, y, work);
	    workoffsetx+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character draw nothing, assume width, and skip to the next character
	    workoffsetx+=width + spacingx;
	}
    }
}

void MugenFont::load(){

    /* 16 skips the header stuff */
    int location = 16;
    // Lets go ahead and skip the crap -> (Elecbyte signature and version) start at the 16th byte
    ifile.seekg(location,ios::beg);
    unsigned long pcxlocation;
    unsigned long pcxsize;
    unsigned long txtlocation;
    unsigned long txtsize;
    unsigned char *pcx;

    ifile.read( (char *)&pcxlocation, sizeof(unsigned long) );
    ifile.read( (char *)&pcxsize, sizeof(unsigned long) );
    ifile.read( (char *)&txtlocation, sizeof(unsigned long) );
    ifile.read( (char *)&txtsize, sizeof(unsigned long) );
    Global::debug(1) << "PCX Location: " << pcxlocation << " | PCX Size: " << pcxsize << endl;
    Global::debug(1) << "TXT Location: " << txtlocation << " | TXT Actual location: " << pcxlocation + pcxsize << " | TXT Size: " << txtsize << endl;

    // Get the pcx load our bitmap
    ifile.seekg(pcxlocation,ios::beg);
    pcx = new unsigned char[pcxsize];
    ifile.read((char *)pcx, pcxsize);

    bmp = new Bitmap(Bitmap::memoryPCX((unsigned char*) pcx, pcxsize));

    delete [] pcx;

    // Get the text
    ifile.seekg(pcxlocation+pcxsize, ios::beg);
    std::vector<std::string> ourText;
    while( !ifile.eof() ){
	std::string line;
	getline( ifile, line );
	ourText.push_back(line);
    }

    std::vector< MugenSection * > collection = MugenUtil::configReader( ourText );

    for( unsigned int i = 0; i < collection.size(); ++i ){
	const std::string &head = collection[i]->getHeader();
	if( head == "Def" ){
	    while( collection[i]->hasItems() ){
		MugenItemContent *content = collection[i]->getNext();
		const MugenItem *item = content->getNext();
		std::string itemhead = item->query();
		MugenUtil::removeSpaces(itemhead);
		// This is so we don't have any problems with crap like Name, NaMe, naMe or whatever
		MugenUtil::fixCase( itemhead );
		if ( itemhead.find("size")!=std::string::npos ){
		    *content->getNext() >> width;
		    *content->getNext() >> height;
		} else if ( itemhead.find("spacing")!=std::string::npos ){
		    *content->getNext() >> spacingx;
		    *content->getNext() >> spacingy;
		} else if ( itemhead.find("colors")!=std::string::npos ){
		    *content->getNext() >> colors;
		} else if ( itemhead.find("offset")!=std::string::npos ){
		    *content->getNext() >> offsetx;
		    *content->getNext() >> offsety;
		} else if ( itemhead.find("type")!=std::string::npos ){
		    std::string temp;
		    *content->getNext() >> temp;
		    MugenUtil::removeSpaces(temp);
		    MugenUtil::fixCase(temp);
		    if (temp == "variable")type = Variable;
		    else if (temp == "fixed")type = Fixed;
		    Global::debug(1) << "Type: " << temp << endl;
		} //else throw MugenException( "Unhandled option in Info Section: " + itemhead );
	    }
	    Global::debug(1) << "Size X: " << width << ", Size Y: " << height << ", Spacing X: " << spacingx << ", Spacing Y: " << spacingy << ", Colors: " << colors << ", Offset X: " << offsetx << ", Offset Y: " << offsety << endl;
	}
	if( head == "Map" ){
	    bool beginParse = false;
	    int locationx = 0;
	    for (std::vector<std::string>::iterator l = ourText.begin(); l != ourText.end(); ++l){
		std::string line = *l;
		if (!beginParse){
		    if (line.find("[Map]")==std::string::npos){
			continue;
		    } else{
			beginParse = true;
			continue;
		    }
		}
		MugenItemContent *opt = getOpts(line);
		std::string character;
		int startx = locationx * width;
		int chrwidth = width;
		*opt->getNext() >> character;
		if( character != "empty" ) {
		    if (character == "0x5b") character = "[";
		    else if (character == "0x3b") character = ";";
		    if (type != Fixed){
			// get other two
			*opt->getNext() >> startx;
			*opt->getNext() >> chrwidth;
		    }
		    FontLocation loc;
		    loc.startx = startx;
		    loc.width = chrwidth;
		    char code = character[0];
		    Global::debug(1) << "Storing Character: " << code << " | startx: " << loc.startx << " | width: " << loc.width << endl;
		    positions[code] = loc;
		}
		delete opt;
		++locationx;
	    }
	}
    }

    // Time to get rid of collection
    for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
        if(*i)delete (*i);
    }

    ifile.close();

}

<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_font.h"

#include "mugen_item.h"
#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"
#include "mugen_util.h"
#include "globals.h"

// If you use this, please delete the item after you use it, this isn't java ok
static MugenItemContent *getOpts( const std::string &opt ){
    std::string contentHolder = "";
    MugenItemContent *temp = new MugenItemContent();
    const char * ignored = " \r\n";
    Global::debug(1) << "Parsing string to ItemContent: " << opt << endl;
    for( unsigned int i = 0; i < opt.size(); ++i ){
	if( opt[i] == ';' )break;
	if( opt[i] == ' ' ){
	    if( !contentHolder.empty() ) *temp << contentHolder;
	    Global::debug(1) << "Got content: " << contentHolder << endl;
	    contentHolder = "";
	}
	//Start grabbing our item
	else if (! strchr(ignored, opt[i])){
		contentHolder += opt[i];
	}
    }
    if( !contentHolder.empty() ){
	*temp << contentHolder;
	Global::debug(1) << "Got content: " << contentHolder << endl;
    }
    return temp;
}

MugenFont::MugenFont( const string & file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( file.c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = file;

    load();
}

MugenFont::MugenFont( const char * file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( file );
    if (!ifile){
        perror("cant open file");
    }
    myfile = string( file );

    load();
}

MugenFont::MugenFont( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;
}

MugenFont::~MugenFont(){
    if(bmp){
	delete bmp;
    }
}

MugenFont & MugenFont::operator=( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;

    return *this;
}

// Implement Font stuff
void MugenFont::setSize( const int x, const int y ){
    // We don't change sizes
    if  ( (x < 0 || y < 0) && type!=Fixed ){
	return;
    }
}
const int MugenFont::getSizeX() const{
    return width;
}
const int MugenFont::getSizeY() const{
    return height;
}

const int MugenFont::textLength( const char * text ) const{
    std::string str(text);
    int size =0;
    for (unsigned int i = 0; i < str.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(str[i]);
	if (loc!=positions.end()){
	   size+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character assume regular width and skip to the next character
	    size+=width + spacingx;
	}
    }
    return size;
}

const int MugenFont::getHeight( const string & str ) const{
    // What? I guess this is for freetype?
    return getHeight();
}

const int MugenFont::getHeight() const{
    return height;
}

void MugenFont::printf( int x, int y, int color, const Bitmap & work, const string & str, int marker, ... ) const{
    // need to get VA List later and append it to str or whatever
    int workoffsetx = 0;
    for (unsigned int i = 0; i < str.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(str[i]);
	if (loc!=positions.end()){
	   /* Bitmap character = Bitmap::temporaryBitmap( loc->second.width, height);
	    bmp->Stretch( character, loc->second.startx + offsetx, offsety, loc->second.width, height, x + workoffsetx, y, width, height );
	    character.draw( x + offsetx, y, work);*/
	    bmp->Blit(loc->second.startx + offsetx, offsety, loc->second.width, height, x + workoffsetx, y, work);
	    workoffsetx+=loc->second.width + spacingx;
	    Global::debug(1) << "Current letter: " << str[i] << " | Printing from: " << loc->second.startx + offsetx << " | width: " << loc->second.width << endl;
	} else{
	    // Couldn't find a position for this character draw nothing, assume width, and skip to the next character
	    workoffsetx+=width + spacingx;
	}
    }

    bmp->draw(0, y + 40, work);
}

void MugenFont::load(){

    /* 16 skips the header stuff */
    int location = 16;
    // Lets go ahead and skip the crap -> (Elecbyte signature and version) start at the 16th byte
    ifile.seekg(location,ios::beg);
    unsigned long pcxlocation;
    unsigned long pcxsize;
    unsigned long txtlocation;
    unsigned long txtsize;
    unsigned char *pcx;

    ifile.read( (char *)&pcxlocation, sizeof(unsigned long) );
    ifile.read( (char *)&pcxsize, sizeof(unsigned long) );
    ifile.read( (char *)&txtlocation, sizeof(unsigned long) );
    ifile.read( (char *)&txtsize, sizeof(unsigned long) );
    Global::debug(1) << "PCX Location: " << pcxlocation << " | PCX Size: " << pcxsize << endl;
    Global::debug(1) << "TXT Location: " << txtlocation << " | TXT Actual location: " << pcxlocation + pcxsize << " | TXT Size: " << txtsize << endl;

    // Get the pcx load our bitmap
    ifile.seekg(pcxlocation,ios::beg);
    pcx = new unsigned char[pcxsize];
    ifile.read((char *)pcx, pcxsize);

    bmp = new Bitmap(Bitmap::memoryPCX((unsigned char*) pcx, pcxsize));

    delete [] pcx;

    // Get the text
    ifile.seekg(pcxlocation+pcxsize, ios::beg);
    std::vector<std::string> ourText;
    while( !ifile.eof() ){
	std::string line;
	getline( ifile, line );
	ourText.push_back(line);
    }

    std::vector< MugenSection * > collection = MugenUtil::configReader( ourText );

    for( unsigned int i = 0; i < collection.size(); ++i ){
	const std::string &head = collection[i]->getHeader();
	if( head == "Def" ){
	    while( collection[i]->hasItems() ){
		MugenItemContent *content = collection[i]->getNext();
		const MugenItem *item = content->getNext();
		std::string itemhead = item->query();
		MugenUtil::removeSpaces(itemhead);
		// This is so we don't have any problems with crap like Name, NaMe, naMe or whatever
		MugenUtil::fixCase( itemhead );
		if ( itemhead.find("size")!=std::string::npos ){
		    *content->getNext() >> width;
		    *content->getNext() >> height;
		} else if ( itemhead.find("spacing")!=std::string::npos ){
		    *content->getNext() >> spacingx;
		    *content->getNext() >> spacingy;
		} else if ( itemhead.find("colors")!=std::string::npos ){
		    *content->getNext() >> colors;
		} else if ( itemhead.find("offset")!=std::string::npos ){
		    *content->getNext() >> offsetx;
		    *content->getNext() >> offsety;
		} else if ( itemhead.find("type")!=std::string::npos ){
		    std::string temp;
		    *content->getNext() >> temp;
		    MugenUtil::removeSpaces(temp);
		    MugenUtil::fixCase(temp);
		    if (temp == "variable")type = Variable;
		    else if (temp == "fixed")type = Fixed;
		} //else throw MugenException( "Unhandled option in Info Section: " + itemhead );
	    }
	}
	if( head == "Map" ){
	    bool beginParse = false;
	    int locationx = 0;
	    for (std::vector<std::string>::iterator l = ourText.begin(); l != ourText.end(); ++l){
		std::string line = *l;
		if (!beginParse){
		    if (line.find("[Map]")==std::string::npos){
			continue;
		    } else{
			beginParse = true;
			continue;
		    }
		}
		MugenItemContent *opt = getOpts(line);
		std::string character;
		int startx = locationx;
		int chrwidth = width;
		*opt->getNext() >> character;
		if( character == "empty" ) continue;
		if (character == "0x5b") character = "[";
		else if (character == "0x3b") character = ";";
		if (type != Fixed){
		    // get other two
		    *opt->getNext() >> locationx;
		    *opt->getNext() >> width;
		}
		delete opt;
		FontLocation loc;
		loc.startx = startx;
		loc.width = chrwidth;
		char code = character[0];
		Global::debug(1) << "Storing Character: " << code << " | startx: " << loc.startx << " | width: " << loc.width << endl;
		positions[code] = loc;
		locationx+=width;
	    }
	}
    }

    // Time to get rid of collection
    for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
        if(*i)delete (*i);
    }

    ifile.close();

}

<commit_msg>Some fonts render properly, others are off<commit_after>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_font.h"

#include "mugen_item.h"
#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"
#include "mugen_util.h"
#include "globals.h"

// If you use this, please delete the item after you use it, this isn't java ok
static MugenItemContent *getOpts( const std::string &opt ){
    std::string contentHolder = "";
    MugenItemContent *temp = new MugenItemContent();
    const char * ignored = " \r\n";
    Global::debug(1) << "Parsing string to ItemContent: " << opt << endl;
    for( unsigned int i = 0; i < opt.size(); ++i ){
	if( opt[i] == ';' )break;
	if( opt[i] == ' ' ){
	    if( !contentHolder.empty() ) *temp << contentHolder;
	    Global::debug(1) << "Got content: " << contentHolder << endl;
	    contentHolder = "";
	}
	//Start grabbing our item
	else if (! strchr(ignored, opt[i])){
		contentHolder += opt[i];
	}
    }
    if( !contentHolder.empty() ){
	*temp << contentHolder;
	Global::debug(1) << "Got content: " << contentHolder << endl;
    }
    return temp;
}

MugenFont::MugenFont( const string & file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( file.c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = file;

    load();
}

MugenFont::MugenFont( const char * file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( file );
    if (!ifile){
        perror("cant open file");
    }
    myfile = string( file );

    load();
}

MugenFont::MugenFont( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;
}

MugenFont::~MugenFont(){
    if(bmp){
	delete bmp;
    }
}

MugenFont & MugenFont::operator=( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;

    return *this;
}

// Implement Font stuff
void MugenFont::setSize( const int x, const int y ){
    // We don't change sizes
    if  ( (x < 0 || y < 0) && type!=Fixed ){
	return;
    }
}
const int MugenFont::getSizeX() const{
    return width;
}
const int MugenFont::getSizeY() const{
    return height;
}

const int MugenFont::textLength( const char * text ) const{
    std::string str(text);
    int size =0;
    for (unsigned int i = 0; i < str.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(str[i]);
	if (loc!=positions.end()){
	   size+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character assume regular width and skip to the next character
	    size+=width + spacingx;
	}
    }
    return size;
}

const int MugenFont::getHeight( const string & str ) const{
    // What? I guess this is for freetype?
    return getHeight();
}

const int MugenFont::getHeight() const{
    return height;
}

void MugenFont::printf( int x, int y, int color, const Bitmap & work, const string & str, int marker, ... ) const{
    // need to get VA List later and append it to str or whatever
    int workoffsetx = 0;
    for (unsigned int i = 0; i < str.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(str[i]);
	if (loc!=positions.end()){
	    Bitmap character = Bitmap::temporaryBitmap( loc->second.width, height);
	    bmp->Blit( loc->second.startx + offsetx, offsety, loc->second.width, height,0,0, character );
	    character.draw( x + workoffsetx, y, work);
	    workoffsetx+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character draw nothing, assume width, and skip to the next character
	    workoffsetx+=width + spacingx;
	}
    }
}

void MugenFont::load(){

    /* 16 skips the header stuff */
    int location = 16;
    // Lets go ahead and skip the crap -> (Elecbyte signature and version) start at the 16th byte
    ifile.seekg(location,ios::beg);
    unsigned long pcxlocation;
    unsigned long pcxsize;
    unsigned long txtlocation;
    unsigned long txtsize;
    unsigned char *pcx;

    ifile.read( (char *)&pcxlocation, sizeof(unsigned long) );
    ifile.read( (char *)&pcxsize, sizeof(unsigned long) );
    ifile.read( (char *)&txtlocation, sizeof(unsigned long) );
    ifile.read( (char *)&txtsize, sizeof(unsigned long) );
    Global::debug(1) << "PCX Location: " << pcxlocation << " | PCX Size: " << pcxsize << endl;
    Global::debug(1) << "TXT Location: " << txtlocation << " | TXT Actual location: " << pcxlocation + pcxsize << " | TXT Size: " << txtsize << endl;

    // Get the pcx load our bitmap
    ifile.seekg(pcxlocation,ios::beg);
    pcx = new unsigned char[pcxsize];
    ifile.read((char *)pcx, pcxsize);

    bmp = new Bitmap(Bitmap::memoryPCX((unsigned char*) pcx, pcxsize));

    delete [] pcx;

    // Get the text
    ifile.seekg(pcxlocation+pcxsize, ios::beg);
    std::vector<std::string> ourText;
    while( !ifile.eof() ){
	std::string line;
	getline( ifile, line );
	ourText.push_back(line);
    }

    std::vector< MugenSection * > collection = MugenUtil::configReader( ourText );

    for( unsigned int i = 0; i < collection.size(); ++i ){
	const std::string &head = collection[i]->getHeader();
	if( head == "Def" ){
	    while( collection[i]->hasItems() ){
		MugenItemContent *content = collection[i]->getNext();
		const MugenItem *item = content->getNext();
		std::string itemhead = item->query();
		MugenUtil::removeSpaces(itemhead);
		// This is so we don't have any problems with crap like Name, NaMe, naMe or whatever
		MugenUtil::fixCase( itemhead );
		if ( itemhead.find("size")!=std::string::npos ){
		    *content->getNext() >> width;
		    *content->getNext() >> height;
		} else if ( itemhead.find("spacing")!=std::string::npos ){
		    *content->getNext() >> spacingx;
		    *content->getNext() >> spacingy;
		} else if ( itemhead.find("colors")!=std::string::npos ){
		    *content->getNext() >> colors;
		} else if ( itemhead.find("offset")!=std::string::npos ){
		    *content->getNext() >> offsetx;
		    *content->getNext() >> offsety;
		} else if ( itemhead.find("type")!=std::string::npos ){
		    std::string temp;
		    *content->getNext() >> temp;
		    MugenUtil::removeSpaces(temp);
		    MugenUtil::fixCase(temp);
		    if (temp == "variable")type = Variable;
		    else if (temp == "fixed")type = Fixed;
		    Global::debug(1) << "Type: " << temp << endl;
		} //else throw MugenException( "Unhandled option in Info Section: " + itemhead );
	    }
	    Global::debug(1) << "Size X: " << width << ", Size Y: " << height << ", Spacing X: " << spacingx << ", Spacing Y: " << spacingy << ", Colors: " << colors << ", Offset X: " << offsetx << ", Offset Y: " << offsety << endl;
	}
	if( head == "Map" ){
	    bool beginParse = false;
	    int locationx = 0;
	    for (std::vector<std::string>::iterator l = ourText.begin(); l != ourText.end(); ++l){
		std::string line = *l;
		if (!beginParse){
		    if (line.find("[Map]")==std::string::npos){
			continue;
		    } else{
			beginParse = true;
			continue;
		    }
		}
		MugenItemContent *opt = getOpts(line);
		std::string character;
		int startx = locationx;
		int chrwidth = width;
		*opt->getNext() >> character;
		if( character == "empty" ) continue;
		if (character == "0x5b") character = "[";
		else if (character == "0x3b") character = ";";
		if (type != Fixed){
		    // get other two
		    *opt->getNext() >> locationx;
		    *opt->getNext() >> width;
		}
		delete opt;
		FontLocation loc;
		loc.startx = startx;
		loc.width = chrwidth;
		char code = character[0];
		Global::debug(1) << "Storing Character: " << code << " | startx: " << loc.startx << " | width: " << loc.width << endl;
		positions[code] = loc;
		locationx+=width;
	    }
	}
    }

    // Time to get rid of collection
    for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
        if(*i)delete (*i);
    }

    ifile.close();

}

<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>

#include <cstdlib>
#include <cassert>

#include "dataset.hh"

using std::cerr;
using std::ofstream;

MSZDataSet::MSZDataSet(double **matrix, size_t nrows, size_t ncols, size_t outputs)
  : matrix(matrix), nrows(nrows), ncols(ncols), outputs(outputs) {}

MSZDataSet::~MSZDataSet() {

  // Please God, do not let this Seg Fault!

  // Clean up matrix by deleting each line.
  for(size_t row = 0; row < nrows; row++)
    free(matrix[row]);

  free(matrix);

}

void MSZDataSet::dumpPlotFiles(const vector<string> &labels, const string &prefix) {

  if(labels.size() != ncols) {
    cerr << "Warning: Trying to dump plot files but labels vector is too small.\n";
    return;
  }

  // Dump the files
  for(size_t out = 0; out < outputs; out++) {
    for(size_t feature = outputs; feature < ncols; feature++) {
      ofstream file;
      file.open((prefix + "_" + labels[out] + "_" + labels[feature] + ".dat").c_str());

      file << "# This file is generated by MatSATZilla\n"
	   << "# It should be used with gnuplot to plot\n"
	   << "# the feature " << labels[feature] << " against\n"
	   << "# the output " << labels[out] << "\n"
	   << "#\n"
	// Outputting timestamp could be nice.
	//<< "# Timestamp: " <<
	   << "#\n"
	   << "# " << labels[feature] << "\t\t" << labels[out] << "\n";

      // For each instance
      for(size_t i = 0; i < nrows; i++)
	file << matrix[i][feature] << "\t\t" << matrix[i][out] << "\n";

      file.close();
    }
  }
}

void MSZDataSet::dumpPlotFiles(char **labels, size_t len, char *prefix) {

  vector<string> vec(len);

  for(size_t i = 0; i < len; i++)
    vec[i] = string(labels[i]);

  dumpPlotFiles(vec, string(prefix));
}

double MSZDataSet::getOutputValue(size_t row, size_t col) const {
  assert(row < nrows);
  assert(col < outputs);

  return matrix[row][col];
}

double MSZDataSet::getFeatureValue(size_t row, size_t col) const {
  assert(row < nrows);
  assert(col < ncols - outputs);

  return matrix[row][col+outputs];
}

/////////////////////////////////////////
/////////////////////////////////////////
//
// API Entrace Function for Data Set creation
//
/////////////////////////////////////////
/////////////////////////////////////////

MSZDataSet *createDataSet(double** matrix, size_t nrows, size_t ncols, size_t outputs) {
  assert(nrows > 0);
  assert(ncols > 0);
  assert(matrix != 0);
  assert(outputs > 0);

#ifndef NDEBUG
  for(size_t r = 0; r < nrows; r++)
    assert(matrix[r] != 0);
#endif // NDEBUG

  // The call!
  MSZDataSet *ds = new MSZDataSet(matrix, nrows, ncols, outputs);
  if(!ds) {
    cerr << "Error: Allocation of Dataset\n";
    exit(EXIT_FAILURE);
  }

  return ds;
}
<commit_msg>Assertion that the number of rows is greater or equal to the number of features.<commit_after>#include <iostream>
#include <fstream>

#include <cstdlib>
#include <cassert>

#include "dataset.hh"

using std::cerr;
using std::ofstream;

MSZDataSet::MSZDataSet(double **matrix, size_t nrows, size_t ncols, size_t outputs)
  : matrix(matrix), nrows(nrows), ncols(ncols), outputs(outputs) {}

MSZDataSet::~MSZDataSet() {

  // Please God, do not let this Seg Fault!

  // Clean up matrix by deleting each line.
  for(size_t row = 0; row < nrows; row++)
    free(matrix[row]);

  free(matrix);

}

void MSZDataSet::dumpPlotFiles(const vector<string> &labels, const string &prefix) {

  if(labels.size() != ncols) {
    cerr << "Warning: Trying to dump plot files but labels vector is too small.\n";
    return;
  }

  // Dump the files
  for(size_t out = 0; out < outputs; out++) {
    for(size_t feature = outputs; feature < ncols; feature++) {
      ofstream file;
      file.open((prefix + "_" + labels[out] + "_" + labels[feature] + ".dat").c_str());

      file << "# This file is generated by MatSATZilla\n"
	   << "# It should be used with gnuplot to plot\n"
	   << "# the feature " << labels[feature] << " against\n"
	   << "# the output " << labels[out] << "\n"
	   << "#\n"
	// Outputting timestamp could be nice.
	//<< "# Timestamp: " <<
	   << "#\n"
	   << "# " << labels[feature] << "\t\t" << labels[out] << "\n";

      // For each instance
      for(size_t i = 0; i < nrows; i++)
	file << matrix[i][feature] << "\t\t" << matrix[i][out] << "\n";

      file.close();
    }
  }
}

void MSZDataSet::dumpPlotFiles(char **labels, size_t len, char *prefix) {

  vector<string> vec(len);

  for(size_t i = 0; i < len; i++)
    vec[i] = string(labels[i]);

  dumpPlotFiles(vec, string(prefix));
}

double MSZDataSet::getOutputValue(size_t row, size_t col) const {
  assert(row < nrows);
  assert(col < outputs);

  return matrix[row][col];
}

double MSZDataSet::getFeatureValue(size_t row, size_t col) const {
  assert(row < nrows);
  assert(col < ncols - outputs);

  return matrix[row][col+outputs];
}

/////////////////////////////////////////
/////////////////////////////////////////
//
// API Entrace Function for Data Set creation
//
/////////////////////////////////////////
/////////////////////////////////////////

MSZDataSet *createDataSet(double** matrix, size_t nrows, size_t ncols, size_t outputs) {
  assert(nrows > 0);
  assert(ncols > 0);
  assert(matrix != 0);
  assert(outputs > 0);
  assert(nrows >= ncols - outputs);

#ifndef NDEBUG
  for(size_t r = 0; r < nrows; r++)
    assert(matrix[r] != 0);
#endif // NDEBUG

  // The call!
  MSZDataSet *ds = new MSZDataSet(matrix, nrows, ncols, outputs);
  if(!ds) {
    cerr << "Error: Allocation of Dataset\n";
    exit(EXIT_FAILURE);
  }

  return ds;
}
<|endoftext|>