<commit_before>#include <iostream>
#include <fstream>
#include <sstream>
#include <cmath>
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include <vector>
#include <algorithm>

#ifndef M_PI
    #define M_PI 3.14159265359
#endif

typedef unsigned char uchar;

// Load Hipparcos catalog
// The catalog is a (n,3) cv::Mat of mag, ra, de
cv::Mat load_catalog(const char* filename) {
    cv::Mat catalog(0, 3, CV_32FC1);
    std::ifstream file(filename);
    std::string line, cell;

    if (!file) {
        std::cerr << "Can't open catalog " << filename << std::endl;
        return catalog;
    }

    // Skip first line
    std::getline(file, line);

    // Extract each line data
    while (std::getline(file, line)) {
        std::stringstream line_str(line);

        // Read fields
        double hip(0.0), mag(0.0), ra(0.0), de(0.0);
        line_str >> hip; line_str.get();
        line_str >> mag; line_str.get();
        line_str >> ra; line_str.get();
        line_str >> de; line_str.get();

        // Convert angles to radians
        const double deg_to_rad = M_PI / 180.0;
        cv::Mat catline = (cv::Mat_<float>(1,3) << mag, ra * deg_to_rad, de * deg_to_rad);
        catalog.push_back(catline);
    }
    return catalog;
}

// Equivalent angle in specified interval
double angle_modulo(double angle, double min, double max) {
    while (angle < min) {
        angle += 2 * M_PI;
    }
    while (angle > max) {
        angle -= 2 * M_PI;
    }
    return angle;
}

struct planetarium {
    // Max size of the spread to one side in pixels
    // e.g. 1 means the square of pixels modified will be 3x3
    double psf_spread_size;

    // Screen
    double screen_distance; // Meters
    double screen_width; // Pixels
    double screen_height; // Pixels
    double screen_horizontal_pixel_size; // Meters per pixel
    double screen_vertical_pixel_size; // Meters per pixel

    // Attitude in radians
    double attitude_ra;
    double attitude_de;

    // The gaussian function
    float psf_gaussian(float distance, float amplitude, float spread) const {
        return amplitude * exp(-(distance*distance) / spread);
    }

    // Draw a gaussian psf at given screen coordinates
    void draw_gaussian(cv::Mat image, float star_x, float star_y, float amplitude, float spread) const {
        // Closest discrete pixel to the star location
        const int center_x = round(star_x);
        const int center_y = round(star_y);

        // For each pixel around the star
        for (int x = center_x - psf_spread_size; x <= center_x + psf_spread_size; x++) {
            for (int y = center_y - psf_spread_size; y <= center_y + psf_spread_size; y++) {

                // Get the point spread function value at that distance from the star
                float distance = sqrt(pow(star_x - x, 2) + pow(star_y - y, 2));

                // If within bounds, add it to current value
                if (y > 0 && x > 0 && y < image.rows && x < image.cols) {
                    image.at<float>(y,x) += psf_gaussian(distance, amplitude, spread);
                }
            }
        }
    }

    void draw_star(cv::Mat image, float star_x, float star_y, float mag) const {
        draw_gaussian(image, star_x, star_y, 1.0, 1.0);
    }

    // True if a (ra,de) coordinate is visible on the screen
    bool is_star_visible(const double ra, const double de) const {
        const double max_ra = std::atan((screen_width * screen_horizontal_pixel_size) / (2*screen_distance));
        const double max_de = std::atan((screen_height * screen_vertical_pixel_size) / (2*screen_distance));

        // RA is in [0;2pi] but DE is in [-pi;pi]
        return (ra > 2*M_PI - max_ra || ra < max_ra)
            && (de > -max_de && de < max_de);
    }

    void draw_visible_stars(cv::Mat image, cv::Mat catalog) const {
        // For each entry in the catalog
        for (int i = 0; i < catalog.rows; i++) {
            float mag = catalog.at<float>(i, 0);
            double ra = catalog.at<float>(i, 1);
            double de = catalog.at<float>(i, 2);

            // Translate star by current attitude
            ra = angle_modulo(ra - attitude_ra, 0, 2*M_PI);
            de = angle_modulo(de - attitude_de, -M_PI, M_PI);

            // If star is visible
            if (is_star_visible(ra, de)) {
                const double x = screen_distance * tan(ra);
                const double y = screen_distance * tan(de);

                // Convert between:
                // Origin in the center, (x,y) in meters
                // Origin in the corner, (x_screen,y_screen) in pixels
                const int x_screen = round(-x / screen_horizontal_pixel_size + screen_width / 2);
                const int y_screen = round(-y / screen_vertical_pixel_size + screen_height / 2);

                draw_star(image, x_screen, y_screen, mag);
            }
        }
    }

    cv::Mat render(cv::Mat catalog) const {
        // Black background
        cv::Mat image = cv::Mat::zeros(screen_height, screen_width, CV_32FC1);

        draw_visible_stars(image, catalog);

        // Threshold to 1.0
        cv::threshold(image, image, 1.0, 0.0, cv::THRESH_TRUNC);

        return image;
    }
};

int main() {
    cv::namedWindow("Planetarium", cv::WINDOW_AUTOSIZE);

    planetarium wall;

    wall.psf_spread_size = 5;

    wall.screen_distance = .3;
    wall.screen_width = 1000;
    wall.screen_height = 700;
    wall.screen_horizontal_pixel_size = 0.0002 ;
    wall.screen_vertical_pixel_size = 0.0002;

    wall.attitude_ra = 0*M_PI/180;
    wall.attitude_de = 0*M_PI/180;

    // Load star catalog
    cv::Mat catalog = load_catalog("../hip6.tsv");

    cv::Mat image = wall.render(catalog);

    int k;
    while((k = cvWaitKey(30)) != 27) {
        // Left
        if (k == 65361) {
            wall.attitude_ra += 1*M_PI/180;
            image = wall.render(catalog);
        }
        // Right
        else if (k == 65363) {
            wall.attitude_ra -= 1*M_PI/180;
            image = wall.render(catalog);
        }
        // Up
        else if (k == 65362) {
            wall.attitude_de += 1*M_PI/180;
            image = wall.render(catalog);
        }
        // Down
        else if (k == 65364) {
            wall.attitude_de -= 1*M_PI/180;
            image = wall.render(catalog);
        }

        cv::imshow("Planetarium", image);
    }

    return 0;
}
<commit_msg>Star rendering with correct relative magnitude<commit_after>#include <iostream>
#include <fstream>
#include <sstream>
#include <cmath>
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include <vector>
#include <algorithm>

#ifndef M_PI
    #define M_PI 3.14159265359
#endif

typedef unsigned char uchar;

// Load Hipparcos catalog
// The catalog is a (n,3) cv::Mat of mag, ra, de
cv::Mat load_catalog(const char* filename) {
    cv::Mat catalog(0, 3, CV_32FC1);
    std::ifstream file(filename);
    std::string line, cell;

    if (!file) {
        std::cerr << "Can't open catalog " << filename << std::endl;
        return catalog;
    }

    // Skip first line
    std::getline(file, line);

    // Extract each line data
    while (std::getline(file, line)) {
        std::stringstream line_str(line);

        // Read fields
        double hip(0.0), mag(0.0), ra(0.0), de(0.0);
        line_str >> hip; line_str.get();
        line_str >> mag; line_str.get();
        line_str >> ra; line_str.get();
        line_str >> de; line_str.get();

        // Convert angles to radians
        const double deg_to_rad = M_PI / 180.0;
        cv::Mat catline = (cv::Mat_<float>(1,3) << mag, ra * deg_to_rad, de * deg_to_rad);
        catalog.push_back(catline);
    }
    return catalog;
}

// Equivalent angle in specified interval
double angle_modulo(double angle, double min, double max) {
    while (angle < min) {
        angle += 2 * M_PI;
    }
    while (angle > max) {
        angle -= 2 * M_PI;
    }
    return angle;
}

struct planetarium {
    // Max size of the spread to one side in pixels
    // e.g. 1 means the square of pixels modified will be 3x3
    double psf_spread_size;

    // Screen
    double screen_distance; // Meters
    double screen_width; // Pixels
    double screen_height; // Pixels
    double screen_horizontal_pixel_size; // Meters per pixel
    double screen_vertical_pixel_size; // Meters per pixel

    // Attitude in radians
    double attitude_ra;
    double attitude_de;

    // Star rendering parameters
    double I_ref, m_ref, sigma_0;

    // Linear inverse gamma function
    float gamma_inverse(float intensity) const {
        float gamma = I_ref;
        return intensity / gamma;
    }

    // The gaussian function
    float psf_gaussian(float distance, float alpha, float sigma) const {
        return alpha * exp(-(distance*distance) / (sigma*sigma));
    }

    // Draw a gaussian psf at given screen coordinates
    void draw_gaussian(cv::Mat image, float star_x, float star_y, float alpha, float sigma) const {
        // Closest discrete pixel to the star location
        const int center_x = round(star_x);
        const int center_y = round(star_y);

        // For each pixel around the star
        for (int x = center_x - psf_spread_size; x <= center_x + psf_spread_size; x++) {
            for (int y = center_y - psf_spread_size; y <= center_y + psf_spread_size; y++) {

                // Get the point spread function value at that distance from the star
                float distance = sqrt(pow(star_x - x, 2) + pow(star_y - y, 2));

                // If within bounds, add it to current value
                if (y > 0 && x > 0 && y < image.rows && x < image.cols) {
                    image.at<float>(y,x) += gamma_inverse(psf_gaussian(distance, alpha, sigma));
                }
            }
        }
    }

    void draw_star(cv::Mat image, float star_x, float star_y, float mag) const {
        // Intensity of the star we are rendering
        const float I_star = I_ref * pow(10, (m_ref - mag)/2.5);

        // Maximum for rendering star with fixed sigma
        const float I_max = I_ref * sigma_0 * sigma_0 * M_PI;

        float alpha, sigma;
        if (I_star <= I_max) {
            alpha = I_star / (sigma_0 * sigma_0 * M_PI);
            sigma = sigma_0;
        }
        else {
            alpha = I_ref;
            sigma = sqrt(I_star / (I_ref * M_PI));
        }

        draw_gaussian(image, star_x, star_y, alpha, sigma);
    }

    // True if a (ra,de) coordinate is visible on the screen
    bool is_star_visible(const double ra, const double de) const {
        const double max_ra = std::atan((screen_width * screen_horizontal_pixel_size) / (2*screen_distance));
        const double max_de = std::atan((screen_height * screen_vertical_pixel_size) / (2*screen_distance));

        // RA is in [0;2pi] but DE is in [-pi;pi]
        return (ra > 2*M_PI - max_ra || ra < max_ra)
            && (de > -max_de && de < max_de);
    }

    void draw_visible_stars(cv::Mat image, cv::Mat catalog) const {
        // For each entry in the catalog
        for (int i = 0; i < catalog.rows; i++) {
            float mag = catalog.at<float>(i, 0);
            double ra = catalog.at<float>(i, 1);
            double de = catalog.at<float>(i, 2);

            // Translate star by current attitude
            ra = angle_modulo(ra - attitude_ra, 0, 2*M_PI);
            de = angle_modulo(de - attitude_de, -M_PI, M_PI);

            // If star is visible
            if (is_star_visible(ra, de)) {
                const double x = screen_distance * tan(ra);
                const double y = screen_distance * tan(de);

                // Convert between:
                // Origin in the center, (x,y) in meters
                // Origin in the corner, (x_screen,y_screen) in pixels
                const int x_screen = round(-x / screen_horizontal_pixel_size + screen_width / 2);
                const int y_screen = round(-y / screen_vertical_pixel_size + screen_height / 2);

                draw_star(image, x_screen, y_screen, mag);
            }
        }
    }

    cv::Mat render(cv::Mat catalog) const {
        // Black background
        cv::Mat image = cv::Mat::zeros(screen_height, screen_width, CV_32FC1);

        draw_visible_stars(image, catalog);

        // Threshold to 1.0
        cv::threshold(image, image, 1.0, 0.0, cv::THRESH_TRUNC);

        return image;
    }
};

int main() {
    cv::namedWindow("Planetarium", cv::WINDOW_AUTOSIZE);

    planetarium wall;

    wall.psf_spread_size = 5;

    wall.screen_distance = .3;
    wall.screen_width = 1000;
    wall.screen_height = 700;
    wall.screen_horizontal_pixel_size = 0.0002 ;
    wall.screen_vertical_pixel_size = 0.0002;

    wall.attitude_ra = 45*M_PI/180;
    wall.attitude_de = 20*M_PI/180;

    wall.I_ref = 1.0;
    wall.m_ref = 3.0;
    wall.sigma_0 = 0.5;

    // Load star catalog
    cv::Mat catalog = load_catalog("../hip6.tsv");

    cv::Mat image = wall.render(catalog);

    int k;
    while((k = cvWaitKey(30)) != 27) {
        // Left
        if (k == 65361) {
            wall.attitude_ra += 1*M_PI/180;
            image = wall.render(catalog);
        }
        // Right
        else if (k == 65363) {
            wall.attitude_ra -= 1*M_PI/180;
            image = wall.render(catalog);
        }
        // Up
        else if (k == 65362) {
            wall.attitude_de += 1*M_PI/180;
            image = wall.render(catalog);
        }
        // Down
        else if (k == 65364) {
            wall.attitude_de -= 1*M_PI/180;
            image = wall.render(catalog);
        }

        cv::imshow("Planetarium", image);
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <limits>
#include <map>
#include <string>
#include <stdexcept>

#include "shunting-yard.h"

void assert(double actual, double expected, const char* expr = 0) {
  double diff = actual - expected;
  if (diff < 0) diff *= -1;
  if (diff < 1e-15) {
    if(expr) {
      std::cout << "  '" << expr << "' indeed evaluated to " <<
        expected << "." << std::endl;
    } else {
      std::cout << "  actual value '" << actual <<
        "' indeed matches the expected value '" << expected << "'" << std::endl;
    }
  } else {
    if(expr) {
      std::cout << "  FAILURE '" << expr << "' evaluated to " <<
        actual << " and NOT " << expected << "!" << std::endl;
    } else {
      std::cout << "  FAILURE, actual value '" << actual <<
        "' does not match the expected value '" << expected <<
        "'" << std::endl;
    }
  }
}
void assert(const char* expr, double expected,
    std::map<std::string, double>* vars = 0) {
  double actual = calculator::calculate(expr, vars);
  assert(actual, expected, expr);
}

int main(int argc, char** argv) {
  std::map<std::string, double> vars;
  vars["pi"] = 3.14;
  vars["b1"] = 0;

  std::cout << "\nTests with static calculate::calculate()\n" << std::endl;

  assert("-pi + 1", -2.14, &vars);
  assert("-pi + 1 * b1", -3.14, &vars);

  assert("(20+10)*3/2-3", 42.0);
  assert("1 << 4", 16.0);
  assert("1+(-2*3)", -5);

  std::cout << "\nTests with calculate::compile() & calculate::eval()\n" << std::endl;

  calculator c1;
  c1.compile("-pi+1", &vars);
  assert(c1.eval(), -2.14);

  calculator c2("pi+4", &vars);
  assert(c2.eval(), 7.14);
  assert(c2.eval(), 7.14);

  calculator c3("pi+b1+b2", &vars);

  vars["b2"] = 1;
  assert(c3.eval(&vars), 4.14);

  vars["b2"] = .86;
  assert(c3.eval(&vars), 4);

  std::cout << "\nTesting boolean expressions\n" << std::endl;

  assert("3 < 3", false);
  assert("3 <= 3", true);
  assert("3 > 3", false);
  assert("3 >= 3", true);
  assert("3 == 3", true);
  assert("3 != 3", false);

  assert("(3 && true) == true", true);
  assert("(3 && 0) == true", false);
  assert("(3 || 0) == true", true);
  assert("(false || 0) == true", false);

  std::cout << "\nTesting exception management\n" << std::endl;

  try {
    c3.eval();
  } catch(std::domain_error err) {
    std::cout << "  THROWS as expected" << std::endl;
  }

  try {
    vars.erase("b2");
    c3.eval(&vars);
  } catch(std::domain_error err) {
    std::cout << "  THROWS as expected" << std::endl;
  }

  try {
    vars.erase("b1");
    vars["b2"] = 0;
    c3.eval(&vars);
    std::cout << "  Do not THROW as expected" << std::endl;
  } catch(std::domain_error err) {
    std::cout << "  If it THROWS it's a problem!" << std::endl;
  }

  std::cout << "\nEnd testing" << std::endl;

  return 0;
}
<commit_msg>Add assert_throws and assert_not_throw to test-*.cpp<commit_after>#include <iostream>
#include <limits>
#include <map>
#include <string>
#include <stdexcept>

#include "shunting-yard.h"

void assert(double actual, double expected, const char* expr = 0) {
  double diff = actual - expected;
  if (diff < 0) diff *= -1;
  if (diff < 1e-15) {
    if(expr) {
      std::cout << "  '" << expr << "' indeed evaluated to " <<
        expected << "." << std::endl;
    } else {
      std::cout << "  actual value '" << actual <<
        "' indeed matches the expected value '" << expected << "'" << std::endl;
    }
  } else {
    if(expr) {
      std::cout << "  FAILURE '" << expr << "' evaluated to " <<
        actual << " and NOT " << expected << "!" << std::endl;
    } else {
      std::cout << "  FAILURE, actual value '" << actual <<
        "' does not match the expected value '" << expected <<
        "'" << std::endl;
    }
  }
}
void assert(const char* expr, double expected,
    std::map<std::string, double>* vars = 0) {
  double actual = calculator::calculate(expr, vars);
  assert(actual, expected, expr);
}

#define assert_throws(a) {try {\
  a; \
  std::cout << "  FAILURE, it did not THROW as expected" << std::endl; \
} catch(...) { \
  std::cout << "  THROWS as expected" << std::endl; \
}}

#define assert_not_throw(a) {try {\
  a; \
  std::cout << "  Do not THROW as expected" << std::endl; \
} catch(...) { \
  std::cout << "  FAILURE, it did THROW which was unexpected" << std::endl; \
}}

int main(int argc, char** argv) {
  std::map<std::string, double> vars;
  vars["pi"] = 3.14;
  vars["b1"] = 0;

  std::cout << "\nTests with static calculate::calculate()\n" << std::endl;

  assert("-pi + 1", -2.14, &vars);
  assert("-pi + 1 * b1", -3.14, &vars);

  assert("(20+10)*3/2-3", 42.0);
  assert("1 << 4", 16.0);
  assert("1+(-2*3)", -5);

  std::cout << "\nTests with calculate::compile() & calculate::eval()\n" << std::endl;

  calculator c1;
  c1.compile("-pi+1", &vars);
  assert(c1.eval(), -2.14);

  calculator c2("pi+4", &vars);
  assert(c2.eval(), 7.14);
  assert(c2.eval(), 7.14);

  calculator c3("pi+b1+b2", &vars);

  vars["b2"] = 1;
  assert(c3.eval(&vars), 4.14);

  vars["b2"] = .86;
  assert(c3.eval(&vars), 4);

  std::cout << "\nTesting boolean expressions\n" << std::endl;

  assert("3 < 3", false);
  assert("3 <= 3", true);
  assert("3 > 3", false);
  assert("3 >= 3", true);
  assert("3 == 3", true);
  assert("3 != 3", false);

  assert("(3 && true) == true", true);
  assert("(3 && 0) == true", false);
  assert("(3 || 0) == true", true);
  assert("(false || 0) == true", false);

  std::cout << "\nTesting exception management\n" << std::endl;

  assert_throws(c3.eval());

  assert_throws({
    vars.erase("b2");
    c3.eval(&vars);
  });

  assert_not_throw({
    vars["b2"] = 0;
    vars.erase("b1");
    c3.eval(&vars);
  });

  std::cout << "\nEnd testing" << std::endl;

  return 0;
}
<|endoftext|>


<commit_before>#pragma once
#include "game/detail/entity_handle_mixins/inventory_mixin.h"
#include "game/detail/inventory/direct_attachment_offset.h"
#include "augs/templates/continue_or_callback_result.h"
#include "augs/templates/traits/is_nullopt.h"

template <class E>
template <class S, class I>
callback_result inventory_mixin<E>::for_each_contained_slot_and_item_recursive(
	S&& slot_callback,
	I&& item_callback,
	const optional_slot_flags& filter
) const {
	const auto this_container = *static_cast<const E*>(this);
	auto& cosm = this_container.get_cosmos();

	return this_container.template dispatch_on_having_all_ret<invariants::container>([&](const auto& typed_container) {
		if constexpr(is_nullopt_v<decltype(typed_container)>) {
			return callback_result::CONTINUE;
		}
		else {
			auto& container = typed_container.template get<invariants::container>();

			for (const auto& s : container.slots) {
				if (filter && !filter->test(s.first)) {
					continue;
				}

				const auto this_slot_id = inventory_slot_id(s.first, typed_container.get_id());
				const auto slot_callback_result = continue_or_recursive_callback_result(std::forward<S>(slot_callback), cosm[this_slot_id]);

				if (slot_callback_result == recursive_callback_result::ABORT) {
					return callback_result::ABORT;
				}
				else if (slot_callback_result == recursive_callback_result::CONTINUE_DONT_RECURSE) {
					continue;
				}
				else if (slot_callback_result == recursive_callback_result::CONTINUE_AND_RECURSE) {
					const auto items = typed_container[s.first].get_items_inside();

					for (const auto& id : items) {
						const auto result = cosm[id].template dispatch_on_having_all_ret<components::item>(
							[&](const auto& child_item_handle) {
								if constexpr(!is_nullopt_v<decltype(child_item_handle)>) {
									const auto r = continue_or_recursive_callback_result(std::forward<I>(item_callback), child_item_handle);

									if (r == recursive_callback_result::CONTINUE_AND_RECURSE) {
										const auto next_r = child_item_handle.for_each_contained_slot_and_item_recursive(std::forward<S>(slot_callback), std::forward<I>(item_callback), filter);

										if (callback_result::ABORT == next_r) {
											return recursive_callback_result::ABORT;
										}
									}

									return r;
								}
								else {
									return recursive_callback_result::ABORT;
								}
							}
						);

						if (result == recursive_callback_result::ABORT) {
							return callback_result::ABORT;
						}
						else if (result == recursive_callback_result::CONTINUE_DONT_RECURSE) {
							continue;
						}
					}
				}
			}

			return callback_result::CONTINUE;
		}
	});
}

template <class E>
template <class A, class B, class G>
void inventory_mixin<E>::for_each_attachment_recursive(
	A attachment_callback,
	B should_recurse,
	G get_offsets_by_torso,
	const attachment_offset_settings& settings,
	const bool flip_hands_order
) const {
	struct node {
		inventory_slot_id parent;
		entity_id child;
		transformr offset;
	};

	thread_local std::vector<node> container_stack;
	container_stack.clear();

	const auto root_container = *static_cast<const E*>(this);
	auto& cosm = root_container.get_cosmos();

	container_stack.push_back({ {}, root_container, transformr() });

	std::size_t stack_i = 0;

	while (stack_i < container_stack.size()) {
		const auto it = container_stack[stack_i++];

		cosm[it.child].template dispatch_on_having_any<invariants::container, components::item>(
			[&](const auto this_attachment) {
				auto get_attachment_offset_for = [&settings, &get_offsets_by_torso](
					const auto for_container,
					const auto for_attachment,
					const auto for_type
				) {
					return direct_attachment_offset(
						for_container,
						for_attachment,
						get_offsets_by_torso,
						settings,
						for_type
					);
				};

				const auto total_offset = [&]() {
					if (it.parent.container_entity.is_set()) {
						/* Don't do it for the root */
						const auto next_offset = get_attachment_offset_for(
							cosm[it.parent.container_entity],
							this_attachment,
							it.parent.type
						);

						const auto total_offset = it.offset * next_offset;

						this_attachment.template dispatch_on_having_all<components::item>([&](const auto& typed_attachment) {
							attachment_callback(typed_attachment, total_offset);
						});

						return total_offset;
					}

					return it.offset;
				}();

				const auto& this_container = this_attachment;

				if (const auto container = this_container.template find<invariants::container>()) {
					for (const auto& s : container->slots) {
						const auto type = s.first;

						if (s.second.makes_physical_connection()) {
							const auto this_container_id = this_container.get_id();

							for (const auto& id : this_container[type].get_items_inside()) {
								const auto inside_item_handle = cosm[id];

								if (!should_recurse(inside_item_handle)) {
									continue;
								}

								auto insert_where = container_stack.size();

								if (flip_hands_order) {
									if (type == slot_function::SECONDARY_HAND) {
										if (container_stack.back().parent.type == slot_function::PRIMARY_HAND) {
											insert_where--;
										}
									}
								}

								{
									const auto& maybe_gun = inside_item_handle;

									/* Insert early */

									if (const auto mag_slot = maybe_gun[slot_function::GUN_DETACHABLE_MAGAZINE]; mag_slot && mag_slot.has_items()) {
										if (mag_slot->draw_under_container) {
											const auto mag_inside = mag_slot.get_item_if_any();
											const auto where_it = container_stack.begin() + insert_where;
											const auto attachment_offset = total_offset * get_attachment_offset_for(this_container, maybe_gun, type);
											const auto next_node = node {
												mag_slot,
												mag_inside.get_id(),
												attachment_offset
											};

											container_stack.insert(where_it, next_node);
											++insert_where;
										}
									}
									else if (const auto slot = inside_item_handle.get_current_slot(); slot && slot.get_type() == slot_function::GUN_DETACHABLE_MAGAZINE && slot->draw_under_container) {
										/* Was earlier inserted */
										continue;
									}
								}

								const auto where_it = container_stack.begin() + insert_where;
								const auto next_node = node {
									{ type, this_container_id },
									id,
									total_offset
							   	};

								container_stack.insert(where_it, next_node);
							}
						}
					}
				}
			}
		);
	}
}

template <class E>
template <class I>
void inventory_mixin<E>::for_each_contained_item_recursive(I&& item_callback, const optional_slot_flags& filter) const {
	for_each_contained_slot_and_item_recursive(
		[](auto) {},
		std::forward<I>(item_callback),
		filter
	);
}

template <class E>
template <class S>
void inventory_mixin<E>::for_each_contained_slot_recursive(S&& slot_callback, const optional_slot_flags& filter) const {
	for_each_contained_slot_and_item_recursive(
		std::forward<S>(slot_callback),
		[](auto...) {},
		filter
	);
}

template <class E>
template <class G>
ltrb inventory_mixin<E>::calc_attachments_aabb(G&& get_offsets_by_torso) const {
	ltrb result;

	for_each_attachment_recursive(
		[&result](
			const auto attachment_entity,
			const auto attachment_offset
		) {
			result.contain(attachment_entity.get_aabb(attachment_offset));
		},
		[](const auto&) {
			return true;
		},
		std::forward<G>(get_offsets_by_torso),
		attachment_offset_settings::for_logic()
	);

	return result;
}
<commit_msg>refactor for_each_attachment_recursive<commit_after>#pragma once
#include "game/detail/entity_handle_mixins/inventory_mixin.h"
#include "game/detail/inventory/direct_attachment_offset.h"
#include "augs/templates/continue_or_callback_result.h"
#include "augs/templates/traits/is_nullopt.h"

template <class E>
template <class S, class I>
callback_result inventory_mixin<E>::for_each_contained_slot_and_item_recursive(
	S&& slot_callback,
	I&& item_callback,
	const optional_slot_flags& filter
) const {
	const auto this_container = *static_cast<const E*>(this);
	auto& cosm = this_container.get_cosmos();

	return this_container.template dispatch_on_having_all_ret<invariants::container>([&](const auto& typed_container) {
		if constexpr(is_nullopt_v<decltype(typed_container)>) {
			return callback_result::CONTINUE;
		}
		else {
			auto& container = typed_container.template get<invariants::container>();

			for (const auto& s : container.slots) {
				if (filter && !filter->test(s.first)) {
					continue;
				}

				const auto this_slot_id = inventory_slot_id(s.first, typed_container.get_id());
				const auto slot_callback_result = continue_or_recursive_callback_result(std::forward<S>(slot_callback), cosm[this_slot_id]);

				if (slot_callback_result == recursive_callback_result::ABORT) {
					return callback_result::ABORT;
				}
				else if (slot_callback_result == recursive_callback_result::CONTINUE_DONT_RECURSE) {
					continue;
				}
				else if (slot_callback_result == recursive_callback_result::CONTINUE_AND_RECURSE) {
					const auto items = typed_container[s.first].get_items_inside();

					for (const auto& id : items) {
						const auto result = cosm[id].template dispatch_on_having_all_ret<components::item>(
							[&](const auto& child_item_handle) {
								if constexpr(!is_nullopt_v<decltype(child_item_handle)>) {
									const auto r = continue_or_recursive_callback_result(std::forward<I>(item_callback), child_item_handle);

									if (r == recursive_callback_result::CONTINUE_AND_RECURSE) {
										const auto next_r = child_item_handle.for_each_contained_slot_and_item_recursive(std::forward<S>(slot_callback), std::forward<I>(item_callback), filter);

										if (callback_result::ABORT == next_r) {
											return recursive_callback_result::ABORT;
										}
									}

									return r;
								}
								else {
									return recursive_callback_result::ABORT;
								}
							}
						);

						if (result == recursive_callback_result::ABORT) {
							return callback_result::ABORT;
						}
						else if (result == recursive_callback_result::CONTINUE_DONT_RECURSE) {
							continue;
						}
					}
				}
			}

			return callback_result::CONTINUE;
		}
	});
}

template <class E>
template <class A, class B, class G>
void inventory_mixin<E>::for_each_attachment_recursive(
	A attachment_callback,
	B should_recurse,
	G get_offsets_by_torso,
	const attachment_offset_settings& settings,
	const bool flip_hands_order
) const {
	struct node {
		inventory_slot_id parent;
		entity_id child;
		transformr offset;
	};

	thread_local std::vector<node> container_stack;
	container_stack.clear();

	const auto root_container = *static_cast<const E*>(this);
	auto& cosm = root_container.get_cosmos();

	container_stack.push_back({ {}, root_container, transformr() });

	std::size_t stack_i = 0;

	while (stack_i < container_stack.size()) {
		const auto it = container_stack[stack_i++];

		cosm[it.child].template dispatch_on_having_any<invariants::container, components::item>(
			[&](const auto this_attachment) {
				auto get_attachment_offset_for = [&settings, &get_offsets_by_torso](
					const auto for_container,
					const auto for_attachment,
					const auto for_type
				) {
					return direct_attachment_offset(
						for_container,
						for_attachment,
						get_offsets_by_torso,
						settings,
						for_type
					);
				};

				const auto total_offset = [&]() {
					if (it.parent.container_entity.is_set()) {
						/* Don't do it for the root */
						const auto next_offset = get_attachment_offset_for(
							cosm[it.parent.container_entity],
							this_attachment,
							it.parent.type
						);

						const auto total_offset = it.offset * next_offset;

						this_attachment.template dispatch_on_having_all<components::item>([&](const auto& typed_attachment) {
							attachment_callback(typed_attachment, total_offset);
						});

						return total_offset;
					}

					return it.offset;
				}();

				const auto& this_container = this_attachment;

				if (const auto container = this_container.template find<invariants::container>()) {
					for (const auto& s : container->slots) {
						if (!s.second.makes_physical_connection()) {
							continue;
						}

						const auto type = s.first;
						const auto this_slot = this_container[type];

						for (const auto& id : this_slot.get_items_inside()) {
							const auto inside_item_handle = cosm[id];

							if (!should_recurse(inside_item_handle)) {
								continue;
							}

							auto insert_where = container_stack.size();

							if (flip_hands_order) {
								if (type == slot_function::SECONDARY_HAND) {
									if (container_stack.back().parent.type == slot_function::PRIMARY_HAND) {
										insert_where--;
									}
								}
							}

							{
								const auto& maybe_gun = inside_item_handle;

								/* Insert early */

								if (const auto mag_slot = maybe_gun[slot_function::GUN_DETACHABLE_MAGAZINE]; mag_slot && mag_slot.has_items()) {
									if (mag_slot->draw_under_container) {
										const auto mag_inside = mag_slot.get_item_if_any();
										const auto where_it = container_stack.begin() + insert_where;
										const auto attachment_offset = total_offset * get_attachment_offset_for(this_container, maybe_gun, type);
										const auto next_node = node {
											mag_slot,
											mag_inside.get_id(),
											attachment_offset
										};

										container_stack.insert(where_it, next_node);
										++insert_where;
									}
								}
								else if (const auto slot = inside_item_handle.get_current_slot(); slot && slot.get_type() == slot_function::GUN_DETACHABLE_MAGAZINE && slot->draw_under_container) {
									/* Was earlier inserted */
									continue;
								}
							}

							const auto where_it = container_stack.begin() + insert_where;
							const auto next_node = node { this_slot, id, total_offset };

							container_stack.insert(where_it, next_node);
						}
					}
				}
			}
		);
	}
}

template <class E>
template <class I>
void inventory_mixin<E>::for_each_contained_item_recursive(I&& item_callback, const optional_slot_flags& filter) const {
	for_each_contained_slot_and_item_recursive(
		[](auto) {},
		std::forward<I>(item_callback),
		filter
	);
}

template <class E>
template <class S>
void inventory_mixin<E>::for_each_contained_slot_recursive(S&& slot_callback, const optional_slot_flags& filter) const {
	for_each_contained_slot_and_item_recursive(
		std::forward<S>(slot_callback),
		[](auto...) {},
		filter
	);
}

template <class E>
template <class G>
ltrb inventory_mixin<E>::calc_attachments_aabb(G&& get_offsets_by_torso) const {
	ltrb result;

	for_each_attachment_recursive(
		[&result](
			const auto attachment_entity,
			const auto attachment_offset
		) {
			result.contain(attachment_entity.get_aabb(attachment_offset));
		},
		[](const auto&) {
			return true;
		},
		std::forward<G>(get_offsets_by_torso),
		attachment_offset_settings::for_logic()
	);

	return result;
}
<|endoftext|>


<commit_before>#include <cmath>

#include "ingameelements/weapons/peacemaker.h"
#include "renderer.h"
#include "ingameelements/projectiles/peacemakerbullet.h"
#include "ingameelements/heroes/mccree.h"
#include "ingameelements/explosion.h"
#include "engine.h"

Peacemaker::Peacemaker(uint64_t id_, Gamestate *state, EntityPtr owner_) : Weapon(id_, state, owner_, constructparameters(state)),
                        fthanim("heroes/mccree/fanthehammerstart/", std::bind(&Peacemaker::firesecondary, this, state)), isfthing(false)
{
    fthanim.active(false);
}

Peacemaker::~Peacemaker()
{
    //dtor
}

void Peacemaker::render(Renderer *renderer, Gamestate *state)
{
    std::string mainsprite;
    double dir = aimdirection;
    Mccree *c = state->get<Mccree>(state->get<Player>(owner)->character);
    if (firinganim.active())
    {
        mainsprite = firinganim.getframe();
    }
    else if (reloadanim.active())
    {
        mainsprite = reloadanim.getframe();
        dir = 3.1415*c->isflipped;
    }
    else if (fthanim.active())
    {
        mainsprite = fthanim.getframe();
    }
    else
    {
        mainsprite = c->getcharacterfolder()+"arm/1";
    }
    ALLEGRO_BITMAP *sprite = renderer->spriteloader.requestsprite(mainsprite);
    int spriteoffset_x = renderer->spriteloader.get_spriteoffset_x(mainsprite);
    int spriteoffset_y = renderer->spriteloader.get_spriteoffset_y(mainsprite);

    al_set_target_bitmap(renderer->midground);
    if (not c->rollanim.active())
    {
        if (c->isflipped)
        {
            al_draw_scaled_rotated_bitmap(sprite, -getattachpoint_x()-spriteoffset_x, getattachpoint_y()+spriteoffset_y, x - renderer->cam_x, y - renderer->cam_y, 1, -1, dir, 0);
        }
        else
        {
            al_draw_rotated_bitmap(sprite, getattachpoint_x()+spriteoffset_x, getattachpoint_y()+spriteoffset_y, x - renderer->cam_x, y - renderer->cam_y, dir, 0);
        }
    }
}

void Peacemaker::midstep(Gamestate *state, double frametime)
{
    Weapon::midstep(state, frametime);

    if (isfthing)
    {
        fthanim.active(true);
    }
    fthanim.update(state, frametime);
}

void Peacemaker::reload(Gamestate *state)
{
    if (clip < getclipsize() and not firinganim.active() and not reloadanim.active() and not isfthing)
    {
        // We need to reload
        reloadanim.reset();
        reloadanim.active(true);
    }
}

void Peacemaker::wantfireprimary(Gamestate *state)
{
    if (state->engine->isserver and clip > 0 and not firinganim.active())
    {
        fireprimary(state);
        state->sendbuffer->write<uint8_t>(PRIMARY_FIRED);
        state->sendbuffer->write<uint8_t>(state->findplayerid(owner));
    }
}

void Peacemaker::fireprimary(Gamestate *state)
{
    EntityPtr newshot = state->make_entity<PeacemakerBullet>(state, owner);
    PeacemakerBullet *shot = state->get<PeacemakerBullet>(newshot);
    shot->x = x+std::cos(aimdirection)*10;
    shot->y = y+std::sin(aimdirection)*10;

    shot->hspeed = std::cos(aimdirection) * bulletspeed;
    shot->vspeed = std::sin(aimdirection) * bulletspeed;

    Explosion *e = state->get<Explosion>(state->make_entity<Explosion>(state, "heroes/mccree/projectiletrail/", aimdirection));
    e->x = x+std::cos(aimdirection)*24;
    e->y = y+std::sin(aimdirection)*24;

    --clip;
    firinganim.reset();
    firinganim.active(true);
}

void Peacemaker::wantfiresecondary(Gamestate *state)
{
    if (clip > 0)
    {
        if (not isfthing and state->engine->isserver)
        {
            firesecondary(state);
            state->sendbuffer->write<uint8_t>(SECONDARY_FIRED);
            state->sendbuffer->write<uint8_t>(state->findplayerid(owner));
        }
        else if (isfthing and fthanim.getpercent() >= 1)
        {
            firesecondary(state);
        }
    }
    else
    {
        isfthing = false;
        fthanim.active(false);
    }
}

void Peacemaker::firesecondary(Gamestate *state)
{
    EntityPtr newshot = state->make_entity<PeacemakerBullet>(state, owner);
    PeacemakerBullet *shot = state->get<PeacemakerBullet>(newshot);
    double spread = (2*(rand()/(RAND_MAX+1.0)) - 1)*25*3.1415/180.0;
    shot->x = x+std::cos(aimdirection+spread)*10;
    shot->y = y+std::sin(aimdirection+spread)*10;
    shot->hspeed = std::cos(aimdirection+spread) * bulletspeed;
    shot->vspeed = std::sin(aimdirection+spread) * bulletspeed;

    Explosion *e = state->get<Explosion>(state->make_entity<Explosion>(state, "heroes/mccree/projectiletrail/", aimdirection+spread));
    e->x = x+std::cos(aimdirection+spread)*24;
    e->y = y+std::sin(aimdirection+spread)*24;

    --clip;

    if (clip > 0)
    {
        if (isfthing)
        {
            fthanim = Animation("heroes/mccree/fanthehammerloop/", std::bind(&Peacemaker::wantfiresecondary, this, state));
        }
        else
        {
            fthanim = Animation("heroes/mccree/fanthehammerstart/", std::bind(&Peacemaker::wantfiresecondary, this, state));
            isfthing = true;
        }
    }
}

WeaponChildParameters Peacemaker::constructparameters(Gamestate *state)
{
    WeaponChildParameters p;
    p.clipsize = 6;
    p.characterfolder = "heroes/mccree/";
    p.reloadfunction = std::bind(&Peacemaker::restoreclip, this, state);
    return p;
}
<commit_msg>Fixed projectile trail drawing offset.<commit_after>#include <cmath>

#include "ingameelements/weapons/peacemaker.h"
#include "renderer.h"
#include "ingameelements/projectiles/peacemakerbullet.h"
#include "ingameelements/heroes/mccree.h"
#include "ingameelements/explosion.h"
#include "engine.h"

Peacemaker::Peacemaker(uint64_t id_, Gamestate *state, EntityPtr owner_) : Weapon(id_, state, owner_, constructparameters(state)),
                        fthanim("heroes/mccree/fanthehammerstart/", std::bind(&Peacemaker::firesecondary, this, state)), isfthing(false)
{
    fthanim.active(false);
}

Peacemaker::~Peacemaker()
{
    //dtor
}

void Peacemaker::render(Renderer *renderer, Gamestate *state)
{
    std::string mainsprite;
    double dir = aimdirection;
    Mccree *c = state->get<Mccree>(state->get<Player>(owner)->character);
    if (firinganim.active())
    {
        mainsprite = firinganim.getframe();
    }
    else if (reloadanim.active())
    {
        mainsprite = reloadanim.getframe();
        dir = 3.1415*c->isflipped;
    }
    else if (fthanim.active())
    {
        mainsprite = fthanim.getframe();
    }
    else
    {
        mainsprite = c->getcharacterfolder()+"arm/1";
    }
    ALLEGRO_BITMAP *sprite = renderer->spriteloader.requestsprite(mainsprite);
    int spriteoffset_x = renderer->spriteloader.get_spriteoffset_x(mainsprite);
    int spriteoffset_y = renderer->spriteloader.get_spriteoffset_y(mainsprite);

    al_set_target_bitmap(renderer->midground);
    if (not c->rollanim.active())
    {
        if (c->isflipped)
        {
            al_draw_scaled_rotated_bitmap(sprite, -getattachpoint_x()-spriteoffset_x, getattachpoint_y()+spriteoffset_y, x - renderer->cam_x, y - renderer->cam_y, 1, -1, dir, 0);
        }
        else
        {
            al_draw_rotated_bitmap(sprite, getattachpoint_x()+spriteoffset_x, getattachpoint_y()+spriteoffset_y, x - renderer->cam_x, y - renderer->cam_y, dir, 0);
        }
    }
}

void Peacemaker::midstep(Gamestate *state, double frametime)
{
    Weapon::midstep(state, frametime);

    if (isfthing)
    {
        fthanim.active(true);
    }
    fthanim.update(state, frametime);
}

void Peacemaker::reload(Gamestate *state)
{
    if (clip < getclipsize() and not firinganim.active() and not reloadanim.active() and not isfthing)
    {
        // We need to reload
        reloadanim.reset();
        reloadanim.active(true);
    }
}

void Peacemaker::wantfireprimary(Gamestate *state)
{
    if (state->engine->isserver and clip > 0 and not firinganim.active())
    {
        fireprimary(state);
        state->sendbuffer->write<uint8_t>(PRIMARY_FIRED);
        state->sendbuffer->write<uint8_t>(state->findplayerid(owner));
    }
}

void Peacemaker::fireprimary(Gamestate *state)
{
    EntityPtr newshot = state->make_entity<PeacemakerBullet>(state, owner);
    PeacemakerBullet *shot = state->get<PeacemakerBullet>(newshot);
    shot->x = x+std::cos(aimdirection)*10;
    shot->y = y+std::sin(aimdirection)*10;

    shot->hspeed = std::cos(aimdirection) * bulletspeed;
    shot->vspeed = std::sin(aimdirection) * bulletspeed;

    Explosion *e = state->get<Explosion>(state->make_entity<Explosion>(state, "heroes/mccree/projectiletrail/", aimdirection));
    e->x = x+std::cos(aimdirection-0.1)*24;
    e->y = y+std::sin(aimdirection-0.1)*24;

    --clip;
    firinganim.reset();
    firinganim.active(true);
}

void Peacemaker::wantfiresecondary(Gamestate *state)
{
    if (clip > 0)
    {
        if (not isfthing and state->engine->isserver)
        {
            firesecondary(state);
            state->sendbuffer->write<uint8_t>(SECONDARY_FIRED);
            state->sendbuffer->write<uint8_t>(state->findplayerid(owner));
        }
        else if (isfthing and fthanim.getpercent() >= 1)
        {
            firesecondary(state);
        }
    }
    else
    {
        isfthing = false;
        fthanim.active(false);
    }
}

void Peacemaker::firesecondary(Gamestate *state)
{
    EntityPtr newshot = state->make_entity<PeacemakerBullet>(state, owner);
    PeacemakerBullet *shot = state->get<PeacemakerBullet>(newshot);
    double spread = (2*(rand()/(RAND_MAX+1.0)) - 1)*25*3.1415/180.0;
    shot->x = x+std::cos(aimdirection+spread)*10;
    shot->y = y+std::sin(aimdirection+spread)*10;
    shot->hspeed = std::cos(aimdirection+spread) * bulletspeed;
    shot->vspeed = std::sin(aimdirection+spread) * bulletspeed;

    Explosion *e = state->get<Explosion>(state->make_entity<Explosion>(state, "heroes/mccree/projectiletrail/", aimdirection+spread));
    e->x = x+std::cos(aimdirection+spread)*24;
    e->y = y+std::sin(aimdirection+spread)*24;

    --clip;

    if (clip > 0)
    {
        if (isfthing)
        {
            fthanim = Animation("heroes/mccree/fanthehammerloop/", std::bind(&Peacemaker::wantfiresecondary, this, state));
        }
        else
        {
            fthanim = Animation("heroes/mccree/fanthehammerstart/", std::bind(&Peacemaker::wantfiresecondary, this, state));
            isfthing = true;
        }
    }
}

WeaponChildParameters Peacemaker::constructparameters(Gamestate *state)
{
    WeaponChildParameters p;
    p.clipsize = 6;
    p.characterfolder = "heroes/mccree/";
    p.reloadfunction = std::bind(&Peacemaker::restoreclip, this, state);
    return p;
}
<|endoftext|>


<commit_before>/*
 Adapted from ciUI's Moving Graph by @brucelane with permission from @rezaali
 https://github.com/rezaali/ciUI
*/

#include "Graph.h"

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace MinimalUI;

int MovingGraph::DEFAULT_HEIGHT = UIElement::DEFAULT_HEIGHT;
int MovingGraph::DEFAULT_WIDTH = 96;

// common initialization
void MovingGraph::init()
{
	// initialize unique variables
	mMin = hasParam("min") ? getParam<float>("min") : 0.0f;
	mMax = hasParam("max") ? getParam<float>("max") : 1.0f;

	// set size
	int x = hasParam("width") ? getParam<int>("width") : MovingGraph::DEFAULT_WIDTH;
	int y = hasParam("height") ? getParam<int>("height") : MovingGraph::DEFAULT_HEIGHT;
	setSize(Vec2i(x, y));

	// set position and bounds
	setPositionAndBounds();
	mScreenMin = mBounds.getX1();
	mScreenMax = mBounds.getX2();

	mBufferSize = 128;
	mScale = mBounds.getHeight() * 0.5f;
	mInc = mBounds.getWidth() / ((float)mBufferSize - 1.0f);

	renderNameTexture();
	// set screen value
	update();
}

// without event handler
MovingGraph::MovingGraph(UIController *aUIController, const string &aName, float *aValueToLink, const string &aParamString)
: UIElement(aUIController, aName, aParamString), mLinkedValue(aValueToLink)
{
    init();
}

// with event handler
MovingGraph::MovingGraph(UIController *aUIController, const string &aName, float *aValueToLink, const std::function<void(bool)>& aEventHandler, const string &aParamString)
	: UIElement(aUIController, aName, aParamString), mLinkedValue(aValueToLink)
{
	// initialize unique variables
	addEventHandler(aEventHandler);
	mPressed = hasParam("pressed") ? getParam<bool>("pressed") : false;
	mStateless = hasParam("stateless") ? getParam<bool>("stateless") : true;
	mExclusive = hasParam("exclusive") ? getParam<bool>("exclusive") : false;
	mCallbackOnRelease = hasParam("callbackOnRelease") ? getParam<bool>("callbackOnRelease") : true;
	mContinuous = hasParam("continuous") ? getParam<bool>("continuous") : false;

    init();
}

// without event handler
UIElementRef MovingGraph::create(UIController *aUIController, const string &aName, float *aValueToLink, const string &aParamString)
{
	return shared_ptr<MovingGraph>(new MovingGraph(aUIController, aName, aValueToLink, aParamString));
}

// with event handler
UIElementRef MovingGraph::create(UIController *aUIController, const string &aName, float *aValueToLink, const std::function<void(bool)>& aEventHandler, const string &aParamString)
{
	return shared_ptr<MovingGraph>(new MovingGraph(aUIController, aName, aValueToLink, aEventHandler, aParamString));
}

void MovingGraph::draw()
{
	// draw the outer rect
	gl::color(UIController::DEFAULT_STROKE_COLOR);
	gl::drawStrokedRect(getBounds());
	// draw the background
	drawBackground();

	// draw the graph
	gl::color( UIController::ACTIVE_STROKE_COLOR );
	gl::pushMatrices();
	gl::translate( mBounds.getX1(), mBounds.getY1() + mScale );

	mShape.clear();
	mShape.moveTo( 0.0f, lmap<float>( mBuffer[0], mMin, mMax, mScale, -mScale ) );
	for (int i = 1; i < mBuffer.size(); i++)
	{
		mShape.lineTo( mInc * (float)i, lmap<float>( mBuffer[i], mMin, mMax, mScale, -mScale ) );
	}
	gl::draw( mShape );
	gl::popMatrices();
	// draw the label
	drawLabel();
}
void MovingGraph::release()
{
	if (mPressed) {
		mPressed = false;
		if (mCallbackOnRelease) {
			callEventHandlers();
		}
	}
}

void MovingGraph::handleMouseUp(const Vec2i &aMousePos)
{
	if (mStateless) {
		// mPressed should always be false if it's a stateless button; just call the handler
		callEventHandlers();

	}
	else {
		if (mPressed) {
			// if the button is in an exclusive group and it's already pressed, don't do anything
			if (!mExclusive) {
				// release the button
				mPressed = false;
				callEventHandlers();
			}
		}
		else {
			// if the button is an exclusive group and isn't pressed, release all the buttons in the group first
			if (mExclusive) {
				getParent()->releaseGroup(getGroup());
			}
			// press the button
			mPressed = true;
			callEventHandlers();
		}
	}
}

void MovingGraph::addEventHandler(const std::function<void(bool)>& aEventHandler)
{
	mEventHandlers.push_back(aEventHandler);
}

void MovingGraph::callEventHandlers()
{
	for (int i = 0; i < mEventHandlers.size(); i++) {
		mEventHandlers[i](mPressed);
	}
}

void MovingGraph::update()
{
	if (mContinuous && mStateless && isActive()) {
		callEventHandlers();
	}
	mBuffer.push_back( *mLinkedValue );

	if( mBuffer.size() >= mBufferSize )
	{
		mBuffer.erase( mBuffer.begin(), mBuffer.begin() + 1 );
	}
}
<commit_msg>graph butoon mode feedback<commit_after>/*
 Adapted from ciUI's Moving Graph by @brucelane with permission from @rezaali
 https://github.com/rezaali/ciUI
*/

#include "Graph.h"

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace MinimalUI;

int MovingGraph::DEFAULT_HEIGHT = UIElement::DEFAULT_HEIGHT;
int MovingGraph::DEFAULT_WIDTH = 96;

// common initialization
void MovingGraph::init()
{
	// initialize unique variables
	mMin = hasParam("min") ? getParam<float>("min") : 0.0f;
	mMax = hasParam("max") ? getParam<float>("max") : 1.0f;

	// set size
	int x = hasParam("width") ? getParam<int>("width") : MovingGraph::DEFAULT_WIDTH;
	int y = hasParam("height") ? getParam<int>("height") : MovingGraph::DEFAULT_HEIGHT;
	setSize(Vec2i(x, y));

	// set position and bounds
	setPositionAndBounds();
	mScreenMin = mBounds.getX1();
	mScreenMax = mBounds.getX2();

	mBufferSize = 128;
	mScale = mBounds.getHeight() * 0.5f;
	mInc = mBounds.getWidth() / ((float)mBufferSize - 1.0f);

	renderNameTexture();
	// set screen value
	update();
}

// without event handler
MovingGraph::MovingGraph(UIController *aUIController, const string &aName, float *aValueToLink, const string &aParamString)
: UIElement(aUIController, aName, aParamString), mLinkedValue(aValueToLink)
{
    init();
}

// with event handler
MovingGraph::MovingGraph(UIController *aUIController, const string &aName, float *aValueToLink, const std::function<void(bool)>& aEventHandler, const string &aParamString)
	: UIElement(aUIController, aName, aParamString), mLinkedValue(aValueToLink)
{
	// initialize unique variables
	addEventHandler(aEventHandler);
	mPressed = hasParam("pressed") ? getParam<bool>("pressed") : false;
	mStateless = hasParam("stateless") ? getParam<bool>("stateless") : true;
	mExclusive = hasParam("exclusive") ? getParam<bool>("exclusive") : false;
	mCallbackOnRelease = hasParam("callbackOnRelease") ? getParam<bool>("callbackOnRelease") : true;
	mContinuous = hasParam("continuous") ? getParam<bool>("continuous") : false;

    init();
}

// without event handler
UIElementRef MovingGraph::create(UIController *aUIController, const string &aName, float *aValueToLink, const string &aParamString)
{
	return shared_ptr<MovingGraph>(new MovingGraph(aUIController, aName, aValueToLink, aParamString));
}

// with event handler
UIElementRef MovingGraph::create(UIController *aUIController, const string &aName, float *aValueToLink, const std::function<void(bool)>& aEventHandler, const string &aParamString)
{
	return shared_ptr<MovingGraph>(new MovingGraph(aUIController, aName, aValueToLink, aEventHandler, aParamString));
}

void MovingGraph::draw()
{
	// set the color
	if (isActive()) {
		gl::color(UIController::ACTIVE_STROKE_COLOR);
	}
	else if (mPressed) {
		gl::color(UIController::DEFAULT_STROKE_COLOR);
	}
	else {
		gl::color(getBackgroundColor());
	}
	// draw the outer rect
	gl::drawStrokedRect(getBounds());
	// draw the background
	drawBackground();

	// draw the graph
	gl::color( UIController::ACTIVE_STROKE_COLOR );
	gl::pushMatrices();
	gl::translate( mBounds.getX1(), mBounds.getY1() + mScale );

	mShape.clear();
	mShape.moveTo( 0.0f, lmap<float>( mBuffer[0], mMin, mMax, mScale, -mScale ) );
	for (int i = 1; i < mBuffer.size(); i++)
	{
		mShape.lineTo( mInc * (float)i, lmap<float>( mBuffer[i], mMin, mMax, mScale, -mScale ) );
	}
	gl::draw( mShape );
	gl::popMatrices();
	// draw the label
	drawLabel();
}
void MovingGraph::release()
{
	if (mPressed) {
		mPressed = false;
		if (mCallbackOnRelease) {
			callEventHandlers();
		}
	}
}

void MovingGraph::handleMouseUp(const Vec2i &aMousePos)
{
	if (mStateless) {
		// mPressed should always be false if it's a stateless button; just call the handler
		callEventHandlers();

	}
	else {
		if (mPressed) {
			// if the button is in an exclusive group and it's already pressed, don't do anything
			if (!mExclusive) {
				// release the button
				mPressed = false;
				callEventHandlers();
			}
		}
		else {
			// if the button is an exclusive group and isn't pressed, release all the buttons in the group first
			if (mExclusive) {
				getParent()->releaseGroup(getGroup());
			}
			// press the button
			mPressed = true;
			callEventHandlers();
		}
	}
}

void MovingGraph::addEventHandler(const std::function<void(bool)>& aEventHandler)
{
	mEventHandlers.push_back(aEventHandler);
}

void MovingGraph::callEventHandlers()
{
	for (int i = 0; i < mEventHandlers.size(); i++) {
		mEventHandlers[i](mPressed);
	}
}

void MovingGraph::update()
{
	if (mContinuous && mStateless && isActive()) {
		callEventHandlers();
	}
	mBuffer.push_back( *mLinkedValue );

	if( mBuffer.size() >= mBufferSize )
	{
		mBuffer.erase( mBuffer.begin(), mBuffer.begin() + 1 );
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

#include <copasi/optimization/COptPopulationMethod.h>
#include <copasi/randomGenerator/CRandom.h>
#include <copasi/utilities/CProcessReport.h>
#include <copasi/report/CCopasiObject.h>
#include <copasi/report/CCopasiObjectReference.h>

COptPopulationMethod::COptPopulationMethod(const CCopasiContainer * pParent,
  const CTaskEnum::Method & methodType,
  const CTaskEnum::Task & taskType /*= CTaskEnum::optimization*/)
  : COptMethod(pParent, methodType, taskType)
  , mPopulationSize(0)
  , mGenerations(0)
  , mCurrentGeneration(0)
  , mhGenerations(C_INVALID_INDEX)
  , mVariableSize(0)
  , mIndividuals()
  , mValues()
  , mpRandom(NULL)
{
  initObjects();
}

COptPopulationMethod::COptPopulationMethod(const COptPopulationMethod & src,
  const CCopasiContainer * pParent)
  : COptMethod(src, pParent)
  , mPopulationSize(0)
  , mGenerations(0)
  , mCurrentGeneration(0)
  , mhGenerations(C_INVALID_INDEX)
  , mVariableSize(0)
  , mIndividuals()
  , mValues()
  , mpRandom(NULL)
{
  initObjects();
}

COptPopulationMethod::~COptPopulationMethod()
{
  cleanup();
}

void COptPopulationMethod::initObjects()
{
  if (getSubType() != CTaskEnum::ParticleSwarm && getSubType() != CTaskEnum::ScatterSearch)
  addObjectReference("Current Generation", mCurrentGeneration, CCopasiObject::ValueInt);
}

#include <iostream>

bool
COptPopulationMethod::initialize()
{
  cleanup();

  if (!COptMethod::initialize()) return false;

  mCurrentGeneration = 0;
  mGenerations = 0;

  if (getParameter("Number of Generations") != NULL)
    mGenerations = getValue< unsigned C_INT32 >("Number of Generations");

  if (mpCallBack
    && (getSubType() != CTaskEnum::ParticleSwarm && getSubType() != CTaskEnum::ScatterSearch))
  {
    mhGenerations =
    mpCallBack->addItem("Current Generation",
      mCurrentGeneration,
      &mGenerations);
  }

  mCurrentGeneration++;

  if (getParameter("Population Size") != NULL)
  mPopulationSize = getValue< unsigned C_INT32 >("Population Size");
  else mPopulationSize = 0;

  if (getParameter("Random Number Generator") != NULL && getParameter("Seed") != NULL)
    mpRandom = CRandom::createGenerator((CRandom::Type) getValue< unsigned C_INT32 >("Random Number Generator"),
      getValue< unsigned C_INT32 >("Seed"));

  mVariableSize = mpOptItem->size();

  return true;
}

bool
COptPopulationMethod::cleanup()
{
  size_t i;

  pdelete(mpRandom);

  for (i = 0; i < mIndividuals.size(); i++)
    pdelete(mIndividuals[i]);
  mIndividuals.clear();
  return true;
}

void COptPopulationMethod::print(std::ostream * ostream) const
{
  *ostream << *this;
}

std::ostream &operator<<(std::ostream &os, const COptPopulationMethod & o)
{
  os << "Population Information: " << std::endl;
  os << "Population Size: " << o.mPopulationSize << std::endl;
  os << "# Generations / Iterations: " << o.mGenerations << std::endl;
  os << "Current Generation / Iteration: " << o.mCurrentGeneration << std::endl;
  os << "Population Values: " << std::endl << "   " << o.mValues << std::endl << std::endl;
  os << "Population:" << std::endl;

  std::vector< CVector < C_FLOAT64 > * >::const_iterator it = o.mIndividuals.begin();
  for (; it != o.mIndividuals.end(); ++it)
  {
    os << "   " << **it << std::endl;
  }

  return os;
}
<commit_msg>- additionally print regular results from coptmethod<commit_after>// Copyright (C) 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

#include <copasi/optimization/COptPopulationMethod.h>
#include <copasi/randomGenerator/CRandom.h>
#include <copasi/utilities/CProcessReport.h>
#include <copasi/report/CCopasiObject.h>
#include <copasi/report/CCopasiObjectReference.h>

COptPopulationMethod::COptPopulationMethod(const CCopasiContainer * pParent,
  const CTaskEnum::Method & methodType,
  const CTaskEnum::Task & taskType /*= CTaskEnum::optimization*/)
  : COptMethod(pParent, methodType, taskType)
  , mPopulationSize(0)
  , mGenerations(0)
  , mCurrentGeneration(0)
  , mhGenerations(C_INVALID_INDEX)
  , mVariableSize(0)
  , mIndividuals()
  , mValues()
  , mpRandom(NULL)
{
  initObjects();
}

COptPopulationMethod::COptPopulationMethod(const COptPopulationMethod & src,
  const CCopasiContainer * pParent)
  : COptMethod(src, pParent)
  , mPopulationSize(0)
  , mGenerations(0)
  , mCurrentGeneration(0)
  , mhGenerations(C_INVALID_INDEX)
  , mVariableSize(0)
  , mIndividuals()
  , mValues()
  , mpRandom(NULL)
{
  initObjects();
}

COptPopulationMethod::~COptPopulationMethod()
{
  cleanup();
}

void COptPopulationMethod::initObjects()
{
  if (getSubType() != CTaskEnum::ParticleSwarm && getSubType() != CTaskEnum::ScatterSearch)
  addObjectReference("Current Generation", mCurrentGeneration, CCopasiObject::ValueInt);
}

#include <iostream>

bool
COptPopulationMethod::initialize()
{
  cleanup();

  if (!COptMethod::initialize()) return false;

  mCurrentGeneration = 0;
  mGenerations = 0;

  if (getParameter("Number of Generations") != NULL)
    mGenerations = getValue< unsigned C_INT32 >("Number of Generations");

  if (mpCallBack
    && (getSubType() != CTaskEnum::ParticleSwarm && getSubType() != CTaskEnum::ScatterSearch))
  {
    mhGenerations =
    mpCallBack->addItem("Current Generation",
      mCurrentGeneration,
      &mGenerations);
  }

  mCurrentGeneration++;

  if (getParameter("Population Size") != NULL)
  mPopulationSize = getValue< unsigned C_INT32 >("Population Size");
  else mPopulationSize = 0;

  if (getParameter("Random Number Generator") != NULL && getParameter("Seed") != NULL)
    mpRandom = CRandom::createGenerator((CRandom::Type) getValue< unsigned C_INT32 >("Random Number Generator"),
      getValue< unsigned C_INT32 >("Seed"));

  mVariableSize = mpOptItem->size();

  return true;
}

bool
COptPopulationMethod::cleanup()
{
  size_t i;

  pdelete(mpRandom);

  for (i = 0; i < mIndividuals.size(); i++)
    pdelete(mIndividuals[i]);
  mIndividuals.clear();
  return true;
}

void COptPopulationMethod::print(std::ostream * ostream) const
{
  COptMethod::print(ostream);

  *ostream << std::endl << *this;
}

std::ostream &operator<<(std::ostream &os, const COptPopulationMethod & o)
{
  os << "Population Information: " << std::endl;
  os << "Population Size: " << o.mPopulationSize << std::endl;
  os << "# Generations / Iterations: " << o.mGenerations << std::endl;
  os << "Current Generation / Iteration: " << o.mCurrentGeneration << std::endl;
  os << "Population Values: " << std::endl << "   " << o.mValues << std::endl << std::endl;
  os << "Population:" << std::endl;

  std::vector< CVector < C_FLOAT64 > * >::const_iterator it = o.mIndividuals.begin();
  for (; it != o.mIndividuals.end(); ++it)
  {
    os << "   " << **it << std::endl;
  }

  return os;
}
<|endoftext|>


<commit_before>/*
 * bamreader.cpp for MSIsensor
 * Copyright (c) 2013 Beifang Niu && Kai Ye WUGSC All Rights Reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// System header files
#include <iomanip>
#include <iostream>
#include <fstream>
#include <cmath>
#include <assert.h>

// Samtools header files
#include "bam.h"
#include "sam.h"
#include "kstring.h"
#include "kseq.h"
#include "khash.h"
#include "ksort.h"

// Bam header files
#include "bamreader.h"
#include "distribution.h"

// Static function declaration
static int fetch_func_SR (const bam1_t * b1, void *data);

unsigned int g_InWinPlus = 0;
unsigned int g_InWinMinus = 0;
unsigned int g_NumReadScanned = 0;
unsigned int g_NumReadInWindow = 0;
unsigned int g_CloseMappedPlus = 0;
unsigned int g_CloseMappedMinus = 0;

//init hash/maps for read pairing on the fly
KSORT_INIT_GENERIC (uint32_t) KHASH_MAP_INIT_STR (read_name, bam1_t *)
struct fetch_func_data_SR {
    fetch_func_data_SR () {
        LeftReads = NULL;
        read_to_map_qual = NULL;
        header = NULL;
        b1_flags = NULL;
        b2_flags = NULL;
        Tag = "";
        InsertSize = 0;
    }
    std::vector < SPLIT_READ > *LeftReads;
    khash_t (read_name) * read_to_map_qual;
    bam_header_t *header;
    flags_hit *b1_flags;
    flags_hit *b2_flags;
    std::string Tag;
    int InsertSize;
};

void parse_flags_and_tags (const bam1_t * b, flags_hit * flags) {
    const bam1_core_t *c = &b->core;
    char xt_code = '\0';
    int mf_code = 0, nm_code = 0, best_hits = 0;
    flags->unique = 0;
    flags->mapped = !(c->flag & BAM_FUNMAP);
    uint8_t *s = bam_aux_get (b, "XT");
    if (s != 0) {
        xt_code = bam_aux2A (s);
        if (xt_code == 'U') {
            flags->unique = 1;
        } else {
            flags->unique = 0;
        }
    } else { flags->unique = 1; }
    s = NULL;
    s = bam_aux_get (b, "X0");
    if (s != 0) {
        best_hits = bam_aux2i (s);
    }
    s = NULL;
    s = bam_aux_get (b, "X1");
    if (s != 0) {
        int sub_hits = bam_aux2i (s);
        if (best_hits + sub_hits == 1) {
            flags->suboptimal = 0;
        } else { flags->suboptimal = 1; }
    } else { flags->suboptimal = 0; }
    if (xt_code == 'M' || mf_code == 130) {
        //short term fix to unset unique if the maq read was s-w mapped.
        //bwa can't set U and M at once.
        flags->sw = 1;
    } else { flags->sw = 0; }
    s = NULL;
    s = bam_aux_get (b, "NM");
    if (s != 0) {
        nm_code = bam_aux2i (s);
        flags->edits = nm_code;
    } else {
        nm_code = 0;
        flags->edits = nm_code;
    }

    return;
}

/*

static int fetch_func_ALL (const bam1_t * b1, void *data) {
    fetch_func_data_SR *data_for_bam = (fetch_func_data_SR *) data;
    khash_t (read_name) * read_to_map_qual = (khash_t (read_name) *) data_for_bam->read_to_map_qual;

    flags_hit *b1_flags = data_for_bam->b1_flags;
    flags_hit *b2_flags = data_for_bam->b2_flags;

    //SPLIT_READ Temp_One_Read;
    const bam1_core_t *b1_core;
    bam1_t *b2;
    bam1_core_t *b2_core;
    b1_core = &b1->core;
    std::string read_name = bam1_qname (b1);
    khint_t key = kh_get (read_name, read_to_map_qual, bam1_qname (b1));

    if (key == kh_end (read_to_map_qual)) {
        int ret = 0;
        key = kh_put (read_name, read_to_map_qual, strdup (bam1_qname (b1)), &ret);
        kh_value (read_to_map_qual, key) = bam_dup1 (b1);
        return 0;
    } else {
        b2 = bam_dup1 (kh_value (read_to_map_qual, key));
        bam_destroy1 (kh_value (read_to_map_qual, key));
        b2_core = &b2->core;
        //this seems stupid, but in order to manage the read names, necessary
        free ((char *) kh_key (read_to_map_qual, key));
        kh_del (read_name, read_to_map_qual, key);
        std::string c_sequence;
    }
    parse_flags_and_tags (b1, b1_flags);
    parse_flags_and_tags (b2, b2_flags);
    build_record(b1, b2, data, b1_flags);
    build_record(b2, b1, data, b2_flags);
    bam_destroy1 (b2);
    return 0;
}

*/

// new version fetch function for single end_reads
static int fetch_func_ALL (const bam1_t * b1, void *data) {
    fetch_func_data_SR *data_for_bam = (fetch_func_data_SR *) data;
    khash_t (read_name) * read_to_map_qual = (khash_t (read_name) *) data_for_bam->read_to_map_qual;

    flags_hit *b1_flags = data_for_bam->b1_flags;

    //SPLIT_READ Temp_One_Read;
    const bam1_core_t *b1_core;
    b1_core = &b1->core;
    parse_flags_and_tags (b1, b1_flags);
    build_record( b1, data, b1_flags );

    return 0;
}

/** 'ReadInRead' reads in reads from Pindel input file. */
bool ReadInBamReads( const char *bam_path,
                     const std::string & FragName,
                     unsigned start,
                     unsigned end,
                     std::vector < SPLIT_READ > & AllReads,
                     std::string Tag) {
    bamFile fp;
    fp = bam_open (bam_path, "r");
    assert (fp);
    bam_index_t *idx;
    idx = bam_index_load (bam_path); // load BAM index
    assert (idx);
    bam_header_t *header = bam_header_read (fp);
    bam_init_header_hash (header);
    assert (header);

    int tid;

    tid = bam_get_tid (header, FragName.c_str ());
    fetch_func_data_SR data;
    data.header = header;
    data.LeftReads = &AllReads;
    data.read_to_map_qual = NULL;
    data.read_to_map_qual = kh_init (read_name);

    flags_hit b1_flags, b2_flags;
    data.b1_flags = &b1_flags;
    data.b2_flags = &b2_flags;
    data.Tag = Tag;
    // std:: cout << " before bam_fetch " << std::endl;
    bam_fetch (fp, idx, tid, start, end, &data, fetch_func_ALL);
    // std:: cout << " after bam_fetch " << std::endl;
    khint_t key;
    if (kh_size (data.read_to_map_qual) > 0) {
        for (key = kh_begin (data.read_to_map_qual); key != kh_end (data.read_to_map_qual); ++key) {
            if (kh_exist (data.read_to_map_qual, key)) {
                bam_destroy1 (kh_value (data.read_to_map_qual, key));
                free ((char *) kh_key (data.read_to_map_qual, key));
            }
        }
    }
    kh_clear (read_name, data.read_to_map_qual);
    kh_destroy (read_name, data.read_to_map_qual);
    bam_header_destroy (header);
    bam_index_destroy (idx);
    bam_close (fp);

    return true;
}

// new version build_record for single end reads
void build_record( const bam1_t * current_read,
                   void *data,
                   const flags_hit *flag_current_read ) {

    SPLIT_READ Temp_One_Read;
    fetch_func_data_SR *data_for_bam = (fetch_func_data_SR *) data;
    bam_header_t *header = (bam_header_t *) data_for_bam->header;
    std::string Tag = (std::string) data_for_bam->Tag;

    const bam1_core_t *current_core;
    current_core = &current_read->core;
    // Determine sample name for read.
    // std::string c_sequence;
    uint8_t *s = bam1_seq (current_read);
    for (int i = 0; i <current_core->l_qseq; ++i) {
        Temp_One_Read.ReadSeq.append (1, bam_nt16_rev_table[bam1_seqi (s, i)]);
    }
    //std::cout<<Temp_One_Read.ReadSeq<<"\n";
    if ( !flag_current_read->mapped ) {
       Temp_One_Read.Mapped = false;
    } else {
       Temp_One_Read.MatchedRelPos = current_core->pos;
       Temp_One_Read.Mapped = true;
    }
    //std::cout<< Temp_One_Read.MatchedRelPos <<"\n";
    //
    // load one read
    data_for_bam->LeftReads->push_back(Temp_One_Read);

    return;
}

/*
void build_record( const bam1_t * current_read,
                   const bam1_t * mate_read,
                   void *data,
                   const flags_hit *flag_current_read ) {

    SPLIT_READ Temp_One_Read;
    fetch_func_data_SR *data_for_bam = (fetch_func_data_SR *) data;
    bam_header_t *header = (bam_header_t *) data_for_bam->header;
    std::string Tag = (std::string) data_for_bam->Tag;

    const bam1_core_t *current_core;
    const bam1_core_t *mate_core;

    current_core = &current_read->core;
    mate_core = &mate_read->core;
    // Determine sample name for read.
    // std::string c_sequence;
    uint8_t *s = bam1_seq (current_read);
    for (int i = 0; i <current_core->l_qseq; ++i) {
        Temp_One_Read.ReadSeq.append (1, bam_nt16_rev_table[bam1_seqi (s, i)]);
    }
    //std::cout<<Temp_One_Read.ReadSeq<<"\n";
    if ( !flag_current_read->mapped ) {
       Temp_One_Read.Mapped = false;
    } else {
       Temp_One_Read.MatchedRelPos = current_core->pos;
       Temp_One_Read.Mapped = true;
    }
    //std::cout<< Temp_One_Read.MatchedRelPos <<"\n";
    //
    // load one read
    data_for_bam->LeftReads->push_back(Temp_One_Read);

    return;
}

*/

int32_t bam_cigar2len (const bam1_core_t * c, const uint32_t * cigar) {
    uint32_t k;
    int32_t l = 0;
    for (k = 0; k < c->n_cigar; ++k) {
        int op = cigar[k] & BAM_CIGAR_MASK;
        if (op == BAM_CMATCH || op == BAM_CINS || op == BAM_CSOFT_CLIP) {
            l += cigar[k] >> BAM_CIGAR_SHIFT;
        }
        if (op == BAM_CDEL) {
            l -= cigar[k] >> BAM_CIGAR_SHIFT;
        }
   }
   return l;
}

int32_t bam_cigar2mismatch( const bam1_core_t *readCore, const uint32_t *cigar) {
    uint32_t cigarIndex;
    int32_t numberOfMismatches = 0;
    for (cigarIndex = 0; cigarIndex < readCore->n_cigar; ++cigarIndex) {
        int elementType = cigar[cigarIndex] & BAM_CIGAR_MASK;
        if (elementType != BAM_CMATCH) {
            numberOfMismatches += cigar[cigarIndex] >> BAM_CIGAR_SHIFT;
        }
    }
    return numberOfMismatches;
}

<commit_msg>give a warning message and program aborts when bamfetch fails caused by different reference files used in scan and msi steps<commit_after>/*
 * bamreader.cpp for MSIsensor
 * Copyright (c) 2013 Beifang Niu && Kai Ye WUGSC All Rights Reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// System header files
#include <iomanip>
#include <iostream>
#include <fstream>
#include <cmath>
#include <assert.h>

// Samtools header files
#include "bam.h"
#include "sam.h"
#include "kstring.h"
#include "kseq.h"
#include "khash.h"
#include "ksort.h"

// Bam header files
#include "bamreader.h"
#include "distribution.h"

// Static function declaration
static int fetch_func_SR (const bam1_t * b1, void *data);

unsigned int g_InWinPlus = 0;
unsigned int g_InWinMinus = 0;
unsigned int g_NumReadScanned = 0;
unsigned int g_NumReadInWindow = 0;
unsigned int g_CloseMappedPlus = 0;
unsigned int g_CloseMappedMinus = 0;

//init hash/maps for read pairing on the fly
KSORT_INIT_GENERIC (uint32_t) KHASH_MAP_INIT_STR (read_name, bam1_t *)
struct fetch_func_data_SR {
    fetch_func_data_SR () {
        LeftReads = NULL;
        read_to_map_qual = NULL;
        header = NULL;
        b1_flags = NULL;
        b2_flags = NULL;
        Tag = "";
        InsertSize = 0;
    }
    std::vector < SPLIT_READ > *LeftReads;
    khash_t (read_name) * read_to_map_qual;
    bam_header_t *header;
    flags_hit *b1_flags;
    flags_hit *b2_flags;
    std::string Tag;
    int InsertSize;
};

void parse_flags_and_tags (const bam1_t * b, flags_hit * flags) {
    const bam1_core_t *c = &b->core;
    char xt_code = '\0';
    int mf_code = 0, nm_code = 0, best_hits = 0;
    flags->unique = 0;
    flags->mapped = !(c->flag & BAM_FUNMAP);
    uint8_t *s = bam_aux_get (b, "XT");
    if (s != 0) {
        xt_code = bam_aux2A (s);
        if (xt_code == 'U') {
            flags->unique = 1;
        } else {
            flags->unique = 0;
        }
    } else { flags->unique = 1; }
    s = NULL;
    s = bam_aux_get (b, "X0");
    if (s != 0) {
        best_hits = bam_aux2i (s);
    }
    s = NULL;
    s = bam_aux_get (b, "X1");
    if (s != 0) {
        int sub_hits = bam_aux2i (s);
        if (best_hits + sub_hits == 1) {
            flags->suboptimal = 0;
        } else { flags->suboptimal = 1; }
    } else { flags->suboptimal = 0; }
    if (xt_code == 'M' || mf_code == 130) {
        //short term fix to unset unique if the maq read was s-w mapped.
        //bwa can't set U and M at once.
        flags->sw = 1;
    } else { flags->sw = 0; }
    s = NULL;
    s = bam_aux_get (b, "NM");
    if (s != 0) {
        nm_code = bam_aux2i (s);
        flags->edits = nm_code;
    } else {
        nm_code = 0;
        flags->edits = nm_code;
    }

    return;
}

/*

static int fetch_func_ALL (const bam1_t * b1, void *data) {
    fetch_func_data_SR *data_for_bam = (fetch_func_data_SR *) data;
    khash_t (read_name) * read_to_map_qual = (khash_t (read_name) *) data_for_bam->read_to_map_qual;

    flags_hit *b1_flags = data_for_bam->b1_flags;
    flags_hit *b2_flags = data_for_bam->b2_flags;

    //SPLIT_READ Temp_One_Read;
    const bam1_core_t *b1_core;
    bam1_t *b2;
    bam1_core_t *b2_core;
    b1_core = &b1->core;
    std::string read_name = bam1_qname (b1);
    khint_t key = kh_get (read_name, read_to_map_qual, bam1_qname (b1));

    if (key == kh_end (read_to_map_qual)) {
        int ret = 0;
        key = kh_put (read_name, read_to_map_qual, strdup (bam1_qname (b1)), &ret);
        kh_value (read_to_map_qual, key) = bam_dup1 (b1);
        return 0;
    } else {
        b2 = bam_dup1 (kh_value (read_to_map_qual, key));
        bam_destroy1 (kh_value (read_to_map_qual, key));
        b2_core = &b2->core;
        //this seems stupid, but in order to manage the read names, necessary
        free ((char *) kh_key (read_to_map_qual, key));
        kh_del (read_name, read_to_map_qual, key);
        std::string c_sequence;
    }
    parse_flags_and_tags (b1, b1_flags);
    parse_flags_and_tags (b2, b2_flags);
    build_record(b1, b2, data, b1_flags);
    build_record(b2, b1, data, b2_flags);
    bam_destroy1 (b2);
    return 0;
}

*/

// new version fetch function for single end_reads
static int fetch_func_ALL (const bam1_t * b1, void *data) {
    fetch_func_data_SR *data_for_bam = (fetch_func_data_SR *) data;
    khash_t (read_name) * read_to_map_qual = (khash_t (read_name) *) data_for_bam->read_to_map_qual;

    flags_hit *b1_flags = data_for_bam->b1_flags;

    //SPLIT_READ Temp_One_Read;
    const bam1_core_t *b1_core;
    b1_core = &b1->core;
    parse_flags_and_tags (b1, b1_flags);
    build_record( b1, data, b1_flags );

    return 0;
}

/** 'ReadInRead' reads in reads from Pindel input file. */
bool ReadInBamReads( const char *bam_path,
                     const std::string & FragName,
                     unsigned start,
                     unsigned end,
                     std::vector < SPLIT_READ > & AllReads,
                     std::string Tag) {
    bamFile fp;
    fp = bam_open (bam_path, "r");
    assert (fp);
    bam_index_t *idx;
    idx = bam_index_load (bam_path); // load BAM index
    assert (idx);
    bam_header_t *header = bam_header_read (fp);
    bam_init_header_hash (header);
    assert (header);

    int tid;

    tid = bam_get_tid (header, FragName.c_str ());
    fetch_func_data_SR data;
    data.header = header;
    data.LeftReads = &AllReads;
    data.read_to_map_qual = NULL;
    data.read_to_map_qual = kh_init (read_name);

    flags_hit b1_flags, b2_flags;
    data.b1_flags = &b1_flags;
    data.b2_flags = &b2_flags;
    data.Tag = Tag;
    // std:: cout << " before bam_fetch " << std::endl;
    // give warning and abort if using dif refs
    if (tid == -1) {
        std::cout << "Program aborted: " << std::endl;
        std::cout << "Same reference genome file should be used in both 'msisensor scan' and 'msisensor msi' steps!!!"<<std::endl;
        exit(1);
    }
    bam_fetch (fp, idx, tid, start, end, &data, fetch_func_ALL);
    // std:: cout << " after bam_fetch " << std::endl;
    khint_t key;
    if (kh_size (data.read_to_map_qual) > 0) {
        for (key = kh_begin (data.read_to_map_qual); key != kh_end (data.read_to_map_qual); ++key) {
            if (kh_exist (data.read_to_map_qual, key)) {
                bam_destroy1 (kh_value (data.read_to_map_qual, key));
                free ((char *) kh_key (data.read_to_map_qual, key));
            }
        }
    }
    kh_clear (read_name, data.read_to_map_qual);
    kh_destroy (read_name, data.read_to_map_qual);
    bam_header_destroy (header);
    bam_index_destroy (idx);
    bam_close (fp);

    return true;
}

// new version build_record for single end reads
void build_record( const bam1_t * current_read,
                   void *data,
                   const flags_hit *flag_current_read ) {

    SPLIT_READ Temp_One_Read;
    fetch_func_data_SR *data_for_bam = (fetch_func_data_SR *) data;
    bam_header_t *header = (bam_header_t *) data_for_bam->header;
    std::string Tag = (std::string) data_for_bam->Tag;

    const bam1_core_t *current_core;
    current_core = &current_read->core;
    // Determine sample name for read.
    // std::string c_sequence;
    uint8_t *s = bam1_seq (current_read);
    for (int i = 0; i <current_core->l_qseq; ++i) {
        Temp_One_Read.ReadSeq.append (1, bam_nt16_rev_table[bam1_seqi (s, i)]);
    }
    //std::cout<<Temp_One_Read.ReadSeq<<"\n";
    if ( !flag_current_read->mapped ) {
       Temp_One_Read.Mapped = false;
    } else {
       Temp_One_Read.MatchedRelPos = current_core->pos;
       Temp_One_Read.Mapped = true;
    }
    //std::cout<< Temp_One_Read.MatchedRelPos <<"\n";
    //
    // load one read
    data_for_bam->LeftReads->push_back(Temp_One_Read);

    return;
}

/*
void build_record( const bam1_t * current_read,
                   const bam1_t * mate_read,
                   void *data,
                   const flags_hit *flag_current_read ) {

    SPLIT_READ Temp_One_Read;
    fetch_func_data_SR *data_for_bam = (fetch_func_data_SR *) data;
    bam_header_t *header = (bam_header_t *) data_for_bam->header;
    std::string Tag = (std::string) data_for_bam->Tag;

    const bam1_core_t *current_core;
    const bam1_core_t *mate_core;

    current_core = &current_read->core;
    mate_core = &mate_read->core;
    // Determine sample name for read.
    // std::string c_sequence;
    uint8_t *s = bam1_seq (current_read);
    for (int i = 0; i <current_core->l_qseq; ++i) {
        Temp_One_Read.ReadSeq.append (1, bam_nt16_rev_table[bam1_seqi (s, i)]);
    }
    //std::cout<<Temp_One_Read.ReadSeq<<"\n";
    if ( !flag_current_read->mapped ) {
       Temp_One_Read.Mapped = false;
    } else {
       Temp_One_Read.MatchedRelPos = current_core->pos;
       Temp_One_Read.Mapped = true;
    }
    //std::cout<< Temp_One_Read.MatchedRelPos <<"\n";
    //
    // load one read
    data_for_bam->LeftReads->push_back(Temp_One_Read);

    return;
}

*/

int32_t bam_cigar2len (const bam1_core_t * c, const uint32_t * cigar) {
    uint32_t k;
    int32_t l = 0;
    for (k = 0; k < c->n_cigar; ++k) {
        int op = cigar[k] & BAM_CIGAR_MASK;
        if (op == BAM_CMATCH || op == BAM_CINS || op == BAM_CSOFT_CLIP) {
            l += cigar[k] >> BAM_CIGAR_SHIFT;
        }
        if (op == BAM_CDEL) {
            l -= cigar[k] >> BAM_CIGAR_SHIFT;
        }
   }
   return l;
}

int32_t bam_cigar2mismatch( const bam1_core_t *readCore, const uint32_t *cigar) {
    uint32_t cigarIndex;
    int32_t numberOfMismatches = 0;
    for (cigarIndex = 0; cigarIndex < readCore->n_cigar; ++cigarIndex) {
        int elementType = cigar[cigarIndex] & BAM_CIGAR_MASK;
        if (elementType != BAM_CMATCH) {
            numberOfMismatches += cigar[cigarIndex] >> BAM_CIGAR_SHIFT;
        }
    }
    return numberOfMismatches;
}

<|endoftext|>