<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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

*/

#include "libtorrent/pch.hpp"

#include <string>
#include <stdexcept>
#include <sstream>
#include <iomanip>
#include <cctype>
#include <algorithm>
#include <iostream>

#include <boost/optional.hpp>

#include "libtorrent/assert.hpp"

namespace libtorrent
{
	std::string unescape_string(std::string const& s)
	{
		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
		{
			if(*i == '+')
			{
				ret += ' ';
			}
			else if (*i != '%')
			{
				ret += *i;
			}
			else
			{
				++i;
				if (i == s.end())
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				int high;
				if(*i >= '0' && *i <= '9') high = *i - '0';
				else if(*i >= 'A' && *i <= 'F') high = *i + 10 - 'A';
				else if(*i >= 'a' && *i <= 'f') high = *i + 10 - 'a';
				else
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				++i;
				if (i == s.end())
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				int low;
				if(*i >= '0' && *i <= '9') low = *i - '0';
				else if(*i >= 'A' && *i <= 'F') low = *i + 10 - 'A';
				else if(*i >= 'a' && *i <= 'f') low = *i + 10 - 'a';
				else
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				ret += char(high * 16 + low);
			}
		}
		return ret;
	}

	std::string escape_string(const char* str, int len)
	{
		TORRENT_ASSERT(str != 0);
		TORRENT_ASSERT(len >= 0);
		// http://www.ietf.org/rfc/rfc2396.txt
		// section 2.3
		// some trackers seems to require that ' is escaped
//		static const char unreserved_chars[] = "-_.!~*'()";
		static const char unreserved_chars[] = "-_.!~*()"
			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
			"0123456789";

		std::stringstream ret;
		ret << std::hex << std::setfill('0');
		for (int i = 0; i < len; ++i)
		{
			if (std::count(
					unreserved_chars
					, unreserved_chars+sizeof(unreserved_chars)-1
					, *str))
			{
				ret << *str;
			}
			else
			{
				ret << '%'
					<< std::setw(2)
					<< (int)static_cast<unsigned char>(*str);
			}
			++str;
		}
		return ret.str();
	}

	std::string escape_path(const char* str, int len)
	{
		TORRENT_ASSERT(str != 0);
		TORRENT_ASSERT(len >= 0);
		static const char unreserved_chars[] = "/-_.!~*()"
			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
			"0123456789";

		std::stringstream ret;
		ret << std::hex << std::setfill('0');
		for (int i = 0; i < len; ++i)
		{
			if (std::count(
					unreserved_chars
					, unreserved_chars+sizeof(unreserved_chars)-1
					, *str))
			{
				ret << *str;
			}
			else
			{
				ret << '%'
					<< std::setw(2)
					<< (int)static_cast<unsigned char>(*str);
			}
			++str;
		}
		return ret.str();
	}

	std::string base64encode(const std::string& s)
	{
		static const char base64_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
			'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
			'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
			'w', 'x', 'y', 'z', '0', '1', '2', '3',
			'4', '5', '6', '7', '8', '9', '+', '/'
		};

		unsigned char inbuf[3];
		unsigned char outbuf[4];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			// available input is 1,2 or 3 bytes
			// since we read 3 bytes at a time at most
			int available_input = (std::min)(3, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+3, 0);

			// read a chunk of input into inbuf
			std::copy(i, i + available_input, inbuf);
			i += available_input;

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xfc) >> 2;
			outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
			outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
			outbuf[3] = inbuf[2] & 0x3f;

			// write output
			for (int j = 0; j < available_input+1; ++j)
			{
				ret += base64_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 3 - available_input; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	std::string base32encode(std::string const& s)
	{
		static const char base32_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', '2', '3', '4', '5', '6', '7'
		};

		int input_output_mapping[] = {0, 2, 4, 5, 7, 8};

		unsigned char inbuf[5];
		unsigned char outbuf[8];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			int available_input = (std::min)(5, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+5, 0);

			// read a chunk of input into inbuf
			std::copy(i, i + available_input, inbuf);
			i += available_input;

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xf8) >> 3;
			outbuf[1] = ((inbuf[0] & 0x07) << 2) | ((inbuf[1] & 0xc0) >> 6);
			outbuf[2] = ((inbuf[1] & 0x3e) >> 1);
			outbuf[3] = ((inbuf[1] & 0x01) << 4) | ((inbuf[2] & 0xf0) >> 4);
			outbuf[4] = ((inbuf[2] & 0x0f) << 1) | ((inbuf[3] & 0x80) >> 7);
			outbuf[5] = ((inbuf[3] & 0x7c) >> 2);
			outbuf[6] = ((inbuf[3] & 0x03) << 3) | ((inbuf[4] & 0xe0) >> 5);
			outbuf[7] = inbuf[4] & 0x1f;

			// write output
			int num_out = input_output_mapping[available_input];
			for (int j = 0; j < num_out; ++j)
			{
				ret += base32_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 8 - num_out; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	std::string base32decode(std::string const& s)
	{
		unsigned char inbuf[8];
		unsigned char outbuf[5];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			int available_input = (std::min)(8, (int)std::distance(i, s.end()));

			int pad_start = 0;
			if (available_input < 8) pad_start = available_input;

			// clear input buffer
			std::fill(inbuf, inbuf+8, 0);
			for (int j = 0; j < available_input; ++j)
			{
				char in = std::toupper(*i++);
				if (in >= 'A' && in <= 'Z')
					inbuf[j] = in - 'A';
				else if (in >= '2' && in <= '7')
					inbuf[j] = in - '2' + ('Z' - 'A') + 1;
				else if (in == '=')
				{
					inbuf[j] = 0;
					if (pad_start == 0) pad_start = j;
				}
				else if (in == '1')
					inbuf[j] = 'I' - 'A';
				else
					return std::string();
				TORRENT_ASSERT(inbuf[j] == (inbuf[j] & 0x1f));
			}

			// decode inbuf to outbuf
			outbuf[0] = inbuf[0] << 3;
			outbuf[0] |= inbuf[1] >> 2;
			outbuf[1] = (inbuf[1] & 0x3) << 6;
			outbuf[1] |= inbuf[2] << 1;
			outbuf[1] |= (inbuf[3] & 0x10) >> 4;
			outbuf[2] = (inbuf[3] & 0x0f) << 4;
			outbuf[2] |= (inbuf[4] & 0x1e) >> 1;
			outbuf[3] = (inbuf[4] & 0x01) << 7;
			outbuf[3] |= (inbuf[5] & 0x1f) << 2;
			outbuf[3] |= (inbuf[6] & 0x18) >> 3;
			outbuf[4] = (inbuf[6] & 0x07) << 5;
			outbuf[4] |= inbuf[7];

			int input_output_mapping[] = {5, 1, 1, 2, 2, 3, 4, 4, 5};
			int num_out = input_output_mapping[pad_start];

			// write output
			std::copy(outbuf, outbuf + num_out, std::back_inserter(ret));
		}
		return ret;
	}

	boost::optional<std::string> url_has_argument(
		std::string const& url, std::string argument)
	{
		size_t i = url.find('?');
		if (i == std::string::npos) return boost::optional<std::string>();
		++i;

		argument += '=';

		if (url.compare(i, argument.size(), argument) == 0)
		{
			size_t pos = i + argument.size();
			return url.substr(pos, url.find('&', pos) - pos);
		}
		argument.insert(0, "&");
		i = url.find(argument, i);
		if (i == std::string::npos) return boost::optional<std::string>();
		size_t pos = i + argument.size();
		return url.substr(pos, url.find('&', pos) - pos);
	}

	TORRENT_EXPORT std::string to_hex(std::string const& s)
	{
		std::string ret;
		char* digits = "0123456789abcdef";
		for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
		{
			ret += digits[((unsigned char)*i) >> 4];
			ret += digits[((unsigned char)*i) & 0xf];
		}
		return ret;
	}

}

<commit_msg>fixed illegal type conversion<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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

*/

#include "libtorrent/pch.hpp"

#include <string>
#include <stdexcept>
#include <sstream>
#include <iomanip>
#include <cctype>
#include <algorithm>
#include <iostream>

#include <boost/optional.hpp>

#include "libtorrent/assert.hpp"

namespace libtorrent
{
	std::string unescape_string(std::string const& s)
	{
		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
		{
			if(*i == '+')
			{
				ret += ' ';
			}
			else if (*i != '%')
			{
				ret += *i;
			}
			else
			{
				++i;
				if (i == s.end())
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				int high;
				if(*i >= '0' && *i <= '9') high = *i - '0';
				else if(*i >= 'A' && *i <= 'F') high = *i + 10 - 'A';
				else if(*i >= 'a' && *i <= 'f') high = *i + 10 - 'a';
				else
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				++i;
				if (i == s.end())
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				int low;
				if(*i >= '0' && *i <= '9') low = *i - '0';
				else if(*i >= 'A' && *i <= 'F') low = *i + 10 - 'A';
				else if(*i >= 'a' && *i <= 'f') low = *i + 10 - 'a';
				else
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				ret += char(high * 16 + low);
			}
		}
		return ret;
	}

	std::string escape_string(const char* str, int len)
	{
		TORRENT_ASSERT(str != 0);
		TORRENT_ASSERT(len >= 0);
		// http://www.ietf.org/rfc/rfc2396.txt
		// section 2.3
		// some trackers seems to require that ' is escaped
//		static const char unreserved_chars[] = "-_.!~*'()";
		static const char unreserved_chars[] = "-_.!~*()"
			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
			"0123456789";

		std::stringstream ret;
		ret << std::hex << std::setfill('0');
		for (int i = 0; i < len; ++i)
		{
			if (std::count(
					unreserved_chars
					, unreserved_chars+sizeof(unreserved_chars)-1
					, *str))
			{
				ret << *str;
			}
			else
			{
				ret << '%'
					<< std::setw(2)
					<< (int)static_cast<unsigned char>(*str);
			}
			++str;
		}
		return ret.str();
	}

	std::string escape_path(const char* str, int len)
	{
		TORRENT_ASSERT(str != 0);
		TORRENT_ASSERT(len >= 0);
		static const char unreserved_chars[] = "/-_.!~*()"
			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
			"0123456789";

		std::stringstream ret;
		ret << std::hex << std::setfill('0');
		for (int i = 0; i < len; ++i)
		{
			if (std::count(
					unreserved_chars
					, unreserved_chars+sizeof(unreserved_chars)-1
					, *str))
			{
				ret << *str;
			}
			else
			{
				ret << '%'
					<< std::setw(2)
					<< (int)static_cast<unsigned char>(*str);
			}
			++str;
		}
		return ret.str();
	}

	std::string base64encode(const std::string& s)
	{
		static const char base64_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
			'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
			'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
			'w', 'x', 'y', 'z', '0', '1', '2', '3',
			'4', '5', '6', '7', '8', '9', '+', '/'
		};

		unsigned char inbuf[3];
		unsigned char outbuf[4];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			// available input is 1,2 or 3 bytes
			// since we read 3 bytes at a time at most
			int available_input = (std::min)(3, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+3, 0);

			// read a chunk of input into inbuf
			std::copy(i, i + available_input, inbuf);
			i += available_input;

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xfc) >> 2;
			outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
			outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
			outbuf[3] = inbuf[2] & 0x3f;

			// write output
			for (int j = 0; j < available_input+1; ++j)
			{
				ret += base64_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 3 - available_input; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	std::string base32encode(std::string const& s)
	{
		static const char base32_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', '2', '3', '4', '5', '6', '7'
		};

		int input_output_mapping[] = {0, 2, 4, 5, 7, 8};

		unsigned char inbuf[5];
		unsigned char outbuf[8];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			int available_input = (std::min)(5, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+5, 0);

			// read a chunk of input into inbuf
			std::copy(i, i + available_input, inbuf);
			i += available_input;

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xf8) >> 3;
			outbuf[1] = ((inbuf[0] & 0x07) << 2) | ((inbuf[1] & 0xc0) >> 6);
			outbuf[2] = ((inbuf[1] & 0x3e) >> 1);
			outbuf[3] = ((inbuf[1] & 0x01) << 4) | ((inbuf[2] & 0xf0) >> 4);
			outbuf[4] = ((inbuf[2] & 0x0f) << 1) | ((inbuf[3] & 0x80) >> 7);
			outbuf[5] = ((inbuf[3] & 0x7c) >> 2);
			outbuf[6] = ((inbuf[3] & 0x03) << 3) | ((inbuf[4] & 0xe0) >> 5);
			outbuf[7] = inbuf[4] & 0x1f;

			// write output
			int num_out = input_output_mapping[available_input];
			for (int j = 0; j < num_out; ++j)
			{
				ret += base32_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 8 - num_out; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	std::string base32decode(std::string const& s)
	{
		unsigned char inbuf[8];
		unsigned char outbuf[5];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			int available_input = (std::min)(8, (int)std::distance(i, s.end()));

			int pad_start = 0;
			if (available_input < 8) pad_start = available_input;

			// clear input buffer
			std::fill(inbuf, inbuf+8, 0);
			for (int j = 0; j < available_input; ++j)
			{
				char in = std::toupper(*i++);
				if (in >= 'A' && in <= 'Z')
					inbuf[j] = in - 'A';
				else if (in >= '2' && in <= '7')
					inbuf[j] = in - '2' + ('Z' - 'A') + 1;
				else if (in == '=')
				{
					inbuf[j] = 0;
					if (pad_start == 0) pad_start = j;
				}
				else if (in == '1')
					inbuf[j] = 'I' - 'A';
				else
					return std::string();
				TORRENT_ASSERT(inbuf[j] == (inbuf[j] & 0x1f));
			}

			// decode inbuf to outbuf
			outbuf[0] = inbuf[0] << 3;
			outbuf[0] |= inbuf[1] >> 2;
			outbuf[1] = (inbuf[1] & 0x3) << 6;
			outbuf[1] |= inbuf[2] << 1;
			outbuf[1] |= (inbuf[3] & 0x10) >> 4;
			outbuf[2] = (inbuf[3] & 0x0f) << 4;
			outbuf[2] |= (inbuf[4] & 0x1e) >> 1;
			outbuf[3] = (inbuf[4] & 0x01) << 7;
			outbuf[3] |= (inbuf[5] & 0x1f) << 2;
			outbuf[3] |= (inbuf[6] & 0x18) >> 3;
			outbuf[4] = (inbuf[6] & 0x07) << 5;
			outbuf[4] |= inbuf[7];

			int input_output_mapping[] = {5, 1, 1, 2, 2, 3, 4, 4, 5};
			int num_out = input_output_mapping[pad_start];

			// write output
			std::copy(outbuf, outbuf + num_out, std::back_inserter(ret));
		}
		return ret;
	}

	boost::optional<std::string> url_has_argument(
		std::string const& url, std::string argument)
	{
		size_t i = url.find('?');
		if (i == std::string::npos) return boost::optional<std::string>();
		++i;

		argument += '=';

		if (url.compare(i, argument.size(), argument) == 0)
		{
			size_t pos = i + argument.size();
			return url.substr(pos, url.find('&', pos) - pos);
		}
		argument.insert(0, "&");
		i = url.find(argument, i);
		if (i == std::string::npos) return boost::optional<std::string>();
		size_t pos = i + argument.size();
		return url.substr(pos, url.find('&', pos) - pos);
	}

	TORRENT_EXPORT std::string to_hex(std::string const& s)
	{
		std::string ret;
		char const* digits = "0123456789abcdef";
		for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
		{
			ret += digits[((unsigned char)*i) >> 4];
			ret += digits[((unsigned char)*i) & 0xf];
		}
		return ret;
	}

}

<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "FormattedTable.h"
#include "MooseError.h"

#include <iomanip>
#include <iterator>

// Used for terminal width
#include <sys/ioctl.h>

const unsigned short FormattedTable::_column_width = 15;

FormattedTable::FormattedTable() :
    _stream_open(false),
    _last_key(-1)
{}

FormattedTable::FormattedTable(const FormattedTable &o) :
    _column_names(o._column_names),
    _stream_open(o._stream_open),
    _last_key(o._last_key)
{
  if (_stream_open)
    mooseError ("Copying a FormattedTable with an open stream is not supported");

  std::map<Real, std::map<std::string, Real> >::const_iterator it = o._data.begin();

  for ( ; it != o._data.end(); ++it)
    _data[it->first] = it->second;
}

FormattedTable::~FormattedTable()
{
  if (_stream_open)
  {
    _output_file.flush();
    _output_file.close();
    _stream_open = false;
  }
}

bool
FormattedTable::empty() const
{
  return _last_key == -1;
}

void
FormattedTable::addData(const std::string & name, Real value, Real time)
{
  _data[time][name] = value;
  _column_names.insert(name);
  _last_key = time;
}

Real &
FormattedTable::getLastData(const std::string & name)
{
  mooseAssert(_last_key != -1, "No Data stored in the FormattedTable");

  std::map<std::string, Real>::iterator it = (_data[_last_key]).find(name);
  if (it == (_data[_last_key]).end())
    mooseError("No Data found for name: " + name);

  return it->second;
}

void
FormattedTable::printOmittedRow(std::ostream & out, std::map<std::string, unsigned short> & col_widths,
                                std::set<std::string>::iterator & col_begin, std::set<std::string>::iterator & col_end) const
{
  printNoDataRow(':', ' ', out, col_widths, col_begin, col_end);
}

void
FormattedTable::printRowDivider(std::ostream & out, std::map<std::string, unsigned short> & col_widths,
                                std::set<std::string>::iterator & col_begin, std::set<std::string>::iterator & col_end) const
{
  printNoDataRow('+', '-', out, col_widths, col_begin, col_end);
}

void
FormattedTable::printNoDataRow(char intersect_char, char fill_char,
                               std::ostream & out, std::map<std::string, unsigned short> & col_widths,
                               std::set<std::string>::iterator & col_begin, std::set<std::string>::iterator & col_end) const
{
  out.fill(fill_char);
  out << std::right << intersect_char << std::setw(_column_width+2) << intersect_char;
  for (std::set<std::string>::iterator header = col_begin; header != col_end; ++header)
  {
    out << std::setw(col_widths[*header]+2) << intersect_char;
  }
  out << "\n";

  // Clear the fill character
  out.fill(' ');
}

void
FormattedTable::printTable(const std::string & file_name)
{
  // We only want to do file I/O on processor zero
  if (libMesh::processor_id() != 0)
    return;

  if (!_stream_open)
  {
    _output_file.open(file_name.c_str(), std::ios::trunc);
    _stream_open = true;
  }
  printTable(_output_file);
}

void
FormattedTable::printTable(std::ostream & out, unsigned int last_n_entries)
{
  printTable(out, last_n_entries, false);
}

void
FormattedTable::printTable(std::ostream & out, unsigned int last_n_entries, bool fit_to_term_width)
{
  unsigned int term_width;
  if (fit_to_term_width)
    term_width = getTermWidth();
  else
    term_width = std::numeric_limits<unsigned int>::max();

  std::set<std::string>::iterator col_it = _column_names.begin();
  std::set<std::string>::iterator col_end = _column_names.end();

  std::set<std::string>::iterator curr_begin = col_it;
  std::set<std::string>::iterator curr_end;
  while (col_it != col_end)
  {
    std::map<std::string, unsigned short> col_widths;
    unsigned int curr_width = _column_width + 4;
    unsigned int cols_in_group = 0;
    while (curr_width < term_width && col_it != col_end)
    {
      curr_end = col_it;
      col_widths[*col_it] = col_it->length() > _column_width ? col_it->length()+1 : _column_width;

      curr_width += col_widths[*col_it] + 3;
      ++col_it;
      ++cols_in_group;
    }
    if (col_it != col_end && cols_in_group >= 2)
    {
      curr_width -= col_widths[*curr_end];
      col_widths.erase(*curr_end);
      col_it = curr_end;
    }

    printTablePiece(out, last_n_entries, col_widths, curr_begin, curr_end);
    curr_begin = curr_end;
  }
}

void
FormattedTable::printTablePiece(std::ostream & out, unsigned int last_n_entries, std::map<std::string, unsigned short> & col_widths,
                                std::set<std::string>::iterator & col_begin, std::set<std::string>::iterator & col_end)
{
  std::map<Real, std::map<std::string, Real> >::iterator i;
  std::set<std::string>::iterator header;

  /**
   * Print out the header row
   */
  printRowDivider(out, col_widths, col_begin, col_end);
  out << "|" << std::setw(_column_width) << std::left << " time" << " |";
  for (header = col_begin; header != col_end; ++header)
  {
    out << " " << std::setw(col_widths[*header])  <<  *header << "|";
  }
  out << "\n";
  printRowDivider(out, col_widths, col_begin, col_end);

  /**
   * Skip over values that we don't want to see.
   * This step may be able to optimized if the table gets really big.  We could
   * iterate backwards from the end and create a new forward iterator from there.
   */
  i = _data.begin();
  if (last_n_entries)
  {
    if (_data.size() > last_n_entries)
      // Print a blank row to indicate that values have been ommited
      printOmittedRow(out, col_widths, col_begin, col_end);

    for (int counter=0; counter < static_cast<int>(_data.size() - last_n_entries); ++counter)
      ++i;
  }
  // Now print the remaining data rows
  for ( ; i != _data.end(); ++i)
  {
    out << "|" << std::right << std::setw(_column_width) << i->first << " |";
    for (header = col_begin; header != col_end; ++header)
    {
      std::map<std::string, Real> &tmp = i->second;
      out << std::setw(col_widths[*header]) << tmp[*header] << " |";
    }
    out << "\n";
  }

  printRowDivider(out, col_widths, col_begin, col_end);
}

void
FormattedTable::printCSV(const std::string & file_name, int interval)
{
  std::map<Real, std::map<std::string, Real> >::iterator i;
  std::set<std::string>::iterator header;

  // We only want to do file I/O on processor zero
  if (libMesh::processor_id() != 0)
    return;

  if (!_stream_open)
  {
    _output_file.open(file_name.c_str(), std::ios::trunc | std::ios::out);
    _stream_open = true;
  }

  _output_file.seekp(0, std::ios::beg);
  _output_file << "time";
  for (header = _column_names.begin(); header != _column_names.end(); ++header)
  {
    _output_file << "," << *header;
  }
  _output_file << "\n";

  int counter = 0;
  for (i = _data.begin(); i != _data.end(); ++i)
  {
    if (counter++ % interval == 0)
    {
      _output_file << i->first;
      for (header = _column_names.begin(); header != _column_names.end(); ++header)
      {
        std::map<std::string, Real> &tmp = i->second;
        _output_file << "," << std::setprecision(14) << tmp[*header];
      }
      _output_file << "\n";
    }
  }
  _output_file << "\n";
  _output_file.flush();
}

// const strings that the gnuplot generator needs
namespace gnuplot
{
  const std::string before_terminal = "set terminal ";
  const std::string before_ext      = "\nset output 'all";
  const std::string after_ext       = "'\nset title 'All Postprocessors'\nset xlabel 'time'\nset ylabel 'values'\nplot";
}

void
FormattedTable::makeGnuplot(const std::string & base_file, const std::string & format)
{
  // TODO: run this once at end of simulation, right now it runs every iteration
  // TODO: do I need to be more careful escaping column names?
  // Note: open and close the files each time, having open files may mess with gnuplot
  std::map<Real, std::map<std::string, Real> >::iterator i;
  std::set<std::string>::iterator header;

  // supported filetypes: ps, png
  std::string extension, terminal;
  if (format == "png")
  {
    extension = ".png"; terminal = "png";
  }
  else if (format == "ps")
  {
    extension = ".ps";  terminal = "postscript";
  }
  else if (format == "gif")
  {
    extension = ".gif"; terminal = "gif";
  }
  else
  {
    mooseError("gnuplot format \"" + format + "\" is not supported.");
  }

  // Write the data to disk
  std::string dat_name = base_file + ".dat";
  std::ofstream datfile;
  datfile.open(dat_name.c_str(), std::ios::trunc | std::ios::out);

  datfile << "# time";
  for (header = _column_names.begin(); header != _column_names.end(); ++header)
    datfile << '\t' << *header;
  datfile << '\n';

  for (i = _data.begin(); i != _data.end(); ++i)
  {
    datfile << i->first;
    for (header = _column_names.begin(); header != _column_names.end(); ++header)
    {
      std::map<std::string, Real> &tmp = i->second;
      datfile << '\t' << tmp[*header];
    }
    datfile << '\n';
  }
  datfile.flush();
  datfile.close();

  // Write the gnuplot script
  std::string gp_name = base_file + ".gp";
  std::ofstream gpfile;
  gpfile.open(gp_name.c_str(), std::ios::trunc | std::ios::out);

  gpfile << gnuplot::before_terminal << terminal << gnuplot::before_ext << extension << gnuplot::after_ext;

  // plot all postprocessors in one plot
  int column = 2;
  for (header = _column_names.begin(); header != _column_names.end(); ++header)
  {
    gpfile << " '" << dat_name << "' using 1:" << column << " title '" << *header << "' with linespoints";
    column++;
    if ( column - 2 < (int) _column_names.size() )
      gpfile << ", \\\n";
  }
  gpfile << "\n\n";

  // plot the postprocessors individually
  column = 2;
  for (header = _column_names.begin(); header != _column_names.end(); ++header)
  {
    gpfile << "set output '" << *header << extension << "'\n";
    gpfile << "set ylabel '" << *header << "'\n";
    gpfile << "plot '" << dat_name << "' using 1:" << column << " title '" << *header << "' with linespoints\n\n";
    column++;
  }

  gpfile.flush();
  gpfile.close();

  // Run the gnuplot script
/* We aren't going to run gnuplot automatically

  if (!system(NULL))
    mooseError("No way to run gnuplot on this computer");

  std::string command = "gnuplot " + gp_name;
  if (system(command.c_str()))
    mooseError("gnuplot command failed");
*/
}

void
FormattedTable::clear()
{
  _data.clear();
}

unsigned int
FormattedTable::getTermWidth() const
{
  struct winsize w;
  ioctl(0, TIOCGWINSZ, &w);

  return w.ws_col;
}
<commit_msg>Let's try one more thing... - refs #1938<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "FormattedTable.h"
#include "MooseError.h"

#include <iomanip>
#include <iterator>

// Used for terminal width
#include <sys/ioctl.h>

const unsigned short FormattedTable::_column_width = 15;

FormattedTable::FormattedTable() :
    _stream_open(false),
    _last_key(-1)
{}

FormattedTable::FormattedTable(const FormattedTable &o) :
    _column_names(o._column_names),
    _stream_open(o._stream_open),
    _last_key(o._last_key)
{
  if (_stream_open)
    mooseError ("Copying a FormattedTable with an open stream is not supported");

  std::map<Real, std::map<std::string, Real> >::const_iterator it = o._data.begin();

  for ( ; it != o._data.end(); ++it)
    _data[it->first] = it->second;
}

FormattedTable::~FormattedTable()
{
  if (_stream_open)
  {
    _output_file.flush();
    _output_file.close();
    _stream_open = false;
  }
}

bool
FormattedTable::empty() const
{
  return _last_key == -1;
}

void
FormattedTable::addData(const std::string & name, Real value, Real time)
{
  _data[time][name] = value;
  _column_names.insert(name);
  _last_key = time;
}

Real &
FormattedTable::getLastData(const std::string & name)
{
  mooseAssert(_last_key != -1, "No Data stored in the FormattedTable");

  std::map<std::string, Real>::iterator it = (_data[_last_key]).find(name);
  if (it == (_data[_last_key]).end())
    mooseError("No Data found for name: " + name);

  return it->second;
}

void
FormattedTable::printOmittedRow(std::ostream & out, std::map<std::string, unsigned short> & col_widths,
                                std::set<std::string>::iterator & col_begin, std::set<std::string>::iterator & col_end) const
{
  printNoDataRow(':', ' ', out, col_widths, col_begin, col_end);
}

void
FormattedTable::printRowDivider(std::ostream & out, std::map<std::string, unsigned short> & col_widths,
                                std::set<std::string>::iterator & col_begin, std::set<std::string>::iterator & col_end) const
{
  printNoDataRow('+', '-', out, col_widths, col_begin, col_end);
}

void
FormattedTable::printNoDataRow(char intersect_char, char fill_char,
                               std::ostream & out, std::map<std::string, unsigned short> & col_widths,
                               std::set<std::string>::iterator & col_begin, std::set<std::string>::iterator & col_end) const
{
  out.fill(fill_char);
  out << std::right << intersect_char << std::setw(_column_width+2) << intersect_char;
  for (std::set<std::string>::iterator header = col_begin; header != col_end; ++header)
  {
    out << std::setw(col_widths[*header]+2) << intersect_char;
  }
  out << "\n";

  // Clear the fill character
  out.fill(' ');
}

void
FormattedTable::printTable(const std::string & file_name)
{
  // We only want to do file I/O on processor zero
  if (libMesh::processor_id() != 0)
    return;

  if (!_stream_open)
  {
    _output_file.open(file_name.c_str(), std::ios::trunc);
    _stream_open = true;
  }
  printTable(_output_file);
}

void
FormattedTable::printTable(std::ostream & out, unsigned int last_n_entries)
{
  printTable(out, last_n_entries, false);
}

void
FormattedTable::printTable(std::ostream & out, unsigned int last_n_entries, bool fit_to_term_width)
{
  unsigned int term_width;
  if (fit_to_term_width)
    term_width = getTermWidth();
  else
    term_width = std::numeric_limits<unsigned int>::max();

  std::set<std::string>::iterator col_it = _column_names.begin();
  std::set<std::string>::iterator col_end = _column_names.end();

  std::set<std::string>::iterator curr_begin = col_it;
  std::set<std::string>::iterator curr_end;
  while (col_it != col_end)
  {
    std::map<std::string, unsigned short> col_widths;
    unsigned int curr_width = _column_width + 4;
    unsigned int cols_in_group = 0;
    while (curr_width < term_width && col_it != col_end)
    {
      curr_end = col_it;
      col_widths[*col_it] = col_it->length() > _column_width ? col_it->length()+1 : _column_width;

      curr_width += col_widths[*col_it] + 3;
      ++col_it;
      ++cols_in_group;
    }
    if (col_it != col_end && cols_in_group >= 2)
    {
      curr_width -= col_widths[*curr_end];
      col_widths.erase(*curr_end);
      col_it = curr_end;
    }

    printTablePiece(out, last_n_entries, col_widths, curr_begin, curr_end);
    curr_begin = curr_end;
  }
}

void
FormattedTable::printTablePiece(std::ostream & out, unsigned int last_n_entries, std::map<std::string, unsigned short> & col_widths,
                                std::set<std::string>::iterator & col_begin, std::set<std::string>::iterator & col_end)
{
  std::map<Real, std::map<std::string, Real> >::iterator i;
  std::set<std::string>::iterator header;

  /**
   * Print out the header row
   */
  printRowDivider(out, col_widths, col_begin, col_end);
  out << "|" << std::setw(_column_width) << std::left << " time" << " |";
  for (header = col_begin; header != col_end; ++header)
  {
    out << " " << std::setw(col_widths[*header])  <<  *header << "|";
  }
  out << "\n";
  printRowDivider(out, col_widths, col_begin, col_end);

  /**
   * Skip over values that we don't want to see.
   * This step may be able to optimized if the table gets really big.  We could
   * iterate backwards from the end and create a new forward iterator from there.
   */
  i = _data.begin();
  if (last_n_entries)
  {
    if (_data.size() > last_n_entries)
      // Print a blank row to indicate that values have been ommited
      printOmittedRow(out, col_widths, col_begin, col_end);

    for (int counter=0; counter < static_cast<int>(_data.size() - last_n_entries); ++counter)
      ++i;
  }
  // Now print the remaining data rows
  for ( ; i != _data.end(); ++i)
  {
    out << "|" << std::right << std::setw(_column_width) << i->first << " |";
    for (header = col_begin; header != col_end; ++header)
    {
      std::map<std::string, Real> &tmp = i->second;
      out << std::setw(col_widths[*header]) << tmp[*header] << " |";
    }
    out << "\n";
  }

  printRowDivider(out, col_widths, col_begin, col_end);
}

void
FormattedTable::printCSV(const std::string & file_name, int interval)
{
  std::map<Real, std::map<std::string, Real> >::iterator i;
  std::set<std::string>::iterator header;

  // We only want to do file I/O on processor zero
  if (libMesh::processor_id() != 0)
    return;

  if (!_stream_open)
  {
    _output_file.open(file_name.c_str(), std::ios::trunc | std::ios::out);
    _stream_open = true;
  }

  _output_file.seekp(0, std::ios::beg);
  _output_file << "time";
  for (header = _column_names.begin(); header != _column_names.end(); ++header)
  {
    _output_file << "," << *header;
  }
  _output_file << "\n";

  int counter = 0;
  for (i = _data.begin(); i != _data.end(); ++i)
  {
    if (counter++ % interval == 0)
    {
      _output_file << i->first;
      for (header = _column_names.begin(); header != _column_names.end(); ++header)
      {
        std::map<std::string, Real> &tmp = i->second;
        _output_file << "," << std::setprecision(14) << tmp[*header];
      }
      _output_file << "\n";
    }
  }
  _output_file << "\n";
  _output_file.flush();
}

// const strings that the gnuplot generator needs
namespace gnuplot
{
  const std::string before_terminal = "set terminal ";
  const std::string before_ext      = "\nset output 'all";
  const std::string after_ext       = "'\nset title 'All Postprocessors'\nset xlabel 'time'\nset ylabel 'values'\nplot";
}

void
FormattedTable::makeGnuplot(const std::string & base_file, const std::string & format)
{
  // TODO: run this once at end of simulation, right now it runs every iteration
  // TODO: do I need to be more careful escaping column names?
  // Note: open and close the files each time, having open files may mess with gnuplot
  std::map<Real, std::map<std::string, Real> >::iterator i;
  std::set<std::string>::iterator header;

  // supported filetypes: ps, png
  std::string extension, terminal;
  if (format == "png")
  {
    extension = ".png"; terminal = "png";
  }
  else if (format == "ps")
  {
    extension = ".ps";  terminal = "postscript";
  }
  else if (format == "gif")
  {
    extension = ".gif"; terminal = "gif";
  }
  else
  {
    mooseError("gnuplot format \"" + format + "\" is not supported.");
  }

  // Write the data to disk
  std::string dat_name = base_file + ".dat";
  std::ofstream datfile;
  datfile.open(dat_name.c_str(), std::ios::trunc | std::ios::out);

  datfile << "# time";
  for (header = _column_names.begin(); header != _column_names.end(); ++header)
    datfile << '\t' << *header;
  datfile << '\n';

  for (i = _data.begin(); i != _data.end(); ++i)
  {
    datfile << i->first;
    for (header = _column_names.begin(); header != _column_names.end(); ++header)
    {
      std::map<std::string, Real> &tmp = i->second;
      datfile << '\t' << tmp[*header];
    }
    datfile << '\n';
  }
  datfile.flush();
  datfile.close();

  // Write the gnuplot script
  std::string gp_name = base_file + ".gp";
  std::ofstream gpfile;
  gpfile.open(gp_name.c_str(), std::ios::trunc | std::ios::out);

  gpfile << gnuplot::before_terminal << terminal << gnuplot::before_ext << extension << gnuplot::after_ext;

  // plot all postprocessors in one plot
  int column = 2;
  for (header = _column_names.begin(); header != _column_names.end(); ++header)
  {
    gpfile << " '" << dat_name << "' using 1:" << column << " title '" << *header << "' with linespoints";
    column++;
    if ( column - 2 < (int) _column_names.size() )
      gpfile << ", \\\n";
  }
  gpfile << "\n\n";

  // plot the postprocessors individually
  column = 2;
  for (header = _column_names.begin(); header != _column_names.end(); ++header)
  {
    gpfile << "set output '" << *header << extension << "'\n";
    gpfile << "set ylabel '" << *header << "'\n";
    gpfile << "plot '" << dat_name << "' using 1:" << column << " title '" << *header << "' with linespoints\n\n";
    column++;
  }

  gpfile.flush();
  gpfile.close();

  // Run the gnuplot script
/* We aren't going to run gnuplot automatically

  if (!system(NULL))
    mooseError("No way to run gnuplot on this computer");

  std::string command = "gnuplot " + gp_name;
  if (system(command.c_str()))
    mooseError("gnuplot command failed");
*/
}

void
FormattedTable::clear()
{
  _data.clear();
}

unsigned int
FormattedTable::getTermWidth() const
{
  struct winsize w;

  try
  {
    ioctl(0, TIOCGWINSZ, &w);
  }
  catch(...)
  {
    return std::numeric_limits<unsigned int>::max();
  }

  return w.ws_col;
}
<|endoftext|>


<commit_before>#include "display_buffer.hh"

#include "assert.hh"
#include "buffer.hh"
#include "buffer_utils.hh"
#include "face_registry.hh"
#include "utf8.hh"

#include "face_registry.hh"

namespace Kakoune
{

BufferIterator get_iterator(const Buffer& buffer, BufferCoord coord)
{
    // Correct one past the end of line as next line
    if (not buffer.is_end(coord) and coord.column == buffer[coord.line].length())
        coord = coord.line+1;
    return buffer.iterator_at(coord);
}

StringView DisplayAtom::content() const
{
    switch (m_type)
    {
        case Range:
        {
            auto line = (*m_buffer)[m_range.begin.line];
            if (m_range.begin.line == m_range.end.line)
                return line.substr(m_range.begin.column, m_range.end.column - m_range.begin.column);
            else if (m_range.begin.line+1 == m_range.end.line and m_range.end.column == 0)
                return line.substr(m_range.begin.column);
            break;
        }
        case Text:
        case ReplacedRange:
            return m_text;
    }
    kak_assert(false);
    return {};
}

ColumnCount DisplayAtom::length() const
{
    switch (m_type)
    {
        case Range:
            return utf8::column_distance(get_iterator(*m_buffer, m_range.begin),
                                         get_iterator(*m_buffer, m_range.end));
        case Text:
        case ReplacedRange:
            return m_text.column_length();
    }
    kak_assert(false);
    return 0;
}

void DisplayAtom::trim_begin(ColumnCount count)
{
    if (m_type == Range)
        m_range.begin = utf8::advance(get_iterator(*m_buffer, m_range.begin),
                                      get_iterator(*m_buffer, m_range.end),
                                      count).coord();
    else
        m_text = m_text.substr(count).str();
}

void DisplayAtom::trim_end(ColumnCount count)
{
    if (m_type == Range)
        m_range.end = utf8::advance(get_iterator(*m_buffer, m_range.end),
                                    get_iterator(*m_buffer, m_range.begin),
                                    -count).coord();
    else
        m_text = m_text.substr(0, m_text.column_length() - count).str();
}

DisplayLine::DisplayLine(AtomList atoms)
    : m_atoms(std::move(atoms))
{
    compute_range();
}

DisplayLine::iterator DisplayLine::split(iterator it, BufferCoord pos)
{
    kak_assert(it->type() == DisplayAtom::Range);
    kak_assert(it->begin() < pos);
    kak_assert(it->end() > pos);

    DisplayAtom atom = *it;
    atom.m_range.end = pos;
    it->m_range.begin = pos;
    return m_atoms.insert(it, std::move(atom));
}

DisplayLine::iterator DisplayLine::split(iterator it, ColumnCount count)
{
    kak_assert(count > 0);
    kak_assert(count < it->length());

    if (it->type() == DisplayAtom::Text or it->type() == DisplayAtom::ReplacedRange)
    {
        DisplayAtom atom = *it;
        atom.m_text = atom.m_text.substr(0, count).str();
        it->m_text = it->m_text.substr(count).str();
        return m_atoms.insert(it, std::move(atom));
    }
    auto pos = utf8::advance(get_iterator(it->buffer(), it->begin()),
                             get_iterator(it->buffer(), it->end()),
                             count).coord();
    return split(it, pos);
}

DisplayLine::iterator DisplayLine::insert(iterator it, DisplayAtom atom)
{
    if (atom.has_buffer_range())
    {
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    return m_atoms.insert(it, std::move(atom));
}

void DisplayLine::push_back(DisplayAtom atom)
{
    if (atom.has_buffer_range())
    {
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    m_atoms.push_back(std::move(atom));
}

DisplayLine::iterator DisplayLine::erase(iterator beg, iterator end)
{
    auto res = m_atoms.erase(beg, end);
    compute_range();
    return res;
}

void DisplayLine::optimize()
{
    if (m_atoms.empty())
        return;

    auto atom_it = m_atoms.begin();
    for (auto next_it = atom_it + 1; next_it != m_atoms.end(); ++next_it)
    {
        auto& atom = *atom_it;
        auto& next = *next_it;

        const auto type = atom.type();
        if (type == next.type() and atom.face == next.face)
        {
            if (type == DisplayAtom::Text)
                atom.m_text += next.m_text;
            else if ((type == DisplayAtom::Range or
                      type == DisplayAtom::ReplacedRange) and
                     next.begin() == atom.end())
            {
                atom.m_range.end = next.end();
                if (type == DisplayAtom::ReplacedRange)
                    atom.m_text += next.m_text;
            }
            else
                *++atom_it = std::move(*next_it);
        }
        else
            *++atom_it = std::move(*next_it);
    }
    m_atoms.erase(atom_it+1, m_atoms.end());
}

ColumnCount DisplayLine::length() const
{
    ColumnCount len = 0;
    for (auto& atom : m_atoms)
        len += atom.length();
    return len;
}

bool DisplayLine::trim(ColumnCount first_col, ColumnCount col_count)
{
    for (auto it = begin(); first_col > 0 and it != end(); )
    {
        auto len = it->length();
        if (len <= first_col)
        {
            m_atoms.erase(it);
            first_col -= len;
        }
        else
        {
            it->trim_begin(first_col);
            first_col = 0;
        }
    }
    auto it = begin();
    for (; it != end() and col_count > 0; ++it)
        col_count -= it->length();

    bool did_trim = it != end() || col_count < 0;
    if (col_count < 0)
        (it-1)->trim_end(-col_count);
    m_atoms.erase(it, end());

    compute_range();
    return did_trim;
}

const BufferRange init_range{ {INT_MAX, INT_MAX}, {INT_MIN, INT_MIN} };

void DisplayLine::compute_range()
{
    m_range = init_range;
    for (auto& atom : m_atoms)
    {
        if (not atom.has_buffer_range())
            continue;
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    if (m_range == init_range)
        m_range = { { 0, 0 }, { 0, 0 } };
    kak_assert(m_range.begin <= m_range.end);
}

void DisplayBuffer::compute_range()
{
    m_range = init_range;
    for (auto& line : m_lines)
    {
        m_range.begin  = std::min(line.range().begin, m_range.begin);
        m_range.end = std::max(line.range().end, m_range.end);
    }
    if (m_range == init_range)
        m_range = { { 0, 0 }, { 0, 0 } };
    kak_assert(m_range.begin <= m_range.end);
}

void DisplayBuffer::optimize()
{
    for (auto& line : m_lines)
        line.optimize();
}

DisplayLine parse_display_line(StringView line, const FaceRegistry& faces, const HashMap<String, DisplayLine>& builtins)
{
    DisplayLine res;
    bool was_antislash = false;
    auto pos = line.begin();
    String content;
    Face face;
    for (auto it = line.begin(), end = line.end(); it != end; ++it)
    {
        const char c = *it;
        if (c == '{')
        {
            if (was_antislash)
            {
                content += StringView{pos, it};
                content.back() = '{';
                pos = it + 1;
            }
            else
            {
                content += StringView{pos, it};
                res.push_back({std::move(content), face});
                content.clear();
                auto closing = std::find(it+1, end, '}');
                if (closing == end)
                    throw runtime_error("unclosed face definition");
                if (*(it+1) == '{' and closing+1 != end and *(closing+1) == '}')
                {
                    auto builtin_it = builtins.find(StringView{it+2, closing});
                    if (builtin_it == builtins.end())
                        throw runtime_error(format("undefined atom {}", StringView{it+2, closing}));
                    for (auto& atom : builtin_it->value)
                        res.push_back(atom);
                    // closing is now at the first char of "}}", advance it to the second
                    ++closing;
                }
                else if (closing == it+2 and *(it+1) == '\\')
                {
                    pos = closing + 1;
                    break;
                }
                else
                    face = faces[{it+1, closing}];
                it = closing;
                pos = closing + 1;
            }
        }
        if (c == '\n' or c == '\t') // line breaks and tabs are forbidden, replace with space
        {
            content += StringView{pos, it+1};
            content.back() = ' ';
            pos = it + 1;
        }

        if (c == '\\')
        {
            if (was_antislash)
            {
                content += StringView{pos, it};
                pos = it + 1;
                was_antislash = false;
            }
            else
                was_antislash = true;
        }
        else
            was_antislash = false;
    }
    content += StringView{pos, line.end()};
    if (not content.empty())
        res.push_back({std::move(content), face});
    return res;
}

String fix_atom_text(StringView str)
{
    String res;
    auto pos = str.begin();
    for (auto it = str.begin(), end = str.end(); it != end; ++it)
    {
        char c = *it;
        if (c <= 0x21 and c != ' ')
        {
            res += StringView{pos, it};
            res += String{Codepoint{(uint32_t)(0x2400 + c)}};
            pos = it+1;
        }
    }
    res += StringView{pos, str.end()};
    return res;
}

}
<commit_msg>Control character end at 0x1F<commit_after>#include "display_buffer.hh"

#include "assert.hh"
#include "buffer.hh"
#include "buffer_utils.hh"
#include "face_registry.hh"
#include "utf8.hh"

#include "face_registry.hh"

namespace Kakoune
{

BufferIterator get_iterator(const Buffer& buffer, BufferCoord coord)
{
    // Correct one past the end of line as next line
    if (not buffer.is_end(coord) and coord.column == buffer[coord.line].length())
        coord = coord.line+1;
    return buffer.iterator_at(coord);
}

StringView DisplayAtom::content() const
{
    switch (m_type)
    {
        case Range:
        {
            auto line = (*m_buffer)[m_range.begin.line];
            if (m_range.begin.line == m_range.end.line)
                return line.substr(m_range.begin.column, m_range.end.column - m_range.begin.column);
            else if (m_range.begin.line+1 == m_range.end.line and m_range.end.column == 0)
                return line.substr(m_range.begin.column);
            break;
        }
        case Text:
        case ReplacedRange:
            return m_text;
    }
    kak_assert(false);
    return {};
}

ColumnCount DisplayAtom::length() const
{
    switch (m_type)
    {
        case Range:
            return utf8::column_distance(get_iterator(*m_buffer, m_range.begin),
                                         get_iterator(*m_buffer, m_range.end));
        case Text:
        case ReplacedRange:
            return m_text.column_length();
    }
    kak_assert(false);
    return 0;
}

void DisplayAtom::trim_begin(ColumnCount count)
{
    if (m_type == Range)
        m_range.begin = utf8::advance(get_iterator(*m_buffer, m_range.begin),
                                      get_iterator(*m_buffer, m_range.end),
                                      count).coord();
    else
        m_text = m_text.substr(count).str();
}

void DisplayAtom::trim_end(ColumnCount count)
{
    if (m_type == Range)
        m_range.end = utf8::advance(get_iterator(*m_buffer, m_range.end),
                                    get_iterator(*m_buffer, m_range.begin),
                                    -count).coord();
    else
        m_text = m_text.substr(0, m_text.column_length() - count).str();
}

DisplayLine::DisplayLine(AtomList atoms)
    : m_atoms(std::move(atoms))
{
    compute_range();
}

DisplayLine::iterator DisplayLine::split(iterator it, BufferCoord pos)
{
    kak_assert(it->type() == DisplayAtom::Range);
    kak_assert(it->begin() < pos);
    kak_assert(it->end() > pos);

    DisplayAtom atom = *it;
    atom.m_range.end = pos;
    it->m_range.begin = pos;
    return m_atoms.insert(it, std::move(atom));
}

DisplayLine::iterator DisplayLine::split(iterator it, ColumnCount count)
{
    kak_assert(count > 0);
    kak_assert(count < it->length());

    if (it->type() == DisplayAtom::Text or it->type() == DisplayAtom::ReplacedRange)
    {
        DisplayAtom atom = *it;
        atom.m_text = atom.m_text.substr(0, count).str();
        it->m_text = it->m_text.substr(count).str();
        return m_atoms.insert(it, std::move(atom));
    }
    auto pos = utf8::advance(get_iterator(it->buffer(), it->begin()),
                             get_iterator(it->buffer(), it->end()),
                             count).coord();
    return split(it, pos);
}

DisplayLine::iterator DisplayLine::insert(iterator it, DisplayAtom atom)
{
    if (atom.has_buffer_range())
    {
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    return m_atoms.insert(it, std::move(atom));
}

void DisplayLine::push_back(DisplayAtom atom)
{
    if (atom.has_buffer_range())
    {
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    m_atoms.push_back(std::move(atom));
}

DisplayLine::iterator DisplayLine::erase(iterator beg, iterator end)
{
    auto res = m_atoms.erase(beg, end);
    compute_range();
    return res;
}

void DisplayLine::optimize()
{
    if (m_atoms.empty())
        return;

    auto atom_it = m_atoms.begin();
    for (auto next_it = atom_it + 1; next_it != m_atoms.end(); ++next_it)
    {
        auto& atom = *atom_it;
        auto& next = *next_it;

        const auto type = atom.type();
        if (type == next.type() and atom.face == next.face)
        {
            if (type == DisplayAtom::Text)
                atom.m_text += next.m_text;
            else if ((type == DisplayAtom::Range or
                      type == DisplayAtom::ReplacedRange) and
                     next.begin() == atom.end())
            {
                atom.m_range.end = next.end();
                if (type == DisplayAtom::ReplacedRange)
                    atom.m_text += next.m_text;
            }
            else
                *++atom_it = std::move(*next_it);
        }
        else
            *++atom_it = std::move(*next_it);
    }
    m_atoms.erase(atom_it+1, m_atoms.end());
}

ColumnCount DisplayLine::length() const
{
    ColumnCount len = 0;
    for (auto& atom : m_atoms)
        len += atom.length();
    return len;
}

bool DisplayLine::trim(ColumnCount first_col, ColumnCount col_count)
{
    for (auto it = begin(); first_col > 0 and it != end(); )
    {
        auto len = it->length();
        if (len <= first_col)
        {
            m_atoms.erase(it);
            first_col -= len;
        }
        else
        {
            it->trim_begin(first_col);
            first_col = 0;
        }
    }
    auto it = begin();
    for (; it != end() and col_count > 0; ++it)
        col_count -= it->length();

    bool did_trim = it != end() || col_count < 0;
    if (col_count < 0)
        (it-1)->trim_end(-col_count);
    m_atoms.erase(it, end());

    compute_range();
    return did_trim;
}

const BufferRange init_range{ {INT_MAX, INT_MAX}, {INT_MIN, INT_MIN} };

void DisplayLine::compute_range()
{
    m_range = init_range;
    for (auto& atom : m_atoms)
    {
        if (not atom.has_buffer_range())
            continue;
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    if (m_range == init_range)
        m_range = { { 0, 0 }, { 0, 0 } };
    kak_assert(m_range.begin <= m_range.end);
}

void DisplayBuffer::compute_range()
{
    m_range = init_range;
    for (auto& line : m_lines)
    {
        m_range.begin  = std::min(line.range().begin, m_range.begin);
        m_range.end = std::max(line.range().end, m_range.end);
    }
    if (m_range == init_range)
        m_range = { { 0, 0 }, { 0, 0 } };
    kak_assert(m_range.begin <= m_range.end);
}

void DisplayBuffer::optimize()
{
    for (auto& line : m_lines)
        line.optimize();
}

DisplayLine parse_display_line(StringView line, const FaceRegistry& faces, const HashMap<String, DisplayLine>& builtins)
{
    DisplayLine res;
    bool was_antislash = false;
    auto pos = line.begin();
    String content;
    Face face;
    for (auto it = line.begin(), end = line.end(); it != end; ++it)
    {
        const char c = *it;
        if (c == '{')
        {
            if (was_antislash)
            {
                content += StringView{pos, it};
                content.back() = '{';
                pos = it + 1;
            }
            else
            {
                content += StringView{pos, it};
                res.push_back({std::move(content), face});
                content.clear();
                auto closing = std::find(it+1, end, '}');
                if (closing == end)
                    throw runtime_error("unclosed face definition");
                if (*(it+1) == '{' and closing+1 != end and *(closing+1) == '}')
                {
                    auto builtin_it = builtins.find(StringView{it+2, closing});
                    if (builtin_it == builtins.end())
                        throw runtime_error(format("undefined atom {}", StringView{it+2, closing}));
                    for (auto& atom : builtin_it->value)
                        res.push_back(atom);
                    // closing is now at the first char of "}}", advance it to the second
                    ++closing;
                }
                else if (closing == it+2 and *(it+1) == '\\')
                {
                    pos = closing + 1;
                    break;
                }
                else
                    face = faces[{it+1, closing}];
                it = closing;
                pos = closing + 1;
            }
        }
        if (c == '\n' or c == '\t') // line breaks and tabs are forbidden, replace with space
        {
            content += StringView{pos, it+1};
            content.back() = ' ';
            pos = it + 1;
        }

        if (c == '\\')
        {
            if (was_antislash)
            {
                content += StringView{pos, it};
                pos = it + 1;
                was_antislash = false;
            }
            else
                was_antislash = true;
        }
        else
            was_antislash = false;
    }
    content += StringView{pos, line.end()};
    if (not content.empty())
        res.push_back({std::move(content), face});
    return res;
}

String fix_atom_text(StringView str)
{
    String res;
    auto pos = str.begin();
    for (auto it = str.begin(), end = str.end(); it != end; ++it)
    {
        char c = *it;
        if (c <= 0x1F)
        {
            res += StringView{pos, it};
            res += String{Codepoint{(uint32_t)(0x2400 + c)}};
            pos = it+1;
        }
    }
    res += StringView{pos, str.end()};
    return res;
}

}
<|endoftext|>


<commit_before>#include <iostream>

#include <QtGui>

#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QtWidgets>
#endif

#include "view.h"

class QGraphicsScene;

// Construct a view showing problem/solution from the given input stream.
View::View(std::istream &in, EdgeFormat edgeFormat, QGraphicsScene *scene, QWidget *parent) :
    QGraphicsView(scene, parent),
    m_legPen(Qt::black, 0),
    m_currentLegPen(QColor(Qt::green).darker(), 0),
    m_currentLeg(0),
    hudFont("Courier", 10),
    m_solutionLength(0)
{
    resize(900, 600);
    setRenderHints(QPainter::Antialiasing);
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    setDragMode(QGraphicsView::ScrollHandDrag);
    setViewportUpdateMode(QGraphicsView::FullViewportUpdate); // :(

    // Read problem.
    int numPoints;
    in >> numPoints;
    m_points.resize(numPoints);
    float minX = std::numeric_limits<float>::max();
    float minY = std::numeric_limits<float>::max();
    float maxX = std::numeric_limits<float>::lowest();
    float maxY = std::numeric_limits<float>::lowest();
    double sumX = 0;
    double sumY = 0;
    for (int i = 0; i < numPoints; ++i) {
        float x, y;
        in >> x >> y;
        m_points[i].setX(x);
        m_points[i].setY(y);
        minX = qMin(minX, x);
        minY = qMin(minY, y);
        maxX = qMax(maxX, x);
        maxY = qMax(maxY, y);
        sumX += x;
        sumY += y;
    }

    const float margin = qAbs(maxX - minX) / 30;
    setSceneRect(minX - margin, minY - margin, maxX - minX + 2*margin, maxY - minY + 2*margin);

    // Read solution, if any.
    if (edgeFormat == Sequence) {
        readPointSequence(in);
    } else {
        readPointPairs(in);
    }

    // Center view on mean coordinate and zoom to fit entire scene.
    centerOn(QPointF(sumX / numPoints, sumY / numPoints));
    fitInView(sceneRect(), Qt::KeepAspectRatio);
}

void View::wheelEvent(QWheelEvent *event) {
    if (event->modifiers() == Qt::ControlModifier) {
        if (event->delta() > 0) {
            scale(2, 2);
        } else if (event->delta() < 0){
            scale(0.5, 0.5);
        }
        return;
    }
    QGraphicsView::wheelEvent(event);
}

void View::keyPressEvent(QKeyEvent *event) {
    if (event->key() == Qt::Key_Right) {
        int steps = 1;
        if (event->modifiers() == Qt::ControlModifier)
            steps = 10;
        if (event->modifiers() == Qt::ShiftModifier)
            steps = 100;
        moveForward(steps);
    } else if (event->key() == Qt::Key_Left) {
        int steps = 1;
        if (event->modifiers() == Qt::ControlModifier)
            steps = 10;
        if (event->modifiers() == Qt::ShiftModifier)
            steps = 100;
        moveBackward(steps);
    }
}

void View::drawForeground(QPainter *painter, const QRectF& rect) {
    painter->setMatrixEnabled(false);
    painter->setPen(Qt::NoPen);
    painter->setBrush(Qt::black);
    painter->setRenderHint(QPainter::Antialiasing);

    // Draw points.
    const QRectF biggerRect = rect.adjusted(-100, -100, 100, 100);
    const float radius = 2.0;
    foreach (const QPointF& point, m_points) {
        if (biggerRect.contains(point)) {
            painter->drawEllipse(QPointF(mapFromScene(point)), radius, radius);
        }
    }

    // Draw solution length HUD text.
    painter->setFont(hudFont);
    painter->setPen(Qt::gray);
    const QString solutionHud = QString("Solution length: %1").arg(m_solutionLength);
    const QPointF solutionHudPos = rect.bottomLeft() +
        QPointF(10/transform().m11(), -15/transform().m22());
    painter->drawText(mapFromScene(solutionHudPos), solutionHud);

    if (!m_legs.isEmpty()) {
        // Draw leg length HUD text.
        const int legLength = qRound(m_legs[m_currentLeg]->line().length());
        const QString legHud = QString("Leg length: %1").arg(legLength);
        const QPointF legHudPos = rect.bottomLeft() +
            QPointF(10/transform().m11(), -30/transform().m22());
        painter->drawText(mapFromScene(legHudPos), legHud);
    }
}

void View::moveForward(int steps) {
    for (int i = 0; i < steps; ++i) {
        if (m_currentLeg < m_legs.size() - 1) {
            m_legs[m_currentLeg]->setPen(m_legPen);
            ++m_currentLeg;
            m_legs[m_currentLeg]->setVisible(true);
            m_legs[m_currentLeg]->setPen(m_currentLegPen);
        }
    }
}

void View::moveBackward(int steps) {
    for (int i = 0; i < steps; ++i) {
        if (m_currentLeg > 0) {
            m_legs[m_currentLeg]->setVisible(false);
            m_legs[m_currentLeg]->setPen(m_legPen);
            --m_currentLeg;
            m_legs[m_currentLeg]->setPen(m_currentLegPen);
        }
    }
}

void View::readPointSequence(std::istream& in) {
    int firstIndex, startIndex, endIndex;
    endIndex = -1;
    in >> firstIndex;
    if (!in.eof()) {
        startIndex = firstIndex;
        while (endIndex != firstIndex) {
            if (in.eof())
                endIndex = firstIndex;
            else
                in >> endIndex;
            QPointF start = m_points[startIndex];
            QPointF end = m_points[endIndex];
            QGraphicsLineItem *leg = scene()->addLine(QLineF(start, end), m_legPen);
            leg->setVisible(false);
            m_legs.append(leg);
            m_solutionLength += qRound(leg->line().length());
            startIndex = endIndex;
        }
        m_legs[m_currentLeg]->setPen(m_currentLegPen);
        m_legs[m_currentLeg]->setVisible(true);
    }
}

void View::readPointPairs(std::istream& in) {
    while (!in.eof()) {
        int startIndex, endIndex;
        in >> startIndex >> endIndex;
        if (in.eof())
            break; // Hack: To avoid last edge being added twice.
        QPointF start = m_points[startIndex];
        QPointF end = m_points[endIndex];
        QGraphicsLineItem *leg = scene()->addLine(QLineF(start, end), m_legPen);
        leg->setVisible(false);
        m_legs.append(leg);
        m_solutionLength += qRound(leg->line().length());
    }
    if (!m_legs.isEmpty()) {
        m_legs[m_currentLeg]->setPen(m_currentLegPen);
        m_legs[m_currentLeg]->setVisible(true);
    }
}
<commit_msg>Make vertices items instead of drawing in view.<commit_after>#include <iostream>

#include <QtGui>

#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QtWidgets>
#endif

#include "view.h"

class QGraphicsScene;

// Construct a view showing problem/solution from the given input stream.
View::View(std::istream &in, EdgeFormat edgeFormat, QGraphicsScene *scene, QWidget *parent) :
    QGraphicsView(scene, parent),
    m_legPen(Qt::black, 0),
    m_currentLegPen(QColor(Qt::green).darker(), 0),
    m_currentLeg(0),
    hudFont("Courier", 10),
    m_solutionLength(0)
{
    resize(900, 600);
    setRenderHints(QPainter::Antialiasing);
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    setDragMode(QGraphicsView::ScrollHandDrag);
    setViewportUpdateMode(QGraphicsView::FullViewportUpdate); // :(

    // Read problem.
    int numPoints;
    in >> numPoints;
    m_points.resize(numPoints);
    float minX = std::numeric_limits<float>::max();
    float minY = std::numeric_limits<float>::max();
    float maxX = std::numeric_limits<float>::lowest();
    float maxY = std::numeric_limits<float>::lowest();
    double sumX = 0;
    double sumY = 0;
    for (int i = 0; i < numPoints; ++i) {
        float x, y;
        in >> x >> y;
        m_points[i].setX(x);
        m_points[i].setY(y);
        minX = qMin(minX, x);
        minY = qMin(minY, y);
        maxX = qMax(maxX, x);
        maxY = qMax(maxY, y);
        sumX += x;
        sumY += y;
        QGraphicsEllipseItem *item = scene->addEllipse(-2.0, -2.0, 4.0, 4.0);
        item->setPos(x, y);
        item->setPen(Qt::NoPen);
        item->setBrush(Qt::black);
        item->setFlag(QGraphicsItem::ItemIgnoresTransformations);
        item->setZValue(1); // On top of edges.
    }

    const float margin = qAbs(maxX - minX) / 30;
    setSceneRect(minX - margin, minY - margin, maxX - minX + 2*margin, maxY - minY + 2*margin);

    // Read solution, if any.
    if (edgeFormat == Sequence) {
        readPointSequence(in);
    } else {
        readPointPairs(in);
    }

    // Center view on mean coordinate and zoom to fit entire scene.
    centerOn(QPointF(sumX / numPoints, sumY / numPoints));
    fitInView(sceneRect(), Qt::KeepAspectRatio);
}

void View::wheelEvent(QWheelEvent *event) {
    if (event->modifiers() == Qt::ControlModifier) {
        if (event->delta() > 0) {
            scale(2, 2);
        } else if (event->delta() < 0){
            scale(0.5, 0.5);
        }
        return;
    }
    QGraphicsView::wheelEvent(event);
}

void View::keyPressEvent(QKeyEvent *event) {
    if (event->key() == Qt::Key_Right) {
        int steps = 1;
        if (event->modifiers() == Qt::ControlModifier)
            steps = 10;
        if (event->modifiers() == Qt::ShiftModifier)
            steps = 100;
        moveForward(steps);
    } else if (event->key() == Qt::Key_Left) {
        int steps = 1;
        if (event->modifiers() == Qt::ControlModifier)
            steps = 10;
        if (event->modifiers() == Qt::ShiftModifier)
            steps = 100;
        moveBackward(steps);
    }
}

void View::drawForeground(QPainter *painter, const QRectF& rect) {
    painter->setMatrixEnabled(false);
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setFont(hudFont);
    painter->setPen(Qt::gray);

    // Draw solution length HUD text.
    const QString solutionHud = QString("Solution length: %1").arg(m_solutionLength);
    const QPointF solutionHudPos = rect.bottomLeft() +
        QPointF(10/transform().m11(), -15/transform().m22());
    painter->drawText(mapFromScene(solutionHudPos), solutionHud);

    if (!m_legs.isEmpty()) {
        // Draw leg length HUD text.
        const int legLength = qRound(m_legs[m_currentLeg]->line().length());
        const QString legHud = QString("Leg length: %1").arg(legLength);
        const QPointF legHudPos = rect.bottomLeft() +
            QPointF(10/transform().m11(), -30/transform().m22());
        painter->drawText(mapFromScene(legHudPos), legHud);
    }
}

void View::moveForward(int steps) {
    for (int i = 0; i < steps; ++i) {
        if (m_currentLeg < m_legs.size() - 1) {
            m_legs[m_currentLeg]->setPen(m_legPen);
            ++m_currentLeg;
            m_legs[m_currentLeg]->setVisible(true);
            m_legs[m_currentLeg]->setPen(m_currentLegPen);
        }
    }
}

void View::moveBackward(int steps) {
    for (int i = 0; i < steps; ++i) {
        if (m_currentLeg > 0) {
            m_legs[m_currentLeg]->setVisible(false);
            m_legs[m_currentLeg]->setPen(m_legPen);
            --m_currentLeg;
            m_legs[m_currentLeg]->setPen(m_currentLegPen);
        }
    }
}

void View::readPointSequence(std::istream& in) {
    int firstIndex, startIndex, endIndex;
    endIndex = -1;
    in >> firstIndex;
    if (!in.eof()) {
        startIndex = firstIndex;
        while (endIndex != firstIndex) {
            if (in.eof())
                endIndex = firstIndex;
            else
                in >> endIndex;
            QPointF start = m_points[startIndex];
            QPointF end = m_points[endIndex];
            QGraphicsLineItem *leg = scene()->addLine(QLineF(start, end), m_legPen);
            leg->setVisible(false);
            m_legs.append(leg);
            m_solutionLength += qRound(leg->line().length());
            startIndex = endIndex;
        }
        m_legs[m_currentLeg]->setPen(m_currentLegPen);
        m_legs[m_currentLeg]->setVisible(true);
    }
}

void View::readPointPairs(std::istream& in) {
    while (!in.eof()) {
        int startIndex, endIndex;
        in >> startIndex >> endIndex;
        if (in.eof())
            break; // Hack: To avoid last edge being added twice.
        QPointF start = m_points[startIndex];
        QPointF end = m_points[endIndex];
        QGraphicsLineItem *leg = scene()->addLine(QLineF(start, end), m_legPen);
        leg->setVisible(false);
        m_legs.append(leg);
        m_solutionLength += qRound(leg->line().length());
    }
    if (!m_legs.isEmpty()) {
        m_legs[m_currentLeg]->setPen(m_currentLegPen);
        m_legs[m_currentLeg]->setVisible(true);
    }
}
<|endoftext|>


<commit_before>/* The MIT License

   Copyright (c) 2013 Adrian Tan <atks@umich.edu>

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

#include "view.h"

namespace
{

class Igor : Program
{
    public:

    ///////////
    //options//
    ///////////
    std::string input_vcf_file;
    std::string output_vcf_file;
    std::vector<GenomeInterval> intervals;
    std::vector<std::string> samples;
    std::string filter;
    std::string variant;
    uint32_t sort_window_size;
    bool print;

    ///////
    //i/o//
    ///////
    BCFOrderedReader *odr;
    BCFOrderedWriter *odw;

    /////////
    //stats//
    /////////
    uint32_t no_variants;
    uint32_t no_samples;

    Igor(int argc, char **argv)
    {
        version = "0.5";

        //////////////////////////
        //options initialization//
        //////////////////////////
        try
        {
            std::string desc = "Views a VCF or BCF or VCF.GZ file.";

            TCLAP::CmdLine cmd(desc, ' ', version);
            VTOutput my;
            cmd.setOutput(&my);
            TCLAP::ValueArg<std::string> arg_intervals("i", "i", "intervals []", false, "", "str", cmd);
            TCLAP::ValueArg<std::string> arg_interval_list("I", "I", "file containing list of intervals []", false, "", "file", cmd);
            TCLAP::SwitchArg arg_print("p", "p", "print options and summary []", cmd, false);
            TCLAP::ValueArg<uint32_t> arg_sort_window_size("w", "w", "local sorting window size [0]", false, 0, "int", cmd);
            //TCLAP::ValueArg<std::string> arg_sample_list("s", "s", "file containing list of sample []", false, "", "file", cmd);
            //TCLAP::ValueArg<std::string> arg_filter("f", "f", "filter expression []", false, "", "exp", cmd);
            //TCLAP::ValueArg<std::string> arg_variant("v", "v", "variant type []", false, "", "exp", cmd);
            TCLAP::ValueArg<std::string> arg_output_vcf_file("o", "o", "output VCF/VCF.GZ/BCF file [-]", false, "-", "str", cmd);
            TCLAP::UnlabeledValueArg<std::string> arg_input_vcf_file("<in.vcf>", "input VCF file", true, "","file", cmd);

            cmd.parse(argc, argv);

            input_vcf_file = arg_input_vcf_file.getValue();
            output_vcf_file = arg_output_vcf_file.getValue();
            parse_intervals(intervals, arg_interval_list.getValue(), arg_intervals.getValue());
            //read_sample_list(samples, arg_sample_list.getValue());
            print = arg_print.getValue();
            sort_window_size = arg_sort_window_size.getValue();
        }
        catch (TCLAP::ArgException &e)
        {
            std::cerr << "error: " << e.error() << " for arg " << e.argId() << "\n";
            abort();
        }
    };

    void initialize()
    {
        //////////////////////
        //i/o initialization//
        //////////////////////
        odr = new BCFOrderedReader(input_vcf_file, intervals);
        odw = new BCFOrderedWriter(output_vcf_file, sort_window_size);
        odw->link_hdr(odr->hdr);
        odw->write_hdr();

        ////////////////////////
        //stats initialization//
        ////////////////////////
        no_variants = 0;
        no_samples = 0;
    }

    void view()
    {
        bcf1_t *v = odw->get_bcf1_from_pool();

        while (odr->read(v))
        {
            odw->write(v);
            v = odw->get_bcf1_from_pool();
            ++no_variants;
        }

        odr->close();
        odw->close();
    };

    void print_options()
    {
        if (!print) return;

        std::clog << "view v" << version << "\n\n";

        std::clog << "options:     input VCF file           " << input_vcf_file << "\n";
        std::clog << "         [o] output VCF file          " << output_vcf_file << "\n";
        std::clog << "         [w] sort window size         " << sort_window_size << "\n";
        std::clog << "         [p] print options and stats  " << print << "\n";
        print_int_op("         [i] intervals                ", intervals);
        std::clog << "\n";
    }

    void print_stats()
    {
        if (!print) return;

        std::clog << "stats: no. variants  : " << no_variants << "\n";
        std::clog << "       no. samples   : " << no_samples << "\n";
        std::clog << "\n";
    };

    ~Igor() {};

    private:
};

}

bool view(int argc, char ** argv)
{
    Igor igor(argc, argv);
    igor.print_options();
    igor.initialize();
    igor.view();
    igor.print_stats();
    return igor.print;
};
<commit_msg>added print header option, by default no printing of header to be consistent with samtools.<commit_after>/* The MIT License

   Copyright (c) 2013 Adrian Tan <atks@umich.edu>

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

#include "view.h"

namespace
{

class Igor : Program
{
    public:

    ///////////
    //options//
    ///////////
    std::string input_vcf_file;
    std::string output_vcf_file;
    std::vector<GenomeInterval> intervals;
    std::vector<std::string> samples;
    std::string filter;
    std::string variant;
    uint32_t sort_window_size;
    bool print_header;
    bool print;

    ///////
    //i/o//
    ///////
    BCFOrderedReader *odr;
    BCFOrderedWriter *odw;

    /////////
    //stats//
    /////////
    uint32_t no_variants;
    uint32_t no_samples;

    Igor(int argc, char **argv)
    {
        version = "0.5";

        //////////////////////////
        //options initialization//
        //////////////////////////
        try
        {
            std::string desc = "Views a VCF or BCF or VCF.GZ file.";

            TCLAP::CmdLine cmd(desc, ' ', version);
            VTOutput my;
            cmd.setOutput(&my);
            TCLAP::ValueArg<std::string> arg_intervals("i", "i", "intervals []", false, "", "str", cmd);
            TCLAP::ValueArg<std::string> arg_interval_list("I", "I", "file containing list of intervals []", false, "", "file", cmd);
            TCLAP::SwitchArg arg_print("p", "p", "print options and summary []", cmd, false);
            TCLAP::SwitchArg arg_print_header("h", "h", "print header [false]", cmd, false);
            TCLAP::ValueArg<uint32_t> arg_sort_window_size("w", "w", "local sorting window size [0]", false, 0, "int", cmd);
            //TCLAP::ValueArg<std::string> arg_sample_list("s", "s", "file containing list of sample []", false, "", "file", cmd);
            //TCLAP::ValueArg<std::string> arg_filter("f", "f", "filter expression []", false, "", "exp", cmd);
            //TCLAP::ValueArg<std::string> arg_variant("v", "v", "variant type []", false, "", "exp", cmd);
            TCLAP::ValueArg<std::string> arg_output_vcf_file("o", "o", "output VCF/VCF.GZ/BCF file [-]", false, "-", "str", cmd);
            TCLAP::UnlabeledValueArg<std::string> arg_input_vcf_file("<in.vcf>", "input VCF file", true, "","file", cmd);

            cmd.parse(argc, argv);

            input_vcf_file = arg_input_vcf_file.getValue();
            output_vcf_file = arg_output_vcf_file.getValue();
            parse_intervals(intervals, arg_interval_list.getValue(), arg_intervals.getValue());
            //read_sample_list(samples, arg_sample_list.getValue());
            print_header = arg_print_header.getValue();
            print = arg_print.getValue();
            sort_window_size = arg_sort_window_size.getValue();
        }
        catch (TCLAP::ArgException &e)
        {
            std::cerr << "error: " << e.error() << " for arg " << e.argId() << "\n";
            abort();
        }
    };

    void initialize()
    {
        //////////////////////
        //i/o initialization//
        //////////////////////
        odr = new BCFOrderedReader(input_vcf_file, intervals);
        odw = new BCFOrderedWriter(output_vcf_file, sort_window_size);
        odw->link_hdr(odr->hdr);
        if (print_header) odw->write_hdr();

        ////////////////////////
        //stats initialization//
        ////////////////////////
        no_variants = 0;
        no_samples = 0;
    }

    void view()
    {
        bcf1_t *v = odw->get_bcf1_from_pool();

        while (odr->read(v))
        {
            odw->write(v);
            v = odw->get_bcf1_from_pool();
            ++no_variants;
        }

        odr->close();
        odw->close();
    };

    void print_options()
    {
        if (!print) return;

        std::clog << "view v" << version << "\n\n";

        std::clog << "options:     input VCF file           " << input_vcf_file << "\n";
        std::clog << "         [o] output VCF file          " << output_vcf_file << "\n";
        std::clog << "         [w] sort window size         " << sort_window_size << "\n";
        std::clog << "         [h] print header             " << (print_header ? "yes" : "no") << "\n";
        std::clog << "         [p] print options and stats  " << (print ? "yes" : "no") << "\n";
        print_int_op("         [i] intervals                ", intervals);
        std::clog << "\n";
    }

    void print_stats()
    {
        if (!print) return;

        std::clog << "stats: no. variants  : " << no_variants << "\n";
        std::clog << "       no. samples   : " << no_samples << "\n";
        std::clog << "\n";
    };

    ~Igor() {};

    private:
};

}

bool view(int argc, char ** argv)
{
    Igor igor(argc, argv);
    igor.print_options();
    igor.initialize();
    igor.view();
    igor.print_stats();
    return igor.print;
};
<|endoftext|>


<commit_before>#include <HgShader.h>
#include <HgEntity.h>

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <FileWatch.h>
#include <str_utils.h>
#include <stdio.h>

#pragma warning(disable:4996)

#define MAX_SHADERS 1000

HgShader::createShaderCallback HgShader::Create = nullptr;

typedef struct shader_entry {
	uint32_t use_count;
	std::unique_ptr<HgShader> shader;

	char* vertex_path;
	char* frag_path;
} shader_entry;

/* keep shader_names seperate, we iterate through the list, want it cached*/
static char* shader_names[MAX_SHADERS] = { NULL }; //replace strings with CRC32?
shader_entry shader_list[MAX_SHADERS];

static void ShaderFileChanged(void* data) {
	shader_entry* entry = (shader_entry*)data;
	fprintf(stderr, "Shader file changed:%s\n", entry->frag_path);
	entry->shader->load();
}

HgShader* HgShader::acquire(HgShader* shader)
{
	for (int i = 0; i < MAX_SHADERS; ++i)
	{
		if (shader_list[i].shader.get() == shader)
		{
			if (shader_list[i].use_count > 0)
			{
				shader_list[i].use_count++;
				return shader;
			}
			return nullptr;
		}
	}
	return nullptr;
}

HgShader* HgShader::acquire(const char* vert, const char* frag) {
	uint32_t i = 0;
	char* name = str_cat(vert, frag);
	uint32_t funused = 0xFFFFFFFF;
	for (i = 0; i < MAX_SHADERS; ++i) {
		if (shader_names[i] == NULL && funused == 0xFFFFFFFF) funused = i;
		if (shader_names[i] == NULL) continue;
		if (strcmp(name, shader_names[i]) == 0) {
			free(name);
			shader_list[i].use_count++;
			return shader_list[i].shader.get();
		}
	}

	assert(funused != 0xFFFFFFFF); //out of shader spaces! increase MAX_SHADERS

	i = funused;
	shader_names[i] = name;
	shader_list[i].use_count = 1;
	shader_list[i].shader = HgShader::Create(vert, frag);
	shader_list[i].frag_path = str_cat(frag, "");
	shader_list[i].vertex_path = str_cat(vert, "");
	WatchFileForChange(frag, ShaderFileChanged, shader_list+i);
	WatchFileForChange(vert, ShaderFileChanged, shader_list + i);

	shader_list[i].shader->load();

	return shader_list[i].shader.get();
}

void HgShader::release(HgShader* s) {
	uint32_t i = 0;
	for (i = 0; i < MAX_SHADERS; ++i) {
		if (s == shader_list[i].shader.get()) {
			shader_list[i].use_count--;
			return;
		}
	}
}<commit_msg>shaders need some work.<commit_after>#include <HgShader.h>
#include <HgEntity.h>

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <FileWatch.h>
#include <str_utils.h>
#include <stdio.h>

#pragma warning(disable:4996)

#define MAX_SHADERS 1000

HgShader::createShaderCallback HgShader::Create = nullptr;

typedef struct shader_entry {
	uint32_t use_count;
	std::unique_ptr<HgShader> shader;
	std::string vertex_path, frag_path;
} shader_entry;

/* keep shader_names seperate, we iterate through the list, want it cached*/
static char* shader_names[MAX_SHADERS] = { NULL }; //replace strings with CRC32?
shader_entry shader_list[MAX_SHADERS];

static void ShaderFileChanged(void* data) {
	shader_entry* entry = (shader_entry*)data;
	fprintf(stderr, "Shader file changed:%s\n", entry->frag_path);
	entry->shader->load();
}

HgShader* HgShader::acquire(HgShader* shader)
{
	for (int i = 0; i < MAX_SHADERS; ++i)
	{
		if (shader_list[i].shader.get() == shader)
		{
			if (shader_list[i].use_count > 0)
			{
				shader_list[i].use_count++;
				return shader;
			}
			return nullptr;
		}
	}
	return nullptr;
}

HgShader* HgShader::acquire(const char* vert, const char* frag) {
	uint32_t i = 0;
	char* name = str_cat(vert, frag);
	uint32_t funused = 0xFFFFFFFF;
	for (i = 0; i < MAX_SHADERS; ++i) {
		if (shader_names[i] == NULL && funused == 0xFFFFFFFF) funused = i;
		if (shader_names[i] == NULL) continue;
		if (strcmp(name, shader_names[i]) == 0) {
			free(name);
			shader_list[i].use_count++;
			return shader_list[i].shader.get();
		}
	}

	assert(funused != 0xFFFFFFFF); //out of shader spaces! increase MAX_SHADERS

	i = funused;
	shader_names[i] = name;
	shader_list[i].use_count = 1;
	shader_list[i].shader = HgShader::Create(vert, frag);
	shader_list[i].frag_path = std::string(frag);
	shader_list[i].vertex_path = std::string(vert);
	WatchFileForChange(frag, ShaderFileChanged, shader_list+i);
	WatchFileForChange(vert, ShaderFileChanged, shader_list + i);

	shader_list[i].shader->load();

	return shader_list[i].shader.get();
}

void HgShader::release(HgShader* s) {
	uint32_t i = 0;
	for (i = 0; i < MAX_SHADERS; ++i) {
		if (s == shader_list[i].shader.get()) {
			shader_list[i].use_count--;
			return;
		}
	}
}<|endoftext|>


<commit_before><commit_msg>ifp default add horizontal and vertical tracks<commit_after><|endoftext|>


<commit_before>#include "B2dSplitter.h"
#include <splitter/TextureMapper.h>
#include <components/PhysicsComponent.h>
#include <components/Texcoords.h>
#include <vector>
#include <set>
#include <algorithm>
#include <opengl/TextureLoader.h>

class B2dSplitter::B2dSplitterImpl{

public:

	B2dSplitterImpl(b2World& box2dWorld, anax::World& anaxWorld) :  m_world(&box2dWorld), m_anaxWorld(&anaxWorld), m_textureMapper(Box2DConstants::WORLD_SCALE){
	}

	~B2dSplitterImpl(){
	}

	Splitter m_splitter;
    std::unique_ptr<anax::World> m_anaxWorld;
    TextureMapper m_textureMapper;
    TextureLoader m_textureLoader;

	std::set<anax::Entity, CompareEntities> m_entitiesToKill;
	std::set<b2Body*> m_bodiesToKill;
    std::unique_ptr<b2World> m_world;

	void deleteEntities() {
		for(b2Body * body : m_bodiesToKill){
			m_world->DestroyBody(body);
		}

		for (auto entity : m_entitiesToKill) {
			entity.kill();
		}

		m_bodiesToKill.clear();
		m_entitiesToKill.clear();
	}

	void  createNewSplitBodies(B2BoxBuilder& builder,b2Body* body, anax::Entity& entity){
		Texcoords oldTexCoords = entity.getComponent<Texcoords>();
		m_bodiesToKill.insert(body);
		m_entitiesToKill.insert(entity);

	    b2Body* newSplitBody = builder.build(*m_world);
		auto objectEntity = m_anaxWorld->createEntity();
	    auto& texCoordsComp = objectEntity.addComponent<Texcoords>();
	    auto& physComp = objectEntity.addComponent<PhysicsComponent>();

	    physComp.physicsBody = newSplitBody;

	    texCoordsComp.textCoords = m_textureMapper.mapSplitBody(newSplitBody, body,oldTexCoords.textCoords);
	    texCoordsComp.image = oldTexCoords.image;

	    texCoordsComp.texture = TextureLoader::loadAsOpenglTexture(texCoordsComp.texture, texCoordsComp.image);

	    objectEntity.activate();
	}

	void onb2BodySplit(std::vector<B2BoxBuilder>& splitBodies,b2Body* body, std::vector<anax::Entity> entities) {
		if (body->GetMass() < 0.1f) return;
		for (auto builder : splitBodies) {
			for (auto entity : entities) {
				if (entity.getComponent<PhysicsComponent>().physicsBody == body) {
					createNewSplitBodies(builder, body, entity);
					break;
				}
			}
		}
	}

};

B2dSplitter::B2dSplitter(b2World& box2dWorld,  anax::World& anaxWorld) : Base(anax::ComponentFilter().requires<Texcoords, PhysicsComponent>()),
		m_impl(new B2dSplitterImpl(box2dWorld, anaxWorld)){
	m_impl->m_splitter.registerBodySplitCallback(this);
}

B2dSplitter::~B2dSplitter() {
}

void B2dSplitter::onb2BodySplit(std::vector<B2BoxBuilder>& splitBodies, b2Body* body) {
	auto entities = getEntities();
	m_impl->onb2BodySplit(splitBodies, body, entities);
}

void B2dSplitter::split(b2Vec2 startPoint, b2Vec2 endPoint) {
	m_impl->m_world->RayCast(&m_impl->m_splitter,startPoint, endPoint);
	m_impl->m_world->RayCast(&m_impl->m_splitter,endPoint, startPoint);
}

void B2dSplitter::clearIntersects() {
	m_impl->m_splitter.clearIntersects();
}

void B2dSplitter::deleteEntities() {
	m_impl->deleteEntities();
}

<commit_msg>refactor code<commit_after>#include "B2dSplitter.h"
#include <splitter/TextureMapper.h>
#include <components/PhysicsComponent.h>
#include <components/Texcoords.h>
#include <vector>
#include <set>
#include <algorithm>
#include <opengl/TextureLoader.h>

class B2dSplitter::B2dSplitterImpl{

public:

	B2dSplitterImpl(b2World& box2dWorld, anax::World& anaxWorld) :  m_world(&box2dWorld), m_anaxWorld(&anaxWorld), m_textureMapper(Box2DConstants::WORLD_SCALE){
	}

	~B2dSplitterImpl(){
	}

	Splitter m_splitter;
    std::unique_ptr<anax::World> m_anaxWorld;
    TextureMapper m_textureMapper;
    TextureLoader m_textureLoader;

	std::set<anax::Entity, CompareEntities> m_entitiesToKill;
	std::set<b2Body*> m_bodiesToKill;
    std::unique_ptr<b2World> m_world;

	void deleteEntities() {
		for(b2Body * body : m_bodiesToKill){
			m_world->DestroyBody(body);
		}

		for (auto entity : m_entitiesToKill) {
			entity.kill();
		}

		m_bodiesToKill.clear();
		m_entitiesToKill.clear();
	}

	void createSplitBodyEntityFromOldTexCoords(b2Body* newSplitBody, b2Body* body, Texcoords oldTexCoords){
		auto objectEntity = m_anaxWorld->createEntity();
	    auto& texCoordsComp = objectEntity.addComponent<Texcoords>();
	    auto& physComp = objectEntity.addComponent<PhysicsComponent>();

	    physComp.physicsBody = newSplitBody;

	    texCoordsComp.textCoords = m_textureMapper.mapSplitBody(newSplitBody, body,oldTexCoords.textCoords);
	    texCoordsComp.image = oldTexCoords.image;

	    texCoordsComp.texture = TextureLoader::loadAsOpenglTexture(texCoordsComp.texture, texCoordsComp.image);

	    objectEntity.activate();
	}

	void  createNewSplitBody(B2BoxBuilder& newSplitB2bodyBuilder,b2Body* oldBodyToSplit, anax::Entity& entity){
		Texcoords oldBodyTexCoords = entity.getComponent<Texcoords>();
		m_bodiesToKill.insert(oldBodyToSplit);
		m_entitiesToKill.insert(entity);
		b2Body* newSplitBody = newSplitB2bodyBuilder.build(*m_world)
		createSplitBodyEntityFromOldTexCoords(newSplitBody, oldBodyToSplit, oldBodyTexCoords);
	}

	void onb2BodySplit(std::vector<B2BoxBuilder>& splitBodies,b2Body* body, std::vector<anax::Entity> entities) {
		if (body->GetMass() < 0.1f) return;
		for (auto builder : splitBodies) {
			for (auto entity : entities) {
				if (entity.getComponent<PhysicsComponent>().physicsBody == body) {
					createNewSplitBody(builder, body, entity);
					break;
				}
			}
		}
	}

};

B2dSplitter::B2dSplitter(b2World& box2dWorld,  anax::World& anaxWorld) : Base(anax::ComponentFilter().requires<Texcoords, PhysicsComponent>()),
		m_impl(new B2dSplitterImpl(box2dWorld, anaxWorld)){
	m_impl->m_splitter.registerBodySplitCallback(this);
}

B2dSplitter::~B2dSplitter() {
}

void B2dSplitter::onb2BodySplit(std::vector<B2BoxBuilder>& splitBodies, b2Body* body) {
	auto entities = getEntities();
	m_impl->onb2BodySplit(splitBodies, body, entities);
}

void B2dSplitter::split(b2Vec2 startPoint, b2Vec2 endPoint) {
	m_impl->m_world->RayCast(&m_impl->m_splitter,startPoint, endPoint);
	m_impl->m_world->RayCast(&m_impl->m_splitter,endPoint, startPoint);
}

void B2dSplitter::clearIntersects() {
	m_impl->m_splitter.clearIntersects();
}

void B2dSplitter::deleteEntities() {
	m_impl->deleteEntities();
}

<|endoftext|>