<commit_before>// Petter Strandmark 2013
// petter.strandmark@gmail.com

#include <iostream>
#include <stdexcept>
#include <vector>
using std::vector;
using std::size_t;

#include <easy-ip.h>

class MyIP :
	public IP
{
public:
	void add_connected_constraint(const vector<vector<BooleanVariable>>& grid)
	{
		auto m = grid.size();
		if (m == 0) return;
		auto n = grid[0].size();

		// Pad grid with zeroes to be able to add constraints everywhere.
		vector<vector<BooleanVariable>> padded_grid;
		for (int i = 0; i < m + 2; ++i) {
			padded_grid.push_back(vector<BooleanVariable>());
			for (int j = 0; j < n + 2; ++j) {
				if (i == 0 || i == m + 1 || j == 0 || j == n + 1) {
					auto zero_var = add_boolean();
					set_bounds(0, zero_var, 0);
					padded_grid.back().push_back(zero_var);
				}
				else {
					padded_grid.back().push_back(grid[i-1][j-1]);
				}
			}
		}

		Sum turn_sum;

		auto add_triple_constraints =
			[&]
			(const BooleanVariable& x1, const BooleanVariable& x2, const BooleanVariable& y)
			{
				auto v1 = add_boolean();
				// v1  <=>  y && !x1 && !x2.
				// <=
				add_constraint( y + (1-x1) + (1-x2) <= 2 + v1 );
				// =>
				add_constraint( implication(v1, !x1) );
				add_constraint( implication(v1, !x2) );
				add_constraint( implication(v1, y) );
				turn_sum += v1;

				auto v2 = add_boolean();
				// v2  <=>  !y && x1 && x2.
				// <=
				add_constraint( (1-y) + x1 + x2 <= 2 + v2 );
				// =>
				add_constraint( implication(v2, x1) );
				add_constraint( implication(v2, x2) );
				add_constraint( implication(v2, !y) );
				turn_sum -= v2;
			};

		for (int i = 0; i < m + 1; ++i) {
			for (int j = 0; j < n + 1; ++j) {

				//  X
				//  YX
				{
					auto& x1 = padded_grid[i][j];
					auto& x2 = padded_grid[i+1][j+1];
					auto& y  = padded_grid[i][j+1];
					add_triple_constraints(x1, x2, y);
				}

				// XY
				//  X
				{
					auto& x1 = padded_grid[i][j];
					auto& x2 = padded_grid[i+1][j+1];
					auto& y  = padded_grid[i+1][j];
					add_triple_constraints(x1, x2, y);
				}

				// YX
				// X
				{
					auto& x1 = padded_grid[i+1][j];
					auto& x2 = padded_grid[i][j+1];
					auto& y  = padded_grid[i][j];
					add_triple_constraints(x1, x2, y);
				}

				//  X
				// XY
				{
					auto& x1 = padded_grid[i+1][j];
					auto& x2 = padded_grid[i][j+1];
					auto& y  = padded_grid[i+1][j+1];
					add_triple_constraints(x1, x2, y);
				}
			}
		}

		add_constraint(4, turn_sum, 4);

		// Forbid the two configurations
		//
 		//  01     10
		//  10 and 01
		//
		// This is not completely correct, but the code
		// above can not handle them.
		for (int i = 0; i < m + 1; ++i) {
			for (int j = 0; j < n + 1; ++j) {
				add_constraint(padded_grid[i][i] + (1 - padded_grid[i+1][j]) +
				               (1 - padded_grid[i][j+1]) + padded_grid[i+1][j+1] <= 3);
				add_constraint((1 - padded_grid[i][i]) + padded_grid[i+1][j] +
				               padded_grid[i][j+1] + (1 - padded_grid[i+1][j+1]) <= 3);
			}
		}
	}
};

int main_program()
{
	using namespace std;

	int n = 6;

	MyIP ip;

	// Parking spots. We want to maximize the number of these.
	auto P = ip.add_boolean_grid(n, n, -1.0);
	// Transporation to parking spots.
	auto T = ip.add_boolean_grid(n, n);

	// Entrance to the parking lot.
	ip.add_constraint( T[0][1] );

	// T[0][0] == 1
	//. P P P P P
	//. . . . . .
	//. P P P P P
	//. P P P P P
	//. . . . . .
	//P P P P P P
	// 21

	// T[0][1] == 1
	//P . P P P P
	//P . . . . .
	//P . P P P P
	//P . P P P P
	//P . . . . .
	//  P P P P P
	// 22

	// T[0][2] == 1
	//P . . . . P
	//P . P P . P
	//P . P P . P
	//P . P P . P
	//P . P P . P
	//P . P P . P
	// 22

	// We can not have both parking and transportation.
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			ip.add_constraint(P[i][j] + T[i][j] <= 1);
		}
	}

	// Every parking lot needs to be adjacent to a transport square.
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			Sum neighborhood;
			if (i > 0) {
				neighborhood += T[i-1][j];
			}
			if (i < n - 1) {
				neighborhood += T[i+1][j];
			}
			if (j > 0) {
				neighborhood += T[i][j-1];
			}
			if (j < n - 1) {
				neighborhood += T[i][j+1];
			}

			ip.add_constraint( P[i][j] <= neighborhood );
			ip.add_constraint( T[i][j] <= neighborhood + P[i][j] );
		}
	}

	// The hardest part: the transport squares need to be
	// connected to each other.
	ip.add_connected_constraint(T);

	auto print_solution = [&] ()
	{
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < n; ++j) {
				auto p = ip.get_solution(P[i][j]);
				auto t = ip.get_solution(T[i][j]);
				if (p && t) {
					// Infeasible.
					cout << '#';
				}
				else if (!p && !t) {
					cout << ' ';
				}
				else if (p) {
					cout << 'P';
				}
				else {
					cout << '.';
				}
				cout << ' ';
			}
			cout << endl;
		}
		cout << endl;
	};

	//ip.set_external_solver(IP::MOSEK);
	attest(ip.solve());

	do {
		print_solution();
	} while (false /*ip.next_solution()*/);

	return 0;
}

int main()
{
	try {
		return main_program();
	}
	catch (std::exception& err) {
		std::cerr << "ERROR: " << err.what() << std::endl;
	}
}
<commit_msg>New connectivity constraint.<commit_after>// Petter Strandmark 2013
// petter.strandmark@gmail.com

#include <iostream>
#include <stdexcept>
#include <vector>
using std::vector;
using std::size_t;

#include <easy-ip.h>

//
// This class adds connectivity constraints to the IP class.
// It does so in two different ways, but they both result in
// problems that are quite difficult to solve.
//
class MyIP :
	public IP
{
public:

	// The first way is based on following the perimeter around the
	// area and counting left and right turns.
	void add_connected_constraint_perimeter(const vector<vector<BooleanVariable>>& grid)
	{
		auto m = grid.size();
		if (m == 0) return;
		auto n = grid[0].size();

		// Pad grid with zeroes to be able to add constraints everywhere.
		vector<vector<BooleanVariable>> padded_grid;
		for (int i = 0; i < m + 2; ++i) {
			padded_grid.push_back(vector<BooleanVariable>());
			for (int j = 0; j < n + 2; ++j) {
				if (i == 0 || i == m + 1 || j == 0 || j == n + 1) {
					auto zero_var = add_boolean();
					set_bounds(0, zero_var, 0);
					padded_grid.back().push_back(zero_var);
				}
				else {
					padded_grid.back().push_back(grid[i-1][j-1]);
				}
			}
		}

		Sum turn_sum;

		auto add_triple_constraints =
			[&]
			(const BooleanVariable& x1, const BooleanVariable& x2, const BooleanVariable& y)
			{
				auto v1 = add_boolean();
				// v1  <=>  y && !x1 && !x2.
				// <=
				add_constraint( y + (1-x1) + (1-x2) <= 2 + v1 );
				// =>
				add_constraint( implication(v1, !x1) );
				add_constraint( implication(v1, !x2) );
				add_constraint( implication(v1, y) );
				turn_sum += v1;

				auto v2 = add_boolean();
				// v2  <=>  !y && x1 && x2.
				// <=
				add_constraint( (1-y) + x1 + x2 <= 2 + v2 );
				// =>
				add_constraint( implication(v2, x1) );
				add_constraint( implication(v2, x2) );
				add_constraint( implication(v2, !y) );
				turn_sum -= v2;
			};

		for (size_t i = 0; i < m + 1; ++i) {
			for (size_t j = 0; j < n + 1; ++j) {

				//  X
				//  YX
				{
					auto& x1 = padded_grid[i][j];
					auto& x2 = padded_grid[i+1][j+1];
					auto& y  = padded_grid[i][j+1];
					add_triple_constraints(x1, x2, y);
				}

				// XY
				//  X
				{
					auto& x1 = padded_grid[i][j];
					auto& x2 = padded_grid[i+1][j+1];
					auto& y  = padded_grid[i+1][j];
					add_triple_constraints(x1, x2, y);
				}

				// YX
				// X
				{
					auto& x1 = padded_grid[i+1][j];
					auto& x2 = padded_grid[i][j+1];
					auto& y  = padded_grid[i][j];
					add_triple_constraints(x1, x2, y);
				}

				//  X
				// XY
				{
					auto& x1 = padded_grid[i+1][j];
					auto& x2 = padded_grid[i][j+1];
					auto& y  = padded_grid[i+1][j+1];
					add_triple_constraints(x1, x2, y);
				}
			}
		}

		add_constraint(4, turn_sum, 4);

		// Forbid the two configurations
		//
		//  01     10
		//  10 and 01
		//
		// This is not completely correct, but the code
		// above can not handle them.
		for (int i = 0; i < m + 1; ++i) {
			for (int j = 0; j < n + 1; ++j) {
				add_constraint(padded_grid[i][i] + (1 - padded_grid[i+1][j]) +
				               (1 - padded_grid[i][j+1]) + padded_grid[i+1][j+1] <= 3);
				add_constraint((1 - padded_grid[i][i]) + padded_grid[i+1][j] +
				               padded_grid[i][j+1] + (1 - padded_grid[i+1][j+1]) <= 3);
			}
		}
	}

	// The second way is based on adding flow to one square and
	// requiring it to dissipate through the grid.
	void add_connected_constraint_flow(const vector<vector<BooleanVariable>>& grid,
	                                   int start_i, int start_j)
	{
		auto m = grid.size();
		if (m == 0) return;
		auto n = grid[0].size();

		auto num_elements = double(m * n);

		vector<vector<Sum>> node_balance(m, vector<Sum>(n, 0.0));
		Sum number_of_active_nodes = 0;

		for (size_t i = 0; i < m; ++i) {
			for (size_t j = 0; j < n; ++j) {

				number_of_active_nodes += grid[i][j];

				if (i < m - 1) {
					auto fij = add_variable(Real);
					node_balance[i][j]   += fij;
					node_balance[i+1][j] -= fij;

					add_constraint( fij >= 0 );
					add_constraint( fij <= num_elements*grid[i][j] );
					add_constraint( fij <= num_elements*grid[i+1][j] );
				}

				if (i > 0) {
					auto fij = add_variable(Real);
					node_balance[i][j]   += fij;
					node_balance[i-1][j] -= fij;

					add_constraint( fij >= 0 );
					add_constraint( fij <= num_elements*grid[i][j] );
					add_constraint( fij <= num_elements*grid[i-1][j] );
				}

				if (j < n - 1) {
					auto fij = add_variable(Real);
					node_balance[i][j]   += fij;
					node_balance[i][j+1] -= fij;

					add_constraint( fij >= 0 );
					add_constraint( fij <= num_elements*grid[i][j] );
					add_constraint( fij <= num_elements*grid[i][j+1] );
				}

				if (j > 0) {
					auto fij = add_variable(Real);
					node_balance[i][j]   += fij;
					node_balance[i][j-1] -= fij;

					add_constraint( fij >= 0 );
					add_constraint( fij <= num_elements*grid[i][j] );
					add_constraint( fij <= num_elements*grid[i][j-1] );
				}
			}
		}

		auto total_flow = add_variable(Real);
		set_bounds(0, total_flow, num_elements);
		add_constraint(total_flow == number_of_active_nodes);

		node_balance[start_i][start_j] += total_flow;

		for (int i = 0; i < m; ++i) {
			for (int j = 0; j < n; ++j) {
				auto f_it = add_variable(Real);
				set_bounds(0, f_it, 1);
				node_balance[i][j] -= f_it;

				add_constraint(node_balance[i][j] == 0);
			}
		}
	}

};

int main_program()
{
	using namespace std;

	int n = 6;

	MyIP ip;

	// Parking spots. We want to maximize the number of these.
	auto P = ip.add_boolean_grid(n, n, -1.0);
	// Transporation to parking spots.
	auto T = ip.add_boolean_grid(n, n);

	int starti = 0;
	int startj = 1;

	// Entrance to the parking lot.
	ip.add_constraint( T[starti][startj] );

	// T[0][0] == 1
	//. P P P P P
	//. . . . . .
	//. P P P P P
	//. P P P P P
	//. . . . . .
	//P P P P P P
	// 21

	// T[0][1] == 1
	//P . P P P P
	//P . . . . .
	//P . P P P P
	//P . P P P P
	//P . . . . .
	//  P P P P P
	// 22

	// T[0][2] == 1
	//P . . . . P
	//P . P P . P
	//P . P P . P
	//P . P P . P
	//P . P P . P
	//P . P P . P
	// 22

	// T[0][1] == 1
	// P . P P P P P P . P
	// P . P . . . . . . P
	// P . P P P P P P . P
	// P . P   P P P P . P
	// P . P P . . . . . P
	// P . P P . P . P . P
	// P . P P . P P P . P
	// P . P P . P P P P P
	// . . . . . . . . . .
	// P P P P P P P P P P
	// 61

	// Border
	/*
	Sum above_border = 0;
	for (int i = 0; i < n; ++i) {
		above_border += T[0][i];
	}
	// There has to be an entrance.
	ip.add_constraint(above_border >= 1);
	*/

	// We can not have both parking and transportation.
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			// Not allowing both to be zero seems to give a slightly
			// stronger formulation.
			ip.add_constraint(P[i][j] + T[i][j] == 1);
		}
	}

	// Every parking lot needs to be adjacent to a transport square.
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			Sum neighborhood;
			if (i > 0) {
				neighborhood += T[i-1][j];
			}
			if (i < n - 1) {
				neighborhood += T[i+1][j];
			}
			if (j > 0) {
				neighborhood += T[i][j-1];
			}
			if (j < n - 1) {
				neighborhood += T[i][j+1];
			}

			ip.add_constraint( P[i][j] <= neighborhood );
			ip.add_constraint( T[i][j] <= neighborhood + P[i][j] );
		}
	}

	// The hardest part: the transport squares need to be
	// connected to each other.
	ip.add_connected_constraint_perimeter(T);
	//ip.add_connected_constraint_flow(T, starti, startj);

	auto print_solution = [&] ()
	{
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < n; ++j) {
				auto p = ip.get_solution(P[i][j]);
				auto t = ip.get_solution(T[i][j]);
				if (p && t) {
					// Infeasible.
					cout << '#';
				}
				else if (!p && !t) {
					cout << ' ';
				}
				else if (p) {
					cout << 'P';
				}
				else {
					cout << '.';
				}
				cout << ' ';
			}
			cout << endl;
		}
		cout << endl;
	};

	//ip.set_external_solver(IP::MOSEK);
	attest(ip.solve(print_solution));

	do {
		print_solution();
	} while (false /*ip.next_solution()*/);

	return 0;
}

int main()
{
	try {
		return main_program();
	}
	catch (std::exception& err) {
		std::cerr << "ERROR: " << err.what() << std::endl;
	}
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, 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 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include <Eigen/StdVector>
#include "main.h"
#include <Eigen/Geometry>

template<typename MatrixType>
void check_stdvector_matrix(const MatrixType& m)
{
  int rows = m.rows();
  int cols = m.cols();
  MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
  std::vector<MatrixType> v(10, MatrixType(rows,cols)), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  MatrixType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i]==w[(i-23)%w.size()]);
  }
}

template<typename TransformType>
void check_stdvector_transform(const TransformType&)
{
  typedef typename TransformType::MatrixType MatrixType;
  TransformType x(MatrixType::Random()), y(MatrixType::Random());
  std::vector<TransformType> v(10), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  TransformType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
  }
}

template<typename QuaternionType>
void check_stdvector_quaternion(const QuaternionType&)
{
  typedef typename QuaternionType::Coefficients Coefficients;
  QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
  std::vector<QuaternionType> v(10), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  QuaternionType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
  }
}

void test_stdvector()
{
  // some non vectorizable fixed sizes
  CALL_SUBTEST(check_stdvector_matrix(Vector2f()));
  CALL_SUBTEST(check_stdvector_matrix(Matrix3f()));
  CALL_SUBTEST(check_stdvector_matrix(Matrix3d()));

  // some vectorizable fixed sizes
  CALL_SUBTEST(check_stdvector_matrix(Matrix2f()));
  CALL_SUBTEST(check_stdvector_matrix(Vector4f()));
  CALL_SUBTEST(check_stdvector_matrix(Matrix4f()));
  CALL_SUBTEST(check_stdvector_matrix(Matrix4d()));

  // some dynamic sizes
  CALL_SUBTEST(check_stdvector_matrix(MatrixXd(1,1)));
  CALL_SUBTEST(check_stdvector_matrix(VectorXd(20)));
  CALL_SUBTEST(check_stdvector_matrix(RowVectorXf(20)));
  CALL_SUBTEST(check_stdvector_matrix(MatrixXcf(10,10)));

  // some Transform
  CALL_SUBTEST(check_stdvector_transform(Transform2f()));
  CALL_SUBTEST(check_stdvector_transform(Transform3f()));
  CALL_SUBTEST(check_stdvector_transform(Transform3d()));
  //CALL_SUBTEST(check_stdvector_transform(Transform4d()));

  // some Quaternion
  CALL_SUBTEST(check_stdvector_quaternion(Quaternionf()));
  CALL_SUBTEST(check_stdvector_quaternion(Quaternionf()));
}
<commit_msg>"forgot to commit the required changes in stdvector unit test"<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, 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 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include <Eigen/StdVector>
#include "main.h"
#include <Eigen/Geometry>

template<typename MatrixType>
void check_stdvector_matrix(const MatrixType& m)
{
  int rows = m.rows();
  int cols = m.cols();
  MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
  std::vector<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  MatrixType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i]==w[(i-23)%w.size()]);
  }
}

template<typename TransformType>
void check_stdvector_transform(const TransformType&)
{
  typedef typename TransformType::MatrixType MatrixType;
  TransformType x(MatrixType::Random()), y(MatrixType::Random());
  std::vector<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  TransformType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
  }
}

template<typename QuaternionType>
void check_stdvector_quaternion(const QuaternionType&)
{
  typedef typename QuaternionType::Coefficients Coefficients;
  QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
  std::vector<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  QuaternionType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
  }
}

void test_stdvector()
{
  // some non vectorizable fixed sizes
  CALL_SUBTEST(check_stdvector_matrix(Vector2f()));
  CALL_SUBTEST(check_stdvector_matrix(Matrix3f()));
  CALL_SUBTEST(check_stdvector_matrix(Matrix3d()));

  // some vectorizable fixed sizes
  CALL_SUBTEST(check_stdvector_matrix(Matrix2f()));
  CALL_SUBTEST(check_stdvector_matrix(Vector4f()));
  CALL_SUBTEST(check_stdvector_matrix(Matrix4f()));
  CALL_SUBTEST(check_stdvector_matrix(Matrix4d()));

  // some dynamic sizes
  CALL_SUBTEST(check_stdvector_matrix(MatrixXd(1,1)));
  CALL_SUBTEST(check_stdvector_matrix(VectorXd(20)));
  CALL_SUBTEST(check_stdvector_matrix(RowVectorXf(20)));
  CALL_SUBTEST(check_stdvector_matrix(MatrixXcf(10,10)));

  // some Transform
  CALL_SUBTEST(check_stdvector_transform(Transform2f()));
  CALL_SUBTEST(check_stdvector_transform(Transform3f()));
  CALL_SUBTEST(check_stdvector_transform(Transform3d()));
  //CALL_SUBTEST(check_stdvector_transform(Transform4d()));

  // some Quaternion
  CALL_SUBTEST(check_stdvector_quaternion(Quaternionf()));
  CALL_SUBTEST(check_stdvector_quaternion(Quaternionf()));
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016, oasi-adamay
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of glsCV nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdafx.h"

/*-----------------------------------------------------------------------------
include
*/
#include "glsMacro.h"
#include "GlsMat.h"
#include "glsShader.h"

#include "glsResize.h"

namespace gls
{

//-----------------------------------------------------------------------------
// glsShaderResize
class glsShaderResizeBase : public glsShaderBase
{
protected:
	list<string> UniformNameList(void){
		list<string> lst;
		lst.push_back("texSrc");
		lst.push_back("fx");
		lst.push_back("fy");
		lst.push_back("flag");
		return lst;
	}
public:
	glsShaderResizeBase(const string& _name) :glsShaderBase(_name){}
};

//-----------------------------------------------------------------------------
// glsShaderResize
class glsShaderResize : public glsShaderResizeBase
{
protected:
	string FragmentShaderCode(void);
public:
	glsShaderResize(void) :glsShaderResizeBase(__FUNCTION__){}
};

//-----------------------------------------------------------------------------
//glsShaderResize
string glsShaderResize::FragmentShaderCode(void){
	const char fragmentShaderCode[] = TO_STR(
#version 330 core\n
precision highp float; \n
uniform sampler2D	texSrc; \n
uniform float fx; \n
uniform float fy; \n
uniform int flag; \n
layout(location = 0) out vec4 dst; \n
#define BOUND_PVT(x,pl,pr) ((x)<(pl)?2*(pl)-(x) :(x)>(pr)? 2*(pr)-(x): (x))\n
vec4 cubic(float x){
	float A = -0.75;
	vec4 coeffs;
	coeffs[0] = ((A*(x + 1) - 5 * A)*(x + 1) + 8 * A)*(x + 1) - 4 * A;
	coeffs[1] = ((A + 2)*x - (A + 3))*x*x + 1;
	coeffs[2] = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1;
	coeffs[3] = 1.0 - coeffs[0] - coeffs[1] - coeffs[2];
	return coeffs; \n
} \n
vec4 textureBicubic(sampler2D sampler, vec2 texCoords){	\n
	ivec2 texSize = textureSize(sampler, 0); \n
	texCoords = texCoords * vec2(texSize) - vec2(0.5);  \n
	vec2 fxy = fract(texCoords);  \n
	vec4 xcubic = cubic(fxy.x);  \n
	vec4 ycubic = cubic(fxy.y); \n
	texCoords -= fxy; \n
	vec4 sum = vec4(0.0);
	for (int i = -1; i < 3; i++){
		vec4 xsum = vec4(0.0);
		for (int j = -1; j < 3; j++){
			ivec2 coord = ivec2(texCoords.x + j, texCoords.y + i);
			//TODO: 画像外周部の扱いをCVと合わせる。
//			coord.x = BOUND_PVT(coord.x, 0, texSize.x -1);
//			coord.y = BOUND_PVT(coord.y, 0, texSize.y -1);
			if (coord.x < 0) coord.x = 0;
			if (coord.x > texSize.x - 1) coord.x = texSize.x - 1;
			if (coord.y < 0) coord.y = 0;
			if (coord.y > texSize.y - 1) coord.y = texSize.y - 1;
			vec4  sample = texelFetch(sampler, coord, 0);
			xsum += sample * vec4(xcubic[j + 1]);
		}
		sum += xsum * vec4(ycubic[i + 1]);
	}
	return sum; \n
} \n
void main(void)\n
{ \n
	ivec2 texSize = textureSize(texSrc, 0); \n
	vec2 coord = gl_FragCoord.xy; \n
	coord = vec2(coord.x / (float(texSize.x)*fx), coord.y / (float(texSize.y)*fy)); \n
	if (flag == 0){
	\n
		dst = texture(texSrc, coord); \n
	}\n
	else{ \n
		dst = textureBicubic(texSrc, coord); \n
	} \n
}\n
);
	return fragmentShaderCode;
}

//-----------------------------------------------------------------------------
// glsShaderResizeU
class glsShaderResizeU : public glsShaderResizeBase
{
protected:
	string FragmentShaderCode(void);
public:
	glsShaderResizeU(void) :glsShaderResizeBase(__FUNCTION__){}
};

//-----------------------------------------------------------------------------
//glsShaderResizeU
string glsShaderResizeU::FragmentShaderCode(void){
	const char fragmentShaderCode[] = TO_STR(
#version 330 core\n
precision highp float; \n
uniform usampler2D	texSrc; \n
uniform float fx; \n
uniform float fy; \n
uniform int flag; \n
layout(location = 0) out uvec4 dst; \n
vec4 cubic(float x){
	float A = -0.75;
	vec4 coeffs;
	coeffs[0] = ((A*(x + 1) - 5 * A)*(x + 1) + 8 * A)*(x + 1) - 4 * A;
	coeffs[1] = ((A + 2)*x - (A + 3))*x*x + 1;
	coeffs[2] = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1;
	coeffs[3] = 1.0 - coeffs[0] - coeffs[1] - coeffs[2];
	return coeffs; \n
} \n
uvec4 textureBicubic(usampler2D sampler, vec2 texCoords){	\n
	ivec2 texSize = textureSize(sampler, 0); \n
	texCoords = texCoords * vec2(texSize) - vec2(0.5);  \n
	vec2 fxy = fract(texCoords);  \n
	vec4 xcubic = cubic(fxy.x);  \n
	vec4 ycubic = cubic(fxy.y); \n
	texCoords -= fxy; \n
	vec4 sum = vec4(0.0);
	for (int i = -1; i < 3; i++){
		vec4 xsum = vec4(0.0);
		for (int j = -1; j < 3; j++){
			ivec2 coord = ivec2(texCoords.x + j, texCoords.y + i);
			if (coord.x < 0) coord.x = 0;
			if (coord.x > texSize.x - 1) coord.x = texSize.x - 1;
			if (coord.y < 0) coord.y = 0;
			if (coord.y > texSize.y - 1) coord.y = texSize.y - 1;
			vec4  sample = vec4(texelFetch(sampler, coord, 0));
			xsum += sample * vec4(xcubic[j + 1]);
		}
		sum += xsum * vec4(ycubic[i + 1]);
	}
	return uvec4(sum); \n
} \n
void main(void)\n
{ \n
	ivec2 texSize = textureSize(texSrc, 0); \n
	vec2 coord = gl_FragCoord.xy; \n
	coord = vec2(coord.x / (float(texSize.x)*fx), coord.y / (float(texSize.y)*fy)); \n
	if (flag == 0){	\n
		dst = uvec4(texture(texSrc, coord)); \n
//		dst = uvec4(128); \n
	}\n
	else{ \n
	dst = textureBicubic(texSrc, coord); \n
	} \n
}\n
);
	return fragmentShaderCode;
}

//-----------------------------------------------------------------------------
//global
glsShaderResize ShaderResize;
glsShaderResizeU ShaderResizeU;

static
glsShaderBase* selectShader(int type){
	glsShaderBase* shader = 0;
	switch (CV_MAT_DEPTH(type)){
	case(CV_32F) : shader = &ShaderResize; break;
	case(CV_8U) :
	case(CV_16U) : shader = &ShaderResizeU; break;
	//case(CV_8S) :
	//case(CV_16S) :
	//case(CV_32S) : shader = &ShaderResizeI; break;
	default: GLS_Assert(0);		//not implement
	}
	return shader;
}

void resize(const GlsMat& src, GlsMat& dst, Size dsize, double fx, double fy, int interpolation){
	GLS_Assert(src.depth() == CV_32F
			|| src.depth() == CV_8U
			|| src.depth() == CV_16U);
	GLS_Assert(interpolation == INTER_NEAREST
			|| interpolation == INTER_LINEAR
			|| interpolation == INTER_CUBIC);
	GLS_Assert((fx == 0 && fy == 0 && dsize != Size(0, 0))
		|| (fx > 0 && fy > 0 && dsize == Size(0, 0)));

	if (fx == 0 && fy == 0){
		fx = dsize.width / (double)src.cols;
		fy = dsize.height / (double)src.rows;
	}
	else{
		dsize = Size((int)round(fx*src.cols), (int)round(fy*src.rows));
	}

	int flag;

	GlsMat _dst = getDstMat(dsize, src.type(), dst);
	glsShaderBase* shader = selectShader(src.type());
	switch (interpolation){
	case(INTER_NEAREST) : {
		src.setInterpolation(GL_NEAREST);
		flag = 0;
	}break;
	case(INTER_LINEAR) : {
		src.setInterpolation(GL_LINEAR);
		flag = 0;
	}break;
	case(INTER_CUBIC) : {
//		src.setInterpolation(GL_LINEAR);
		src.setInterpolation(GL_NEAREST);
		flag = 1;
	}break;
	default: GLS_Assert(0);
	}

	shader->Execute(src, fx, fy, flag, _dst);
	dst = _dst;
}

}//namespace gls

<commit_msg>glsResize 8U Bilinear の出力が全黒なのを修正<commit_after>/*
Copyright (c) 2016, oasi-adamay
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of glsCV nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdafx.h"

/*-----------------------------------------------------------------------------
include
*/
#include "glsMacro.h"
#include "GlsMat.h"
#include "glsShader.h"

#include "glsResize.h"

namespace gls
{

//-----------------------------------------------------------------------------
// glsShaderResize
class glsShaderResizeBase : public glsShaderBase
{
protected:
	list<string> UniformNameList(void){
		list<string> lst;
		lst.push_back("texSrc");
		lst.push_back("fx");
		lst.push_back("fy");
		lst.push_back("flag");
		return lst;
	}
public:
	glsShaderResizeBase(const string& _name) :glsShaderBase(_name){}
};

//-----------------------------------------------------------------------------
// glsShaderResize
class glsShaderResize : public glsShaderResizeBase
{
protected:
	string FragmentShaderCode(void);
public:
	glsShaderResize(void) :glsShaderResizeBase(__FUNCTION__){}
};

//-----------------------------------------------------------------------------
//glsShaderResize
string glsShaderResize::FragmentShaderCode(void){
	const char fragmentShaderCode[] = TO_STR(
#version 330 core\n
precision highp float; \n
uniform sampler2D	texSrc; \n
uniform float fx; \n
uniform float fy; \n
uniform int flag; \n
layout(location = 0) out vec4 dst; \n
#define BOUND_PVT(x,pl,pr) ((x)<(pl)?2*(pl)-(x) :(x)>(pr)? 2*(pr)-(x): (x))\n
vec4 cubic(float x){
	float A = -0.75;
	vec4 coeffs;
	coeffs[0] = ((A*(x + 1) - 5 * A)*(x + 1) + 8 * A)*(x + 1) - 4 * A;
	coeffs[1] = ((A + 2)*x - (A + 3))*x*x + 1;
	coeffs[2] = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1;
	coeffs[3] = 1.0 - coeffs[0] - coeffs[1] - coeffs[2];
	return coeffs; \n
} \n
vec4 textureBicubic(sampler2D sampler, vec2 texCoords){	\n
	ivec2 texSize = textureSize(sampler, 0); \n
	texCoords = texCoords * vec2(texSize) - vec2(0.5);  \n
	vec2 fxy = fract(texCoords);  \n
	vec4 xcubic = cubic(fxy.x);  \n
	vec4 ycubic = cubic(fxy.y); \n
	texCoords -= fxy; \n
	vec4 sum = vec4(0.0);
	for (int i = -1; i < 3; i++){
		vec4 xsum = vec4(0.0);
		for (int j = -1; j < 3; j++){
			ivec2 coord = ivec2(texCoords.x + j, texCoords.y + i);
			//TODO: 画像外周部の扱いをCVと合わせる。
//			coord.x = BOUND_PVT(coord.x, 0, texSize.x -1);
//			coord.y = BOUND_PVT(coord.y, 0, texSize.y -1);
			if (coord.x < 0) coord.x = 0;
			if (coord.x > texSize.x - 1) coord.x = texSize.x - 1;
			if (coord.y < 0) coord.y = 0;
			if (coord.y > texSize.y - 1) coord.y = texSize.y - 1;
			vec4  sample = texelFetch(sampler, coord, 0);
			xsum += sample * vec4(xcubic[j + 1]);
		}
		sum += xsum * vec4(ycubic[i + 1]);
	}
	return sum; \n
} \n
void main(void)\n
{ \n
	ivec2 texSize = textureSize(texSrc, 0); \n
	vec2 coord = gl_FragCoord.xy; \n
	coord = vec2(coord.x / (float(texSize.x)*fx), coord.y / (float(texSize.y)*fy)); \n
	if (flag == 0){
	\n
		dst = texture(texSrc, coord); \n
	}\n
	else{ \n
		dst = textureBicubic(texSrc, coord); \n
	} \n
}\n
);
	return fragmentShaderCode;
}

//-----------------------------------------------------------------------------
// glsShaderResizeU
class glsShaderResizeU : public glsShaderResizeBase
{
protected:
	string FragmentShaderCode(void);
public:
	glsShaderResizeU(void) :glsShaderResizeBase(__FUNCTION__){}
};

//-----------------------------------------------------------------------------
//glsShaderResizeU
string glsShaderResizeU::FragmentShaderCode(void){
	const char fragmentShaderCode[] = TO_STR(
#version 330 core\n
precision highp float; \n
uniform usampler2D	texSrc; \n
uniform float fx; \n
uniform float fy; \n
uniform int flag; \n
layout(location = 0) out uvec4 dst; \n
vec4 cubic(float x){
	float A = -0.75;
	vec4 coeffs;
	coeffs[0] = ((A*(x + 1) - 5 * A)*(x + 1) + 8 * A)*(x + 1) - 4 * A;
	coeffs[1] = ((A + 2)*x - (A + 3))*x*x + 1;
	coeffs[2] = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1;
	coeffs[3] = 1.0 - coeffs[0] - coeffs[1] - coeffs[2];
	return coeffs; \n
} \n
uvec4 textureBicubic(usampler2D sampler, vec2 texCoords){	\n
	ivec2 texSize = textureSize(sampler, 0); \n
	texCoords = texCoords * vec2(texSize) - vec2(0.5);  \n
	vec2 fxy = fract(texCoords);  \n
	vec4 xcubic = cubic(fxy.x);  \n
	vec4 ycubic = cubic(fxy.y); \n
	texCoords -= fxy; \n
	vec4 sum = vec4(0.0);
	for (int i = -1; i < 3; i++){
		vec4 xsum = vec4(0.0);
		for (int j = -1; j < 3; j++){
			ivec2 coord = ivec2(texCoords.x + j, texCoords.y + i);
			if (coord.x < 0) coord.x = 0;
			if (coord.x > texSize.x - 1) coord.x = texSize.x - 1;
			if (coord.y < 0) coord.y = 0;
			if (coord.y > texSize.y - 1) coord.y = texSize.y - 1;
			vec4  sample = vec4(texelFetch(sampler, coord, 0));
			xsum += sample * vec4(xcubic[j + 1]);
		}
		sum += xsum * vec4(ycubic[i + 1]);
	}
	return uvec4(sum); \n
} \n
vec2 linear(float x){
	vec2 coeffs;
	coeffs[0] = 1.0-x;
	coeffs[1] = x;
	return coeffs; \n
} \n
uvec4 textureBilinear(usampler2D sampler, vec2 texCoords){	\n
	ivec2 texSize = textureSize(sampler, 0); \n
	texCoords = texCoords * vec2(texSize) - vec2(0.5);  \n
	vec2 fxy = fract(texCoords);  \n
	vec2 xlinear = linear(fxy.x);  \n
	vec2 ylinear = linear(fxy.y); \n
	texCoords -= fxy; \n
	vec4 sum = vec4(0.0);
	for (int i = 0; i < 2; i++){
		vec4 xsum = vec4(0.0);
		for (int j = 0; j < 2; j++){
			ivec2 coord = ivec2(texCoords.x + j, texCoords.y + i);
			if (coord.x < 0) coord.x = 0;
			if (coord.x > texSize.x - 1) coord.x = texSize.x - 1;
			if (coord.y < 0) coord.y = 0;
			if (coord.y > texSize.y - 1) coord.y = texSize.y - 1;
			vec4  sample = vec4(texelFetch(sampler, coord, 0));
			xsum += sample * vec4(xlinear[j]);
		}
		sum += xsum * vec4(ylinear[i]);
	}
	return uvec4(sum); \n
} \n

void main(void)\n
{ \n
	ivec2 texSize = textureSize(texSrc, 0); \n
	vec2 coord = gl_FragCoord.xy; \n
	coord = vec2(coord.x / (float(texSize.x)*fx), coord.y / (float(texSize.y)*fy)); \n
	if (flag == 0){	\n
		dst = uvec4(texture(texSrc, coord)); \n
//		dst = uvec4(128); \n
	}\n
	else if (flag == 1){	\n
		dst = textureBicubic(texSrc, coord); \n
	} \n
	else{\n
		dst = textureBilinear(texSrc, coord); \n
	} \n
}\n
);
	return fragmentShaderCode;
}

//-----------------------------------------------------------------------------
//global
glsShaderResize ShaderResize;
glsShaderResizeU ShaderResizeU;

static
glsShaderBase* selectShader(int type){
	glsShaderBase* shader = 0;
	switch (CV_MAT_DEPTH(type)){
	case(CV_32F) : shader = &ShaderResize; break;
	case(CV_8U) :
	case(CV_16U) : shader = &ShaderResizeU; break;
	//case(CV_8S) :
	//case(CV_16S) :
	//case(CV_32S) : shader = &ShaderResizeI; break;
	default: GLS_Assert(0);		//not implement
	}
	return shader;
}

void resize(const GlsMat& src, GlsMat& dst, Size dsize, double fx, double fy, int interpolation){
	GLS_Assert(src.depth() == CV_32F
			|| src.depth() == CV_8U
			|| src.depth() == CV_16U);
	GLS_Assert(interpolation == INTER_NEAREST
			|| interpolation == INTER_LINEAR
			|| interpolation == INTER_CUBIC);
	GLS_Assert((fx == 0 && fy == 0 && dsize != Size(0, 0))
		|| (fx > 0 && fy > 0 && dsize == Size(0, 0)));

	if (fx == 0 && fy == 0){
		fx = dsize.width / (double)src.cols;
		fy = dsize.height / (double)src.rows;
	}
	else{
		dsize = Size((int)round(fx*src.cols), (int)round(fy*src.rows));
	}

	int flag;

	GlsMat _dst = getDstMat(dsize, src.type(), dst);
	glsShaderBase* shader = selectShader(src.type());
	switch (interpolation){
	case(INTER_NEAREST) : {
		src.setInterpolation(GL_NEAREST);
		flag = 0;
	}break;
	case(INTER_LINEAR) : {
		if (src.depth() == CV_32F){
			src.setInterpolation(GL_LINEAR);
			flag = 0;
		}
		else{
			src.setInterpolation(GL_NEAREST);
			flag = 2;
		}
	}break;
	case(INTER_CUBIC) : {
//		src.setInterpolation(GL_LINEAR);
		src.setInterpolation(GL_NEAREST);
		flag = 1;
	}break;
	default: GLS_Assert(0);
	}

	shader->Execute(src, fx, fy, flag, _dst);
	dst = _dst;
}

}//namespace gls

<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "runtime/core/sequencetypes.h"
#include "runtime/util/iterator_impl.h"
#include "system/globalenv.h"
#include "zorbaerrors/error_manager.h"
#include "types/casting.h"
#include "types/typeops.h"
#include "store/api/item_factory.h"
#include "context/static_context.h"

using namespace std;

namespace zorba
{

/*******************************************************************************

********************************************************************************/
InstanceOfIterator::InstanceOfIterator(
   const QueryLoc& loc,
   PlanIter_t& aTreatExpr,
   xqtref_t aSequenceType)
  :
  UnaryBaseIterator<InstanceOfIterator, PlanIteratorState> ( loc, aTreatExpr ),
  theSequenceType (aSequenceType)
{
}

InstanceOfIterator::~InstanceOfIterator()
{
}

bool
InstanceOfIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t lTreatItem;
  xqtref_t lTreatType;
  TypeConstants::quantifier_t lQuantifier;
  bool lResult;
  RootTypeManager& ts = GENV_TYPESYSTEM;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  lQuantifier = TypeOps::quantifier(*theSequenceType);
  if (consumeNext(lTreatItem, theChild.getp(), planState))
  {
    if (TypeOps::is_treatable(lTreatItem, *theSequenceType))
    {
      if (consumeNext(lTreatItem, theChild.getp(), planState))
      {
        if (lQuantifier == TypeConstants::QUANT_ONE ||
            lQuantifier == TypeConstants::QUANT_QUESTION)
        {
          lResult = false;
        }
        else
        {
          lResult = true;
          do
          {
            if (!TypeOps::is_treatable(lTreatItem, *theSequenceType))
            {
              lResult = false;
            }
          } while (consumeNext(lTreatItem, theChild.getp(), planState));
        }
      }
      else
      {
        lResult = true;
      }
    }
    else
    {
      lResult = false;
    }
  }
  else
  {
    if ((lQuantifier == TypeConstants::QUANT_ONE ||
         lQuantifier == TypeConstants::QUANT_PLUS) &&
        !TypeOps::is_equal(*ts.EMPTY_TYPE, *theSequenceType))
    {
      lResult = false;
    }
    else
    {
      lResult = true;
    }
  }

  STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, lResult), state);
  STACK_END (state);
}

/*******************************************************************************

********************************************************************************/
void
CastIteratorState::init(PlanState& aPlanState)
{
  PlanIteratorState::init(aPlanState);
  theIndex = 0;
}

void
CastIteratorState::reset(PlanState& aPlanState)
{
  PlanIteratorState::reset(aPlanState);
  theSimpleParseItems.clear();
  theIndex = 0;
}

CastIterator::CastIterator(
    const QueryLoc& loc,
    PlanIter_t& aChild,
    const xqtref_t& aCastType)
  : UnaryBaseIterator<CastIterator, CastIteratorState>(loc, aChild)
{
  theCastType = TypeOps::prime_type (*aCastType);
  theQuantifier = TypeOps::quantifier(*aCastType);
  if (aCastType->type_kind() == XQType::USER_DEFINED_KIND)
  {
    const UserDefinedXQType* lType = static_cast<const UserDefinedXQType*>(aCastType.getp());
    theIsSimpleType = !lType->isComplex();
  }
  else
    theIsSimpleType = false;
}

CastIterator::~CastIterator(){}

bool CastIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t lItem;
  bool valid = false;

  CastIteratorState* state;
  DEFAULT_STACK_INIT(CastIteratorState, state, planState);

  if (!consumeNext(lItem, theChild.getp(), planState))
  {
    if (theQuantifier == TypeConstants::QUANT_PLUS ||
        theQuantifier == TypeConstants::QUANT_ONE)
    {
      ZORBA_ERROR_LOC_DESC( XPTY0004, loc,
        "Empty sequences cannot be casted to a type with quantifier ONE or PLUS!"
      );
    }
  }
  else if (theQuantifier == TypeConstants::QUANT_ONE ||
          theQuantifier == TypeConstants::QUANT_QUESTION)
  {
    //--
    if (theIsSimpleType) {
      state->reset(planState);
      valid = GenericCast::instance()->castToSimple(xqpString(lItem->getStringValue().getp()),
                                            theCastType,
                                            state->theSimpleParseItems);
    }
    else
      valid = GenericCast::instance()->castToAtomic(result, lItem, theCastType);
    //--
    if (consumeNext(lItem, theChild.getp(), planState))
    {
      ZORBA_ERROR_LOC_DESC( XPTY0004, loc,
                        "Sequence with more than one item cannot be casted to a type with quantifier ONE or QUESTION!");
    }

    if (theIsSimpleType) {
      while(state->theIndex < state->theSimpleParseItems.size()) {
        result = state->theSimpleParseItems[state->theIndex++];
        STACK_PUSH(true, state);
      }
    }
    else
      STACK_PUSH(valid, state);
  }
  else
  {
    //--
    if (theIsSimpleType) {
      state->reset(planState);
      GenericCast::instance()->castToSimple(xqpString(lItem->getStringValue().getp()),
                                            theCastType,
                                            state->theSimpleParseItems);
      while(state->theIndex < state->theSimpleParseItems.size()) {
        result = state->theSimpleParseItems[state->theIndex++];
        STACK_PUSH(true, state);
      }
    }
    else
      STACK_PUSH(GenericCast::instance()->castToAtomic(result, lItem, theCastType), state);
    //--

    while (consumeNext(lItem, theChild.getp(), planState))
    {
      //--
      if (theIsSimpleType) {
        state->reset(planState);
        GenericCast::instance()->castToSimple(xqpString(lItem->getStringValue().getp()),
                                              theCastType,
                                              state->theSimpleParseItems);
        while(state->theIndex < state->theSimpleParseItems.size()) {
          result = state->theSimpleParseItems[state->theIndex++];
          STACK_PUSH(true, state);
        }
      }
      else
        STACK_PUSH(GenericCast::instance()->castToAtomic(result, lItem, theCastType), state);
      //--
    }
  }

  STACK_END (state);
}

/*******************************************************************************

********************************************************************************/

CastableIterator::CastableIterator(
  const QueryLoc& aLoc,
  PlanIter_t& aChild,
  const xqtref_t& aCastType)
:
  UnaryBaseIterator<CastableIterator, PlanIteratorState>(aLoc, aChild)
{
  theCastType = TypeOps::prime_type (*aCastType);
  theQuantifier = TypeOps::quantifier(*aCastType);
}

CastableIterator::~CastableIterator(){}

bool CastableIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  bool lBool;
  store::Item_t lItem;

  PlanIteratorState* lState;
  DEFAULT_STACK_INIT(PlanIteratorState, lState, planState);
  if (!consumeNext(lItem, theChild.getp(), planState)) {
    if (theQuantifier == TypeConstants::QUANT_PLUS || theQuantifier == TypeConstants::QUANT_ONE) {
      lBool = false;
    } else {
      lBool = true;
    }
  } else {
    lBool = GenericCast::instance()->isCastable(lItem, theCastType);
    if (lBool) {
      if (consumeNext(lItem, theChild.getp(), planState)) {
        if (theQuantifier == TypeConstants::QUANT_ONE || theQuantifier == TypeConstants::QUANT_QUESTION) {
          lBool = false;
        } else {
          do {
            lBool = GenericCast::instance()->isCastable(lItem, theCastType);
          } while (lBool && consumeNext(lItem, theChild.getp(), planState));
        }
      }
    }
  }
  STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, lBool), lState);
  STACK_END (lState);
}

PromoteIterator::PromoteIterator(const QueryLoc& aLoc, PlanIter_t& aChild, const xqtref_t& aPromoteType)
  : UnaryBaseIterator<PromoteIterator, PlanIteratorState>(aLoc, aChild)
{
  thePromoteType = TypeOps::prime_type (*aPromoteType);
  theQuantifier = TypeOps::quantifier(*aPromoteType);
}

PromoteIterator::~PromoteIterator(){}

bool PromoteIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t lItem;
  store::Item_t temp;
  PlanIteratorState* lState;
  DEFAULT_STACK_INIT(PlanIteratorState, lState, planState);

  if (!consumeNext(lItem, theChild.getp(), planState))
  {
    if (theQuantifier == TypeConstants::QUANT_PLUS || theQuantifier == TypeConstants::QUANT_ONE) {
      ZORBA_ERROR_LOC_DESC(  XPTY0004, loc,
      "Empty seq cannot be promoted to QUANT_ONE or QUANT_PLUS type.");
    }
  }
  else if(theQuantifier == TypeConstants::QUANT_QUESTION
         || theQuantifier == TypeConstants::QUANT_ONE)
  {
    if (! GenericCast::instance()->promote(result, lItem, thePromoteType))
      ZORBA_ERROR_LOC_DESC(XPTY0004, loc,
                           "Type promotion not possible: " + TypeOps::toString (*planState.theCompilerCB->m_sctx->get_typemanager()->create_value_type (lItem)) + " -> " + TypeOps::toString (*thePromoteType) );

    if(consumeNext(temp, theChild.getp(), planState))
    {
      ZORBA_ERROR_LOC_DESC(  XPTY0004, loc,
      "Seq with 2 or more items cannot be promoted to a QUANT_QUESTION or QUANT_ONE type.");
    }
    STACK_PUSH(true, lState);
  }
  else
  {
    do
    {
      if (! GenericCast::instance()->promote(result, lItem, thePromoteType))
        ZORBA_ERROR_LOC_DESC( XPTY0004, loc,  "Type promotion not possible: " + TypeOps::toString (*planState.theCompilerCB->m_sctx->get_typemanager()->create_value_type (lItem)) + " -> " + TypeOps::toString (*thePromoteType) );
      else
        STACK_PUSH(true, lState);
    } while (consumeNext(lItem, theChild.getp(), planState));
  }
  STACK_END (lState);
}

TreatIterator::TreatIterator(const QueryLoc& aLoc, std::vector<PlanIter_t>& aChildren, const xqtref_t& aTreatType, bool check_prime_, XQUERY_ERROR aErrorCode)
  : NaryBaseIterator<TreatIterator, PlanIteratorState>(aLoc, aChildren),
    check_prime (check_prime_), theErrorCode (aErrorCode)
{
  theTreatType = TypeOps::prime_type (*aTreatType);
  theQuantifier = TypeOps::quantifier(*aTreatType);
}

bool TreatIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t temp;

  PlanIteratorState* lState;
  DEFAULT_STACK_INIT(PlanIteratorState, lState, planState);

  if (!CONSUME (result, 0))
  {
    if (theQuantifier == TypeConstants::QUANT_PLUS ||
        theQuantifier == TypeConstants::QUANT_ONE)
    {
      ZORBA_ERROR_LOC_DESC( theErrorCode, loc,
      "Cannot treat empty sequence as <type>+ or <type>.");
    }
  }
  else if(theQuantifier == TypeConstants::QUANT_QUESTION
         || theQuantifier == TypeConstants::QUANT_ONE)
  {
    if (CONSUME (temp, 0))
    {
      ZORBA_ERROR_LOC_DESC( theErrorCode, loc,
      "Cannot treat sequence with 2 or more items as <type>? or <type>.");
    }

    if ( check_prime && !TypeOps::is_treatable(result, *theTreatType))
    {
      ZORBA_ERROR_LOC_DESC( theErrorCode, loc,  "Cannot treat " + TypeOps::toString (*planState.theCompilerCB->m_sctx->get_typemanager()->create_value_type (result)) + " as " + TypeOps::toString (*theTreatType) );
    }
    else
    {
      STACK_PUSH(true, lState);
    }
  }
  else
  {
    do
    {
      if ( check_prime && !TypeOps::is_treatable(result, *theTreatType))
      {
        ZORBA_ERROR_LOC_DESC( theErrorCode, loc,  "Cannot treat " + TypeOps::toString (*planState.theCompilerCB->m_sctx->get_typemanager()->create_value_type (result)) + " as " + TypeOps::toString (*theTreatType) );
      }
      else
      {
        STACK_PUSH(true, lState);
      }
    } while (CONSUME (result, 0));
  }
  STACK_END (lState);
}

bool EitherNodesOrAtomicsIterator::nextImpl(store::Item_t& result, PlanState& planState) const {
  store::Item_t item;

  EitherNodesOrAtomicsIteratorState *lState;
  DEFAULT_STACK_INIT(EitherNodesOrAtomicsIteratorState, lState, planState);

  if (CONSUME (result, 0)) {
    lState->atomics = item->isAtomic ();
    STACK_PUSH (true, lState);

    while (CONSUME (result, 0)) {
      if (lState->atomics != item->isAtomic ())
        ZORBA_ERROR_LOC (XPTY0018, loc);
      STACK_PUSH (true, lState);
    }
  }

  STACK_END (lState);
}

/*******************************************************************************

********************************************************************************/

} /* namespace zorba */

<commit_msg>fixed bug in EitherNodesOrAtomicsIterator<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "runtime/core/sequencetypes.h"
#include "runtime/util/iterator_impl.h"
#include "system/globalenv.h"
#include "zorbaerrors/error_manager.h"
#include "types/casting.h"
#include "types/typeops.h"
#include "store/api/item_factory.h"
#include "context/static_context.h"

using namespace std;

namespace zorba
{

/*******************************************************************************

********************************************************************************/
InstanceOfIterator::InstanceOfIterator(
   const QueryLoc& loc,
   PlanIter_t& aTreatExpr,
   xqtref_t aSequenceType)
  :
  UnaryBaseIterator<InstanceOfIterator, PlanIteratorState> ( loc, aTreatExpr ),
  theSequenceType (aSequenceType)
{
}

InstanceOfIterator::~InstanceOfIterator()
{
}

bool
InstanceOfIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t lTreatItem;
  xqtref_t lTreatType;
  TypeConstants::quantifier_t lQuantifier;
  bool lResult;
  RootTypeManager& ts = GENV_TYPESYSTEM;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  lQuantifier = TypeOps::quantifier(*theSequenceType);
  if (consumeNext(lTreatItem, theChild.getp(), planState))
  {
    if (TypeOps::is_treatable(lTreatItem, *theSequenceType))
    {
      if (consumeNext(lTreatItem, theChild.getp(), planState))
      {
        if (lQuantifier == TypeConstants::QUANT_ONE ||
            lQuantifier == TypeConstants::QUANT_QUESTION)
        {
          lResult = false;
        }
        else
        {
          lResult = true;
          do
          {
            if (!TypeOps::is_treatable(lTreatItem, *theSequenceType))
            {
              lResult = false;
            }
          } while (consumeNext(lTreatItem, theChild.getp(), planState));
        }
      }
      else
      {
        lResult = true;
      }
    }
    else
    {
      lResult = false;
    }
  }
  else
  {
    if ((lQuantifier == TypeConstants::QUANT_ONE ||
         lQuantifier == TypeConstants::QUANT_PLUS) &&
        !TypeOps::is_equal(*ts.EMPTY_TYPE, *theSequenceType))
    {
      lResult = false;
    }
    else
    {
      lResult = true;
    }
  }

  STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, lResult), state);
  STACK_END (state);
}

/*******************************************************************************

********************************************************************************/
void
CastIteratorState::init(PlanState& aPlanState)
{
  PlanIteratorState::init(aPlanState);
  theIndex = 0;
}

void
CastIteratorState::reset(PlanState& aPlanState)
{
  PlanIteratorState::reset(aPlanState);
  theSimpleParseItems.clear();
  theIndex = 0;
}

CastIterator::CastIterator(
    const QueryLoc& loc,
    PlanIter_t& aChild,
    const xqtref_t& aCastType)
  : UnaryBaseIterator<CastIterator, CastIteratorState>(loc, aChild)
{
  theCastType = TypeOps::prime_type (*aCastType);
  theQuantifier = TypeOps::quantifier(*aCastType);
  if (aCastType->type_kind() == XQType::USER_DEFINED_KIND)
  {
    const UserDefinedXQType* lType = static_cast<const UserDefinedXQType*>(aCastType.getp());
    theIsSimpleType = !lType->isComplex();
  }
  else
    theIsSimpleType = false;
}

CastIterator::~CastIterator(){}

bool CastIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t lItem;
  bool valid = false;

  CastIteratorState* state;
  DEFAULT_STACK_INIT(CastIteratorState, state, planState);

  if (!consumeNext(lItem, theChild.getp(), planState))
  {
    if (theQuantifier == TypeConstants::QUANT_PLUS ||
        theQuantifier == TypeConstants::QUANT_ONE)
    {
      ZORBA_ERROR_LOC_DESC( XPTY0004, loc,
        "Empty sequences cannot be casted to a type with quantifier ONE or PLUS!"
      );
    }
  }
  else if (theQuantifier == TypeConstants::QUANT_ONE ||
          theQuantifier == TypeConstants::QUANT_QUESTION)
  {
    //--
    if (theIsSimpleType) {
      state->reset(planState);
      valid = GenericCast::instance()->castToSimple(xqpString(lItem->getStringValue().getp()),
                                            theCastType,
                                            state->theSimpleParseItems);
    }
    else
      valid = GenericCast::instance()->castToAtomic(result, lItem, theCastType);
    //--
    if (consumeNext(lItem, theChild.getp(), planState))
    {
      ZORBA_ERROR_LOC_DESC( XPTY0004, loc,
                        "Sequence with more than one item cannot be casted to a type with quantifier ONE or QUESTION!");
    }

    if (theIsSimpleType) {
      while(state->theIndex < state->theSimpleParseItems.size()) {
        result = state->theSimpleParseItems[state->theIndex++];
        STACK_PUSH(true, state);
      }
    }
    else
      STACK_PUSH(valid, state);
  }
  else
  {
    //--
    if (theIsSimpleType) {
      state->reset(planState);
      GenericCast::instance()->castToSimple(xqpString(lItem->getStringValue().getp()),
                                            theCastType,
                                            state->theSimpleParseItems);
      while(state->theIndex < state->theSimpleParseItems.size()) {
        result = state->theSimpleParseItems[state->theIndex++];
        STACK_PUSH(true, state);
      }
    }
    else
      STACK_PUSH(GenericCast::instance()->castToAtomic(result, lItem, theCastType), state);
    //--

    while (consumeNext(lItem, theChild.getp(), planState))
    {
      //--
      if (theIsSimpleType) {
        state->reset(planState);
        GenericCast::instance()->castToSimple(xqpString(lItem->getStringValue().getp()),
                                              theCastType,
                                              state->theSimpleParseItems);
        while(state->theIndex < state->theSimpleParseItems.size()) {
          result = state->theSimpleParseItems[state->theIndex++];
          STACK_PUSH(true, state);
        }
      }
      else
        STACK_PUSH(GenericCast::instance()->castToAtomic(result, lItem, theCastType), state);
      //--
    }
  }

  STACK_END (state);
}

/*******************************************************************************

********************************************************************************/

CastableIterator::CastableIterator(
  const QueryLoc& aLoc,
  PlanIter_t& aChild,
  const xqtref_t& aCastType)
:
  UnaryBaseIterator<CastableIterator, PlanIteratorState>(aLoc, aChild)
{
  theCastType = TypeOps::prime_type (*aCastType);
  theQuantifier = TypeOps::quantifier(*aCastType);
}

CastableIterator::~CastableIterator(){}

bool CastableIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  bool lBool;
  store::Item_t lItem;

  PlanIteratorState* lState;
  DEFAULT_STACK_INIT(PlanIteratorState, lState, planState);
  if (!consumeNext(lItem, theChild.getp(), planState)) {
    if (theQuantifier == TypeConstants::QUANT_PLUS || theQuantifier == TypeConstants::QUANT_ONE) {
      lBool = false;
    } else {
      lBool = true;
    }
  } else {
    lBool = GenericCast::instance()->isCastable(lItem, theCastType);
    if (lBool) {
      if (consumeNext(lItem, theChild.getp(), planState)) {
        if (theQuantifier == TypeConstants::QUANT_ONE || theQuantifier == TypeConstants::QUANT_QUESTION) {
          lBool = false;
        } else {
          do {
            lBool = GenericCast::instance()->isCastable(lItem, theCastType);
          } while (lBool && consumeNext(lItem, theChild.getp(), planState));
        }
      }
    }
  }
  STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, lBool), lState);
  STACK_END (lState);
}

PromoteIterator::PromoteIterator(const QueryLoc& aLoc, PlanIter_t& aChild, const xqtref_t& aPromoteType)
  : UnaryBaseIterator<PromoteIterator, PlanIteratorState>(aLoc, aChild)
{
  thePromoteType = TypeOps::prime_type (*aPromoteType);
  theQuantifier = TypeOps::quantifier(*aPromoteType);
}

PromoteIterator::~PromoteIterator(){}

bool PromoteIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t lItem;
  store::Item_t temp;
  PlanIteratorState* lState;
  DEFAULT_STACK_INIT(PlanIteratorState, lState, planState);

  if (!consumeNext(lItem, theChild.getp(), planState))
  {
    if (theQuantifier == TypeConstants::QUANT_PLUS || theQuantifier == TypeConstants::QUANT_ONE) {
      ZORBA_ERROR_LOC_DESC(  XPTY0004, loc,
      "Empty seq cannot be promoted to QUANT_ONE or QUANT_PLUS type.");
    }
  }
  else if(theQuantifier == TypeConstants::QUANT_QUESTION
         || theQuantifier == TypeConstants::QUANT_ONE)
  {
    if (! GenericCast::instance()->promote(result, lItem, thePromoteType))
      ZORBA_ERROR_LOC_DESC(XPTY0004, loc,
                           "Type promotion not possible: " + TypeOps::toString (*planState.theCompilerCB->m_sctx->get_typemanager()->create_value_type (lItem)) + " -> " + TypeOps::toString (*thePromoteType) );

    if(consumeNext(temp, theChild.getp(), planState))
    {
      ZORBA_ERROR_LOC_DESC(  XPTY0004, loc,
      "Seq with 2 or more items cannot be promoted to a QUANT_QUESTION or QUANT_ONE type.");
    }
    STACK_PUSH(true, lState);
  }
  else
  {
    do
    {
      if (! GenericCast::instance()->promote(result, lItem, thePromoteType))
        ZORBA_ERROR_LOC_DESC( XPTY0004, loc,  "Type promotion not possible: " + TypeOps::toString (*planState.theCompilerCB->m_sctx->get_typemanager()->create_value_type (lItem)) + " -> " + TypeOps::toString (*thePromoteType) );
      else
        STACK_PUSH(true, lState);
    } while (consumeNext(lItem, theChild.getp(), planState));
  }
  STACK_END (lState);
}

TreatIterator::TreatIterator(const QueryLoc& aLoc, std::vector<PlanIter_t>& aChildren, const xqtref_t& aTreatType, bool check_prime_, XQUERY_ERROR aErrorCode)
  : NaryBaseIterator<TreatIterator, PlanIteratorState>(aLoc, aChildren),
    check_prime (check_prime_), theErrorCode (aErrorCode)
{
  theTreatType = TypeOps::prime_type (*aTreatType);
  theQuantifier = TypeOps::quantifier(*aTreatType);
}

bool TreatIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t temp;

  PlanIteratorState* lState;
  DEFAULT_STACK_INIT(PlanIteratorState, lState, planState);

  if (!CONSUME (result, 0))
  {
    if (theQuantifier == TypeConstants::QUANT_PLUS ||
        theQuantifier == TypeConstants::QUANT_ONE)
    {
      ZORBA_ERROR_LOC_DESC( theErrorCode, loc,
      "Cannot treat empty sequence as <type>+ or <type>.");
    }
  }
  else if(theQuantifier == TypeConstants::QUANT_QUESTION
         || theQuantifier == TypeConstants::QUANT_ONE)
  {
    if (CONSUME (temp, 0))
    {
      ZORBA_ERROR_LOC_DESC( theErrorCode, loc,
      "Cannot treat sequence with 2 or more items as <type>? or <type>.");
    }

    if ( check_prime && !TypeOps::is_treatable(result, *theTreatType))
    {
      ZORBA_ERROR_LOC_DESC( theErrorCode, loc,  "Cannot treat " + TypeOps::toString (*planState.theCompilerCB->m_sctx->get_typemanager()->create_value_type (result)) + " as " + TypeOps::toString (*theTreatType) );
    }
    else
    {
      STACK_PUSH(true, lState);
    }
  }
  else
  {
    do
    {
      if ( check_prime && !TypeOps::is_treatable(result, *theTreatType))
      {
        ZORBA_ERROR_LOC_DESC( theErrorCode, loc,  "Cannot treat " + TypeOps::toString (*planState.theCompilerCB->m_sctx->get_typemanager()->create_value_type (result)) + " as " + TypeOps::toString (*theTreatType) );
      }
      else
      {
        STACK_PUSH(true, lState);
      }
    } while (CONSUME (result, 0));
  }
  STACK_END (lState);
}

/*******************************************************************************

********************************************************************************/
bool EitherNodesOrAtomicsIterator::nextImpl(
    store::Item_t& result,
    PlanState& planState) const
{
  EitherNodesOrAtomicsIteratorState *lState;
  DEFAULT_STACK_INIT(EitherNodesOrAtomicsIteratorState, lState, planState);

  if (CONSUME (result, 0))
  {
    lState->atomics = result->isAtomic ();
    STACK_PUSH (true, lState);

    while (CONSUME (result, 0))
    {
      if (lState->atomics != result->isAtomic ())
        ZORBA_ERROR_LOC (XPTY0018, loc);
      STACK_PUSH (true, lState);
    }
  }

  STACK_END (lState);
}

/*******************************************************************************

********************************************************************************/

} /* namespace zorba */

<|endoftext|>


<commit_before>#include <fstream>
#include <cassert>
#include <memory.h>
#include <math.h>

#include "world.h"
#include "logging.h"
#include "utils.h"

using std::ifstream;
using std::ofstream;
using std::ios;

// -----------------  WORLD CLASS STATIC INITIALIZATION  ----------------------------

unsigned char world::car_pixels[360][CAR_HEIGHT][CAR_WIDTH];
short world::get_view_dx_tbl[360][MAX_GET_VIEW_XY][MAX_GET_VIEW_XY];
short world::get_view_dy_tbl[360][MAX_GET_VIEW_XY][MAX_GET_VIEW_XY];  // xxx make these tables bigger

void world::static_init(void)
{
    //
    // init car_pixels ...
    //

    // create car at 0 degree rotation
    unsigned char (&car)[CAR_HEIGHT][CAR_WIDTH] = car_pixels[0];
    memset(car, display::TRANSPARENT, sizeof(car));
    for (int h = 5; h <= 11; h++) {
        for (int w = 1; w <= 15; w++) {
            car[h][w] = display::BLUE;
        }
    }
    car[5][15]  = display::WHITE;   // head lights
    car[6][15]  = display::WHITE;
    car[10][15] = display::WHITE;
    car[11][15] = display::WHITE;
    car[5][14]  = display::WHITE;
    car[6][14]  = display::WHITE;
    car[10][14] = display::WHITE;
    car[11][14] = display::WHITE;
    car[5][1]   = display::RED;     // tail lights
    car[6][1]   = display::RED;
    car[10][1]  = display::RED;
    car[11][1]  = display::RED;
    car[5][2]   = display::RED;
    car[6][2]   = display::RED;
    car[10][2]  = display::RED;
    car[11][2]  = display::RED;

    // create cars at 1 to 359 degrees rotation,
    // using the car created above at 0 degrees as a template
    for (int dir = 1; dir <= 359; dir++) {
        double sin_dir = sin(dir *  M_PI/180.0);
        double cos_dir = cos(dir *  M_PI/180.0);
        unsigned char (&carprime)[CAR_HEIGHT][CAR_WIDTH] = car_pixels[dir];
        int x,y,xprime,yprime;

        #define OVSF 2  // Over Sample Factor
        memset(carprime, display::TRANSPARENT, sizeof(car));
        for (y = 0; y < CAR_HEIGHT*OVSF; y++) {
            for (x = 0; x < CAR_WIDTH*OVSF; x++) {
                xprime = (x-CAR_WIDTH*OVSF/2) * cos_dir - (y-CAR_HEIGHT*OVSF/2) * sin_dir + CAR_WIDTH*OVSF/2 + 0.0001;
                yprime = (x-CAR_WIDTH*OVSF/2) * sin_dir + (y-CAR_HEIGHT*OVSF/2) * cos_dir + CAR_HEIGHT*OVSF/2 + 0.0001;
                if (xprime < 0 || xprime >= CAR_WIDTH*OVSF || yprime < 0 || yprime >= CAR_HEIGHT*OVSF) {
                    continue;
                }
                carprime[yprime/OVSF][xprime/OVSF] = car[y/OVSF][x/OVSF];
            }
        }
    }

    //
    // init get_view rotation tables
    //

    int d1,h1,w1;
    INFO("sizeof of tables " <<
           (sizeof(get_view_dx_tbl) + sizeof(get_view_dy_tbl)) / 0x100000 << " MB" << endl);
    for (d1 = 0; d1 < 360; d1++) {
        double sindir = sin(d1 * (M_PI/180.0));
        double cosdir = cos(d1 * (M_PI/180.0));
        for (h1 = 0; h1 < MAX_GET_VIEW_XY; h1++) {
            for (w1 = -MAX_GET_VIEW_XY/2; w1 < -MAX_GET_VIEW_XY/2 + MAX_GET_VIEW_XY; w1++) {
                get_view_dx_tbl[d1][h1][w1+(MAX_GET_VIEW_XY/2)] = w1 * cosdir + h1 * sindir;
                get_view_dy_tbl[d1][h1][w1+(MAX_GET_VIEW_XY/2)] = w1 * sindir - h1 * cosdir;
            }
        }
    }
}

// -----------------  CONSTRUCTOR / DESTRUCTOR  -------------------------------------

world::world(display &display, string fn) : d(display)
{
    static_pixels           = new unsigned char [WORLD_HEIGHT] [WORLD_WIDTH];
    memset(static_pixels, 0, WORLD_HEIGHT*WORLD_WIDTH);
    pixels                  = new unsigned char [WORLD_HEIGHT] [WORLD_WIDTH];
    memset(pixels, 0, WORLD_HEIGHT*WORLD_WIDTH);
    texture                 = NULL;
    memset(placed_car_list, 0, sizeof(placed_car_list));
    max_placed_car_list     = 0;
    filename                = "";
    read_ok_flag            = false;
    write_ok_flag           = false;

    filename = fn;
    read();
    if (!read_ok_flag) {
        clear();
    }
    assert(texture);
}

world::~world()
{
    d.texture_destroy(texture);
    delete [] static_pixels;
    delete [] pixels;
}

// -----------------  CAR SUPPORT  --------------------------------------------------

void world::place_car_init()
{
    for (int i = 0; i < max_placed_car_list; i++) {
        struct rect &rect = placed_car_list[i];

        // restores pixels from static_pixels
        // XXX check for y or x out of bouncds
        for (int y = rect.y; y < rect.y+rect.h; y++) {
            memcpy(&pixels[y][rect.x], &static_pixels[y][rect.x], CAR_WIDTH);
        }

        // restores the texture
        d.texture_set_rect(texture,
                           rect.x, rect.y, rect.w, rect.h,
                           &pixels[rect.y][rect.x],
                           WORLD_WIDTH);
    }
    max_placed_car_list = 0;
}

void world::place_car(double x_arg, double y_arg, double dir_arg)
{
    // convert dir to integer, and adjust so 0 degrees is up
    int dir = (dir_arg + 0.5);
    dir = ((dir + 270) % 360);
    if (dir < 0) dir += 360;

    // convert x,y to integer, and adjust to the top left corner of the car rect
    int x  = (x_arg + 0.5);
    int y  = (y_arg + 0.5);
    x -= CAR_WIDTH / 2;
    y -= CAR_HEIGHT / 2;

    // save the location of the car being placed on placed_car_list
    struct rect &rect = placed_car_list[max_placed_car_list];
    rect.x = x;
    rect.y = y;
    rect.w = CAR_WIDTH;
    rect.h = CAR_HEIGHT;
    max_placed_car_list++;

    // copy non transparent car pixels to pixels
    unsigned char * cp = reinterpret_cast<unsigned char *>(car_pixels[dir]);  //xxx cast
    for (y = rect.y; y < rect.y+rect.h; y++) {
        for (x = rect.x; x < rect.x+rect.w; x++) {
            if (*cp != display::TRANSPARENT) {
                pixels[y][x] = *cp;
            }
            cp++;
        }
    }

    // update the texture
    d.texture_set_rect(texture,
                       rect.x, rect.y, rect.w, rect.h,
                       &pixels[rect.y][rect.x],
                       WORLD_WIDTH);
}

// -----------------  GET VIEW OF THE WORLD  ----------------------------------------

void world::get_view(double x_arg, double y_arg, double dir_arg, int w_arg, int h_arg, unsigned char * p_arg)
{
    int x = x_arg + 0.5;
    int y = y_arg + 0.5;
    int d = dir_arg + 0.5;

    if (d == 360) d = 0;  // XXX

    assert(d >= 0 && d <= 359);

    // XXX check size and bounds

    for (int h = h_arg-1; h >= 0; h--) {
        for (int w = -w_arg/2; w < -w_arg/2+w_arg; w++) {
            int dx = get_view_dx_tbl[d][h][w+(MAX_GET_VIEW_XY/2)];
            int dy = get_view_dy_tbl[d][h][w+(MAX_GET_VIEW_XY/2)];
            *p_arg++ = pixels[y+dy][x+dx];
        }
    }
}

// -----------------  DRAW THE WORLD  -----------------------------------------------

void world::draw(int pid, double center_x, double center_y, double zoom)
{
    int w, h, x, y;

    w = WORLD_WIDTH / zoom;
    h = WORLD_HEIGHT / zoom;
    x = center_x - w/2;
    y = center_y - h/2;

    d.texture_draw(texture, x, y, w, h, pid);
}

// -----------------  EDIT STATIC PIXELS SUPPORT  -----------------------------------

void world::create_road_slice(double &x, double &y, double dir)
{
    double dx, dy, dpx, dpy, tmpx, tmpy;

    dir += 270;

    dy  = .5 * sin(dir * (M_PI/180.0));
    dx  = .5 * cos(dir * (M_PI/180.0));
    dpy = .5 * sin((dir+90) * (M_PI/180.0));
    dpx = .5 * cos((dir+90) * (M_PI/180.0));

    set_static_pixel(x,y,display::YELLOW);

    tmpx = x;
    tmpy = y;
    for (int i = 1; i <= 24; i++) {
        tmpx += dpx;
        tmpy += dpy;
        if (get_static_pixel(tmpx,tmpy) == display::GREEN) {
            set_static_pixel(tmpx,tmpy,display::BLACK);
        }
    }

    tmpx = x;
    tmpy = y;
    for (int i = 1; i <= 24; i++) {
        tmpx -= dpx;
        tmpy -= dpy;
        if (get_static_pixel(tmpx,tmpy) == display::GREEN) {
            set_static_pixel(tmpx,tmpy,display::BLACK);
        }
    }

    x += dx;
    y += dy;
}

void world::set_static_pixel(double x, double y, unsigned char p)
{
    int ix = x + .5;
    int iy = y + .5;

    if (ix < 0 || ix >= WORLD_WIDTH || iy < 0 || iy >= WORLD_HEIGHT) {
        return;
    }

    static_pixels[iy][ix] = p;
    d.texture_set_pixel(texture, ix, iy, p);
}

unsigned char world::get_static_pixel(double x, double y)
{
    int ix = x + .5;
    int iy = y + .5;

    if (ix < 0 || ix >= WORLD_WIDTH || iy < 0 || iy >= WORLD_HEIGHT) {
        ERROR("ix " << ix << " iy " << iy << endl);
        return display::GREEN;
    }

    return static_pixels[iy][ix];
}

void world::clear()
{
    memset(static_pixels, display::GREEN, WORLD_WIDTH*WORLD_HEIGHT);
    d.texture_destroy(texture);
    texture = d.texture_create(reinterpret_cast<unsigned char *>(static_pixels),
                                             WORLD_WIDTH, WORLD_HEIGHT);
}

void world::read()
{
    ifstream ifs;

    read_ok_flag = false;
    ifs.open(filename, ios::in|ios::ate|ios::binary);
    if (!ifs.is_open()) {
        ERROR(filename << " does not exist" << endl);
        return;
    }
    if (ifs.tellg() != WORLD_WIDTH*WORLD_HEIGHT) {
        ERROR(filename << " has incorrect size" << endl);
        return;
    }
    ifs.seekg(0,ios::beg);
    ifs.read(reinterpret_cast<char*>(static_pixels), WORLD_WIDTH*WORLD_HEIGHT);
    if (!ifs.good()) {
        ERROR(filename << " read failed" << endl);
        return;
    }
    read_ok_flag = true;

    memcpy(pixels, static_pixels, WORLD_WIDTH*WORLD_HEIGHT);

    d.texture_destroy(texture);
    texture = d.texture_create(reinterpret_cast<unsigned char *>(static_pixels),
                               WORLD_WIDTH, WORLD_HEIGHT);
}

void world::write()
{
    ofstream ofs;

    write_ok_flag = false;
    ofs.open(filename, ios::out|ios::binary|ios::trunc);
    if (!ofs.is_open()) {
        ERROR(filename << " create failed" << endl);
        return;
    }
    ofs.write(reinterpret_cast<char*>(static_pixels), WORLD_WIDTH*WORLD_HEIGHT);
    if (!ofs.good()) {
        ERROR(filename << " write failed" << endl);
        return;
    }
    write_ok_flag = true;
}
<commit_msg>check bounds in world.cpp<commit_after>#include <fstream>
#include <cassert>
#include <memory.h>
#include <math.h>

#include "world.h"
#include "logging.h"
#include "utils.h"

using std::ifstream;
using std::ofstream;
using std::ios;

// -----------------  WORLD CLASS STATIC INITIALIZATION  ----------------------------

unsigned char world::car_pixels[360][CAR_HEIGHT][CAR_WIDTH];
short world::get_view_dx_tbl[360][MAX_GET_VIEW_XY][MAX_GET_VIEW_XY];
short world::get_view_dy_tbl[360][MAX_GET_VIEW_XY][MAX_GET_VIEW_XY];  // xxx make these tables bigger

void world::static_init(void)
{
    //
    // init car_pixels ...
    //

    // create car at 0 degree rotation
    unsigned char (&car)[CAR_HEIGHT][CAR_WIDTH] = car_pixels[0];
    memset(car, display::TRANSPARENT, sizeof(car));
    for (int h = 5; h <= 11; h++) {
        for (int w = 1; w <= 15; w++) {
            car[h][w] = display::BLUE;
        }
    }
    car[5][15]  = display::WHITE;   // head lights
    car[6][15]  = display::WHITE;
    car[10][15] = display::WHITE;
    car[11][15] = display::WHITE;
    car[5][14]  = display::WHITE;
    car[6][14]  = display::WHITE;
    car[10][14] = display::WHITE;
    car[11][14] = display::WHITE;
    car[5][1]   = display::RED;     // tail lights
    car[6][1]   = display::RED;
    car[10][1]  = display::RED;
    car[11][1]  = display::RED;
    car[5][2]   = display::RED;
    car[6][2]   = display::RED;
    car[10][2]  = display::RED;
    car[11][2]  = display::RED;

    // create cars at 1 to 359 degrees rotation,
    // using the car created above at 0 degrees as a template
    for (int dir = 1; dir <= 359; dir++) {
        double sin_dir = sin(dir *  M_PI/180.0);
        double cos_dir = cos(dir *  M_PI/180.0);
        unsigned char (&carprime)[CAR_HEIGHT][CAR_WIDTH] = car_pixels[dir];
        int x,y,xprime,yprime;

        #define OVSF 3  // Over Sample Factor
        memset(carprime, display::TRANSPARENT, sizeof(car));
        for (y = 0; y < CAR_HEIGHT*OVSF; y++) {
            for (x = 0; x < CAR_WIDTH*OVSF; x++) {
                xprime = (x-CAR_WIDTH*OVSF/2) * cos_dir - (y-CAR_HEIGHT*OVSF/2) * sin_dir + CAR_WIDTH*OVSF/2 + 0.001;
                yprime = (x-CAR_WIDTH*OVSF/2) * sin_dir + (y-CAR_HEIGHT*OVSF/2) * cos_dir + CAR_HEIGHT*OVSF/2 + 0.001;
                if (xprime < 0 || xprime >= CAR_WIDTH*OVSF || yprime < 0 || yprime >= CAR_HEIGHT*OVSF) {
                    continue;
                }
                carprime[yprime/OVSF][xprime/OVSF] = car[y/OVSF][x/OVSF];
            }
        }
    }

    //
    // init get_view rotation tables
    //

    int d1,h1,w1;
    INFO("sizeof of tables " <<
           (sizeof(get_view_dx_tbl) + sizeof(get_view_dy_tbl)) / 0x100000 << " MB" << endl);
    for (d1 = 0; d1 < 360; d1++) {
        double sindir = sin(d1 * (M_PI/180.0));
        double cosdir = cos(d1 * (M_PI/180.0));
        for (h1 = 0; h1 < MAX_GET_VIEW_XY; h1++) {
            for (w1 = -MAX_GET_VIEW_XY/2; w1 < -MAX_GET_VIEW_XY/2 + MAX_GET_VIEW_XY; w1++) {
                get_view_dx_tbl[d1][h1][w1+(MAX_GET_VIEW_XY/2)] = w1 * cosdir + h1 * sindir;
                get_view_dy_tbl[d1][h1][w1+(MAX_GET_VIEW_XY/2)] = w1 * sindir - h1 * cosdir;
            }
        }
    }
}

// -----------------  CONSTRUCTOR / DESTRUCTOR  -------------------------------------

world::world(display &display, string fn) : d(display)
{
    static_pixels           = new unsigned char [WORLD_HEIGHT] [WORLD_WIDTH];
    memset(static_pixels, 0, WORLD_HEIGHT*WORLD_WIDTH);
    pixels                  = new unsigned char [WORLD_HEIGHT] [WORLD_WIDTH];
    memset(pixels, 0, WORLD_HEIGHT*WORLD_WIDTH);
    texture                 = NULL;
    memset(placed_car_list, 0, sizeof(placed_car_list));
    max_placed_car_list     = 0;
    filename                = "";
    read_ok_flag            = false;
    write_ok_flag           = false;

    filename = fn;
    read();
    if (!read_ok_flag) {
        clear();
    }
    assert(texture);
}

world::~world()
{
    d.texture_destroy(texture);
    delete [] static_pixels;
    delete [] pixels;
}

// -----------------  CAR SUPPORT  --------------------------------------------------

void world::place_car_init()
{
    for (int i = 0; i < max_placed_car_list; i++) {
        struct rect &rect = placed_car_list[i];

        // restores pixels from static_pixels
        for (int y = rect.y; y < rect.y+rect.h; y++) {
            memcpy(&pixels[y][rect.x], &static_pixels[y][rect.x], CAR_WIDTH);
        }

        // restores the texture
        d.texture_set_rect(texture,
                           rect.x, rect.y, rect.w, rect.h,
                           &pixels[rect.y][rect.x],
                           WORLD_WIDTH);
    }
    max_placed_car_list = 0;
}

void world::place_car(double x_arg, double y_arg, double dir_arg)
{
    // convert dir to integer, and adjust so 0 degrees is up
    int dir = (dir_arg + 0.5);
    dir = ((dir + 270) % 360);
    if (dir < 0) dir += 360;

    // convert x,y to integer, and adjust to the top left corner of the car rect
    int x  = (x_arg + 0.5);
    int y  = (y_arg + 0.5);
    x -= CAR_WIDTH / 2;
    y -= CAR_HEIGHT / 2;

    // if car is off an edge of the world then skip
    if (x < 0 || x+CAR_WIDTH >= WORLD_WIDTH ||
        y < 0 || y+CAR_HEIGHT >= WORLD_HEIGHT)
    {
        return;
    }

    // save the location of the car being placed on placed_car_list
    struct rect &rect = placed_car_list[max_placed_car_list];
    rect.x = x;
    rect.y = y;
    rect.w = CAR_WIDTH;
    rect.h = CAR_HEIGHT;
    max_placed_car_list++;

    // copy non transparent car pixels to pixels
    unsigned char * cp = reinterpret_cast<unsigned char *>(car_pixels[dir]);  //xxx cast
    for (y = rect.y; y < rect.y+rect.h; y++) {
        for (x = rect.x; x < rect.x+rect.w; x++) {
            if (*cp != display::TRANSPARENT) {
                pixels[y][x] = *cp;
            }
            cp++;
        }
    }

    // update the texture
    d.texture_set_rect(texture,
                       rect.x, rect.y, rect.w, rect.h,
                       &pixels[rect.y][rect.x],
                       WORLD_WIDTH);
}

// -----------------  GET VIEW OF THE WORLD  ----------------------------------------

void world::get_view(double x_arg, double y_arg, double dir_arg, int w_arg, int h_arg, unsigned char * p_arg)
{
    int x = x_arg + 0.5;
    int y = y_arg + 0.5;
    int d = dir_arg + 0.5;

    if (d == 360) d = 0;  // xxx

    assert(d >= 0 && d <= 359);

    for (int h = h_arg-1; h >= 0; h--) {
        for (int w = -w_arg/2; w < -w_arg/2+w_arg; w++) {
            int dx = get_view_dx_tbl[d][h][w+(MAX_GET_VIEW_XY/2)];
            int dy = get_view_dy_tbl[d][h][w+(MAX_GET_VIEW_XY/2)];
            if (y+dy >= 0 && y+dy < WORLD_HEIGHT && x+dx >= 0 && x+dx < WORLD_WIDTH) {
                *p_arg++ = pixels[y+dy][x+dx];
            } else {
                *p_arg++ = display::PURPLE;
            }
        }
    }
}

// -----------------  DRAW THE WORLD  -----------------------------------------------

void world::draw(int pid, double center_x, double center_y, double zoom)
{
    int w, h, x, y;

    w = WORLD_WIDTH / zoom;
    h = WORLD_HEIGHT / zoom;
    x = center_x - w/2;
    y = center_y - h/2;

    d.texture_draw(texture, x, y, w, h, pid);
}

// -----------------  EDIT STATIC PIXELS SUPPORT  -----------------------------------

void world::create_road_slice(double &x, double &y, double dir)
{
    double dpx, dpy, tmpx, tmpy;
    const double distance = 0.5;

    dir += 270;

    dpy = distance * sin((dir+90) * (M_PI/180.0));
    dpx = distance * cos((dir+90) * (M_PI/180.0));

    set_static_pixel(x,y,display::YELLOW);

    tmpx = x;
    tmpy = y;
    for (int i = 1; i <= 24; i++) {
        tmpx += dpx;
        tmpy += dpy;
        if (get_static_pixel(tmpx,tmpy) == display::GREEN) {
            set_static_pixel(tmpx,tmpy,display::BLACK);
        }
    }

    tmpx = x;
    tmpy = y;
    for (int i = 1; i <= 24; i++) {
        tmpx -= dpx;
        tmpy -= dpy;
        if (get_static_pixel(tmpx,tmpy) == display::GREEN) {
            set_static_pixel(tmpx,tmpy,display::BLACK);
        }
    }
}

void world::set_static_pixel(double x, double y, unsigned char p)
{
    int ix = x + .5;
    int iy = y + .5;

    if (ix < 0 || ix >= WORLD_WIDTH || iy < 0 || iy >= WORLD_HEIGHT) {
        return;
    }

    static_pixels[iy][ix] = p;
    pixels[iy][ix] = p;
    d.texture_set_pixel(texture, ix, iy, p);
}

unsigned char world::get_static_pixel(double x, double y)
{
    int ix = x + .5;
    int iy = y + .5;

    if (ix < 0 || ix >= WORLD_WIDTH || iy < 0 || iy >= WORLD_HEIGHT) {
        ERROR("ix " << ix << " iy " << iy << endl);
        return display::GREEN;
    }

    return static_pixels[iy][ix];
}

void world::clear()
{
    memset(static_pixels, display::GREEN, WORLD_WIDTH*WORLD_HEIGHT);
    memcpy(pixels, static_pixels, WORLD_WIDTH*WORLD_HEIGHT);
    d.texture_destroy(texture);
    texture = d.texture_create(reinterpret_cast<unsigned char *>(static_pixels),
                                             WORLD_WIDTH, WORLD_HEIGHT);
}

void world::read()
{
    ifstream ifs;

    read_ok_flag = false;
    ifs.open(filename, ios::in|ios::ate|ios::binary);
    if (!ifs.is_open()) {
        ERROR(filename << " does not exist" << endl);
        return;
    }
    if (ifs.tellg() != WORLD_WIDTH*WORLD_HEIGHT) {
        ERROR(filename << " has incorrect size" << endl);
        return;
    }
    ifs.seekg(0,ios::beg);
    ifs.read(reinterpret_cast<char*>(static_pixels), WORLD_WIDTH*WORLD_HEIGHT);
    if (!ifs.good()) {
        ERROR(filename << " read failed" << endl);
        return;
    }
    read_ok_flag = true;

    memcpy(pixels, static_pixels, WORLD_WIDTH*WORLD_HEIGHT);

    d.texture_destroy(texture);
    texture = d.texture_create(reinterpret_cast<unsigned char *>(static_pixels),
                               WORLD_WIDTH, WORLD_HEIGHT);
}

void world::write()
{
    ofstream ofs;

    write_ok_flag = false;
    ofs.open(filename, ios::out|ios::binary|ios::trunc);
    if (!ofs.is_open()) {
        ERROR(filename << " create failed" << endl);
        return;
    }
    ofs.write(reinterpret_cast<char*>(static_pixels), WORLD_WIDTH*WORLD_HEIGHT);
    if (!ofs.good()) {
        ERROR(filename << " write failed" << endl);
        return;
    }
    write_ok_flag = true;
}
<|endoftext|>