<commit_before>//
// Copyright (c) 2013-2017 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_GAME_EDITOR_SETTINGSBAR_HPP
#define RJ_GAME_EDITOR_SETTINGSBAR_HPP

#include "button_item.hpp"
#include <rectojump/game/background/background_manager.hpp>
#include <rectojump/game/components/gradient_rect.hpp>
#include <rectojump/game/popup_manager.hpp>
#include <rectojump/global/common.hpp>
#include <rectojump/global/config_settings.hpp>
#include <rectojump/shared/level_manager/level_manager.hpp>
#include <rectojump/ui/connected_buttons.hpp>
#include <rectojump/ui/textbox.hpp>

namespace rj
{
	template<typename Editor>
	class settingsbar
	{
		Editor& m_editor;
		typename Editor::gh_type& m_gamehandler;
		background_manager<typename Editor::gh_type>& m_backgroundmgr;
		rndr& m_render;

		// interface
		sf::RectangleShape m_shape;
		ui::connected_buttons m_buttons;
		ui::button m_toggle_bar_button{{16.f, 16.f}, {16.f, 16.f}};
		sf::Texture m_toggle_bar_button_tx;
		sf::Font m_font;
		std::map<std::string, ui::textbox> m_textboxes;

		// moving
		bool m_is_expanded{true}, m_moving{false}, m_need_move_right{false},
		m_need_move_left{false};
		float m_moved{0.f};
		float m_max_move{m_shape.getSize().x - 32.f};
		static constexpr float m_move_step{1.f};

	public:
		settingsbar(Editor& e, const vec2f& size) :
			m_editor{e},
			m_gamehandler{e.gamehandler()},
			m_backgroundmgr{m_gamehandler.backgroundmgr()},
			m_render{m_gamehandler.rendermgr()},
			m_shape{size},
			m_toggle_bar_button_tx{m_gamehandler.datamgr().template get_as<sf::Texture>
								   ("arrow.png")},
			m_font{m_gamehandler.datamgr().template get_as<sf::Font>("Fipps-Regular.otf")}
		{this->init();}

		~settingsbar()
		{settings::set_editor_settings_expanded(m_is_expanded);}

		void update(dur duration)
		{
			for(auto& a : m_textboxes)
				a.second.update(duration);
			m_buttons.update(duration);
			m_toggle_bar_button.update(duration);

			if(m_toggle_bar_button.pressed() && !m_moving)
			{
				m_moved = 0.f;
				flip_h(m_toggle_bar_button);
				if(m_is_expanded) m_need_move_right = true;
				else m_need_move_left = true;
			}

			if(m_need_move_right)
			{
				if(m_moved > m_max_move)
				{
					m_moving = false;
					m_need_move_right = false;
					m_is_expanded = false;
					return;
				}

				m_moving = true;
				auto move_offset(vec2f{m_move_step, 0.f} * duration);
				this->move(move_offset);
				m_moved += move_offset.x;
			}

			if(m_need_move_left)
			{
				if(m_moved > m_max_move)
				{
					m_moving = false;
					m_need_move_left = false;
					m_is_expanded = true;
					return;
				}

				m_moving = true;
				auto move_offset(vec2f{-m_move_step, 0.f} * duration);
				this->move(move_offset);
				m_moved += -move_offset.x;
			}
		}

		void update_input()
		{
		}

		void render()
		{
			m_render(m_shape, m_toggle_bar_button, m_buttons, m_textboxes);
		}

		std::string get_tb_startcolor_text() noexcept
		{return m_textboxes["tb_bgstartcolor"].getText();}

		std::string get_tb_endcolor_text() noexcept
		{return m_textboxes["tb_bgendcolor"].getText();}

		std::string get_tb_pointcount_text() noexcept
		{return m_textboxes["tb_bgpointcount"].getText();}

		std::string get_tb_lvcreator_text() noexcept
		{return m_textboxes["tb_lvinf_creator"].getText();}

		auto get_bounds() const noexcept
		-> decltype(m_shape.getGlobalBounds())
		{return m_shape.getGlobalBounds();}

		const vec2f& get_size() const noexcept
		{return m_shape.getSize();}

	private:
		void init()
		{
			// TODO: avoid magic numbers here

			// shape
			auto& shape_size(m_shape.getSize());
			m_shape.setOrigin(shape_size / 2.f);
			m_shape.setPosition(shape_size / 2.f);
			m_shape.setFillColor(settings::get_color_default_light());

			// toggle (expand) settings bar
			m_toggle_bar_button.setOrigin(m_toggle_bar_button.getSize() / 2.f);
			m_toggle_bar_button.setTexture(&m_toggle_bar_button_tx);
			if(settings::get_editor_settings_expanded())
				flip_h(m_toggle_bar_button);
			else m_need_move_right = true;

			// button size
			vec2f btn_size{80.f, 25.f};
			// textbox size
			vec2f tb_size{200.f, 30.f};

			// buttons
			auto reset_zoom_btn(m_buttons.add_button_event<button_item>(
									[this]
			{
				m_editor.reset_zoom();
			}, vec2f{160.f, 25.f}, vec2f{shape_size.x / 2.f, shape_size.y / 2.f}));
			this->prepare_button(*reset_zoom_btn);
			reset_zoom_btn->setText("Reset zoom");

			auto reset_center_btn(m_buttons.add_button_event<button_item>(
									  [this]
			{
				m_editor.reset_center();
			}, vec2f{160.f, 25.f}, vec2f{shape_size.x / 2.f, shape_size.y / 2.f + 30.f}));
			this->prepare_button(*reset_center_btn);
			reset_center_btn->setText("Reset center");

			// textboxes
			// level name
			m_textboxes.emplace("tb_lvname", ui::textbox{tb_size,
														 vec2f{shape_size.x / 2.f,
															   shape_size.y - 100.f},
														 m_font, "Level Name"});
			this->prepare_textbox(m_textboxes["tb_lvname"]);

			// level info
			m_textboxes.emplace("tb_lvinf_creator", ui::textbox{tb_size,
																vec2f{shape_size.x / 2.f,
																	  shape_size.y - 60.f},
																m_font, "Level Creator"});
			this->prepare_textbox(m_textboxes["tb_lvinf_creator"]);

			// backgroundcolors
			auto spacing(10.f);
			auto bg_return_key_func(
						[this]
			{
				auto start_color(to_rgb(m_textboxes["tb_bgstartcolor"].getText()));
				auto end_color(to_rgb(m_textboxes["tb_bgendcolor"].getText()));
				auto point_count(m_textboxes["tb_bgpointcount"].getText());
				if(!mlk::stl_string::is_numeric(point_count))
				{
					m_gamehandler.popupmgr().template create_popup<popup_type::error>
							("invalid content (must be numeric): " + point_count);
					return;
				}
				m_backgroundmgr.bg_shape(state::editor).set_startcolor(start_color);
				m_backgroundmgr.bg_shape(state::editor).set_endcolor(end_color);
				m_backgroundmgr.bg_shape(state::editor).set_gradient_points(
							mlk::stl_string::to_int<std::size_t>(point_count));
			});

			m_textboxes.emplace("tb_bgstartcolor", ui::textbox{tb_size,
															   vec2f{shape_size.x / 2.f,
																	 tb_size.y + spacing},
															   m_font, "BG begin color"});
			m_textboxes["tb_bgstartcolor"].on_key_return = bg_return_key_func;
			this->prepare_textbox(m_textboxes["tb_bgstartcolor"]);

			m_textboxes.emplace("tb_bgendcolor", ui::textbox{tb_size,
															 vec2f{shape_size.x / 2.f,
																   (tb_size.y + spacing) * 2},
															 m_font, "BG end color"});
			m_textboxes["tb_bgendcolor"].on_key_return = bg_return_key_func;
			this->prepare_textbox(m_textboxes["tb_bgendcolor"]);

			m_textboxes.emplace("tb_bgpointcount", ui::textbox{tb_size,
															   vec2f{shape_size.x / 2.f,
																	 (tb_size.y + spacing) * 3},
															   m_font, "BG gradient count"});
			m_textboxes["tb_bgpointcount"].on_key_return = bg_return_key_func;
			this->prepare_textbox(m_textboxes["tb_bgpointcount"]);

			// buttons
			auto btn_gradient_apply(m_buttons.add_button_event<button_item>
									(bg_return_key_func, btn_size,
									 vec2f{shape_size.x / 2.f, (tb_size.y + spacing) * 4}));
			btn_gradient_apply->setText("Apply");
			this->prepare_button(*btn_gradient_apply);

			auto go_back_btn(m_buttons.add_button_event<button_item>(
			[this]
			{
				m_gamehandler.switch_to_main_menu();
			}, vec2f{200.f, btn_size.y},
			vec2f{shape_size.x / 2.f,m_textboxes["tb_lvname"].getGlobalBounds().top - 30.f}));
			this->prepare_button(*go_back_btn);
			go_back_btn->setText("Back to Main Menu");

			auto save_btn(m_buttons.add_button_event<button_item>(
			[this]
			{
				m_editor.handle_save(m_textboxes["tb_lvname"].getText());
			}, btn_size, vec2f{shape_size.x / 2.f - 60.f, shape_size.y - btn_size.y}));
			this->prepare_button(*save_btn);
			save_btn->setText("Save");

			auto load_btn(m_buttons.add_button_event<button_item>(
							  [this]
			{
				m_editor.handle_load(m_textboxes["tb_lvname"].getText());
			}, btn_size, vec2f{shape_size.x / 2.f + 60.f, shape_size.y - btn_size.y}));
			this->prepare_button(*load_btn);
			load_btn->setText("Load");
		}

		template<typename Btn_Type>
		void prepare_button(Btn_Type& btn)
		{
			btn.setOrigin(btn.getSize() / 2.f);
			btn.setFont(m_font);
			btn.setFontSize(12);
			btn.setFontColor(settings::get_color_light());
		}

		void prepare_textbox(ui::textbox& tb)
		{
			tb.setOrigin(tb.getSize() / 2.f);
			tb.setTextColor(settings::get_color_light());
			tb.setTextSize(12);
			tb.setOutlineThickness(2.f);
			tb.setOutlineColor(settings::get_color_default_dark());
			tb.setFillColor({0, 0, 0, 0});
		}

		void move(const vec2f& offset) noexcept
		{
			m_shape.move(offset);
			m_toggle_bar_button.move(offset);
			for(auto& a : m_buttons.get_buttons())
				a.second.button->move(offset);
			for(auto& a : m_textboxes)
				a.second.move(offset);
		}
	};
}

#endif // RJ_GAME_EDITOR_SETTINGSBAR_HPP
<commit_msg>fixed bad_alloc, max gradient count == 127<commit_after>//
// Copyright (c) 2013-2017 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_GAME_EDITOR_SETTINGSBAR_HPP
#define RJ_GAME_EDITOR_SETTINGSBAR_HPP

#include "button_item.hpp"
#include <rectojump/game/background/background_manager.hpp>
#include <rectojump/game/components/gradient_rect.hpp>
#include <rectojump/game/popup_manager.hpp>
#include <rectojump/global/common.hpp>
#include <rectojump/global/config_settings.hpp>
#include <rectojump/shared/level_manager/level_manager.hpp>
#include <rectojump/ui/connected_buttons.hpp>
#include <rectojump/ui/textbox.hpp>

namespace rj
{
	template<typename Editor>
	class settingsbar
	{
		Editor& m_editor;
		typename Editor::gh_type& m_gamehandler;
		background_manager<typename Editor::gh_type>& m_backgroundmgr;
		rndr& m_render;

		// interface
		sf::RectangleShape m_shape;
		ui::connected_buttons m_buttons;
		ui::button m_toggle_bar_button{{16.f, 16.f}, {16.f, 16.f}};
		sf::Texture m_toggle_bar_button_tx;
		sf::Font m_font;
		std::map<std::string, ui::textbox> m_textboxes;

		// moving
		bool m_is_expanded{true}, m_moving{false}, m_need_move_right{false},
		m_need_move_left{false};
		float m_moved{0.f};
		float m_max_move{m_shape.getSize().x - 32.f};
		static constexpr float m_move_step{1.f};

	public:
		settingsbar(Editor& e, const vec2f& size) :
			m_editor{e},
			m_gamehandler{e.gamehandler()},
			m_backgroundmgr{m_gamehandler.backgroundmgr()},
			m_render{m_gamehandler.rendermgr()},
			m_shape{size},
			m_toggle_bar_button_tx{m_gamehandler.datamgr().template get_as<sf::Texture>
								   ("arrow.png")},
			m_font{m_gamehandler.datamgr().template get_as<sf::Font>("Fipps-Regular.otf")}
		{this->init();}

		~settingsbar()
		{settings::set_editor_settings_expanded(m_is_expanded);}

		void update(dur duration)
		{
			for(auto& a : m_textboxes)
				a.second.update(duration);
			m_buttons.update(duration);
			m_toggle_bar_button.update(duration);

			if(m_toggle_bar_button.pressed() && !m_moving)
			{
				m_moved = 0.f;
				flip_h(m_toggle_bar_button);
				if(m_is_expanded) m_need_move_right = true;
				else m_need_move_left = true;
			}

			if(m_need_move_right)
			{
				if(m_moved > m_max_move)
				{
					m_moving = false;
					m_need_move_right = false;
					m_is_expanded = false;
					return;
				}

				m_moving = true;
				auto move_offset(vec2f{m_move_step, 0.f} * duration);
				this->move(move_offset);
				m_moved += move_offset.x;
			}

			if(m_need_move_left)
			{
				if(m_moved > m_max_move)
				{
					m_moving = false;
					m_need_move_left = false;
					m_is_expanded = true;
					return;
				}

				m_moving = true;
				auto move_offset(vec2f{-m_move_step, 0.f} * duration);
				this->move(move_offset);
				m_moved += -move_offset.x;
			}
		}

		void update_input()
		{
		}

		void render()
		{
			m_render(m_shape, m_toggle_bar_button, m_buttons, m_textboxes);
		}

		std::string get_tb_startcolor_text() noexcept
		{return m_textboxes["tb_bgstartcolor"].getText();}

		std::string get_tb_endcolor_text() noexcept
		{return m_textboxes["tb_bgendcolor"].getText();}

		std::string get_tb_pointcount_text() noexcept
		{return m_textboxes["tb_bgpointcount"].getText();}

		std::string get_tb_lvcreator_text() noexcept
		{return m_textboxes["tb_lvinf_creator"].getText();}

		auto get_bounds() const noexcept
		-> decltype(m_shape.getGlobalBounds())
		{return m_shape.getGlobalBounds();}

		const vec2f& get_size() const noexcept
		{return m_shape.getSize();}

	private:
		void init()
		{
			// TODO: avoid magic numbers here

			// shape
			auto& shape_size(m_shape.getSize());
			m_shape.setOrigin(shape_size / 2.f);
			m_shape.setPosition(shape_size / 2.f);
			m_shape.setFillColor(settings::get_color_default_light());

			// toggle (expand) settings bar
			m_toggle_bar_button.setOrigin(m_toggle_bar_button.getSize() / 2.f);
			m_toggle_bar_button.setTexture(&m_toggle_bar_button_tx);
			if(settings::get_editor_settings_expanded())
				flip_h(m_toggle_bar_button);
			else m_need_move_right = true;

			// button size
			vec2f btn_size{80.f, 25.f};
			// textbox size
			vec2f tb_size{200.f, 30.f};

			// buttons
			auto reset_zoom_btn(m_buttons.add_button_event<button_item>(
									[this]
			{
				m_editor.reset_zoom();
			}, vec2f{160.f, 25.f}, vec2f{shape_size.x / 2.f, shape_size.y / 2.f}));
			this->prepare_button(*reset_zoom_btn);
			reset_zoom_btn->setText("Reset zoom");

			auto reset_center_btn(m_buttons.add_button_event<button_item>(
									  [this]
			{
				m_editor.reset_center();
			}, vec2f{160.f, 25.f}, vec2f{shape_size.x / 2.f, shape_size.y / 2.f + 30.f}));
			this->prepare_button(*reset_center_btn);
			reset_center_btn->setText("Reset center");

			// textboxes
			// level name
			m_textboxes.emplace("tb_lvname", ui::textbox{tb_size,
														 vec2f{shape_size.x / 2.f,
															   shape_size.y - 100.f},
														 m_font, "Level Name"});
			this->prepare_textbox(m_textboxes["tb_lvname"]);

			// level info
			m_textboxes.emplace("tb_lvinf_creator", ui::textbox{tb_size,
																vec2f{shape_size.x / 2.f,
																	  shape_size.y - 60.f},
																m_font, "Level Creator"});
			this->prepare_textbox(m_textboxes["tb_lvinf_creator"]);

			// backgroundcolors
			auto spacing(10.f);
			auto bg_return_key_func(
			[this]
			{
				auto point_count(m_textboxes["tb_bgpointcount"].getText());
				if(mlk::stl_string::is_numeric(point_count))
				{
					if((point_count.length() > 3) ||
					   (std::stoi(point_count) > (int)std::numeric_limits<char>::max()))
					{
						m_gamehandler.popupmgr().template create_popup<popup_type::error>
								("Max point count is 127: " + point_count);
						return;
					}
				}
				else
				{
					m_gamehandler.popupmgr().template create_popup<popup_type::error>
							("invalid content (must be numeric): " + point_count);
					return;
				}

				auto start_color(to_rgb(m_textboxes["tb_bgstartcolor"].getText()));
				auto end_color(to_rgb(m_textboxes["tb_bgendcolor"].getText()));

				m_backgroundmgr.bg_shape(state::editor).set_startcolor(start_color);
				m_backgroundmgr.bg_shape(state::editor).set_endcolor(end_color);
				m_backgroundmgr.bg_shape(state::editor).set_gradient_points(
							mlk::stl_string::to_int<std::size_t>(point_count));
			});

			m_textboxes.emplace("tb_bgstartcolor", ui::textbox{tb_size,
															   vec2f{shape_size.x / 2.f,
																	 tb_size.y + spacing},
															   m_font, "BG begin color"});
			m_textboxes["tb_bgstartcolor"].on_key_return = bg_return_key_func;
			this->prepare_textbox(m_textboxes["tb_bgstartcolor"]);

			m_textboxes.emplace("tb_bgendcolor", ui::textbox{tb_size,
															 vec2f{shape_size.x / 2.f,
																   (tb_size.y + spacing) * 2},
															 m_font, "BG end color"});
			m_textboxes["tb_bgendcolor"].on_key_return = bg_return_key_func;
			this->prepare_textbox(m_textboxes["tb_bgendcolor"]);

			m_textboxes.emplace("tb_bgpointcount", ui::textbox{tb_size,
															   vec2f{shape_size.x / 2.f,
																	 (tb_size.y + spacing) * 3},
															   m_font, "BG gradient count"});
			m_textboxes["tb_bgpointcount"].on_key_return = bg_return_key_func;
			this->prepare_textbox(m_textboxes["tb_bgpointcount"]);

			// buttons
			auto btn_gradient_apply(m_buttons.add_button_event<button_item>
									(bg_return_key_func, btn_size,
									 vec2f{shape_size.x / 2.f, (tb_size.y + spacing) * 4}));
			btn_gradient_apply->setText("Apply");
			this->prepare_button(*btn_gradient_apply);

			auto go_back_btn(m_buttons.add_button_event<button_item>(
			[this]
			{
				m_gamehandler.switch_to_main_menu();
			}, vec2f{200.f, btn_size.y},
			vec2f{shape_size.x / 2.f,m_textboxes["tb_lvname"].getGlobalBounds().top - 30.f}));
			this->prepare_button(*go_back_btn);
			go_back_btn->setText("Back to Main Menu");

			auto save_btn(m_buttons.add_button_event<button_item>(
			[this]
			{
				m_editor.handle_save(m_textboxes["tb_lvname"].getText());
			}, btn_size, vec2f{shape_size.x / 2.f - 60.f, shape_size.y - btn_size.y}));
			this->prepare_button(*save_btn);
			save_btn->setText("Save");

			auto load_btn(m_buttons.add_button_event<button_item>(
							  [this]
			{
				m_editor.handle_load(m_textboxes["tb_lvname"].getText());
			}, btn_size, vec2f{shape_size.x / 2.f + 60.f, shape_size.y - btn_size.y}));
			this->prepare_button(*load_btn);
			load_btn->setText("Load");
		}

		template<typename Btn_Type>
		void prepare_button(Btn_Type& btn)
		{
			btn.setOrigin(btn.getSize() / 2.f);
			btn.setFont(m_font);
			btn.setFontSize(12);
			btn.setFontColor(settings::get_color_light());
		}

		void prepare_textbox(ui::textbox& tb)
		{
			tb.setOrigin(tb.getSize() / 2.f);
			tb.setTextColor(settings::get_color_light());
			tb.setTextSize(12);
			tb.setOutlineThickness(2.f);
			tb.setOutlineColor(settings::get_color_default_dark());
			tb.setFillColor({0, 0, 0, 0});
		}

		void move(const vec2f& offset) noexcept
		{
			m_shape.move(offset);
			m_toggle_bar_button.move(offset);
			for(auto& a : m_buttons.get_buttons())
				a.second.button->move(offset);
			for(auto& a : m_textboxes)
				a.second.move(offset);
		}
	};
}

#endif // RJ_GAME_EDITOR_SETTINGSBAR_HPP
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Box.h"

#include <jpeglib.h>
#include <png.h>
#include <stdio.h>

#include <GL/gl.h>

#include <boost/bind.hpp>

#include "utf.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

// image/png - 89 50 4E 47 0D 0A 1A 0A
// image/gif - "GIF87a" or "GIF89a"
// image/jpeg - FF D8
// image/bmp - "BM"
// image/vnd.microsoft.icon - 00 00 01 00 (.ico), 00 00 02 00 (.cur)

namespace {

unsigned char* readAsPng(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    png_byte header[8];
    if (fread(header, 1, 8, file) != 8 || png_sig_cmp(header, 0, 8))
        return 0;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 0;
    }
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return 0;
    }

    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    unsigned bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    unsigned color_type = png_get_color_type(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type = GL_RGBA;
    }
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    switch (color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_PALETTE:
        format = GL_RGB;
        break;
    default:
        format = GL_RGBA;
        break;
    }
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_bytep data = (png_bytep) malloc(rowbytes * height);
    png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (unsigned i = 0; i < height; i++)
        row_pointers[i] = &data[rowbytes * i];
    png_read_image(png_ptr, row_pointers);
    free(row_pointers);

    png_read_end(png_ptr, end_info);
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return data;
}

unsigned char* readAsJpeg(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    unsigned char sig[2];
    if (fread(sig, 1, 2, file) != 2 || sig[0] != 0xFF || sig[1] != 0xD8)
        return 0;
    rewind(file);

    JSAMPARRAY img;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);  // TODO: set our own error handdler
    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, true);
    width = cinfo.image_width;
    height = cinfo.image_height;
    jpeg_start_decompress(&cinfo);

    unsigned char* data = (unsigned char*) malloc(height * width * cinfo.out_color_components);
    img = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * height);
    for (unsigned i = 0; i < height; ++i)
        img[i] = (JSAMPROW) &data[cinfo.out_color_components * width * i];

    while(cinfo.output_scanline < cinfo.output_height)
        jpeg_read_scanlines(&cinfo,
                            img + cinfo.output_scanline,
                            cinfo.output_height - cinfo.output_scanline);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(img);

    if (cinfo.out_color_components == 1)
        format = GL_LUMINANCE;
    else
        format = GL_RGB;
    return data;
}

}  // namespace

BoxImage::BoxImage(Box* box) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(0),
    format(GL_RGBA),
    img(static_cast<html::HTMLImageElement*>(0) /* nullptr */)
{
}

BoxImage::BoxImage(Box* box, const std::u16string& base, const std::u16string& url, unsigned repeat) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(repeat),
    format(GL_RGBA),
    img(static_cast<html::HTMLImageElement*>(0) /* nullptr */),
    request(base)
{
    open(url);
}

BoxImage::BoxImage(Box* box, const std::u16string& base, html::HTMLImageElement& img) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(Clamp),
    format(GL_RGBA),
    img(img),
    request(base)
{
    open(img.getSrc());
}

void BoxImage::open(const std::u16string& url)
{
    request.open(u"GET", url);
    request.setHanndler(boost::bind(&BoxImage::notify, this));
    request.send();
    state = Sent;
    if (request.getReadyState() != HttpRequest::DONE)
        return;
    if (request.getErrorFlag()) {
        state = Broken;
        return;
    }
    FILE* file = request.openFile();
    if (!file) {
        state = Broken;
        return;
    }
    pixels = readAsPng(file, naturalWidth, naturalHeight, format);
    if (!pixels) {
        rewind(file);
        pixels = readAsJpeg(file, naturalWidth, naturalHeight, format);
    }
    if (pixels)
        state = CompletelyAvailable;
    else
        state = Broken;
    fclose(file);
}

void BoxImage::notify()
{
    if (state == Sent) {
        if (request.getStatus() == 200)
            box->flags = 1;  // for updating render tree.
        else
            state = Unavailable;
    }
}

}}}}  // org::w3c::dom::bootstrap
<commit_msg>(readAsPng) : Support grayscale images of less than 8 bit depths.<commit_after>/*
 * Copyright 2011 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Box.h"

#include <jpeglib.h>
#include <png.h>
#include <stdio.h>

#include <GL/gl.h>

#include <boost/bind.hpp>

#include "utf.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

// image/png - 89 50 4E 47 0D 0A 1A 0A
// image/gif - "GIF87a" or "GIF89a"
// image/jpeg - FF D8
// image/bmp - "BM"
// image/vnd.microsoft.icon - 00 00 01 00 (.ico), 00 00 02 00 (.cur)

namespace {

unsigned char* readAsPng(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    png_byte header[8];
    if (fread(header, 1, 8, file) != 8 || png_sig_cmp(header, 0, 8))
        return 0;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 0;
    }
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return 0;
    }

    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    unsigned bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    unsigned color_type = png_get_color_type(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_gray_1_2_4_to_8(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type = GL_RGBA;
    }
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    switch (color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_PALETTE:
        format = GL_RGB;
        break;
    default:
        format = GL_RGBA;
        break;
    }
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_bytep data = (png_bytep) malloc(rowbytes * height);
    png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (unsigned i = 0; i < height; i++)
        row_pointers[i] = &data[rowbytes * i];
    png_read_image(png_ptr, row_pointers);
    free(row_pointers);

    png_read_end(png_ptr, end_info);
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return data;
}

unsigned char* readAsJpeg(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    unsigned char sig[2];
    if (fread(sig, 1, 2, file) != 2 || sig[0] != 0xFF || sig[1] != 0xD8)
        return 0;
    rewind(file);

    JSAMPARRAY img;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);  // TODO: set our own error handdler
    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, true);
    width = cinfo.image_width;
    height = cinfo.image_height;
    jpeg_start_decompress(&cinfo);

    unsigned char* data = (unsigned char*) malloc(height * width * cinfo.out_color_components);
    img = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * height);
    for (unsigned i = 0; i < height; ++i)
        img[i] = (JSAMPROW) &data[cinfo.out_color_components * width * i];

    while(cinfo.output_scanline < cinfo.output_height)
        jpeg_read_scanlines(&cinfo,
                            img + cinfo.output_scanline,
                            cinfo.output_height - cinfo.output_scanline);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(img);

    if (cinfo.out_color_components == 1)
        format = GL_LUMINANCE;
    else
        format = GL_RGB;
    return data;
}

}  // namespace

BoxImage::BoxImage(Box* box) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(0),
    format(GL_RGBA),
    img(static_cast<html::HTMLImageElement*>(0) /* nullptr */)
{
}

BoxImage::BoxImage(Box* box, const std::u16string& base, const std::u16string& url, unsigned repeat) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(repeat),
    format(GL_RGBA),
    img(static_cast<html::HTMLImageElement*>(0) /* nullptr */),
    request(base)
{
    open(url);
}

BoxImage::BoxImage(Box* box, const std::u16string& base, html::HTMLImageElement& img) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(Clamp),
    format(GL_RGBA),
    img(img),
    request(base)
{
    open(img.getSrc());
}

void BoxImage::open(const std::u16string& url)
{
    request.open(u"GET", url);
    request.setHanndler(boost::bind(&BoxImage::notify, this));
    request.send();
    state = Sent;
    if (request.getReadyState() != HttpRequest::DONE)
        return;
    if (request.getErrorFlag()) {
        state = Broken;
        return;
    }
    FILE* file = request.openFile();
    if (!file) {
        state = Broken;
        return;
    }
    pixels = readAsPng(file, naturalWidth, naturalHeight, format);
    if (!pixels) {
        rewind(file);
        pixels = readAsJpeg(file, naturalWidth, naturalHeight, format);
    }
    if (pixels)
        state = CompletelyAvailable;
    else
        state = Broken;
    fclose(file);
}

void BoxImage::notify()
{
    if (state == Sent) {
        if (request.getStatus() == 200)
            box->flags = 1;  // for updating render tree.
        else
            state = Unavailable;
    }
}

}}}}  // org::w3c::dom::bootstrap
<|endoftext|>


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

int MAX_CHARACTERS_INPUT = 30000; // max number of characters allowed in buffer
int SEPERATE = 200; // amount of characters to put in each file

std::string readTo(const char*, int, int);

int main(int argc, char *argv[]){
  char file[256]; // hold the filename
  if(argc == 1){ // if there was no parameter for a file name, ask for one
    std::cout << "File: ";
    std::cin >> file;
  }else{ // convert the argv into a usable char array so the file can be used
    std::strcpy(&file[0], argv[1]);
  }

  std::ifstream ifs(file); // open the filestream

  if(ifs.is_open()){
    ifs.seekg (0, ifs.end); // set the pointer of ifs to the end of the file
    int filelen = ifs.tellg(); // store the position of eof() in filelen
    int numfiles = (filelen/200); // calculates how many files will be split
    ifs.seekg (0, ifs.beg); // set the pointer of ifs back to the start

    if(filelen <= MAX_CHARACTERS_INPUT){
      char* buffer = new char[filelen]; // make a buffer using dynamic memory
      std::cout << "Reading file\n"; // update the user as-to what is happening
      ifs.read(buffer, filelen); // read the file into the buffer

      std::ofstream ofs;
      std::cout << "Seperating into " << numfiles << " files\n";

      for(int i = 0; i < numfiles; ++i){
        int begin = (i*SEPERATE);
        int end = begin+SEPERATE;
        std::string filename = "out";
        filename+=i; // add number to the name of the output file
        ofs.open(filename.c_str());
        ofs << readTo(buffer, begin, end);
        ofs.close();
      }

      delete[] buffer; // free the memory from the read file
    }else{ // the file is too big, output a message saying so
      std::cout << "Input exceeds limit\n";
      std::cout << "MAX: " << MAX_CHARACTERS_INPUT << std::endl;
      std::cout << "GIVEN: " << filelen << std::endl;
    }
  }else{ // if there was a problem opening file, output error message
    std::cout << "Error opening file\n"; // if there is any problem opening
  }
  ifs.close(); // close the file!

  std::cout << "Finished."
}

std::string readTo(const char* in, int start, int size){
  std::string result;
  for(int i=start; i < start+size; ++i){
    result+=in[i];
  }
  return result;
}
<commit_msg>Fixed bugs<commit_after>
#include <fstream>
#include <cstring>
#include <string>
#include <iostream>
#include <cassert>
#include <sstream>

int MAX_CHARACTERS_INPUT = 30000; // max number of characters allowed in buffer
int SEPERATE = 200; // amount of characters to put in each file

std::string readTo(const char*, int, int);
std::string readTo(std::string&, int, int);

int main(int argc, char *argv[]){
  char file[256]; // hold the filename
  if(argc == 1){ // if there was no parameter for a file name, ask for one
    std::cout << "File: ";
    std::cin >> file;
  }else{ // convert the argv into a usable char array so the file can be used
    std::strcpy(&file[0], argv[1]);
  }

  std::ifstream ifs(file); // open the filestream

  if(ifs.is_open()){
    ifs.seekg (0, ifs.end); // set the pointer of ifs to the end of the file
    int filelen = ifs.tellg(); // store the position of eof() in filelen
    int numfiles; // how many files will be split
    ifs.seekg (0, ifs.beg); // set the pointer of ifs back to the start

    if(filelen%200 != 0){ // calculates the number of files that will be split
      numfiles = (filelen/SEPERATE)+1;
    }else{
      numfiles = (filelen/SEPERATE);
    }

    if(filelen <= MAX_CHARACTERS_INPUT){
      char* buffer = new char[filelen]; // make a buffer using dynamic memory
      std::cout << "Reading file\n"; // update the user as-to what is happening
      ifs.read(buffer, filelen); // read the file into the buffer

      std::ofstream ofs; // open a out file stream
      std::cout << "Seperating into " << numfiles << " files\n";

      std::string filename;

      for(int i = 0; i < numfiles; ++i){
        int begin = (i*SEPERATE);

        filename = "out";
        filename+='A'+i; // naming mechanism for the output files

        std::cout << "Writing " << filename << "..." << std::endl;
        ofs.open(filename.c_str()); // open the file with the filename
        ofs << readTo(buffer, begin, SEPERATE); // reads each segment
        ofs.close(); // closes the file so the next one can be opened
      }

      delete[] buffer; // free the memory from the read file
    }else{ // the file is too big, output a message saying so
      std::cout << "Input exceeds limit\n";
      std::cout << "MAX: " << MAX_CHARACTERS_INPUT << std::endl;
      std::cout << "GIVEN: " << filelen << std::endl;
    }
  }else{ // if there was a problem opening file, output error message
    std::cout << "Error opening file\n"; // if there is any problem opening
  }
  ifs.close(); // close the file!

  std::cout << "Finished.\n";
}

std::string readTo(const char* in, int start, int size){
  std::string result;
  for(int i=start; i < start+size; ++i){
    if(in[i] != '\0'){
      result+=in[i];
    }else{
      break;
    }
  }
  return result;
}

std::string readTo(std::string& in, int start, int size){
  std::string result;
  for(int i=start; i < start+size; ++i){
    if(i < int(in.length())){
      result+=in[i];
    }
  }
  return result;
}
<|endoftext|>


<commit_before>using namespace GeFiCa;
// calculate and save fields of a PPC
void calculateFields(const char *output="ppc.root")
{
   PointContactDZ *ppc = new PointContactDZ(400,501);
   ppc->V0=1.4*kV; ppc->V1=0;

   ppc->Radius=4.00*cm;
   ppc->Height=5.00*cm;

   ppc->PointContactR=0.30*cm;
   ppc->PointContactH=0.10*cm;

   ppc->WrapArroundR=1.20*cm;
   ppc->TaperW=0.1*cm;
   ppc->TaperH=0.1*cm;
   ppc->CornerW=0.1*cm;
   ppc->CornerH=0.1*cm;

   ppc->HoleH=2.5*cm;
   ppc->HoleR=0.5*cm;
   ppc->HoleTaperH=0.2*cm;
   ppc->HoleTaperW=0.2*cm;

   ppc->GrooveH=0.1*cm;
   ppc->GrooveW=0.1*cm;

   // x in TF3 -> r, y in TF3 -> z
   TF3 *fid = new TF3("fImpDistr","0.7e10");
   ppc->SetImpurity(fid);

   ppc->Csor=1.995;
   ppc->CalculatePotential(kSOR2);

   TFile *file = new TFile(output,"recreate");
   ppc->Write();
   file->Close();
}
<commit_msg>removed kSOR2<commit_after>using namespace GeFiCa;
// calculate and save fields of a PPC
void calculateFields(const char *output="ppc.root")
{
   PointContactDZ *ppc = new PointContactDZ(400,501);
   ppc->V0=1.4*kV; ppc->V1=0;

   ppc->Radius=4.00*cm;
   ppc->Height=5.00*cm;

   ppc->PointContactR=0.30*cm;
   ppc->PointContactH=0.10*cm;

   ppc->WrapAroundR=1.20*cm;
   ppc->TaperW=0.1*cm;
   ppc->TaperH=0.1*cm;
   ppc->CornerW=0.1*cm;
   ppc->CornerH=0.1*cm;

   ppc->HoleH=2.5*cm;
   ppc->HoleR=0.5*cm;
   ppc->HoleTaperH=0.2*cm;
   ppc->HoleTaperW=0.2*cm;

   ppc->GrooveH=0.1*cm;
   ppc->GrooveW=0.1*cm;

   // x in TF3 -> r, y in TF3 -> z
   TF3 *fid = new TF3("fImpDistr","0.7e10");
   ppc->SetImpurity(fid);

   ppc->Csor=1.995;
   ppc->CalculatePotential();

   TFile *file = new TFile(output,"recreate");
   ppc->Write();
   file->Close();
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkXOpenGLTextMapper.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2000 Ken Martin, Will Schroeder, Bill Lorensen
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 name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

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 REGENTS 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 "vtkXOpenGLTextMapper.h"
#include <GL/gl.h>
#include <GL/glx.h>
#include "vtkObjectFactory.h"

//------------------------------------------------------------------------------
vtkXOpenGLTextMapper* vtkXOpenGLTextMapper::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkXOpenGLTextMapper");
  if(ret)
    {
    return (vtkXOpenGLTextMapper*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkXOpenGLTextMapper;
}

struct vtkFontStruct
{
  vtkWindow *Window;
  int   Italic;
  int	Bold;
  int   FontSize;
  int   FontFamily;
  int   ListBase;
  GLXContext ContextId;
};

static vtkFontStruct *cache[30] = {
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL};
static int numCached = 0;

int vtkXOpenGLTextMapper::GetListBaseForFont(vtkTextMapper *tm,
					     vtkViewport *vp,
					     Font CurrentFont)
{
  int i, j;
  vtkWindow *win = vp->GetVTKWindow();

  // has the font been cached ?
  for (i = 0; i < numCached; i++)
    {
    if (cache[i]->Window == win &&
	cache[i]->Italic == tm->GetItalic() &&
	cache[i]->Bold == tm->GetBold() &&
	cache[i]->FontSize == tm->GetFontSize() &&
	cache[i]->FontFamily == tm->GetFontFamily())
      {
      // make this the most recently used
      if (i != 0)
	{
	vtkFontStruct *tmp = cache[i];
	for (j = i-1; j >= 0; j--)
	  {
	  cache[j+1] = cache[j];
	  }
	cache[0] = tmp;
	}
      return cache[0]->ListBase;
      }
    }

  // save the current context
  GLXContext ctx = glXGetCurrentContext();

  // OK the font is not cached
  // so we need to make room for a new font
  if (numCached == 30)
    {
    glXMakeCurrent((Display *)cache[29]->Window->GetGenericDisplayId(),
		   (Window)cache[29]->Window->GetGenericWindowId(),
		   cache[29]->ContextId);
    glDeleteLists(cache[29]->ListBase,255);
    glXMakeCurrent((Display *)win->GetGenericDisplayId(),
		   (Window)win->GetGenericWindowId(), ctx);
    numCached = 29;
    }

  // add the new font
  if (!cache[numCached])
    {
    cache[numCached] = new vtkFontStruct;
    int done = 0;
    cache[numCached]->ListBase = 1000;
    do
      {
      done = 1;
      cache[numCached]->ListBase += 260;
      for (i = 0; i < numCached; i++)
	{
	if (cache[i]->ListBase == cache[numCached]->ListBase)
	  {
	  done = 0;
	  }
	}
      }
    while (!done);
    }

  // set the other info and build the font
  cache[numCached]->Window = win;
  cache[numCached]->Italic = tm->GetItalic();
  cache[numCached]->Bold = tm->GetBold();
  cache[numCached]->FontSize = tm->GetFontSize();
  cache[numCached]->FontFamily = tm->GetFontFamily();
  cache[numCached]->ContextId = ctx;
  glXUseXFont(CurrentFont, 0, 255, cache[numCached]->ListBase);

  // now resort the list
  vtkFontStruct *tmp = cache[numCached];
  for (i = numCached-1; i >= 0; i--)
    {
    cache[i+1] = cache[i];
    }
  cache[0] = tmp;
  numCached++;
  return cache[0]->ListBase;
}

void vtkXOpenGLTextMapper::ReleaseGraphicsResources(vtkWindow *win)
{
  int i,j;

  // free up any cached font associated with this window
  // has the font been cached ?
  for (i = 0; i < numCached; i++)
    {
    if (cache[i]->Window == win)
      {
      glDeleteLists(cache[i]->ListBase,255);
      delete cache[i];
      // resort them
      numCached--;
      for (j = i; j < numCached; j++)
	{
	cache[j] = cache[j+1];
	}
      cache[numCached] = NULL;
      }
    }
  this->LastWindow = NULL;
}

vtkXOpenGLTextMapper::vtkXOpenGLTextMapper()
{
}

vtkXOpenGLTextMapper::~vtkXOpenGLTextMapper()
{
  if (this->LastWindow)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
}

void vtkXOpenGLTextMapper::RenderOpaqueGeometry(vtkViewport* viewport,
						vtkActor2D* actor)
{
  vtkDebugMacro (<< "RenderOpaqueGeometry");

  // turn off texturing in case it is on
  glDisable( GL_TEXTURE_2D );

  // Get the window information for display
  vtkWindow*  window = viewport->GetVTKWindow();
  if (this->LastWindow && this->LastWindow != window)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
  this->LastWindow = window;

  // Check for input
  if ( this->NumberOfLines > 1 )
    {
    this->RenderOpaqueGeometryMultipleLines(viewport, actor);
    return;
    }

  // Check for input
  if (this->Input == NULL || this->Input[0] == '\0')
    {
    vtkDebugMacro (<<"Render - No input");
    return;
    }

  int size[2];
  this->GetSize(viewport, size);

  // Get the position of the text actor
  int* actorPos =
    actor->GetPositionCoordinate()->GetComputedViewportValue(viewport);

  // Set up the font color from the text actor
  unsigned char red = 0;
  unsigned char green = 0;
  unsigned char blue = 0;
  float*  actorColor = actor->GetProperty()->GetColor();
  red = (unsigned char) (actorColor[0] * 255.0);
  green = (unsigned char) (actorColor[1] * 255.0);
  blue = (unsigned char) (actorColor[2] * 255.0);

  // Set up the shadow color
  float intensity;
  intensity = (red + green + blue)/3.0;

  unsigned char shadowRed, shadowGreen, shadowBlue;
  if (intensity > 128)
    {
    shadowRed = shadowBlue = shadowGreen = 0;
    }
  else
    {
    shadowRed = shadowBlue = shadowGreen = 255;
    }

  int pos[2];
  pos[0] = actorPos[0];
  pos[1] = (int)(actorPos[1] - this->LineOffset);

  switch (this->Justification)
    {
    case VTK_TEXT_LEFT: break;
    case VTK_TEXT_CENTERED:
      pos[0] = pos[0] - size[0]/2;
      break;
    case VTK_TEXT_RIGHT:
      pos[0] = pos[0] - size[0];
      break;
    }
  switch (this->VerticalJustification)
    {
    case VTK_TEXT_TOP:
      pos[1] = pos[1] - size[1];
      break;
    case VTK_TEXT_CENTERED:
      pos[1] = pos[1] - size[1]/2;
      break;
    case VTK_TEXT_BOTTOM:
      break;
    }

  // push a 2D matrix on the stack
  int *vsize = viewport->GetSize();
  glMatrixMode( GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  glMatrixMode( GL_MODELVIEW );
  glPushMatrix();
  glLoadIdentity();
  glDisable( GL_LIGHTING);

  glListBase(vtkXOpenGLTextMapper::GetListBaseForFont(this,viewport,
						      this->CurrentFont));

  int front =
    (actor->GetProperty()->GetDisplayLocation() == VTK_FOREGROUND_LOCATION);

  // Set the colors for the shadow
  if (this->Shadow)
    {
    pos[0]++; pos[1]--;
    // set the colors for the foreground
    glColor3ub(shadowRed, shadowGreen, shadowBlue);
    glRasterPos3f((2.0 * (GLfloat)(pos[0]) / vsize[0] - 1),
		  (2.0 * (GLfloat)(pos[1]) / vsize[1] - 1),
		  (front)?(-1):(.99999));

    // Draw the shadow text
    glCallLists (strlen(this->Input), GL_UNSIGNED_BYTE, this->Input);
    pos[0]--;  pos[1]++;
    }

  // set the colors for the foreground
  glColor3ub(red, green, blue);

  glRasterPos3f((2.0 * (GLfloat)(pos[0]) / vsize[0] - 1),
		(2.0 * (GLfloat)(pos[1]) / vsize[1] - 1),
		(front)?(-1):(.99999));

  // display a string: // indicate start of glyph display lists
  glCallLists (strlen(this->Input), GL_UNSIGNED_BYTE, this->Input);

  glMatrixMode( GL_PROJECTION);
  glPopMatrix();
  glMatrixMode( GL_MODELVIEW);
  glPopMatrix();
  glEnable( GL_LIGHTING);
}

<commit_msg>ERR:Fixed text picking bug<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkXOpenGLTextMapper.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2000 Ken Martin, Will Schroeder, Bill Lorensen
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 name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

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 REGENTS 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 "vtkXOpenGLTextMapper.h"
#include <GL/gl.h>
#include <GL/glx.h>
#include "vtkObjectFactory.h"
#include "vtkgluPickMatrix.h"

//--------------------------------------------------------------------------
vtkXOpenGLTextMapper* vtkXOpenGLTextMapper::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkXOpenGLTextMapper");
  if(ret)
    {
    return (vtkXOpenGLTextMapper*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkXOpenGLTextMapper;
}

struct vtkFontStruct
{
  vtkWindow *Window;
  int   Italic;
  int	Bold;
  int   FontSize;
  int   FontFamily;
  int   ListBase;
  GLXContext ContextId;
};

static vtkFontStruct *cache[30] = {
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL};
static int numCached = 0;

int vtkXOpenGLTextMapper::GetListBaseForFont(vtkTextMapper *tm,
					     vtkViewport *vp,
					     Font CurrentFont)
{
  int i, j;
  vtkWindow *win = vp->GetVTKWindow();

  // has the font been cached ?
  for (i = 0; i < numCached; i++)
    {
    if (cache[i]->Window == win &&
	cache[i]->Italic == tm->GetItalic() &&
	cache[i]->Bold == tm->GetBold() &&
	cache[i]->FontSize == tm->GetFontSize() &&
	cache[i]->FontFamily == tm->GetFontFamily())
      {
      // make this the most recently used
      if (i != 0)
	{
	vtkFontStruct *tmp = cache[i];
	for (j = i-1; j >= 0; j--)
	  {
	  cache[j+1] = cache[j];
	  }
	cache[0] = tmp;
	}
      return cache[0]->ListBase;
      }
    }

  // save the current context
  GLXContext ctx = glXGetCurrentContext();

  // OK the font is not cached
  // so we need to make room for a new font
  if (numCached == 30)
    {
    glXMakeCurrent((Display *)cache[29]->Window->GetGenericDisplayId(),
		   (Window)cache[29]->Window->GetGenericWindowId(),
		   cache[29]->ContextId);
    glDeleteLists(cache[29]->ListBase,255);
    glXMakeCurrent((Display *)win->GetGenericDisplayId(),
		   (Window)win->GetGenericWindowId(), ctx);
    numCached = 29;
    }

  // add the new font
  if (!cache[numCached])
    {
    cache[numCached] = new vtkFontStruct;
    int done = 0;
    cache[numCached]->ListBase = 1000;
    do
      {
      done = 1;
      cache[numCached]->ListBase += 260;
      for (i = 0; i < numCached; i++)
	{
	if (cache[i]->ListBase == cache[numCached]->ListBase)
	  {
	  done = 0;
	  }
	}
      }
    while (!done);
    }

  // set the other info and build the font
  cache[numCached]->Window = win;
  cache[numCached]->Italic = tm->GetItalic();
  cache[numCached]->Bold = tm->GetBold();
  cache[numCached]->FontSize = tm->GetFontSize();
  cache[numCached]->FontFamily = tm->GetFontFamily();
  cache[numCached]->ContextId = ctx;
  glXUseXFont(CurrentFont, 0, 255, cache[numCached]->ListBase);

  // now resort the list
  vtkFontStruct *tmp = cache[numCached];
  for (i = numCached-1; i >= 0; i--)
    {
    cache[i+1] = cache[i];
    }
  cache[0] = tmp;
  numCached++;
  return cache[0]->ListBase;
}

void vtkXOpenGLTextMapper::ReleaseGraphicsResources(vtkWindow *win)
{
  int i,j;

  // free up any cached font associated with this window
  // has the font been cached ?
  for (i = 0; i < numCached; i++)
    {
    if (cache[i]->Window == win)
      {
      glDeleteLists(cache[i]->ListBase,255);
      delete cache[i];
      // resort them
      numCached--;
      for (j = i; j < numCached; j++)
	{
	cache[j] = cache[j+1];
	}
      cache[numCached] = NULL;
      }
    }
  this->LastWindow = NULL;
}

vtkXOpenGLTextMapper::vtkXOpenGLTextMapper()
{
}

vtkXOpenGLTextMapper::~vtkXOpenGLTextMapper()
{
  if (this->LastWindow)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
}

void vtkXOpenGLTextMapper::RenderOpaqueGeometry(vtkViewport* viewport,
						vtkActor2D* actor)
{
  vtkDebugMacro (<< "RenderOpaqueGeometry");

  // turn off texturing in case it is on
  glDisable( GL_TEXTURE_2D );

  // Get the window information for display
  vtkWindow*  window = viewport->GetVTKWindow();
  if (this->LastWindow && this->LastWindow != window)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
  this->LastWindow = window;

  // Check for input
  if ( this->NumberOfLines > 1 )
    {
    this->RenderOpaqueGeometryMultipleLines(viewport, actor);
    return;
    }

  // Check for input
  if (this->Input == NULL || this->Input[0] == '\0')
    {
    vtkDebugMacro (<<"Render - No input");
    return;
    }

  int size[2];
  this->GetSize(viewport, size);

  // Get the position of the text actor
  int* actorPos =
    actor->GetPositionCoordinate()->GetComputedViewportValue(viewport);

  // Set up the font color from the text actor
  unsigned char red = 0;
  unsigned char green = 0;
  unsigned char blue = 0;
  float*  actorColor = actor->GetProperty()->GetColor();
  red = (unsigned char) (actorColor[0] * 255.0);
  green = (unsigned char) (actorColor[1] * 255.0);
  blue = (unsigned char) (actorColor[2] * 255.0);

  // Set up the shadow color
  float intensity;
  intensity = (red + green + blue)/3.0;

  unsigned char shadowRed, shadowGreen, shadowBlue;
  if (intensity > 128)
    {
    shadowRed = shadowBlue = shadowGreen = 0;
    }
  else
    {
    shadowRed = shadowBlue = shadowGreen = 255;
    }

  int pos[2];
  pos[0] = actorPos[0];
  pos[1] = (int)(actorPos[1] - this->LineOffset);

  switch (this->Justification)
    {
    case VTK_TEXT_LEFT: break;
    case VTK_TEXT_CENTERED:
      pos[0] = pos[0] - size[0]/2;
      break;
    case VTK_TEXT_RIGHT:
      pos[0] = pos[0] - size[0];
      break;
    }
  switch (this->VerticalJustification)
    {
    case VTK_TEXT_TOP:
      pos[1] = pos[1] - size[1];
      break;
    case VTK_TEXT_CENTERED:
      pos[1] = pos[1] - size[1]/2;
      break;
    case VTK_TEXT_BOTTOM:
      break;
    }

  // push a 2D matrix on the stack
  int *vsize = viewport->GetSize();
  glMatrixMode( GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  if(viewport->GetIsPicking())
    {
    vtkgluPickMatrix(viewport->GetPickX(), viewport->GetPickY(),
		     1, 1, viewport->GetOrigin(), viewport->GetSize());
    }
  glMatrixMode( GL_MODELVIEW );
  glPushMatrix();
  glLoadIdentity();
  glDisable( GL_LIGHTING);

  int front =
    (actor->GetProperty()->GetDisplayLocation() == VTK_FOREGROUND_LOCATION);

  // When picking draw the bounds of the text as a rectangle,
  // as text only picks when the pick point is exactly on the
  // origin of the text
  if(viewport->GetIsPicking())
    {
    float x1 = (2.0*(float)actorPos[0] / vsize[0] - 1);
    float y1 = (2.0*((float)actorPos[1] - this->LineOffset) / vsize[1] - 1);
    float width = 2.0*(float)size[0]/vsize[0];
    float height = 2.0*(float)size[1]/vsize[1];
    glRectf(x1, y1, x1+width, y1+height);

    // Clean up and return after drawing the rectangle
    glMatrixMode( GL_PROJECTION);
    glPopMatrix();
    glMatrixMode( GL_MODELVIEW);
    glPopMatrix();
    glEnable( GL_LIGHTING);

    return;
    }

  glListBase(vtkXOpenGLTextMapper::GetListBaseForFont(this,viewport,
						      this->CurrentFont));

  // Set the colors for the shadow
  if (this->Shadow)
    {
    pos[0]++; pos[1]--;
    // set the colors for the foreground
    glColor3ub(shadowRed, shadowGreen, shadowBlue);
    glRasterPos3f((2.0 * (GLfloat)(pos[0]) / vsize[0] - 1),
		  (2.0 * (GLfloat)(pos[1]) / vsize[1] - 1),
		  (front)?(-1):(.99999));

    // Draw the shadow text
    glCallLists (strlen(this->Input), GL_UNSIGNED_BYTE, this->Input);
    pos[0]--;  pos[1]++;
    }

  // set the colors for the foreground
  glColor3ub(red, green, blue);

  glRasterPos3f((2.0 * (GLfloat)(pos[0]) / vsize[0] - 1),
		(2.0 * (GLfloat)(pos[1]) / vsize[1] - 1),
		(front)?(-1):(.99999));

  // display a string: // indicate start of glyph display lists
  glCallLists (strlen(this->Input), GL_UNSIGNED_BYTE, this->Input);

  glMatrixMode( GL_PROJECTION);
  glPopMatrix();
  glMatrixMode( GL_MODELVIEW);
  glPopMatrix();
  glEnable( GL_LIGHTING);
}

<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software 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 <algorithm>
#include <cassert>

#include "IECore/VectorTraits.h"

namespace IECore
{

template<class BoundIterator>
class BoundedKDTree<BoundIterator>::AxisSort
{
	public :
		AxisSort( unsigned int axis ) : m_axis( axis )
		{
		}

		bool operator() ( BoundIterator i, BoundIterator j )
		{
			return i->center()[m_axis] < j->center()[m_axis];
		}

	private :
		const unsigned int m_axis;
};

template<class BoundIterator>
class BoundedKDTree<BoundIterator>::Node
{
	public :

		Node() : m_cutAxisAndLeaf(0)
		{
			m_bound.makeEmpty();
			m_perm.first = 0;
			m_perm.last = 0;
		}

		inline void makeLeaf( PermutationIterator permFirst, PermutationIterator permLast )
		{
			m_cutAxisAndLeaf = 255;
			m_perm.first = &(*permFirst);
			m_perm.last = &(*permLast);
		}

		inline void makeBranch( unsigned char cutAxis )
		{
			m_cutAxisAndLeaf = cutAxis;
		}

		inline bool isLeaf() const
		{
			return m_cutAxisAndLeaf==255;
		}

		inline BoundIterator *permFirst() const
		{
			assert( isLeaf() );

			return m_perm.first;
		}

		inline BoundIterator *permLast() const
		{
			assert( isLeaf() );

			return m_perm.last;
		}

		inline bool isBranch() const
		{
			return m_cutAxisAndLeaf!=255;
		}

		inline unsigned char cutAxis() const
		{
			assert( isBranch() );

			return m_cutAxisAndLeaf;
		}

		inline Bound &bound()
		{
			return m_bound;
		}

		inline const Bound &bound() const
		{
			return m_bound;
		}

		static NodeIndex rootIndex()
		{
			return 1;
		}

		static NodeIndex lowChildIndex( NodeIndex index )
		{
			return index * 2;
		}

		static NodeIndex highChildIndex( NodeIndex index )
		{
			return index * 2 + 1;
		}

	private :

		unsigned char m_cutAxisAndLeaf;

		Bound m_bound;

		struct {
			BoundIterator *first;
			BoundIterator *last;
		} m_perm;

};

template<class BoundIterator>
unsigned char BoundedKDTree<BoundIterator>::majorAxis( PermutationConstIterator permFirst, PermutationConstIterator permLast )
{
	BaseType min, max;
	for( unsigned char i=0; i<VectorTraits<BaseType>::dimensions(); i++ ) {
		min[i] = Imath::limits<typename BaseType::BaseType>::max();
		max[i] = Imath::limits<typename BaseType::BaseType>::min();
	}

	/// \todo Find a better cutting axis
	for( PermutationConstIterator it=permFirst; it!=permLast; it++ )
	{
		BaseType center = (*it)->center();

		for( unsigned char i=0; i<VectorTraits<BaseType>::dimensions(); i++ )
		{
			if( center[i] < min[i] )
			{
				min[i] = center[i];
			}
			if( center[i] > max[i] )
			{
				max[i] = center[i];
			}
		}

	}
	unsigned char major = 0;
	BaseType size = max - min;
	for( unsigned char i=1; i<VectorTraits<BaseType>::dimensions(); i++ )
	{
		if( size[i] > size[major] )
		{
			major = i;
		}
	}
	return major;
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::bound( NodeIndex nodeIndex  )
{
	assert( nodeIndex < m_nodes.size() );

	Node &node = m_nodes[nodeIndex];

	assert( node.bound().isEmpty() );

	if( node.isLeaf() )
	{
		BoundIterator *permLast = node.permLast();
		for( BoundIterator *perm = node.permFirst(); perm!=permLast; perm++ )
		{
			node.bound().extendBy( **perm );
		}
	}
	else
	{
		assert( node.isBranch() );

		assert( Node::lowChildIndex( nodeIndex ) < m_nodes.size() );
		assert( Node::highChildIndex( nodeIndex ) < m_nodes.size() );

		bound( Node::lowChildIndex( nodeIndex ) );
		bound( Node::highChildIndex( nodeIndex ) );
		node.bound().extendBy( m_nodes[Node::lowChildIndex( nodeIndex )].bound() );
		node.bound().extendBy( m_nodes[Node::highChildIndex( nodeIndex )].bound() );
	}
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::build( NodeIndex nodeIndex, PermutationIterator permFirst, PermutationIterator permLast )
{
	// make room for the new node
	if( nodeIndex>=m_nodes.size() )
	{
		m_nodes.resize( nodeIndex+1 );
	}

	assert( nodeIndex < m_nodes.size() );

	Node &node = m_nodes[nodeIndex];

	if( permLast - permFirst > m_maxLeafSize )
	{
		unsigned int cutAxis = majorAxis( permFirst, permLast );
		PermutationIterator permMid = permFirst  + (permLast - permFirst)/2;
		std::nth_element( permFirst, permMid, permLast, AxisSort( cutAxis ) );

		// insert node
		node.makeBranch( cutAxis );

		build( Node::lowChildIndex( nodeIndex ), permFirst, permMid );
		build( Node::highChildIndex( nodeIndex ), permMid, permLast );
	}
	else
	{
		// leaf node
		node.makeLeaf( permFirst, permLast );
	}
}

template<class BoundIterator>
BoundedKDTree<BoundIterator>::BoundedKDTree( BoundIterator first, BoundIterator last, int maxLeafSize )
	:	m_maxLeafSize( maxLeafSize ), m_lastBound( last )
{
	m_perm.resize( last - first );
	unsigned int i=0;
	for( BoundIterator it=first; it!=last; it++ )
	{
		m_perm[i++] = it;
	}

	build( Node::rootIndex(), m_perm.begin(), m_perm.end() );
	bound( Node::rootIndex() );
}

template<class BoundIterator>
template<typename S>
unsigned int BoundedKDTree<BoundIterator>::intersectingBounds( const S &b, std::vector<BoundIterator> &bounds ) const
{
	bounds.clear();

	intersectingBoundsWalk(Node::rootIndex(), b, bounds );

	return bounds.size();
}

template<class BoundIterator>
template<typename S>
void BoundedKDTree<BoundIterator>::intersectingBoundsWalk(  NodeIndex nodeIndex, const S &b, std::vector<BoundIterator> &bounds ) const
{
	const Node &node = m_nodes[nodeIndex];
	if( node.isLeaf() )
	{
		BoundIterator *permLast = node.permLast();
		for( BoundIterator *perm = node.permFirst(); perm!=permLast; perm++ )
		{
			const Bound &bb = **perm;

			if ( bb.intersects(b) )
			{
				bounds.push_back( *perm );
			}
		}
	}
	else
	{
		NodeIndex firstChild = Node::highChildIndex( nodeIndex );
		if ( m_nodes[firstChild].bound().intersects(b) )
		{
			intersectingBoundsWalk( firstChild, b, bounds );
		}
		NodeIndex secondChild = Node::lowChildIndex( nodeIndex );
		if ( m_nodes[secondChild].bound().intersects(b) )
		{
			intersectingBoundsWalk( secondChild, b, bounds );
		}
	}
}

} // namespace IECore
<commit_msg>Better use of BoxTraits and VectorOps for reusability<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software 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 <algorithm>
#include <cassert>

#include "IECore/VectorTraits.h"
#include "IECore/VectorOps.h"

namespace IECore
{

template<class BoundIterator>
class BoundedKDTree<BoundIterator>::AxisSort
{
	public :
		AxisSort( unsigned int axis ) : m_axis( axis )
		{
		}

		bool operator() ( BoundIterator i, BoundIterator j )
		{
			return VectorTraits< BaseType >::get( BoxTraits<Bound>::center(*i), m_axis)
				< VectorTraits< BaseType >::get( BoxTraits<Bound>::center(*j), m_axis);
		}

	private :
		const unsigned int m_axis;
};

template<class BoundIterator>
class BoundedKDTree<BoundIterator>::Node
{
	public :

		Node() : m_cutAxisAndLeaf(0)
		{
			BoxTraits<Bound>::makeEmpty( m_bound );
			m_perm.first = 0;
			m_perm.last = 0;
		}

		inline void makeLeaf( PermutationIterator permFirst, PermutationIterator permLast )
		{
			m_cutAxisAndLeaf = 255;
			m_perm.first = &(*permFirst);
			m_perm.last = &(*permLast);
		}

		inline void makeBranch( unsigned char cutAxis )
		{
			m_cutAxisAndLeaf = cutAxis;
		}

		inline bool isLeaf() const
		{
			return m_cutAxisAndLeaf==255;
		}

		inline BoundIterator *permFirst() const
		{
			assert( isLeaf() );

			return m_perm.first;
		}

		inline BoundIterator *permLast() const
		{
			assert( isLeaf() );

			return m_perm.last;
		}

		inline bool isBranch() const
		{
			return m_cutAxisAndLeaf!=255;
		}

		inline unsigned char cutAxis() const
		{
			assert( isBranch() );

			return m_cutAxisAndLeaf;
		}

		inline Bound &bound()
		{
			return m_bound;
		}

		inline const Bound &bound() const
		{
			return m_bound;
		}

		static NodeIndex rootIndex()
		{
			return 1;
		}

		static NodeIndex lowChildIndex( NodeIndex index )
		{
			return index * 2;
		}

		static NodeIndex highChildIndex( NodeIndex index )
		{
			return index * 2 + 1;
		}

	private :

		unsigned char m_cutAxisAndLeaf;

		Bound m_bound;

		struct {
			BoundIterator *first;
			BoundIterator *last;
		} m_perm;

};

template<class BoundIterator>
unsigned char BoundedKDTree<BoundIterator>::majorAxis( PermutationConstIterator permFirst, PermutationConstIterator permLast )
{
	BaseType min, max;
	vecSetAll( min, Imath::limits<typename BaseType::BaseType>::max() );
	vecSetAll( max, Imath::limits<typename BaseType::BaseType>::min() );

	/// \todo Find a better cutting axis
	for( PermutationConstIterator it=permFirst; it!=permLast; it++ )
	{
		BaseType center = BoxTraits<Bound>::center(**it);

		for( unsigned char i=0; i<VectorTraits<BaseType>::dimensions(); i++ )
		{
			if( VectorTraits<BaseType>::get(center, i) < VectorTraits<BaseType>::get(min, i) )
			{
				VectorTraits<BaseType>::set(min, i, VectorTraits<BaseType>::get(center, i) );
			}
			if( VectorTraits<BaseType>::get(center, i) > VectorTraits<BaseType>::get(min, i) )
			{
				VectorTraits<BaseType>::set(max, i, VectorTraits<BaseType>::get(center, i) );
			}
		}

	}
	unsigned char major = 0;
	BaseType size;
	vecSub( max, min, size );
	for( unsigned char i=1; i<VectorTraits<BaseType>::dimensions(); i++ )
	{
		if( VectorTraits<BaseType>::get(size, i) > VectorTraits<BaseType>::get(size, major) )
		{
			major = i;
		}
	}
	return major;
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::bound( NodeIndex nodeIndex  )
{
	assert( nodeIndex < m_nodes.size() );

	Node &node = m_nodes[nodeIndex];

	assert( BoxTraits<Bound>::isEmpty( node.bound() ) );

	if( node.isLeaf() )
	{
		BoundIterator *permLast = node.permLast();
		for( BoundIterator *perm = node.permFirst(); perm!=permLast; perm++ )
		{
			BoxTraits<Bound>::extendBy( node.bound(), **perm );
		}
	}
	else
	{
		assert( node.isBranch() );

		assert( Node::lowChildIndex( nodeIndex ) < m_nodes.size() );
		assert( Node::highChildIndex( nodeIndex ) < m_nodes.size() );

		bound( Node::lowChildIndex( nodeIndex ) );
		bound( Node::highChildIndex( nodeIndex ) );
		BoxTraits<Bound>::extendBy( node.bound(), m_nodes[Node::lowChildIndex( nodeIndex )].bound() );
		BoxTraits<Bound>::extendBy( node.bound(), m_nodes[Node::highChildIndex( nodeIndex )].bound() );
	}
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::build( NodeIndex nodeIndex, PermutationIterator permFirst, PermutationIterator permLast )
{
	// make room for the new node
	if( nodeIndex>=m_nodes.size() )
	{
		m_nodes.resize( nodeIndex+1 );
	}

	assert( nodeIndex < m_nodes.size() );

	Node &node = m_nodes[nodeIndex];

	if( permLast - permFirst > m_maxLeafSize )
	{
		unsigned int cutAxis = majorAxis( permFirst, permLast );
		PermutationIterator permMid = permFirst  + (permLast - permFirst)/2;
		std::nth_element( permFirst, permMid, permLast, AxisSort( cutAxis ) );

		// insert node
		node.makeBranch( cutAxis );

		build( Node::lowChildIndex( nodeIndex ), permFirst, permMid );
		build( Node::highChildIndex( nodeIndex ), permMid, permLast );
	}
	else
	{
		// leaf node
		node.makeLeaf( permFirst, permLast );
	}
}

template<class BoundIterator>
BoundedKDTree<BoundIterator>::BoundedKDTree( BoundIterator first, BoundIterator last, int maxLeafSize )
	:	m_maxLeafSize( maxLeafSize ), m_lastBound( last )
{
	m_perm.resize( last - first );
	unsigned int i=0;
	for( BoundIterator it=first; it!=last; it++ )
	{
		m_perm[i++] = it;
	}

	build( Node::rootIndex(), m_perm.begin(), m_perm.end() );
	bound( Node::rootIndex() );
}

template<class BoundIterator>
template<typename S>
unsigned int BoundedKDTree<BoundIterator>::intersectingBounds( const S &b, std::vector<BoundIterator> &bounds ) const
{
	bounds.clear();

	intersectingBoundsWalk(Node::rootIndex(), b, bounds );

	return bounds.size();
}

template<class BoundIterator>
template<typename S>
void BoundedKDTree<BoundIterator>::intersectingBoundsWalk(  NodeIndex nodeIndex, const S &b, std::vector<BoundIterator> &bounds ) const
{
	const Node &node = m_nodes[nodeIndex];
	if( node.isLeaf() )
	{
		BoundIterator *permLast = node.permLast();
		for( BoundIterator *perm = node.permFirst(); perm!=permLast; perm++ )
		{
			const Bound &bb = **perm;

			if ( BoxTraits<Bound>::intersects( bb, b ) )
			{
				bounds.push_back( *perm );
			}
		}
	}
	else
	{
		NodeIndex firstChild = Node::highChildIndex( nodeIndex );
		if ( BoxTraits<Bound>::intersects( m_nodes[firstChild].bound(), b) )
		{
			intersectingBoundsWalk( firstChild, b, bounds );
		}
		NodeIndex secondChild = Node::lowChildIndex( nodeIndex );
		if ( BoxTraits<Bound>::intersects( m_nodes[secondChild].bound(), b) )
		{
			intersectingBoundsWalk( secondChild, b, bounds );
		}
	}
}

} // namespace IECore
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software 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 <algorithm>
#include <cassert>

#include "IECore/VectorTraits.h"
#include "IECore/VectorOps.h"
#include "IECore/BoxOps.h"

namespace IECore
{

template<class BoundIterator>
class BoundedKDTree<BoundIterator>::AxisSort
{
	public :
		AxisSort( unsigned int axis ) : m_axis( axis )
		{
		}

		bool operator() ( BoundIterator i, BoundIterator j )
		{
			return VectorTraits< BaseType >::get( boxCenter(*i), m_axis)
				< VectorTraits< BaseType >::get( boxCenter(*j), m_axis);
		}

	private :
		const unsigned int m_axis;
};

template<class BoundIterator>
BoundedKDTree<BoundIterator>::Node::Node() : m_cutAxisAndLeaf(0)
{
	BoxTraits<Bound>::makeEmpty( m_bound );
	m_perm.first = 0;
	m_perm.last = 0;
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::Node::makeLeaf( PermutationIterator permFirst, PermutationIterator permLast )
{
	m_cutAxisAndLeaf = 255;
	m_perm.first = &(*permFirst);
	m_perm.last = &(*permLast);
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::Node::makeBranch( unsigned char cutAxis )
{
	m_cutAxisAndLeaf = cutAxis;
}

template<class BoundIterator>
bool BoundedKDTree<BoundIterator>::Node::isLeaf() const
{
	return m_cutAxisAndLeaf==255;
}

template<class BoundIterator>
BoundIterator *BoundedKDTree<BoundIterator>::Node::permFirst() const
{
	assert( isLeaf() );

	return m_perm.first;
}

template<class BoundIterator>
BoundIterator *BoundedKDTree<BoundIterator>::Node::permLast() const
{
	assert( isLeaf() );

	return m_perm.last;
}

template<class BoundIterator>
bool BoundedKDTree<BoundIterator>::Node::isBranch() const
{
	return m_cutAxisAndLeaf!=255;
}

template<class BoundIterator>
unsigned char BoundedKDTree<BoundIterator>::Node::cutAxis() const
{
	assert( isBranch() );

	return m_cutAxisAndLeaf;
}

template<class BoundIterator>
typename BoundedKDTree<BoundIterator>::Bound &BoundedKDTree<BoundIterator>::Node::bound()
{
	return m_bound;
}

template<class BoundIterator>
const typename BoundedKDTree<BoundIterator>::Bound &BoundedKDTree<BoundIterator>::Node::bound() const
{
	return m_bound;
}

template<class BoundIterator>
unsigned char BoundedKDTree<BoundIterator>::majorAxis( PermutationConstIterator permFirst, PermutationConstIterator permLast )
{
	BaseType min, max;
	vecSetAll( min, Imath::limits<typename BaseType::BaseType>::max() );
	vecSetAll( max, Imath::limits<typename BaseType::BaseType>::min() );

	/// \todo Find a better cutting axis
	for( PermutationConstIterator it=permFirst; it!=permLast; it++ )
	{
		BaseType center = boxCenter(**it);

		for( unsigned char i=0; i<VectorTraits<BaseType>::dimensions(); i++ )
		{
			if( VectorTraits<BaseType>::get(center, i) < VectorTraits<BaseType>::get(min, i) )
			{
				VectorTraits<BaseType>::set(min, i, VectorTraits<BaseType>::get(center, i) );
			}
			if( VectorTraits<BaseType>::get(center, i) > VectorTraits<BaseType>::get(min, i) )
			{
				VectorTraits<BaseType>::set(max, i, VectorTraits<BaseType>::get(center, i) );
			}
		}

	}
	unsigned char major = 0;
	BaseType size;
	vecSub( max, min, size );
	for( unsigned char i=1; i<VectorTraits<BaseType>::dimensions(); i++ )
	{
		if( VectorTraits<BaseType>::get(size, i) > VectorTraits<BaseType>::get(size, major) )
		{
			major = i;
		}
	}
	return major;
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::bound( NodeIndex nodeIndex  )
{
	assert( nodeIndex < m_nodes.size() );

	Node &node = m_nodes[nodeIndex];

	assert( BoxTraits<Bound>::isEmpty( node.bound() ) );

	if( node.isLeaf() )
	{
		BoundIterator *permLast = node.permLast();
		for( BoundIterator *perm = node.permFirst(); perm!=permLast; perm++ )
		{
			boxExtend( node.bound(), **perm );
		}
	}
	else
	{
		assert( node.isBranch() );

		assert( lowChildIndex( nodeIndex ) < m_nodes.size() );
		assert( highChildIndex( nodeIndex ) < m_nodes.size() );

		bound( lowChildIndex( nodeIndex ) );
		bound( highChildIndex( nodeIndex ) );
		boxExtend( node.bound(), m_nodes[lowChildIndex( nodeIndex )].bound() );
		boxExtend( node.bound(), m_nodes[highChildIndex( nodeIndex )].bound() );
	}
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::build( NodeIndex nodeIndex, PermutationIterator permFirst, PermutationIterator permLast )
{
	// make room for the new node
	if( nodeIndex>=m_nodes.size() )
	{
		m_nodes.resize( nodeIndex+1 );
	}

	assert( nodeIndex < m_nodes.size() );

	Node &node = m_nodes[nodeIndex];

	if( permLast - permFirst > m_maxLeafSize )
	{
		unsigned int cutAxis = majorAxis( permFirst, permLast );
		PermutationIterator permMid = permFirst  + (permLast - permFirst)/2;
		std::nth_element( permFirst, permMid, permLast, AxisSort( cutAxis ) );

		// insert node
		node.makeBranch( cutAxis );

		build( lowChildIndex( nodeIndex ), permFirst, permMid );
		build( highChildIndex( nodeIndex ), permMid, permLast );
	}
	else
	{
		// leaf node
		node.makeLeaf( permFirst, permLast );
	}
}

template<class BoundIterator>
BoundedKDTree<BoundIterator>::BoundedKDTree( BoundIterator first, BoundIterator last, int maxLeafSize )
	:	m_maxLeafSize( maxLeafSize ), m_lastBound( last )
{
	m_perm.resize( last - first );
	unsigned int i=0;
	for( BoundIterator it=first; it!=last; it++ )
	{
		m_perm[i++] = it;
	}

	build( rootIndex(), m_perm.begin(), m_perm.end() );
	bound( rootIndex() );
}

template<class BoundIterator>
const typename BoundedKDTree<BoundIterator>::Node& BoundedKDTree<BoundIterator>::node( NodeIndex idx ) const
{
	assert( idx >= 0 );
	assert( idx < m_nodes.size() );

	return m_nodes[idx];
}

template<class BoundIterator>
typename BoundedKDTree<BoundIterator>::NodeIndex BoundedKDTree<BoundIterator>::rootIndex() const
{
	return 1;
}

template<class BoundIterator>
typename BoundedKDTree<BoundIterator>::NodeIndex BoundedKDTree<BoundIterator>::lowChildIndex( NodeIndex index )
{
	return index * 2;
}

template<class BoundIterator>
typename BoundedKDTree<BoundIterator>::NodeIndex BoundedKDTree<BoundIterator>::highChildIndex( NodeIndex index )
{
	return index * 2 + 1;
}

template<class BoundIterator>
template<typename S>
unsigned int BoundedKDTree<BoundIterator>::intersectingBounds( const S &b, std::vector<BoundIterator> &bounds ) const
{
	bounds.clear();

	intersectingBoundsWalk(rootIndex(), b, bounds );

	return bounds.size();
}

template<class BoundIterator>
template<typename S>
void BoundedKDTree<BoundIterator>::intersectingBoundsWalk(  NodeIndex nodeIndex, const S &b, std::vector<BoundIterator> &bounds ) const
{
	const Node &node = m_nodes[nodeIndex];
	if( node.isLeaf() )
	{
		BoundIterator *permLast = node.permLast();
		for( BoundIterator *perm = node.permFirst(); perm!=permLast; perm++ )
		{
			const Bound &bb = **perm;

			if ( boxIntersects( bb, b ) )
			{
				bounds.push_back( *perm );
			}
		}
	}
	else
	{
		NodeIndex firstChild = highChildIndex( nodeIndex );
		if ( boxIntersects( m_nodes[firstChild].bound(), b) )
		{
			intersectingBoundsWalk( firstChild, b, bounds );
		}
		NodeIndex secondChild = lowChildIndex( nodeIndex );
		if ( boxIntersects( m_nodes[secondChild].bound(), b) )
		{
			intersectingBoundsWalk( secondChild, b, bounds );
		}
	}
}

} // namespace IECore
<commit_msg>Removed todo - turns out the cutting axis we use is actually pretty good<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software 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 <algorithm>
#include <cassert>

#include "IECore/VectorTraits.h"
#include "IECore/VectorOps.h"
#include "IECore/BoxOps.h"

namespace IECore
{

template<class BoundIterator>
class BoundedKDTree<BoundIterator>::AxisSort
{
	public :
		AxisSort( unsigned int axis ) : m_axis( axis )
		{
		}

		bool operator() ( BoundIterator i, BoundIterator j )
		{
			return VectorTraits< BaseType >::get( boxCenter(*i), m_axis)
				< VectorTraits< BaseType >::get( boxCenter(*j), m_axis);
		}

	private :
		const unsigned int m_axis;
};

template<class BoundIterator>
BoundedKDTree<BoundIterator>::Node::Node() : m_cutAxisAndLeaf(0)
{
	BoxTraits<Bound>::makeEmpty( m_bound );
	m_perm.first = 0;
	m_perm.last = 0;
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::Node::makeLeaf( PermutationIterator permFirst, PermutationIterator permLast )
{
	m_cutAxisAndLeaf = 255;
	m_perm.first = &(*permFirst);
	m_perm.last = &(*permLast);
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::Node::makeBranch( unsigned char cutAxis )
{
	m_cutAxisAndLeaf = cutAxis;
}

template<class BoundIterator>
bool BoundedKDTree<BoundIterator>::Node::isLeaf() const
{
	return m_cutAxisAndLeaf==255;
}

template<class BoundIterator>
BoundIterator *BoundedKDTree<BoundIterator>::Node::permFirst() const
{
	assert( isLeaf() );

	return m_perm.first;
}

template<class BoundIterator>
BoundIterator *BoundedKDTree<BoundIterator>::Node::permLast() const
{
	assert( isLeaf() );

	return m_perm.last;
}

template<class BoundIterator>
bool BoundedKDTree<BoundIterator>::Node::isBranch() const
{
	return m_cutAxisAndLeaf!=255;
}

template<class BoundIterator>
unsigned char BoundedKDTree<BoundIterator>::Node::cutAxis() const
{
	assert( isBranch() );

	return m_cutAxisAndLeaf;
}

template<class BoundIterator>
typename BoundedKDTree<BoundIterator>::Bound &BoundedKDTree<BoundIterator>::Node::bound()
{
	return m_bound;
}

template<class BoundIterator>
const typename BoundedKDTree<BoundIterator>::Bound &BoundedKDTree<BoundIterator>::Node::bound() const
{
	return m_bound;
}

template<class BoundIterator>
unsigned char BoundedKDTree<BoundIterator>::majorAxis( PermutationConstIterator permFirst, PermutationConstIterator permLast )
{
	BaseType min, max;
	vecSetAll( min, Imath::limits<typename BaseType::BaseType>::max() );
	vecSetAll( max, Imath::limits<typename BaseType::BaseType>::min() );

	for( PermutationConstIterator it=permFirst; it!=permLast; it++ )
	{
		BaseType center = boxCenter(**it);

		for( unsigned char i=0; i<VectorTraits<BaseType>::dimensions(); i++ )
		{
			if( VectorTraits<BaseType>::get(center, i) < VectorTraits<BaseType>::get(min, i) )
			{
				VectorTraits<BaseType>::set(min, i, VectorTraits<BaseType>::get(center, i) );
			}
			if( VectorTraits<BaseType>::get(center, i) > VectorTraits<BaseType>::get(min, i) )
			{
				VectorTraits<BaseType>::set(max, i, VectorTraits<BaseType>::get(center, i) );
			}
		}

	}
	unsigned char major = 0;
	BaseType size;
	vecSub( max, min, size );
	for( unsigned char i=1; i<VectorTraits<BaseType>::dimensions(); i++ )
	{
		if( VectorTraits<BaseType>::get(size, i) > VectorTraits<BaseType>::get(size, major) )
		{
			major = i;
		}
	}
	return major;
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::bound( NodeIndex nodeIndex  )
{
	assert( nodeIndex < m_nodes.size() );

	Node &node = m_nodes[nodeIndex];

	assert( BoxTraits<Bound>::isEmpty( node.bound() ) );

	if( node.isLeaf() )
	{
		BoundIterator *permLast = node.permLast();
		for( BoundIterator *perm = node.permFirst(); perm!=permLast; perm++ )
		{
			boxExtend( node.bound(), **perm );
		}
	}
	else
	{
		assert( node.isBranch() );

		assert( lowChildIndex( nodeIndex ) < m_nodes.size() );
		assert( highChildIndex( nodeIndex ) < m_nodes.size() );

		bound( lowChildIndex( nodeIndex ) );
		bound( highChildIndex( nodeIndex ) );
		boxExtend( node.bound(), m_nodes[lowChildIndex( nodeIndex )].bound() );
		boxExtend( node.bound(), m_nodes[highChildIndex( nodeIndex )].bound() );
	}
}

template<class BoundIterator>
void BoundedKDTree<BoundIterator>::build( NodeIndex nodeIndex, PermutationIterator permFirst, PermutationIterator permLast )
{
	// make room for the new node
	if( nodeIndex>=m_nodes.size() )
	{
		m_nodes.resize( nodeIndex+1 );
	}

	assert( nodeIndex < m_nodes.size() );

	Node &node = m_nodes[nodeIndex];

	if( permLast - permFirst > m_maxLeafSize )
	{
		unsigned int cutAxis = majorAxis( permFirst, permLast );
		PermutationIterator permMid = permFirst  + (permLast - permFirst)/2;
		std::nth_element( permFirst, permMid, permLast, AxisSort( cutAxis ) );

		// insert node
		node.makeBranch( cutAxis );

		build( lowChildIndex( nodeIndex ), permFirst, permMid );
		build( highChildIndex( nodeIndex ), permMid, permLast );
	}
	else
	{
		// leaf node
		node.makeLeaf( permFirst, permLast );
	}
}

template<class BoundIterator>
BoundedKDTree<BoundIterator>::BoundedKDTree( BoundIterator first, BoundIterator last, int maxLeafSize )
	:	m_maxLeafSize( maxLeafSize ), m_lastBound( last )
{
	m_perm.resize( last - first );
	unsigned int i=0;
	for( BoundIterator it=first; it!=last; it++ )
	{
		m_perm[i++] = it;
	}

	build( rootIndex(), m_perm.begin(), m_perm.end() );
	bound( rootIndex() );
}

template<class BoundIterator>
const typename BoundedKDTree<BoundIterator>::Node& BoundedKDTree<BoundIterator>::node( NodeIndex idx ) const
{
	assert( idx >= 0 );
	assert( idx < m_nodes.size() );

	return m_nodes[idx];
}

template<class BoundIterator>
typename BoundedKDTree<BoundIterator>::NodeIndex BoundedKDTree<BoundIterator>::rootIndex() const
{
	return 1;
}

template<class BoundIterator>
typename BoundedKDTree<BoundIterator>::NodeIndex BoundedKDTree<BoundIterator>::lowChildIndex( NodeIndex index )
{
	return index * 2;
}

template<class BoundIterator>
typename BoundedKDTree<BoundIterator>::NodeIndex BoundedKDTree<BoundIterator>::highChildIndex( NodeIndex index )
{
	return index * 2 + 1;
}

template<class BoundIterator>
template<typename S>
unsigned int BoundedKDTree<BoundIterator>::intersectingBounds( const S &b, std::vector<BoundIterator> &bounds ) const
{
	bounds.clear();

	intersectingBoundsWalk(rootIndex(), b, bounds );

	return bounds.size();
}

template<class BoundIterator>
template<typename S>
void BoundedKDTree<BoundIterator>::intersectingBoundsWalk(  NodeIndex nodeIndex, const S &b, std::vector<BoundIterator> &bounds ) const
{
	const Node &node = m_nodes[nodeIndex];
	if( node.isLeaf() )
	{
		BoundIterator *permLast = node.permLast();
		for( BoundIterator *perm = node.permFirst(); perm!=permLast; perm++ )
		{
			const Bound &bb = **perm;

			if ( boxIntersects( bb, b ) )
			{
				bounds.push_back( *perm );
			}
		}
	}
	else
	{
		NodeIndex firstChild = highChildIndex( nodeIndex );
		if ( boxIntersects( m_nodes[firstChild].bound(), b) )
		{
			intersectingBoundsWalk( firstChild, b, bounds );
		}
		NodeIndex secondChild = lowChildIndex( nodeIndex );
		if ( boxIntersects( m_nodes[secondChild].bound(), b) )
		{
			intersectingBoundsWalk( secondChild, b, bounds );
		}
	}
}

} // namespace IECore
<|endoftext|>