<commit_before>/*

Copyright (c) 2009, 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.

*/

#ifndef TORRENT_I2P_STREAM_HPP_INCLUDED
#define TORRENT_I2P_STREAM_HPP_INCLUDED

#include "libtorrent/config.hpp"

#if TORRENT_USE_I2P

#include <list>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>
#include <boost/bind.hpp>
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/session_settings.hpp"

namespace libtorrent {

	namespace i2p_error {

		enum i2p_error_code
		{
			no_error = 0,
			parse_failed,
			cant_reach_peer,
			i2p_error,
			invalid_key,
			invalid_id,
			timeout,
			key_not_found,
			num_errors
		};
	}

struct TORRENT_EXPORT i2p_error_category : boost::system::error_category
{
	virtual const char* name() const;
	virtual std::string message(int ev) const;
	virtual boost::system::error_condition default_error_condition(int ev) const
	{ return boost::system::error_condition(ev, *this); }
};

extern i2p_error_category i2p_category;

class i2p_stream : public proxy_base
{
public:

	explicit i2p_stream(io_service& io_service)
		: proxy_base(io_service)
		, m_id(0)
		, m_command(cmd_create_session)
		, m_state(0)
	{}

	enum command_t
	{
		cmd_none,
		cmd_create_session,
		cmd_connect,
		cmd_accept,
		cmd_name_lookup,
		cmd_incoming
	};

	void set_command(command_t c) { m_command = c; }

	void set_session_id(char const* id) { m_id = id; }

	void set_destination(std::string const& d) { m_dest = d; }
	std::string const& destination() { return m_dest; }

	typedef boost::function<void(error_code const&)> handler_type;

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		// since we don't support regular endpoints, just ignore the one
		// provided and use m_dest.

		// the connect is split up in the following steps:
		// 1. resolve name of proxy server
		// 2. connect to SAM bridge
		// 4 send command message (CONNECT/ACCEPT)

		// to avoid unnecessary copying of the handler,
		// store it in a shaed_ptr
		boost::shared_ptr<handler_type> h(new handler_type(handler));

		tcp::resolver::query q(m_hostname, to_string(m_port).elems);
		m_resolver.async_resolve(q, boost::bind(
			&i2p_stream::do_connect, this, _1, _2, h));
	}

	std::string name_lookup() const { return m_name_lookup; }
	void set_name_lookup(char const* name) { m_name_lookup = name; }

	void send_name_lookup(boost::shared_ptr<handler_type> h);

private:

	bool handle_error(error_code const& e, boost::shared_ptr<handler_type> const& h);
	void do_connect(error_code const& e, tcp::resolver::iterator i
		, boost::shared_ptr<handler_type> h);
	void connected(error_code const& e, boost::shared_ptr<handler_type> h);
	void start_read_line(error_code const& e, boost::shared_ptr<handler_type> h);
	void read_line(error_code const& e, boost::shared_ptr<handler_type> h);
	void send_connect(boost::shared_ptr<handler_type> h);
	void send_accept(boost::shared_ptr<handler_type> h);
	void send_session_create(boost::shared_ptr<handler_type> h);

	// send and receive buffer
	std::vector<char> m_buffer;
	char const* m_id;
	int m_command; // 0 = connect, 1 = accept
	std::string m_dest;
	std::string m_name_lookup;

	enum state_t
	{
		read_hello_response,
		read_connect_response,
		read_accept_response,
		read_session_create_response,
		read_name_lookup_response
	};

	int m_state;
};

class i2p_connection
{
public:
	i2p_connection(io_service& ios);
	~i2p_connection();

	proxy_settings const& proxy() const { return m_sam_router; }

	bool is_open() const
	{
		return m_sam_socket
			&& m_sam_socket->is_open()
			&& m_state != sam_connecting;
	}
	void open(proxy_settings const& s, i2p_stream::handler_type const& h);
	void close(error_code&);

	char const* session_id() const { return m_session_id.c_str(); }
	std::string const& local_endpoint() const { return m_i2p_local_endpoint; }

	typedef boost::function<void(error_code const&, char const*)> name_lookup_handler;
	void async_name_lookup(char const* name, name_lookup_handler handler);

private:

	void on_sam_connect(error_code const& ec, i2p_stream::handler_type const& h);
	void do_name_lookup(std::string const& name
		, name_lookup_handler const& h);
	void on_name_lookup(error_code const& ec
		, name_lookup_handler handler);

	void set_local_endpoint(error_code const& ec, char const* dest);

	// to talk to i2p SAM bridge
	boost::shared_ptr<i2p_stream> m_sam_socket;
	proxy_settings m_sam_router;

	// our i2p endpoint key
	std::string m_i2p_local_endpoint;
	std::string m_session_id;

	std::list<std::pair<std::string, name_lookup_handler> > m_name_lookup;

	enum state_t
	{
		sam_connecting,
		sam_name_lookup,
		sam_idle
	};

	state_t m_state;

	io_service& m_io_service;
};

}
#endif // TORRENT_USE_I2P

#endif

<commit_msg>some more missing includes<commit_after>/*

Copyright (c) 2009, 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.

*/

#ifndef TORRENT_I2P_STREAM_HPP_INCLUDED
#define TORRENT_I2P_STREAM_HPP_INCLUDED

#include "libtorrent/config.hpp"

#if TORRENT_USE_I2P

#include <list>
#include <string>
#include <vector>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/session_settings.hpp"

namespace libtorrent {

	namespace i2p_error {

		enum i2p_error_code
		{
			no_error = 0,
			parse_failed,
			cant_reach_peer,
			i2p_error,
			invalid_key,
			invalid_id,
			timeout,
			key_not_found,
			num_errors
		};
	}

struct TORRENT_EXPORT i2p_error_category : boost::system::error_category
{
	virtual const char* name() const;
	virtual std::string message(int ev) const;
	virtual boost::system::error_condition default_error_condition(int ev) const
	{ return boost::system::error_condition(ev, *this); }
};

extern i2p_error_category i2p_category;

class i2p_stream : public proxy_base
{
public:

	explicit i2p_stream(io_service& io_service)
		: proxy_base(io_service)
		, m_id(0)
		, m_command(cmd_create_session)
		, m_state(0)
	{}

	enum command_t
	{
		cmd_none,
		cmd_create_session,
		cmd_connect,
		cmd_accept,
		cmd_name_lookup,
		cmd_incoming
	};

	void set_command(command_t c) { m_command = c; }

	void set_session_id(char const* id) { m_id = id; }

	void set_destination(std::string const& d) { m_dest = d; }
	std::string const& destination() { return m_dest; }

	typedef boost::function<void(error_code const&)> handler_type;

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		// since we don't support regular endpoints, just ignore the one
		// provided and use m_dest.

		// the connect is split up in the following steps:
		// 1. resolve name of proxy server
		// 2. connect to SAM bridge
		// 4 send command message (CONNECT/ACCEPT)

		// to avoid unnecessary copying of the handler,
		// store it in a shaed_ptr
		boost::shared_ptr<handler_type> h(new handler_type(handler));

		tcp::resolver::query q(m_hostname, to_string(m_port).elems);
		m_resolver.async_resolve(q, boost::bind(
			&i2p_stream::do_connect, this, _1, _2, h));
	}

	std::string name_lookup() const { return m_name_lookup; }
	void set_name_lookup(char const* name) { m_name_lookup = name; }

	void send_name_lookup(boost::shared_ptr<handler_type> h);

private:

	bool handle_error(error_code const& e, boost::shared_ptr<handler_type> const& h);
	void do_connect(error_code const& e, tcp::resolver::iterator i
		, boost::shared_ptr<handler_type> h);
	void connected(error_code const& e, boost::shared_ptr<handler_type> h);
	void start_read_line(error_code const& e, boost::shared_ptr<handler_type> h);
	void read_line(error_code const& e, boost::shared_ptr<handler_type> h);
	void send_connect(boost::shared_ptr<handler_type> h);
	void send_accept(boost::shared_ptr<handler_type> h);
	void send_session_create(boost::shared_ptr<handler_type> h);

	// send and receive buffer
	std::vector<char> m_buffer;
	char const* m_id;
	int m_command; // 0 = connect, 1 = accept
	std::string m_dest;
	std::string m_name_lookup;

	enum state_t
	{
		read_hello_response,
		read_connect_response,
		read_accept_response,
		read_session_create_response,
		read_name_lookup_response
	};

	int m_state;
};

class i2p_connection
{
public:
	i2p_connection(io_service& ios);
	~i2p_connection();

	proxy_settings const& proxy() const { return m_sam_router; }

	bool is_open() const
	{
		return m_sam_socket
			&& m_sam_socket->is_open()
			&& m_state != sam_connecting;
	}
	void open(proxy_settings const& s, i2p_stream::handler_type const& h);
	void close(error_code&);

	char const* session_id() const { return m_session_id.c_str(); }
	std::string const& local_endpoint() const { return m_i2p_local_endpoint; }

	typedef boost::function<void(error_code const&, char const*)> name_lookup_handler;
	void async_name_lookup(char const* name, name_lookup_handler handler);

private:

	void on_sam_connect(error_code const& ec, i2p_stream::handler_type const& h);
	void do_name_lookup(std::string const& name
		, name_lookup_handler const& h);
	void on_name_lookup(error_code const& ec
		, name_lookup_handler handler);

	void set_local_endpoint(error_code const& ec, char const* dest);

	// to talk to i2p SAM bridge
	boost::shared_ptr<i2p_stream> m_sam_socket;
	proxy_settings m_sam_router;

	// our i2p endpoint key
	std::string m_i2p_local_endpoint;
	std::string m_session_id;

	std::list<std::pair<std::string, name_lookup_handler> > m_name_lookup;

	enum state_t
	{
		sam_connecting,
		sam_name_lookup,
		sam_idle
	};

	state_t m_state;

	io_service& m_io_service;
};

}
#endif // TORRENT_USE_I2P

#endif

<|endoftext|>


<commit_before>/*

Copyright (c) 2009, 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.

*/

#ifndef TORRENT_UTP_STREAM_HPP_INCLUDED
#define TORRENT_UTP_STREAM_HPP_INCLUDED

#include "libtorrent/connection_queue.hpp"
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/packet_buffer.hpp"
#include "libtorrent/error_code.hpp"

#include <boost/bind.hpp>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>

#define CCONTROL_TARGET 100

namespace libtorrent
{
	struct utp_socket_manager;

	// some MTU and protocol header sizes constants
	enum
	{
		TORRENT_IPV4_HEADER = 20,
		TORRENT_IPV6_HEADER = 40,
		TORRENT_UDP_HEADER = 8,
		TORRENT_SOCKS5_HEADER = 6, // plus the size of the destination address

		TORRENT_ETHERNET_MTU = 1500,
		TORRENT_TEREDO_MTU = 1280,
		TORRENT_INET_MIN_MTU = 576,
		TORRENT_INET_MAX_MTU = 0xffff
	};

	// the point of the bif_endian_int is two-fold
	// one purpuse is to not have any alignment requirements
	// so that any byffer received from the network can be cast
	// to it and read as an integer of various sizes without
	// triggering a bus error. The other purpose is to convert
	// from network byte order to host byte order when read and
	// written, to offer a convenient interface to both interpreting
	// and writing network packets
	template <class T> struct big_endian_int
	{
		big_endian_int& operator=(T v)
		{
			char* p = m_storage;
			detail::write_impl(v, p);
			return *this;
		}
		operator T() const
		{
			const char* p = m_storage;
			return detail::read_impl(p, detail::type<T>());
		}
	private:
		char m_storage[sizeof(T)];
	};

	typedef big_endian_int<boost::uint64_t> be_uint64;
	typedef big_endian_int<boost::uint32_t> be_uint32;
	typedef big_endian_int<boost::uint16_t> be_uint16;
	typedef big_endian_int<boost::int64_t> be_int64;
	typedef big_endian_int<boost::int32_t> be_int32;
	typedef big_endian_int<boost::int16_t> be_int16;

/*
	uTP header from BEP 29

	0       4       8               16              24              32
	+-------+-------+---------------+---------------+---------------+
	| type  | ver   | extension     | connection_id                 |
	+-------+-------+---------------+---------------+---------------+
	| timestamp_microseconds                                        |
	+---------------+---------------+---------------+---------------+
	| timestamp_difference_microseconds                             |
	+---------------+---------------+---------------+---------------+
	| wnd_size                                                      |
	+---------------+---------------+---------------+---------------+
	| seq_nr                        | ack_nr                        |
	+---------------+---------------+---------------+---------------+

*/

	enum type { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES };

	struct utp_header
	{
		unsigned char type_ver;
		unsigned char extension;
		be_uint16 connection_id;
		be_uint32 timestamp_microseconds;
		be_uint32 timestamp_difference_microseconds;
		be_uint32 wnd_size;
		be_uint16 seq_nr;
		be_uint16 ack_nr;

		int get_type() const { return type_ver >> 4; }
		int get_version() const { return type_ver & 0xf; }
	};

struct utp_socket_impl;

utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
	, boost::uint16_t send_id, void* userdata
	, utp_socket_manager* sm);
void detach_utp_impl(utp_socket_impl* s);
void delete_utp_impl(utp_socket_impl* s);
bool should_delete(utp_socket_impl* s);
void tick_utp_impl(utp_socket_impl* s, ptime const& now);
void utp_init_mtu(utp_socket_impl* s, int link_mtu, int utp_mtu);
bool utp_incoming_packet(utp_socket_impl* s, char const* p
	, int size, udp::endpoint const& ep, ptime receive_time);
bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id);
udp::endpoint utp_remote_endpoint(utp_socket_impl* s);
boost::uint16_t utp_receive_id(utp_socket_impl* s);
int utp_socket_state(utp_socket_impl const* s);

#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
int socket_impl_size();
#endif

// this is the user-level stream interface to utp sockets.
// the reason why it's split up in a utp_stream class and
// an implementation class is because the socket state has
// to be able to out-live the user level socket. For instance
// when sending data on a stream and then closing it, the
// state holding the send buffer has to be kept around until
// it has been flushed, which may be longer than the client
// will keep the utp_stream object around for.
// for more details, see utp_socket_impl, which is analogous
// to the kernel state for a socket. It's defined in utp_stream.cpp
class TORRENT_EXPORT utp_stream
{
public:

	typedef stream_socket::endpoint_type endpoint_type;
	typedef stream_socket::protocol_type protocol_type;

	explicit utp_stream(asio::io_service& io_service);
	~utp_stream();

	// used for incoming connections
	void set_impl(utp_socket_impl* s);
	utp_socket_impl* get_impl();

#ifndef BOOST_NO_EXCEPTIONS
	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc) {}
#endif

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, error_code& ec) {}

#ifndef BOOST_NO_EXCEPTIONS
	void bind(endpoint_type const& endpoint) {}
#endif

	void bind(endpoint_type const& endpoint, error_code& ec);

#ifndef BOOST_NO_EXCEPTIONS
	template <class SettableSocketOption>
	void set_option(SettableSocketOption const& opt) {}
#endif

	template <class SettableSocketOption>
	error_code set_option(SettableSocketOption const& opt, error_code& ec) { return ec; }

	void close();
	void close(error_code const& ec) { close(); }
	bool is_open() const { return m_open; }

	int read_buffer_size() const;
	static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_connect(void* self, error_code const& ec, bool kill);

	typedef void(*handler_t)(void*, size_t, error_code const&, bool);
	typedef void(*connect_handler_t)(void*, error_code const&, bool);

	void add_read_buffer(void* buf, size_t len);
	void set_read_handler(handler_t h);
	void add_write_buffer(void const* buf, size_t len);
	void set_write_handler(handler_t h);
	size_t read_some(bool clear_buffers);

	void do_connect(tcp::endpoint const& ep, connect_handler_t h);

	endpoint_type local_endpoint() const
	{
		error_code ec;
		return local_endpoint(ec);
	}

	endpoint_type local_endpoint(error_code& ec) const;

	endpoint_type remote_endpoint() const
	{
		error_code ec;
		return remote_endpoint(ec);
	}

	endpoint_type remote_endpoint(error_code& ec) const;

	std::size_t available() const;
	std::size_t available(error_code& ec) const { return available(); }

	asio::io_service& io_service()
	{ return m_io_service; }

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		if (!endpoint.address().is_v4())
		{
			error_code ec = asio::error::operation_not_supported;
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		m_connect_handler = handler;
		do_connect(endpoint, &utp_stream::on_connect);
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_read_handler);
		if (m_read_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}
		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			TORRENT_ASSERT(buffer_size(*i) > 0);
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
		}
		m_read_handler = handler;
		set_read_handler(&utp_stream::on_read);
	}

	void do_async_connect(endpoint_type const& ep
		, boost::function<void(error_code const&)> const& handler);

	template <class Protocol>
	void open(Protocol const& p, error_code& ec)
	{ m_open = true; }

	template <class Protocol>
	void open(Protocol const& p)
	{ m_open = true; }

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
	{
		TORRENT_ASSERT(!m_read_handler);
		if (m_impl == 0)
		{
			ec = asio::error::not_connected;
			return 0;
		}

		if (read_buffer_size() == 0)
		{
			ec = asio::error::would_block;
			return 0;
		}
#ifdef TORRENT_DEBUG
		size_t buf_size = 0;
#endif

		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
#ifdef TORRENT_DEBUG
			buf_size += buffer_size(*i);
#endif
		}
		std::size_t ret = read_some(true);
		TORRENT_ASSERT(int(ret) <= buf_size);
		TORRENT_ASSERT(ret > 0);
		return ret;
	}

	template <class Const_Buffers>
	std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
	{
		// TODO: implement
		return 0;
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_write_handler);
		if (m_write_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		for (typename Const_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			TORRENT_ASSERT(buffer_size(*i) > 0);
			using asio::buffer_cast;
			using asio::buffer_size;
			add_write_buffer((void*)buffer_cast<void const*>(*i), buffer_size(*i));
		}
		m_write_handler = handler;
		set_write_handler(&utp_stream::on_write);
	}

//private:

	void cancel_handlers(error_code const&);

	boost::function1<void, error_code const&> m_connect_handler;
	boost::function2<void, error_code const&, std::size_t> m_read_handler;
	boost::function2<void, error_code const&, std::size_t> m_write_handler;

	asio::io_service& m_io_service;
	utp_socket_impl* m_impl;
	bool m_open;
};

}

#endif
<commit_msg>fix warning in utp_stream<commit_after>/*

Copyright (c) 2009, 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.

*/

#ifndef TORRENT_UTP_STREAM_HPP_INCLUDED
#define TORRENT_UTP_STREAM_HPP_INCLUDED

#include "libtorrent/connection_queue.hpp"
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/packet_buffer.hpp"
#include "libtorrent/error_code.hpp"

#include <boost/bind.hpp>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>

#define CCONTROL_TARGET 100

namespace libtorrent
{
	struct utp_socket_manager;

	// some MTU and protocol header sizes constants
	enum
	{
		TORRENT_IPV4_HEADER = 20,
		TORRENT_IPV6_HEADER = 40,
		TORRENT_UDP_HEADER = 8,
		TORRENT_SOCKS5_HEADER = 6, // plus the size of the destination address

		TORRENT_ETHERNET_MTU = 1500,
		TORRENT_TEREDO_MTU = 1280,
		TORRENT_INET_MIN_MTU = 576,
		TORRENT_INET_MAX_MTU = 0xffff
	};

	// the point of the bif_endian_int is two-fold
	// one purpuse is to not have any alignment requirements
	// so that any byffer received from the network can be cast
	// to it and read as an integer of various sizes without
	// triggering a bus error. The other purpose is to convert
	// from network byte order to host byte order when read and
	// written, to offer a convenient interface to both interpreting
	// and writing network packets
	template <class T> struct big_endian_int
	{
		big_endian_int& operator=(T v)
		{
			char* p = m_storage;
			detail::write_impl(v, p);
			return *this;
		}
		operator T() const
		{
			const char* p = m_storage;
			return detail::read_impl(p, detail::type<T>());
		}
	private:
		char m_storage[sizeof(T)];
	};

	typedef big_endian_int<boost::uint64_t> be_uint64;
	typedef big_endian_int<boost::uint32_t> be_uint32;
	typedef big_endian_int<boost::uint16_t> be_uint16;
	typedef big_endian_int<boost::int64_t> be_int64;
	typedef big_endian_int<boost::int32_t> be_int32;
	typedef big_endian_int<boost::int16_t> be_int16;

/*
	uTP header from BEP 29

	0       4       8               16              24              32
	+-------+-------+---------------+---------------+---------------+
	| type  | ver   | extension     | connection_id                 |
	+-------+-------+---------------+---------------+---------------+
	| timestamp_microseconds                                        |
	+---------------+---------------+---------------+---------------+
	| timestamp_difference_microseconds                             |
	+---------------+---------------+---------------+---------------+
	| wnd_size                                                      |
	+---------------+---------------+---------------+---------------+
	| seq_nr                        | ack_nr                        |
	+---------------+---------------+---------------+---------------+

*/

	enum type { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES };

	struct utp_header
	{
		unsigned char type_ver;
		unsigned char extension;
		be_uint16 connection_id;
		be_uint32 timestamp_microseconds;
		be_uint32 timestamp_difference_microseconds;
		be_uint32 wnd_size;
		be_uint16 seq_nr;
		be_uint16 ack_nr;

		int get_type() const { return type_ver >> 4; }
		int get_version() const { return type_ver & 0xf; }
	};

struct utp_socket_impl;

utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
	, boost::uint16_t send_id, void* userdata
	, utp_socket_manager* sm);
void detach_utp_impl(utp_socket_impl* s);
void delete_utp_impl(utp_socket_impl* s);
bool should_delete(utp_socket_impl* s);
void tick_utp_impl(utp_socket_impl* s, ptime const& now);
void utp_init_mtu(utp_socket_impl* s, int link_mtu, int utp_mtu);
bool utp_incoming_packet(utp_socket_impl* s, char const* p
	, int size, udp::endpoint const& ep, ptime receive_time);
bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id);
udp::endpoint utp_remote_endpoint(utp_socket_impl* s);
boost::uint16_t utp_receive_id(utp_socket_impl* s);
int utp_socket_state(utp_socket_impl const* s);

#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
int socket_impl_size();
#endif

// this is the user-level stream interface to utp sockets.
// the reason why it's split up in a utp_stream class and
// an implementation class is because the socket state has
// to be able to out-live the user level socket. For instance
// when sending data on a stream and then closing it, the
// state holding the send buffer has to be kept around until
// it has been flushed, which may be longer than the client
// will keep the utp_stream object around for.
// for more details, see utp_socket_impl, which is analogous
// to the kernel state for a socket. It's defined in utp_stream.cpp
class TORRENT_EXPORT utp_stream
{
public:

	typedef stream_socket::endpoint_type endpoint_type;
	typedef stream_socket::protocol_type protocol_type;

	explicit utp_stream(asio::io_service& io_service);
	~utp_stream();

	// used for incoming connections
	void set_impl(utp_socket_impl* s);
	utp_socket_impl* get_impl();

#ifndef BOOST_NO_EXCEPTIONS
	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc) {}
#endif

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, error_code& ec) {}

#ifndef BOOST_NO_EXCEPTIONS
	void bind(endpoint_type const& endpoint) {}
#endif

	void bind(endpoint_type const& endpoint, error_code& ec);

#ifndef BOOST_NO_EXCEPTIONS
	template <class SettableSocketOption>
	void set_option(SettableSocketOption const& opt) {}
#endif

	template <class SettableSocketOption>
	error_code set_option(SettableSocketOption const& opt, error_code& ec) { return ec; }

	void close();
	void close(error_code const& ec) { close(); }
	bool is_open() const { return m_open; }

	int read_buffer_size() const;
	static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_connect(void* self, error_code const& ec, bool kill);

	typedef void(*handler_t)(void*, size_t, error_code const&, bool);
	typedef void(*connect_handler_t)(void*, error_code const&, bool);

	void add_read_buffer(void* buf, size_t len);
	void set_read_handler(handler_t h);
	void add_write_buffer(void const* buf, size_t len);
	void set_write_handler(handler_t h);
	size_t read_some(bool clear_buffers);

	void do_connect(tcp::endpoint const& ep, connect_handler_t h);

	endpoint_type local_endpoint() const
	{
		error_code ec;
		return local_endpoint(ec);
	}

	endpoint_type local_endpoint(error_code& ec) const;

	endpoint_type remote_endpoint() const
	{
		error_code ec;
		return remote_endpoint(ec);
	}

	endpoint_type remote_endpoint(error_code& ec) const;

	std::size_t available() const;
	std::size_t available(error_code& ec) const { return available(); }

	asio::io_service& io_service()
	{ return m_io_service; }

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		if (!endpoint.address().is_v4())
		{
			error_code ec = asio::error::operation_not_supported;
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		m_connect_handler = handler;
		do_connect(endpoint, &utp_stream::on_connect);
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_read_handler);
		if (m_read_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}
		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			TORRENT_ASSERT(buffer_size(*i) > 0);
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
		}
		m_read_handler = handler;
		set_read_handler(&utp_stream::on_read);
	}

	void do_async_connect(endpoint_type const& ep
		, boost::function<void(error_code const&)> const& handler);

	template <class Protocol>
	void open(Protocol const& p, error_code& ec)
	{ m_open = true; }

	template <class Protocol>
	void open(Protocol const& p)
	{ m_open = true; }

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
	{
		TORRENT_ASSERT(!m_read_handler);
		if (m_impl == 0)
		{
			ec = asio::error::not_connected;
			return 0;
		}

		if (read_buffer_size() == 0)
		{
			ec = asio::error::would_block;
			return 0;
		}
#ifdef TORRENT_DEBUG
		size_t buf_size = 0;
#endif

		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
#ifdef TORRENT_DEBUG
			buf_size += buffer_size(*i);
#endif
		}
		std::size_t ret = read_some(true);
		TORRENT_ASSERT(ret <= buf_size);
		TORRENT_ASSERT(ret > 0);
		return ret;
	}

	template <class Const_Buffers>
	std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
	{
		// TODO: implement
		return 0;
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_write_handler);
		if (m_write_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		for (typename Const_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			TORRENT_ASSERT(buffer_size(*i) > 0);
			using asio::buffer_cast;
			using asio::buffer_size;
			add_write_buffer((void*)buffer_cast<void const*>(*i), buffer_size(*i));
		}
		m_write_handler = handler;
		set_write_handler(&utp_stream::on_write);
	}

//private:

	void cancel_handlers(error_code const&);

	boost::function1<void, error_code const&> m_connect_handler;
	boost::function2<void, error_code const&, std::size_t> m_read_handler;
	boost::function2<void, error_code const&, std::size_t> m_write_handler;

	asio::io_service& m_io_service;
	utp_socket_impl* m_impl;
	bool m_open;
};

}

#endif
<|endoftext|>


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

#ifndef MAPNIK_MARKER_HELPERS_HPP
#define MAPNIK_MARKER_HELPERS_HPP

#include <mapnik/color.hpp>
#include <mapnik/markers_symbolizer.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/marker.hpp> // for svg_storage_type
#include <mapnik/svg/svg_storage.hpp>
#include <mapnik/markers_placement.hpp>

// agg
#include "agg_ellipse.h"
#include "agg_basics.h"
#include "agg_renderer_base.h"
#include "agg_renderer_scanline.h"
#include "agg_rendering_buffer.h"
#include "agg_scanline_u.h"
#include "agg_image_filters.h"
#include "agg_trans_bilinear.h"
#include "agg_span_allocator.h"
#include "agg_image_accessors.h"
#include "agg_pixfmt_rgba.h"
#include "agg_span_image_filter_rgba.h"

// boost
#include <boost/optional.hpp>

namespace mapnik {

template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector>
struct vector_markers_rasterizer_dispatch
{
    typedef typename SvgRenderer::renderer_base renderer_base;
    typedef typename renderer_base::pixfmt_type pixfmt_type;

    vector_markers_rasterizer_dispatch(BufferType & render_buffer,
                                SvgRenderer & svg_renderer,
                                Rasterizer & ras,
                                box2d<double> const& bbox,
                                agg::trans_affine const& marker_trans,
                                markers_symbolizer const& sym,
                                Detector & detector,
                                double scale_factor)
        : buf_(render_buffer),
        pixf_(buf_),
        renb_(pixf_),
        svg_renderer_(svg_renderer),
        ras_(ras),
        bbox_(bbox),
        marker_trans_(marker_trans),
        sym_(sym),
        detector_(detector),
        scale_factor_(scale_factor)
    {
        pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
    }

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_e placement_method = sym_.get_marker_placement();

        if (placement_method != MARKER_LINE_PLACEMENT)
        {
            double x,y;
            path.rewind(0);
            if (placement_method == MARKER_INTERIOR_PLACEMENT)
            {
                label::interior_position(path, x, y);
            }
            else
            {
                label::centroid(path, x, y);
            }
            agg::trans_affine matrix = marker_trans_;
            matrix.translate(x,y);
            box2d<double> transformed_bbox = bbox_ * matrix;

            if (sym_.get_allow_overlap() ||
                detector_.has_placement(transformed_bbox))
            {
                svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
                if (!sym_.get_ignore_placement())
                {
                    detector_.insert(transformed_bbox);
                }
            }
        }
        else
        {
            markers_placement<T, Detector> placement(path, bbox_, marker_trans_, detector_,
                                                     sym_.get_spacing() * scale_factor_,
                                                     sym_.get_max_error(),
                                                     sym_.get_allow_overlap());
            double x, y, angle;
            while (placement.get_point(x, y, angle))
            {
                agg::trans_affine matrix = marker_trans_;
                matrix.rotate(angle);
                matrix.translate(x, y);
                svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
            }
        }
    }
private:
    agg::scanline_u8 sl_;
    BufferType & buf_;
    pixfmt_type pixf_;
    renderer_base renb_;
    SvgRenderer & svg_renderer_;
    Rasterizer & ras_;
    box2d<double> const& bbox_;
    agg::trans_affine const& marker_trans_;
    markers_symbolizer const& sym_;
    Detector & detector_;
    double scale_factor_;
};

template <typename BufferType, typename Rasterizer, typename Detector>
struct raster_markers_rasterizer_dispatch
{
    typedef agg::rgba8 color_type;
    typedef agg::order_rgba order_type;
    typedef agg::pixel32_type pixel_type;
    typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
    typedef agg::pixfmt_custom_blend_rgba<blender_type, BufferType> pixfmt_comp_type;
    typedef agg::renderer_base<pixfmt_comp_type> renderer_base;

    raster_markers_rasterizer_dispatch(BufferType & render_buffer,
                                       Rasterizer & ras,
                                       image_data_32 const& src,
                                       agg::trans_affine const& marker_trans,
                                       markers_symbolizer const& sym,
                                       Detector & detector,
                                       double scale_factor)
        : buf_(render_buffer),
        pixf_(buf_),
        renb_(pixf_),
        ras_(ras),
        src_(src),
        marker_trans_(marker_trans),
        sym_(sym),
        detector_(detector),
        scale_factor_(scale_factor)
    {
        pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
    }

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_e placement_method = sym_.get_marker_placement();
        box2d<double> bbox_(0,0, src_.width(),src_.height());

        if (placement_method != MARKER_LINE_PLACEMENT)
        {
            double x,y;
            path.rewind(0);
            if (placement_method == MARKER_INTERIOR_PLACEMENT)
            {
                label::interior_position(path, x, y);
            }
            else
            {
                label::centroid(path, x, y);
            }
            agg::trans_affine matrix = marker_trans_;
            matrix.translate(x,y);
            box2d<double> transformed_bbox = bbox_ * matrix;

            if (sym_.get_allow_overlap() ||
                detector_.has_placement(transformed_bbox))
            {
                render_raster_marker(matrix, sym_.get_opacity());
                if (!sym_.get_ignore_placement())
                {
                    detector_.insert(transformed_bbox);
                }
            }
        }
        else
        {
            markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
                                                                      sym_.get_spacing() * scale_factor_,
                                                                      sym_.get_max_error(),
                                                                      sym_.get_allow_overlap());
            double x, y, angle;
            while (placement.get_point(x, y, angle))
            {
                agg::trans_affine matrix = marker_trans_;
                matrix.rotate(angle);
                matrix.translate(x, y);
                render_raster_marker(matrix, sym_.get_opacity());
            }
        }
    }

    void render_raster_marker(agg::trans_affine const& marker_tr,
                              double opacity)
    {
        double width  = src_.width();
        double height = src_.height();
        double p[8];
        p[0] = 0;     p[1] = 0;
        p[2] = width; p[3] = 0;
        p[4] = width; p[5] = height;
        p[6] = 0;     p[7] = height;
        marker_tr.transform(&p[0], &p[1]);
        marker_tr.transform(&p[2], &p[3]);
        marker_tr.transform(&p[4], &p[5]);
        marker_tr.transform(&p[6], &p[7]);
        ras_.move_to_d(p[0],p[1]);
        ras_.line_to_d(p[2],p[3]);
        ras_.line_to_d(p[4],p[5]);
        ras_.line_to_d(p[6],p[7]);
        agg::span_allocator<color_type> sa;
        agg::image_filter_bilinear filter_kernel;
        agg::image_filter_lut filter(filter_kernel, false);
        agg::rendering_buffer marker_buf((unsigned char *)src_.getBytes(),
                                         src_.width(),
                                         src_.height(),
                                         src_.width()*4);
        agg::pixfmt_rgba32_pre pixf(marker_buf);
        typedef agg::image_accessor_clone<agg::pixfmt_rgba32_pre> img_accessor_type;
        typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
        typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
                                                interpolator_type> span_gen_type;
        typedef agg::renderer_scanline_aa_alpha<renderer_base,
                agg::span_allocator<agg::rgba8>,
                span_gen_type> renderer_type;
        img_accessor_type ia(pixf);
        interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) );
        span_gen_type sg(ia, interpolator, filter);
        renderer_type rp(renb_,sa, sg, unsigned(opacity*255));
        agg::render_scanlines(ras_, sl_, rp);
    }

private:
    agg::scanline_u8 sl_;
    BufferType & buf_;
    pixfmt_comp_type pixf_;
    renderer_base renb_;
    Rasterizer & ras_;
    image_data_32 const& src_;
    agg::trans_affine const& marker_trans_;
    markers_symbolizer const& sym_;
    Detector & detector_;
    double scale_factor_;
};

template <typename T>
void build_ellipse(T const& sym, mapnik::feature_impl const& feature, svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path)
{
    expression_ptr const& width_expr = sym.get_width();
    expression_ptr const& height_expr = sym.get_height();
    double width = 0;
    double height = 0;
    if (width_expr && height_expr)
    {
        width = boost::apply_visitor(evaluate<Feature,value_type>(feature), *width_expr).to_double();
        height = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr).to_double();
    }
    else if (width_expr)
    {
        width = boost::apply_visitor(evaluate<Feature,value_type>(feature), *width_expr).to_double();
        height = width;
    }
    else if (height_expr)
    {
        height = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr).to_double();
        width = height;
    }
    svg::svg_converter_type styled_svg(svg_path, marker_ellipse.attributes());
    styled_svg.push_attr();
    styled_svg.begin_path();
    agg::ellipse c(0, 0, width/2.0, height/2.0);
    styled_svg.storage().concat_path(c);
    styled_svg.end_path();
    styled_svg.pop_attr();
    double lox,loy,hix,hiy;
    styled_svg.bounding_rect(&lox, &loy, &hix, &hiy);
    marker_ellipse.set_bounding_box(lox,loy,hix,hiy);
}

template <typename Attr>
bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym)
{
    boost::optional<stroke> const& strk = sym.get_stroke();
    boost::optional<color> const& fill = sym.get_fill();
    boost::optional<float> const& fill_opacity = sym.get_fill_opacity();
    if (strk || fill || fill_opacity)
    {
        bool success = false;
        for(unsigned i = 0; i < src.size(); ++i)
        {
            success = true;
            dst.push_back(src[i]);
            mapnik::svg::path_attributes & attr = dst.last();
            if (attr.stroke_flag)
            {
                // TODO - stroke attributes need to be boost::optional
                // for this to work properly
                if (strk)
                {
                    attr.stroke_width = strk->get_width();
                    color const& s_color = strk->get_color();
                    attr.stroke_color = agg::rgba(s_color.red()/255.0,
                                                  s_color.green()/255.0,
                                                  s_color.blue()/255.0,
                                                  s_color.alpha()/255.0);
                    attr.stroke_opacity = strk->get_opacity();
                }
            }
            if (attr.fill_flag)
            {
                if (fill)
                {
                    color const& f_color = *fill;
                    attr.fill_color = agg::rgba(f_color.red()/255.0,
                                                f_color.green()/255.0,
                                                f_color.blue()/255.0,
                                                f_color.alpha()/255.0);
                }
                if (fill_opacity)
                {
                    attr.fill_opacity = *fill_opacity;
                }
            }
        }
        return success;
    }
    return false;
}

template <typename T>
void setup_label_transform(agg::trans_affine & tr, box2d<double> const& bbox, mapnik::feature_impl const& feature, T const& sym)
{
    double width = 0;
    double height = 0;

    expression_ptr const& width_expr = sym.get_width();
    if (width_expr)
        width = boost::apply_visitor(evaluate<Feature,value_type>(feature), *width_expr).to_double();

    expression_ptr const& height_expr = sym.get_height();
    if (height_expr)
        height = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr).to_double();

    if (width > 0 && height > 0)
    {
        double sx = width/bbox.width();
        double sy = height/bbox.height();
        tr *= agg::trans_affine_scaling(sx,sy);
    }
    else if (width > 0)
    {
        double sx = width/bbox.width();
        tr *= agg::trans_affine_scaling(sx);
    }
    else if (height > 0)
    {
        double sy = height/bbox.height();
        tr *= agg::trans_affine_scaling(sy);
    }
    else
    {
        evaluate_transform(tr, feature, sym.get_image_transform());
    }
}

}

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

#ifndef MAPNIK_MARKER_HELPERS_HPP
#define MAPNIK_MARKER_HELPERS_HPP

#include <mapnik/color.hpp>
#include <mapnik/markers_symbolizer.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/marker.hpp> // for svg_storage_type
#include <mapnik/svg/svg_storage.hpp>
#include <mapnik/markers_placement.hpp>

// agg
#include "agg_ellipse.h"
#include "agg_basics.h"
#include "agg_renderer_base.h"
#include "agg_renderer_scanline.h"
#include "agg_rendering_buffer.h"
#include "agg_scanline_u.h"
#include "agg_image_filters.h"
#include "agg_trans_bilinear.h"
#include "agg_span_allocator.h"
#include "agg_image_accessors.h"
#include "agg_pixfmt_rgba.h"
#include "agg_span_image_filter_rgba.h"

// boost
#include <boost/optional.hpp>

namespace mapnik {

template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector>
struct vector_markers_rasterizer_dispatch
{
    typedef typename SvgRenderer::renderer_base renderer_base;
    typedef typename renderer_base::pixfmt_type pixfmt_type;

    vector_markers_rasterizer_dispatch(BufferType & render_buffer,
                                SvgRenderer & svg_renderer,
                                Rasterizer & ras,
                                box2d<double> const& bbox,
                                agg::trans_affine const& marker_trans,
                                markers_symbolizer const& sym,
                                Detector & detector,
                                double scale_factor)
        : buf_(render_buffer),
        pixf_(buf_),
        renb_(pixf_),
        svg_renderer_(svg_renderer),
        ras_(ras),
        bbox_(bbox),
        marker_trans_(marker_trans),
        sym_(sym),
        detector_(detector),
        scale_factor_(scale_factor)
    {
        pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
    }

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_e placement_method = sym_.get_marker_placement();

        if (placement_method != MARKER_LINE_PLACEMENT)
        {
            double x,y;
            path.rewind(0);
            if (placement_method == MARKER_INTERIOR_PLACEMENT)
            {
                label::interior_position(path, x, y);
            }
            else
            {
                label::centroid(path, x, y);
            }
            agg::trans_affine matrix = marker_trans_;
            matrix.translate(x,y);
            box2d<double> transformed_bbox = bbox_ * matrix;

            if (sym_.get_allow_overlap() ||
                detector_.has_placement(transformed_bbox))
            {
                svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
                if (!sym_.get_ignore_placement())
                {
                    detector_.insert(transformed_bbox);
                }
            }
        }
        else
        {
            markers_placement<T, Detector> placement(path, bbox_, marker_trans_, detector_,
                                                     sym_.get_spacing() * scale_factor_,
                                                     sym_.get_max_error(),
                                                     sym_.get_allow_overlap());
            double x, y, angle;
            while (placement.get_point(x, y, angle))
            {
                agg::trans_affine matrix = marker_trans_;
                matrix.rotate(angle);
                matrix.translate(x, y);
                svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
            }
        }
    }
private:
    agg::scanline_u8 sl_;
    BufferType & buf_;
    pixfmt_type pixf_;
    renderer_base renb_;
    SvgRenderer & svg_renderer_;
    Rasterizer & ras_;
    box2d<double> const& bbox_;
    agg::trans_affine const& marker_trans_;
    markers_symbolizer const& sym_;
    Detector & detector_;
    double scale_factor_;
};

template <typename BufferType, typename Rasterizer, typename Detector>
struct raster_markers_rasterizer_dispatch
{
    typedef agg::rgba8 color_type;
    typedef agg::order_rgba order_type;
    typedef agg::pixel32_type pixel_type;
    typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
    typedef agg::pixfmt_custom_blend_rgba<blender_type, BufferType> pixfmt_comp_type;
    typedef agg::renderer_base<pixfmt_comp_type> renderer_base;

    raster_markers_rasterizer_dispatch(BufferType & render_buffer,
                                       Rasterizer & ras,
                                       image_data_32 const& src,
                                       agg::trans_affine const& marker_trans,
                                       markers_symbolizer const& sym,
                                       Detector & detector,
                                       double scale_factor)
        : buf_(render_buffer),
        pixf_(buf_),
        renb_(pixf_),
        ras_(ras),
        src_(src),
        marker_trans_(marker_trans),
        sym_(sym),
        detector_(detector),
        scale_factor_(scale_factor)
    {
        pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
    }

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_e placement_method = sym_.get_marker_placement();
        box2d<double> bbox_(0,0, src_.width(),src_.height());

        if (placement_method != MARKER_LINE_PLACEMENT)
        {
            double x,y;
            path.rewind(0);
            if (placement_method == MARKER_INTERIOR_PLACEMENT)
            {
                label::interior_position(path, x, y);
            }
            else
            {
                label::centroid(path, x, y);
            }
            agg::trans_affine matrix = marker_trans_;
            matrix.translate(x,y);
            box2d<double> transformed_bbox = bbox_ * matrix;

            if (sym_.get_allow_overlap() ||
                detector_.has_placement(transformed_bbox))
            {
                render_raster_marker(matrix, sym_.get_opacity());
                if (!sym_.get_ignore_placement())
                {
                    detector_.insert(transformed_bbox);
                }
            }
        }
        else
        {
            markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
                                                                      sym_.get_spacing() * scale_factor_,
                                                                      sym_.get_max_error(),
                                                                      sym_.get_allow_overlap());
            double x, y, angle;
            while (placement.get_point(x, y, angle))
            {
                agg::trans_affine matrix = marker_trans_;
                matrix.rotate(angle);
                matrix.translate(x, y);
                render_raster_marker(matrix, sym_.get_opacity());
            }
        }
    }

    void render_raster_marker(agg::trans_affine const& marker_tr,
                              double opacity)
    {
        double width  = src_.width();
        double height = src_.height();
        double p[8];
        p[0] = 0;     p[1] = 0;
        p[2] = width; p[3] = 0;
        p[4] = width; p[5] = height;
        p[6] = 0;     p[7] = height;
        marker_tr.transform(&p[0], &p[1]);
        marker_tr.transform(&p[2], &p[3]);
        marker_tr.transform(&p[4], &p[5]);
        marker_tr.transform(&p[6], &p[7]);
        ras_.move_to_d(p[0],p[1]);
        ras_.line_to_d(p[2],p[3]);
        ras_.line_to_d(p[4],p[5]);
        ras_.line_to_d(p[6],p[7]);
        agg::span_allocator<color_type> sa;
        agg::image_filter_bilinear filter_kernel;
        agg::image_filter_lut filter(filter_kernel, false);
        agg::rendering_buffer marker_buf((unsigned char *)src_.getBytes(),
                                         src_.width(),
                                         src_.height(),
                                         src_.width()*4);
        agg::pixfmt_rgba32_pre pixf(marker_buf);
        typedef agg::image_accessor_clone<agg::pixfmt_rgba32_pre> img_accessor_type;
        typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
        typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
                                                interpolator_type> span_gen_type;
        typedef agg::renderer_scanline_aa_alpha<renderer_base,
                agg::span_allocator<color_type>,
                span_gen_type> renderer_type;
        img_accessor_type ia(pixf);
        interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) );
        span_gen_type sg(ia, interpolator, filter);
        renderer_type rp(renb_,sa, sg, unsigned(opacity*255));
        agg::render_scanlines(ras_, sl_, rp);
    }

private:
    agg::scanline_u8 sl_;
    BufferType & buf_;
    pixfmt_comp_type pixf_;
    renderer_base renb_;
    Rasterizer & ras_;
    image_data_32 const& src_;
    agg::trans_affine const& marker_trans_;
    markers_symbolizer const& sym_;
    Detector & detector_;
    double scale_factor_;
};

template <typename T>
void build_ellipse(T const& sym, mapnik::feature_impl const& feature, svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path)
{
    expression_ptr const& width_expr = sym.get_width();
    expression_ptr const& height_expr = sym.get_height();
    double width = 0;
    double height = 0;
    if (width_expr && height_expr)
    {
        width = boost::apply_visitor(evaluate<Feature,value_type>(feature), *width_expr).to_double();
        height = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr).to_double();
    }
    else if (width_expr)
    {
        width = boost::apply_visitor(evaluate<Feature,value_type>(feature), *width_expr).to_double();
        height = width;
    }
    else if (height_expr)
    {
        height = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr).to_double();
        width = height;
    }
    svg::svg_converter_type styled_svg(svg_path, marker_ellipse.attributes());
    styled_svg.push_attr();
    styled_svg.begin_path();
    agg::ellipse c(0, 0, width/2.0, height/2.0);
    styled_svg.storage().concat_path(c);
    styled_svg.end_path();
    styled_svg.pop_attr();
    double lox,loy,hix,hiy;
    styled_svg.bounding_rect(&lox, &loy, &hix, &hiy);
    marker_ellipse.set_bounding_box(lox,loy,hix,hiy);
}

template <typename Attr>
bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym)
{
    boost::optional<stroke> const& strk = sym.get_stroke();
    boost::optional<color> const& fill = sym.get_fill();
    boost::optional<float> const& fill_opacity = sym.get_fill_opacity();
    if (strk || fill || fill_opacity)
    {
        bool success = false;
        for(unsigned i = 0; i < src.size(); ++i)
        {
            success = true;
            dst.push_back(src[i]);
            mapnik::svg::path_attributes & attr = dst.last();
            if (attr.stroke_flag)
            {
                // TODO - stroke attributes need to be boost::optional
                // for this to work properly
                if (strk)
                {
                    attr.stroke_width = strk->get_width();
                    color const& s_color = strk->get_color();
                    attr.stroke_color = agg::rgba(s_color.red()/255.0,
                                                  s_color.green()/255.0,
                                                  s_color.blue()/255.0,
                                                  s_color.alpha()/255.0);
                    attr.stroke_opacity = strk->get_opacity();
                }
            }
            if (attr.fill_flag)
            {
                if (fill)
                {
                    color const& f_color = *fill;
                    attr.fill_color = agg::rgba(f_color.red()/255.0,
                                                f_color.green()/255.0,
                                                f_color.blue()/255.0,
                                                f_color.alpha()/255.0);
                }
                if (fill_opacity)
                {
                    attr.fill_opacity = *fill_opacity;
                }
            }
        }
        return success;
    }
    return false;
}

template <typename T>
void setup_label_transform(agg::trans_affine & tr, box2d<double> const& bbox, mapnik::feature_impl const& feature, T const& sym)
{
    double width = 0;
    double height = 0;

    expression_ptr const& width_expr = sym.get_width();
    if (width_expr)
        width = boost::apply_visitor(evaluate<Feature,value_type>(feature), *width_expr).to_double();

    expression_ptr const& height_expr = sym.get_height();
    if (height_expr)
        height = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr).to_double();

    if (width > 0 && height > 0)
    {
        double sx = width/bbox.width();
        double sy = height/bbox.height();
        tr *= agg::trans_affine_scaling(sx,sy);
    }
    else if (width > 0)
    {
        double sx = width/bbox.width();
        tr *= agg::trans_affine_scaling(sx);
    }
    else if (height > 0)
    {
        double sy = height/bbox.height();
        tr *= agg::trans_affine_scaling(sy);
    }
    else
    {
        evaluate_transform(tr, feature, sym.get_image_transform());
    }
}

}

#endif //MAPNIK_MARKER_HELPERS_HPP
<|endoftext|>


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

//$Id$

#ifndef PROJ_TRANSFORM_HPP
#define PROJ_TRANSFORM_HPP

// mapnik
#include <mapnik/projection.hpp>
// boost
#include <boost/utility.hpp>

namespace mapnik {

class MAPNIK_DECL proj_transform : private boost::noncopyable
{
public:
    proj_transform(projection const& source,
                   projection const& dest);

    bool equal() const;
    bool forward (double& x, double& y , double& z) const;
    bool backward (double& x, double& y , double& z) const;
    bool forward (box2d<double> & box) const;
    bool backward (box2d<double> & box) const;
    mapnik::projection const& source() const;
    mapnik::projection const& dest() const;

private:
    projection const& source_;
    projection const& dest_;
    bool is_source_longlat_;
    bool is_dest_longlat_;
    bool is_source_equal_dest_;
};
}

#endif // PROJ_TRANSFORM_HPP
<commit_msg>allow copy of mapnik::projection when proj_transform is created - closes #658 - TODO - consider using shared_ptr<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#ifndef PROJ_TRANSFORM_HPP
#define PROJ_TRANSFORM_HPP

// mapnik
#include <mapnik/projection.hpp>
#include <mapnik/box2d.hpp>

// boost
#include <boost/utility.hpp>

namespace mapnik {

class MAPNIK_DECL proj_transform : private boost::noncopyable
{
public:
    proj_transform(projection const& source,
                   projection const& dest);

    bool equal() const;
    bool forward (double& x, double& y , double& z) const;
    bool backward (double& x, double& y , double& z) const;
    bool forward (box2d<double> & box) const;
    bool backward (box2d<double> & box) const;
    mapnik::projection const& source() const;
    mapnik::projection const& dest() const;

private:
    projection const source_;
    projection const dest_;
    bool is_source_longlat_;
    bool is_dest_longlat_;
    bool is_source_equal_dest_;
};
}

#endif // PROJ_TRANSFORM_HPP
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "GridPartitioner.h"

#include "GeneratedMesh.h"
#include "MooseApp.h"

#include "libmesh/mesh_tools.h"
#include "libmesh/elem.h"

registerMooseObject("MooseApp", GridPartitioner);

#include <memory>

defineLegacyParams(GridPartitioner);

InputParameters
GridPartitioner::validParams()
{
  // These two are in this order because they are from different systems
  // so you have to apply _this_ system's second to override the base
  InputParameters params = MoosePartitioner::validParams();

  // Users specify how many processors they need along each direction
  params.addParam<unsigned int>("nx", 1, "Number of processors in the X direction");
  params.addParam<unsigned int>("ny", 1, "Number of processors in the Y direction");
  params.addParam<unsigned int>("nz", 1, "Number of processors in the Z direction");

  params.addClassDescription("Create a uniform grid that overlays the mesh to be partitioned.  "
                             "Assign all elements within each cell of the grid to the same "
                             "processor.");

  return params;
}

GridPartitioner::GridPartitioner(const InputParameters & params)
  : MoosePartitioner(params), _mesh(*getCheckedPointerParam<MooseMesh *>("mesh"))
{
}

GridPartitioner::~GridPartitioner() {}

std::unique_ptr<Partitioner>
GridPartitioner::clone() const
{
  return libmesh_make_unique<GridPartitioner>(_pars);
}

void
GridPartitioner::_do_partition(MeshBase & mesh, const unsigned int /*n*/)
{
  // By default, there are one processor along each direction
  // nx: the number of processors along x direction
  // ny: the number of processors along y direction
  // nz: the number of processors along z direction
  unsigned int nx = 1, ny = 1, nz = 1;

  // Figure out the physical bounds of the given mesh
  auto bounding_box = MeshTools::create_bounding_box(mesh);
  const auto & min = bounding_box.min();
  const auto & max = bounding_box.max();

  auto dim = mesh.mesh_dimension();
  //  Need to make sure the number of cells in the grid matches the number of procs to partition for
  nx = getParam<unsigned int>("nx");

  if (dim >= 2)
    ny = getParam<unsigned int>("ny");

  if (dim == 3)
    nz = getParam<unsigned int>("nz");

  // We should compute a balanced factorization so
  // that we can assign proper processors to each direction.
  // I just want to make grid partitioner smarter.
  if ((nx * ny * nz) != mesh.n_partitions())
  {
    // Anybody knows we are living in a 3D space.
    int dims[] = {0, 0, 0};
    MPI_Dims_create(mesh.n_partitions(), dim, dims);

    nx = dims[0];
    if (dim >= 2)
      ny = dims[1];
    if (dim == 3)
      nz = dims[2];
  }

  // hx: grid interval along x direction
  // hy: grid interval along y direction
  // hz: grid interval along z direction
  // Lx: domain length along x direction
  // Ly: domain length along y direction
  // Lz: domain length along z direction
  Real hx = 1., hy = 1., hz = 1., Lx = 1., Ly = 1., Lz = 1.;
  Lx = max(0) - min(0);
  hx = Lx / nx;
  if (dim >= 2)
  {
    Ly = max(1) - min(1);
    hy = Ly / ny;
  }

  if (dim == 3)
  {
    Lz = max(2) - min(2);
    hz = Lz / nz;
  }

  // Processor coordinates along x, y, z directions
  unsigned int k = 0, j = 0, i = 0;
  // Coordinates for current element centroid
  Real coordx = 0, coordy = 0, coordz = 0;

  // Loop over all of the elements in the given mesh
  for (auto & elem_ptr : mesh.active_element_ptr_range())
  {
    // Find the element it lands in in the GeneratedMesh
    auto centroid = elem_ptr->centroid();

    coordx = centroid(0);
    mooseAssert(coordx >= min(0) && coordy <= max(0),
                "element is outside of bounding box along x direction");
    if (dim >= 2)
    {
      coordy = centroid(1);
      mooseAssert(coordy >= min(1) && coordy <= max(1),
                  "element is outside of bounding box along x direction");
    }
    if (dim == 3)
    {
      coordz = centroid(2);
      mooseAssert(coordz >= min(2) && coordz <= max(2),
                  "element is outside of bounding box along x direction");
    }

    // Compute processor coordinates
    i = (coordx - min(0)) / hx;
    if (dim >= 2)
      j = (coordy - min(1)) / hy;
    if (dim == 3)
      k = (coordz - min(2)) / hz;

    mooseAssert(i < nx && i >= 0, "Index caculation is wrong along x direction");
    mooseAssert(j < ny && j >= 0, "Index caculation is wrong along y direction");
    mooseAssert(k < ny && k >= 0, "Index caculation is wrong along z direction");
    // Assign processor ID to current element
    elem_ptr->processor_id() = k * nx * ny + j * nx + i;
  }
}
<commit_msg>Fixed next for "Remove an intermediate MooseMesh from GridPartitioner #16633"<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "GridPartitioner.h"

#include "GeneratedMesh.h"
#include "MooseApp.h"

#include "libmesh/mesh_tools.h"
#include "libmesh/elem.h"

registerMooseObject("MooseApp", GridPartitioner);

#include <memory>

defineLegacyParams(GridPartitioner);

InputParameters
GridPartitioner::validParams()
{
  // These two are in this order because they are from different systems
  // so you have to apply _this_ system's second to override the base
  InputParameters params = MoosePartitioner::validParams();

  // Users specify how many processors they need along each direction
  params.addParam<unsigned int>("nx", 1, "Number of processors in the X direction");
  params.addParam<unsigned int>("ny", 1, "Number of processors in the Y direction");
  params.addParam<unsigned int>("nz", 1, "Number of processors in the Z direction");

  params.addClassDescription("Create a uniform grid that overlays the mesh to be partitioned.  "
                             "Assign all elements within each cell of the grid to the same "
                             "processor.");

  return params;
}

GridPartitioner::GridPartitioner(const InputParameters & params)
  : MoosePartitioner(params), _mesh(*getCheckedPointerParam<MooseMesh *>("mesh"))
{
}

GridPartitioner::~GridPartitioner() {}

std::unique_ptr<Partitioner>
GridPartitioner::clone() const
{
  return libmesh_make_unique<GridPartitioner>(_pars);
}

void
GridPartitioner::_do_partition(MeshBase & mesh, const unsigned int /*n*/)
{
  // By default, there are one processor along each direction
  // nx: the number of processors along x direction
  // ny: the number of processors along y direction
  // nz: the number of processors along z direction
  unsigned int nx = 1, ny = 1, nz = 1;

  // Figure out the physical bounds of the given mesh
  auto bounding_box = MeshTools::create_bounding_box(mesh);
  const auto & min = bounding_box.min();
  const auto & max = bounding_box.max();

  auto dim = mesh.mesh_dimension();
  //  Need to make sure the number of cells in the grid matches the number of procs to partition for
  nx = getParam<unsigned int>("nx");

  if (dim >= 2)
    ny = getParam<unsigned int>("ny");

  if (dim == 3)
    nz = getParam<unsigned int>("nz");

  // We should compute a balanced factorization so
  // that we can assign proper processors to each direction.
  // I just want to make grid partitioner smarter.
  if ((nx * ny * nz) != mesh.n_partitions())
  {
    // Anybody knows we are living in a 3D space.
    int dims[] = {0, 0, 0};
    MPI_Dims_create(mesh.n_partitions(), dim, dims);

    nx = dims[0];
    if (dim >= 2)
      ny = dims[1];
    if (dim == 3)
      nz = dims[2];
  }

  // hx: grid interval along x direction
  // hy: grid interval along y direction
  // hz: grid interval along z direction
  // Lx: domain length along x direction
  // Ly: domain length along y direction
  // Lz: domain length along z direction
  Real hx = 1., hy = 1., hz = 1., Lx = 1., Ly = 1., Lz = 1.;
  Lx = max(0) - min(0);
  hx = Lx / nx;
  if (dim >= 2)
  {
    Ly = max(1) - min(1);
    hy = Ly / ny;
  }

  if (dim == 3)
  {
    Lz = max(2) - min(2);
    hz = Lz / nz;
  }

  // Processor coordinates along x, y, z directions
  unsigned int k = 0, j = 0, i = 0;
  // Coordinates for current element centroid
  Real coordx = 0, coordy = 0, coordz = 0;

  // Loop over all of the elements in the given mesh
  for (auto & elem_ptr : mesh.active_element_ptr_range())
  {
    // Find the element it lands in in the GeneratedMesh
    auto centroid = elem_ptr->centroid();

    coordx = centroid(0);
    mooseAssert(coordx >= min(0) && coordy <= max(0),
                "element is outside of bounding box along x direction");
    if (dim >= 2)
    {
      coordy = centroid(1);
      mooseAssert(coordy >= min(1) && coordy <= max(1),
                  "element is outside of bounding box along y direction");
    }
    if (dim == 3)
    {
      coordz = centroid(2);
      mooseAssert(coordz >= min(2) && coordz <= max(2),
                  "element is outside of bounding box along z direction");
    }

    // Compute processor coordinates
    j = k = 0;
    i = (coordx - min(0)) / hx;
    if (dim >= 2)
      j = (coordy - min(1)) / hy;
    if (dim == 3)
      k = (coordz - min(2)) / hz;

    mooseAssert(i < nx, "Index caculation is wrong along x direction");
    mooseAssert(j < ny, "Index caculation is wrong along y direction");
    mooseAssert(k < nz, "Index caculation is wrong along z direction");
    // Assign processor ID to current element
    elem_ptr->processor_id() = k * nx * ny + j * nx + i;
  }
}
<|endoftext|>