| #include <cmath> // sqrt() sin() cos() |
| #ifndef M_PI |
| #define M_PI 3.14159265358979323846 |
| #endif |
| #include <iostream> // std::cout |
| #include "igs_maxmin_lens_matrix.h" |
| |
| namespace { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| bool inside_polygon_(double radius, int odd_diameter, double xp, double yp, |
| int polygon_number, double roll_degree) { |
| if (polygon_number < 3) { |
| return true; |
| } |
| double radian = roll_degree * (M_PI / 180), |
| add_radian = 2.0 * M_PI / polygon_number; |
| double x1 = radius * cos(radian), y1 = radius * sin(radian), x2 = 0, y2 = 0, |
| xa = odd_diameter, xb = odd_diameter; |
| radian += add_radian; |
| |
| |
| for (int ii = 0; ii < polygon_number; |
| ++ii, radian += add_radian, x1 = x2, y1 = y2) { |
| |
| |
| |
| |
| |
| |
| x2 = radius * cos(radian); |
| y2 = radius * sin(radian); |
| |
| |
| |
| if (!(((y1 <= yp) && (yp <= y2)) || ((y2 <= yp) && (yp <= y1)))) { |
| continue; |
| } |
| |
| |
| |
| |
| if (y2 == y1) { |
| if (((x1 <= xp) && (xp <= x2)) || ((x2 <= xp) && (xp <= x1))) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| |
| |
| if (xa == odd_diameter) { |
| |
| |
| xa = (yp - y1) * (x2 - x1) / (y2 - y1) + x1; |
| } else |
| |
| if (xb == odd_diameter) { |
| xb = (yp - y1) * (x2 - x1) / (y2 - y1) + x1; |
| if (((xa <= xp) && (xp <= xb)) || ((xb <= xp) && (xp <= xa))) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| } |
| return false; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| double length_to_polygon_(double radius, double xp, double yp, |
| int polygon_number, double roll_degree) { |
| |
| double radian = atan2(yp, xp); |
| if (radian < 0) { |
| radian += M_PI * 2.0; |
| } |
| |
| |
| double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0; |
| const double add_radian = 2.0 * M_PI / polygon_number; |
| double radian1 = roll_degree * (M_PI / 180); |
| |
| while (radian1 < 0.0) { |
| radian1 += add_radian; |
| } |
| double radian2 = radian1 + add_radian; |
| |
| |
| |
| if (radian < radian1) { |
| radian += M_PI * 2.0; |
| } |
| |
| for (int ii = 0; ii < polygon_number; |
| ++ii, radian1 = radian2, radian2 += add_radian) { |
| if (radian1 <= radian && radian <= radian2) { |
| x1 = radius * cos(radian1); |
| y1 = radius * sin(radian1); |
| x2 = radius * cos(radian2); |
| y2 = radius * sin(radian2); |
| break; |
| } |
| } |
| if (x1 == 0.0) { |
| |
| return -1.0; |
| } |
| return fabs((y1 - y2) * xp + (x2 - x1) * yp + x1 * y2 - y1 * x2) / |
| sqrt((y1 - y2) * (y1 - y2) + (x2 - x1) * (x2 - x1)); |
| } |
| void alloc_lens_matrix_(const int odd_diameter, std::vector<int> &lens_offsets, |
| std::vector<int> &lens_sizes, |
| std::vector<std::vector<double>> &lens_ratio) { |
| lens_offsets.resize(odd_diameter); |
| lens_sizes.resize(odd_diameter); |
| lens_ratio.resize(odd_diameter); |
| for (int yy = 0; yy < odd_diameter; ++yy) { |
| lens_ratio.at(yy).resize(odd_diameter); |
| } |
| } |
| void free_lens_matrix_(std::vector<int> &lens_offsets, |
| std::vector<int> &lens_sizes, |
| std::vector<std::vector<double>> &lens_ratio) { |
| lens_ratio.clear(); |
| lens_sizes.clear(); |
| lens_offsets.clear(); |
| } |
| } |
| const int igs::maxmin::diameter_from_outer_radius(const double outer_radius) { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| return (static_cast<int>(ceil(outer_radius + 0.5) + 0.5) - 1) * 2 + 1; |
| } |
| const double igs::maxmin::outer_radius_from_radius( |
| const double radius, const double smooth_outer_range) { |
| if (radius < 1.0) { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| return 1.0 + radius * (radius + smooth_outer_range - 1.0); |
| } |
| return radius + smooth_outer_range; |
| } |
| const int igs::maxmin::alloc_and_shape_lens_matrix( |
| const double radius |
| , |
| const double outer_radius, const int polygon_number |
| , |
| const double roll_degree |
| , |
| std::vector<int> &lens_offsets, std::vector<int> &lens_sizes, |
| std::vector<std::vector<double>> &lens_ratio) { |
| |
| if (radius <= 0.0) { |
| free_lens_matrix_(lens_offsets, lens_sizes, lens_ratio); |
| return 0; |
| } |
| |
| |
| const int odd_diameter = |
| igs::maxmin::diameter_from_outer_radius(outer_radius); |
| |
| |
| alloc_lens_matrix_(odd_diameter, lens_offsets, lens_sizes, lens_ratio); |
| |
| |
| igs::maxmin::reshape_lens_matrix( |
| radius, |
| igs::maxmin::outer_radius_from_radius(radius, outer_radius - radius), |
| odd_diameter, polygon_number, roll_degree, lens_offsets, lens_sizes, |
| lens_ratio); |
| return odd_diameter; |
| } |
| const void igs::maxmin::reshape_lens_matrix( |
| const double radius |
| , |
| const double outer_radius, const int odd_diameter |
| , |
| const int polygon_number |
| , |
| const double roll_degree |
| , |
| std::vector<int> &lens_offsets |
| , |
| std::vector<int> &lens_sizes |
| , |
| std::vector<std::vector<double>> &lens_ratio |
| ) { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| double yp = 0.5 - (odd_diameter / 2.0); |
| for (int yy = 0; yy < odd_diameter; ++yy, yp += 1.0) { |
| |
| lens_offsets.at(yy) = -1; |
| lens_sizes.at(yy) = 0; |
| double xp = 0.5 - (odd_diameter / 2.0); |
| for (int xx = 0; xx < odd_diameter; ++xx, xp += 1.0) { |
| const double current_radius = sqrt(xp * xp + yp * yp); |
| |
| if ((current_radius <= outer_radius) && |
| inside_polygon_(outer_radius, odd_diameter, xp, yp, polygon_number, |
| roll_degree)) { |
| |
| if (lens_offsets.at(yy) < 0) { |
| |
| lens_offsets.at(yy) = xx; |
| } |
| |
| } else { |
| |
| if ((0 <= lens_offsets.at(yy)) && (lens_sizes.at(yy) == 0)) { |
| |
| lens_sizes.at(yy) = xx - lens_offsets.at(yy); |
| } |
| } |
| } |
| |
| if ((0 <= lens_offsets.at(yy)) && (lens_sizes.at(yy) == 0)) { |
| lens_sizes.at(yy) = odd_diameter - lens_offsets.at(yy); |
| } |
| |
| |
| |
| if (lens_sizes.at(yy) <= 0) { |
| continue; |
| } |
| |
| xp = 0.5 - (odd_diameter / 2.0); |
| int xr = 0; |
| for (int xx = 0; xx < odd_diameter; ++xx, xp += 1.0) { |
| const double current_radius = sqrt(xp * xp + yp * yp); |
| |
| if ((current_radius <= outer_radius) && |
| inside_polygon_(outer_radius, odd_diameter, xp, yp, polygon_number, |
| roll_degree)) { |
| |
| if ((current_radius <= radius) && |
| inside_polygon_(radius, odd_diameter, xp, yp, polygon_number, |
| roll_degree)) { |
| lens_ratio.at(yy).at(xr++) = 1.0; |
| } |
| |
| else { |
| if (polygon_number < 3) { |
| lens_ratio.at(yy).at(xr++) = |
| (outer_radius - current_radius) / (outer_radius - radius); |
| } else { |
| const double leninn = |
| length_to_polygon_(radius, xp, yp, polygon_number, roll_degree); |
| const double lenout = length_to_polygon_( |
| outer_radius, xp, yp, polygon_number, roll_degree); |
| lens_ratio.at(yy).at(xr++) = lenout / (leninn + lenout); |
| } |
| } |
| } |
| } |
| } |
| } |