MikkelVisibility.h
#pragma once
#include "pch.h"
static Point_2 empty_point = Point_2(-10000, -10000);
class MikkelVisibility {
public:
bool same(Point_2 a, Point_2 b) {
return a == b;
}
bool isset(Point_2 p)
{
return !same(p, empty_point);
}
bool in_between(Segment_2 s, Point_2 a) {
return s.has_on(a) && !same(a, s.source()) && !same(a, s.target());
}
Point_2 point_intersection(Line_2 pq, Segment_2 sgm, int seg_mode = 0) {
auto result = intersection(pq, sgm);
if (result) {
if (const Segment_2* s = boost::get<Segment_2>(&*result)) {
if (same(s->source(), s->target()))
return empty_point;
else if (seg_mode == 1)
return s->source();
else if (seg_mode == 2)
return s->target();
}
else {
Point_2* p = boost::get<Point_2>(&*result);
return *p;
}
}
return empty_point;
}
Point_2 point_intersection(Ray_2 pq, Segment_2 sgm, int seg_mode = 0) {
if (same(pq.source(), sgm.source()))
return pq.source();
if (same(pq.source(), sgm.target()))
return pq.source();
//if (pq.has_on(sgm.source()))
//return sgm.source();
//if (pq.has_on(sgm.target()))
// return sgm.target();
auto result = intersection(pq, sgm);
if (result) {
if (const Segment_2* s = boost::get<Segment_2>(&*result)) {
if (seg_mode == 1)
return s->source();
else if (seg_mode == 2)
return s->target();
}
else {
Point_2* p = boost::get<Point_2>(&*result);
return *p;
}
}
return empty_point;
}
Point_2 point_intersection(Segment_2 pq, Segment_2 sgm, int seg_mode = 0) {
auto result = intersection(pq, sgm);
if (result) {
if (const Segment_2* s = boost::get<Segment_2>(&*result)) {
if (seg_mode == 1)
return s->source();
else if (seg_mode == 2)
return s->target();
}
else {
Point_2* p = boost::get<Point_2>(&*result);
return *p;
}
}
return empty_point;
}
int difference_in_polygon(int a, int b, int n) {
if (a <= b)
{
return b - a;
}
else
{
return n - a + b;
}
}
Point_2 first_intersection(Point_2 p, Point_2 q, std::vector<Point_2> points) {
Ray_2 pq(p, q);
Point_2 res = q;
std::vector<Point_2> inters = {};
for (int i = 0; i < points.size();i++) {
int prev = (i - 1 + points.size()) % points.size();
int next = (i + 1) % points.size();
int next_next = (next + 1) % points.size();
Segment_2 curseg(points[i], points[next]);
Point_2 inter_point = point_intersection(pq, curseg);
//If q is in the middle of a segment and the next vertex not reflex
if (in_between(curseg, q))
return q;
//if q is a vertex and it is not reflex, there will be no intersection point
if (points[i] == q && CGAL::orientation(points[prev], points[i], points[next]) == CGAL::LEFT_TURN)
return q;
//if q is a vertex and prev is on a different side than next of the ray, there is no intersection
CGAL::Orientation or1 = CGAL::orientation(p, q, points[next]);
CGAL::Orientation or2 = CGAL::orientation(p, q, points[prev]);
if (points[i] == q && or1 != or2 && or1 != CGAL::COLLINEAR && or2 != CGAL::COLLINEAR)
return q;
//If q is on the current segment and p is not, and the current segment is colinear with the ray
bool seg_inside_rayseg = Segment_2(p, q).has_on(points[i]) && Segment_2(p, q).has_on(points[next]);
if (!curseg.has_on(p) && pq.has_on(points[i]) && pq.has_on(points[next]) && curseg.has_on(q) && !seg_inside_rayseg)
return q;
if (isset(inter_point) && !same(inter_point, p) && !same(inter_point, q))
inters.push_back(inter_point);
}
if (inters.size() > 0) {
res = inters[0];
for (int i = 1; i < inters.size();i++) {
if (Segment_2(q, inters[i]).squared_length() < Segment_2(q, res).squared_length())
res = inters[i];
}
}
return res;
}
Arrangement_2 polygon_to_arrangement(std::vector<Point_2> poly) {
Arrangement_2 arr = Arrangement_2();
std::vector<Segment_2> segs = {};
int n = poly.size();
int crisb = -1;
//Create segments from the vertices in the polygon
for (int i = 0; i < poly.size(); i++)
{
Segment_2 to_add(poly[i], poly[(i + 1) % n]);
//segs.push_back(to_add);
if (segs.size() == 0)
segs.push_back(to_add);
else {
Segment_2 prev = segs[segs.size() - 1];
if (prev.has_on(poly[(i + 1) % n])) {
//do not add this segment, and remove previous!
segs.pop_back();
to_add = Segment_2(poly[i - 1], poly[(i + 1) % n]);
}
else if (to_add.has_on(prev.source())) {
//do not add this segment, and remove previous!
segs.pop_back();
to_add = Segment_2(poly[i - 1], poly[(i + 1) % n]);
}
segs.push_back(to_add);
}
}
std::vector<Point_2> new_poly;
for (int i = 0; i < segs.size(); i++) {
int next = (i + 1) % segs.size();
if (!same(segs[next].source(), segs[i].target()))
throw(std::exception());
new_poly.push_back(segs[i].source());
}
if (!CGAL::is_simple_2(new_poly.begin(), new_poly.end())) {
throw(std::exception());
}
//Insert the segments into the arrangement
CGAL::insert_non_intersecting_curves(arr, segs.begin(), segs.end());
return arr;
}
std::vector<Point_2> add_points_between(std::vector<Point_2> points, std::vector<Point_2> original_points, int from, int to)
{
if (from < to)
points.insert(points.end(), original_points.begin() + from, original_points.begin() + to);
else
{
points.insert(points.end(), original_points.begin() + from, original_points.end());
points.insert(points.end(), original_points.begin(), original_points.begin() + to);
}
return points;
}
std::vector<Point_2> reverse_pgn(std::vector<Point_2> points, int i)
{
Point_2 v0 = points[0];
Point_2 v1 = points[1];
points.erase(points.begin(), points.begin() + 2);
points.push_back(v0);
points.push_back(v1);
std::reverse(points.begin(), points.end());
return points;
}
std::vector<Point_2> orientate_pgn(std::vector<Point_2> points, int a_index, int b_index)
{
std::vector<Point_2> results = {};
//add a and b
results.push_back(points[a_index]);
results.push_back(points[b_index]);
//add between b and end and between begin and a
results.insert(results.end(), points.begin() + 1 + b_index, points.end());
results.insert(results.end(), points.begin(), points.begin() + a_index);
return results;
}
bool in_half_plane(std::vector<CGAL::Orientation> sides, Point_2 p, Point_2 q, Point_2 x)
{
bool result = false;
for (int i = 0; i < sides.size(); i++)
{
CGAL::Orientation side = sides[i];
if (side == CGAL::COLLINEAR)
result = result || (CGAL::orientation(p, q, x) == side);
//||
// CGAL::orientation(p, q, Point_2(x.x() + alpha, x.y() + alpha)) == side ||
//CGAL::orientation(p, q, Point_2(x.x() + alpha, x.y() - alpha)) == side ||
//CGAL::orientation(p, q, Point_2(x.x() - alpha, x.y() - alpha)) == side ||
//CGAL::orientation(p, q, Point_2(x.x() - alpha, x.y() + alpha)) == side);
else
result = result || (CGAL::orientation(p, q, x) == side);
//CGAL::orientation(p, q, Point_2(x.x() + alpha, x.y() + alpha)) == side &&
//CGAL::orientation(p, q, Point_2(x.x() + alpha, x.y() - alpha)) == side &&
//CGAL::orientation(p, q, Point_2(x.x() - alpha, x.y() - alpha)) == side &&
//CGAL::orientation(p, q, Point_2(x.x() - alpha, x.y() + alpha)) == side);
}
return result;
}
bool segment_enters_HP_quad(std::vector<Point_2> quad_points, Point_2 p, Point_2 q, Point_2 a, Point_2 b, CGAL::Orientation side)
{
std::vector<CGAL::Orientation> sides = { CGAL::LEFT_TURN, CGAL::COLLINEAR };
bool z = in_half_plane({ side }, p, q, a);
bool x = in_half_plane({ side }, p, q, b);
bool y = in_half_plane(sides, quad_points[0], quad_points[1], a);
bool g = in_half_plane(sides, quad_points[1], quad_points[2], a);
bool e = in_half_plane(sides, quad_points[2], quad_points[3], a);
bool f = in_half_plane(sides, quad_points[3], quad_points[0], b);
bool c = in_half_plane(sides, quad_points[1], quad_points[2], b);
bool d = in_half_plane(sides, quad_points[2], quad_points[3], b);
return (
in_half_plane({ side }, p, q, a) &&
in_half_plane(sides, quad_points[3], quad_points[0], a) && in_half_plane(sides, quad_points[0], quad_points[1], a) &&
in_half_plane(sides, quad_points[1], quad_points[2], a) && in_half_plane(sides, quad_points[2], quad_points[3], a)
) ||
(
in_half_plane({ side }, p, q, b) &&
in_half_plane(sides, quad_points[3], quad_points[0], b) && in_half_plane(sides, quad_points[0], quad_points[1], b) &&
in_half_plane(sides, quad_points[1], quad_points[2], b) && in_half_plane(sides, quad_points[2], quad_points[3], b)
);
}
std::tuple<Segment_2, int> polygon_exits(Ray_2 pq, std::vector<Point_2> points, Point_2 target, int def)
{
std::vector<std::tuple<Segment_2, int>> candidates_and_indices = {};
std::tuple<Segment_2, int> winner = std::make_tuple(Segment_2(pq.source(), pq.source()), def);
for (int i = 0; i < points.size(); i++) {
int prev = i - 1;
if (i == 0)
prev = points.size() - 1;
Segment_2 sgm(points[prev], points[i]);
Point_2 inter_point = point_intersection(pq, sgm, 2);
double x = CGAL::to_double(inter_point.x());
double y = CGAL::to_double(inter_point.y());
if (isset(inter_point))
{
//is s the intersection point? (s = pq.source()), or did we check this already last iteration?
if (same(pq.source(), inter_point) || same(points[prev], inter_point))
continue;
//are we hitting a vertex?
if (same(inter_point, points[prev]) || same(inter_point, points[i]))
{
int next = (i + 1) % points.size();
CGAL::Orientation or1 = CGAL::orientation(pq.source(), target, points[next]);
CGAL::Orientation or2 = CGAL::orientation(pq.source(), target, points[prev]);
//CGAL::Orientation or3 = CGAL::orientation(pq.source(), target, points[i]);
if (or1 == or2)
{
// we never left the polygon
continue;
}
if (or1 == CGAL::COLLINEAR || (or2 == CGAL::COLLINEAR && or1 == CGAL::RIGHT_TURN))
continue; //i is reflex vertex, we are still in!
}
Segment_2 winning_smg = Segment_2(pq.source(), inter_point);
double x = CGAL::to_double(winning_smg.squared_length());
double y = CGAL::to_double(std::get<0>(winner).squared_length());
//We are not intersecting in a vertex and thus leaving the polygon
if (std::get<1>(winner) == def || winning_smg.squared_length() < std::get<0>(winner).squared_length())
winner = std::make_tuple(winning_smg, prev);
}
}
return winner;
}
std::tuple<int, int> find_rightmost_beam(std::vector<Point_2> points, int i)
{
int R = 1, L = i + 1, r = R, l = L, n = points.size() - 1, side = 1;
std::vector<Point_2> quad_points = { points[0], points[1], points[i], points[i + 1] };
Polygon_2 quad(quad_points.begin(), quad_points.end());
Point_2 p = points[1];
Point_2 q = points[i + 1];
std::tuple<int, int> null_val = std::make_tuple(0, 0);
while (r < i || l < n)
{
if (side == 1)
{
if (r < i) {
r++;
//does vr-1vr enter LHP(pq) inter quad?
if (segment_enters_HP_quad(quad_points, p, q, points[r - 1], points[r], CGAL::LEFT_TURN))
{
if (isset(point_intersection(Line_2(points[r - 1], points[r]), Segment_2(points[L], q), 1)))
return null_val;
R = r, l = L;
}
}
}
else {
if (l < n) {
l++;
//does vl-1vl enter RHP(pq) inter quad?
if (segment_enters_HP_quad(quad_points, p, q, points[l - 1], points[l], CGAL::RIGHT_TURN))
{
if (isset(point_intersection(Line_2(points[l - 1], points[l]), Segment_2(points[R], p), 1)))
return null_val;
L = l, r = R;
}
}
}
Point_2 temp_p = point_intersection(Ray_2(points[L], points[R]), Segment_2(points[0], points[1]), 1);
Point_2 temp_q = point_intersection(Ray_2(points[R], points[L]), Segment_2(points[i], points[i + 1]), 1);
if (isset(temp_q) && isset(temp_p))
p = temp_p, q = temp_q;
else
return null_val;
side = -side;
}
Line_2 v0v1(points[0], points[1]);
Line_2 vivi1(points[i], points[i + 1]);
//Is pq in LHP v0v1 and LHP vivi1 (so within the polygon)?
bool is_q_good = in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, points[0], points[1], q);
bool is_p_good = in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, points[i], points[i + 1], p);
bool is_vi1_good = in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, points[0], points[1], points[i + 1]);
bool is_v1_good = in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, points[i], points[i + 1], points[1]);
is_vi1_good = is_vi1_good || !in_half_plane({ CGAL::RIGHT_TURN }, points[0], points[1], points[i + 1]);
is_v1_good = is_vi1_good || !in_half_plane({ CGAL::RIGHT_TURN }, points[i], points[i + 1], points[1]);
//return std::make_tuple(R, L);
if ((is_q_good && is_p_good) || (is_vi1_good && is_v1_good))
return std::make_tuple(R, L);
else
return null_val;
}
Segment_2 point_to_edge_visibility(std::vector<Point_2> points, Point_2 p)
{
Segment_2 empty_segment = Segment_2(empty_point, empty_point);
int L = 0, R = 1, n = points.size();
Point_2 a = points[0], b = points[1];
//is p in LHP(v0v1)? if not, this subroutine does not work.
if (!in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, a, b, p))
return empty_segment;
for (int i = 1; i < n - 1; i++)
{
Point_2 i1 = points[(i + 1) % n];
Segment_2 vivi1(points[i], i1);
//triangle check
if (in_half_plane({ CGAL::LEFT_TURN }, a, b, i1) && in_half_plane({ CGAL::LEFT_TURN }, b, p, i1) && in_half_plane({ CGAL::LEFT_TURN }, p, a, i1))
{
//if vivi1 crosses ap left to right (if there is an intersection, and if vi is in LHP(ap) and vi1 is in RHP(ap)
if (in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, a, p, points[i]) && in_half_plane({ CGAL::RIGHT_TURN, CGAL::COLLINEAR }, a, p, i1) && isset(point_intersection(vivi1, Segment_2(a, p))))
{
//is vi1 in RHP(bp)?
if (in_half_plane({ CGAL::RIGHT_TURN, CGAL::COLLINEAR }, b, p, i1))
return empty_segment;
else
{
Point_2 pi = point_intersection(Ray_2(p, i1), Segment_2(points[0], points[1]));
if (isset(pi)) {
L = (i + 1) % n;
a = point_intersection(Ray_2(p, i1), Segment_2(points[0], points[1]));
}
}
}
//if vivi1 crosses bp right to left (if there is an intersection, and if vi is in RHP(bp) and vi1 is in LHP(bp)
if (in_half_plane({ CGAL::RIGHT_TURN, CGAL::COLLINEAR }, b, p, points[i]) && in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, b, p, i1) && isset(point_intersection(vivi1, Segment_2(b, p))))
{
//is vi1 in LHP(ap)?
if (in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, a, p, i1))
return empty_segment;
else
{
Point_2 pi = point_intersection(Ray_2(p, i1), Segment_2(points[0], points[1]));
if (isset(pi)) {
R = (i + 1) % n;
b = pi;
}
}
}
}
}
return Segment_2(a, b);
}
std::vector<std::vector<Point_2>> split_for_vis(Point_2 a, Point_2 b, std::vector<Point_2>& original_points) {
//find first intersections
Point_2 a_prime = first_intersection(b, a, original_points);
Point_2 b_prime = first_intersection(a, b, original_points);
int a_index = -1, b_index = -1, a_prime_index = -1, b_prime_index = -1;
bool a_b_col_seg = false;
std::vector<int> vertices_hit = {};
//pre process, add a,b, a_exit_point and b_exit_point as vertices to polygon!
for (int i = 0; i < original_points.size(); i++) {
Point_2 cur_point = original_points[i];
Point_2 next_point = original_points[(i + 1) % original_points.size()];
Segment_2 cur_seg(cur_point, next_point);
//if(cur_seg.collinear_has_on(a) && cur_seg.collinear_has_on
//time saver?
if (a_index > -1 && b_index > -1 && a_prime_index > -1 && b_prime_index > -1)
break;
//Vertex checks
if (same(cur_point, a)) //a is at this vertex
a_index = i;
else if (same(cur_point, b)) //b is at this vertex
b_index = i;
if (same(cur_point, a_prime)) //a exits at this vertex
a_prime_index = i;
else if (same(cur_point, b_prime)) //b exits at vertex
b_prime_index = i;
//Segment checks
bool a_between = in_between(cur_seg, a);
bool a_x_between = in_between(cur_seg, a_prime);
bool b_between = in_between(cur_seg, b);
bool b_x_between = in_between(cur_seg, b_prime);
if (a_between || a_x_between) {
if (a_between && a_x_between) {
//both, add only one vertex
auto itPos = original_points.begin() + (i + 1);
original_points.insert(itPos, a);
a_index = i + 1;
a_prime_index = i + 1;
}
else if (a_between) {
auto itPos = original_points.begin() + (i + 1);
original_points.insert(itPos, a);
a_index = i + 1;
}
else {
auto itPos = original_points.begin() + (i + 1);
original_points.insert(itPos, a_prime);
a_prime_index = i + 1;
}
}
else if (b_between || b_x_between) {
//add point in between
if (b_between && b_x_between) {
//both, add only one vertex
auto itPos = original_points.begin() + (i + 1);
original_points.insert(itPos, b);
b_index = i + 1;
b_prime_index = i + 1;
}
else if (b_between) {
auto itPos = original_points.begin() + (i + 1);
original_points.insert(itPos, b);
b_index = i + 1;
}
else {
auto itPos = original_points.begin() + (i + 1);
original_points.insert(itPos, b_prime);
b_prime_index = i + 1;
}
}
if (in_between(Segment_2(a, b), cur_point))
vertices_hit.push_back(i);
}
/*if (a_prime_index == -1)
a_prime_index = a_index;
if(b_prime_index == -1)
b_prime_index = b_index;*/
bool last = (b_index == (original_points.size() - 1) && a_index == 0);
bool will_last = (a_index == (original_points.size() - 1) && b_index == 0);
int diff_ap_b = difference_in_polygon(a_prime_index, b_index, original_points.size());
int diff_ap_bp = difference_in_polygon(a_prime_index, b_prime_index, original_points.size());
int diff_b_ap = difference_in_polygon(b_index, a_prime_index, original_points.size());
int diff_b_a = difference_in_polygon(b_index, a_index, original_points.size());
//if ((a_index > b_index && a_index > -1 && b_index > -1 && !will_last) || last
// ||(b_index == -1 && a_index > -1)) {
if ((diff_ap_bp < diff_ap_b && a_index > -1) || (a_index > -1 && b_index == -1) || (b_index == b_prime_index && diff_b_a < diff_b_ap))
{
if (a_index == -1 && b_index > -1) {
//don't flip!
}
else {
//reverse everything!
int temp_a = a_index, temp_p = a_prime_index;
Point_2 temp_ap = a, temp_pp = a_prime;
a = b, a_prime = b_prime, a_index = b_index, a_prime_index = b_prime_index;
b = temp_ap, b_index = temp_a, b_prime = temp_pp, b_prime_index = temp_p;
diff_ap_b = difference_in_polygon(a_prime_index, b_index, original_points.size());
diff_ap_bp = difference_in_polygon(a_prime_index, b_prime_index, original_points.size());
}
}
//OutputDebugString(std::to_string(a_index).c_str());
//OutputDebugString("\n");
//OutputDebugString(std::to_string(a_prime_index).c_str());
//OutputDebugString("\n");
//OutputDebugString(std::to_string(b_index).c_str());
//OutputDebugString("\n");
//OutputDebugString(std::to_string(b_prime_index).c_str());
//OutputDebugString("\n");
//OutputDebugString("\n");
//OutputDebugString((std::string("a x: ") + std::to_string(CGAL::to_double(a.x()))).c_str());
//OutputDebugString("\n");
//OutputDebugString((std::string("a y: ") + std::to_string(CGAL::to_double(a.y()))).c_str());
//OutputDebugString("\n");
//OutputDebugString((std::string("ap x: ") + std::to_string(CGAL::to_double(a_prime.x()))).c_str());
//OutputDebugString("\n");
//OutputDebugString((std::string("ap y: ") + std::to_string(CGAL::to_double(a_prime.y()))).c_str());
//OutputDebugString("\n");
//OutputDebugString("\n");
//OutputDebugString((std::string("b x: ") + std::to_string(CGAL::to_double(b.x()))).c_str());
//OutputDebugString("\n");
//OutputDebugString((std::string("b y: ") + std::to_string(CGAL::to_double(b.y()))).c_str());
//OutputDebugString("\n");
//OutputDebugString((std::string("bp x: ") + std::to_string(CGAL::to_double(b_prime.x()))).c_str());
//OutputDebugString("\n");
//OutputDebugString((std::string("bp y: ") + std::to_string(CGAL::to_double(b_prime.y()))).c_str());
//OutputDebugString("\n");
//OutputDebugString("\n");
std::vector<std::vector<Point_2>> pgns = {}, p_right = {};
std::vector<Point_2> p_a = {}, p_left = {}, p_b = {}, p_r = {};
std::vector<int> p_r_i, p_a_i, p_l_i, p_b_i, p_right_i;
if (a_index > -1)
vertices_hit.insert(vertices_hit.begin(), a_index);
if (b_index > -1)
vertices_hit.push_back(b_index);
if (a_index != a_prime_index) {
if (a_index > -1) { //a is reflex
p_a = { a,a };
p_a_i = { a_index, a_index };
p_a = add_points_between(p_a, original_points, a_prime_index, a_index);
}
else { //a is floating
if (b_index == -1) {
//both floating
p_r = { b, a };
p_r = add_points_between(p_r, original_points, a_prime_index, b_prime_index);
p_r.push_back(b_prime);
p_right.push_back(p_r);
p_left = { a,b };
p_left = add_points_between(p_left, original_points, b_prime_index, a_prime_index);
p_left.push_back(a_prime);
}
else {
//only a floating
if (b_prime_index == b_index || diff_ap_bp > diff_ap_b) {
p_r = { b, a };
p_r = add_points_between(p_r, original_points, a_prime_index, b_index);
p_r.push_back(b);
p_right.push_back(p_r);
p_left = { a, b };
p_left = add_points_between(p_left, original_points, b_prime_index, a_prime_index);
p_left.push_back(a_prime);
}
else {
p_r = { b, a };
p_r = add_points_between(p_r, original_points, a_prime_index, b_prime_index);
p_r.push_back(b_prime);
p_right.push_back(p_r);
p_left = { a,b };
p_left = add_points_between(p_left, original_points, b_index, a_prime_index);
p_left.push_back(a_prime);
}
}
}
}
if (b_index != b_prime_index && b_index > -1) { //b is reflex
if (diff_ap_b > diff_ap_bp) {
p_b = { b, b };
p_b = add_points_between(p_b, original_points, b_prime_index, b_index);
}
else {
p_b = { b };
p_b = add_points_between(p_b, original_points, b_index, b_prime_index);
p_b.push_back(b_prime);
}
}
if (b_index > -1 && a_index > -1) {//neither floating:
//p_r sorted by for loop
int v_size = vertices_hit.size();
for (int i = 0; i < (v_size - 1);i++) {
int next = i + 1;
p_r = { original_points[vertices_hit[next]], original_points[vertices_hit[i]] };
p_r = add_points_between(p_r, original_points, vertices_hit[i], vertices_hit[next]);
p_r.push_back(original_points[vertices_hit[next]]);
if (p_r.size() > 4)
p_right.push_back(p_r);
}
//p_left simple
p_left = { a };
if (b_prime_index != b_index)
p_left.push_back(b);
p_left = add_points_between(p_left, original_points, b_prime_index, a_prime_index);
if (a_prime_index != a_index)
p_left.push_back(a_prime);
//if(p_right.size() < 1)
//p_left.push_back(a);
}
pgns.push_back(p_b);
pgns.insert(pgns.end(), p_right.begin(), p_right.end());
pgns.push_back(p_left);
pgns.push_back(p_a);
return pgns;
}
std::vector<Point_2> compute_visibility_from_point(Point_2 a, Arrangement_2& env, TEV* tev)
{
//Initialize variables
std::vector<Segment_2> segments;
std::vector<Point_2> points = {};
//Find the face
Arrangement_2::Face_const_handle* face;
CGAL::Arr_naive_point_location<Arrangement_2> pl(env);
CGAL::Arr_point_location_result<Arrangement_2>::Type obj = pl.locate(a);
// The query point locates in the interior of a face
face = boost::get<Arrangement_2::Face_const_handle>(&obj);
Arrangement_2 output_arr;
typedef CGAL::Simple_polygon_visibility_2<Arrangement_2, CGAL::Tag_false> NSPV;
Face_handle fh;
Halfedge_const_handle he = Halfedge_const_handle();
//If the point is within a face, we can compute the visbility that way
if (face != NULL)
{
fh = tev->compute_visibility(a, *face, output_arr);
}
else
{
//If the point in a boundary segment, find the corresponding half edge
he = env.halfedges_begin();
bool cont = !Segment_2(he->source()->point(), he->target()->point()).has_on(a) || he->source()->point() == a || he->face()->is_unbounded();
//While we are not in the right half edge, or while q is the source, continue
while (cont) {
he++;
if (he == env.halfedges_end()) {
throw(std::exception());
}
cont = !Segment_2(he->source()->point(), he->target()->point()).has_on(a) || he->source()->point() == a || he->face()->is_unbounded();
}
//Use the half edge to compute the visibility
fh = tev->compute_visibility(a, he, output_arr);
}
//Make sure the visibility polygon we find has an outer boundary
if (fh->has_outer_ccb()) {
Arrangement_2::Ccb_halfedge_circulator curr = fh->outer_ccb();
//find the right halfedge first
if (he != Halfedge_const_handle())
while (++curr != fh->outer_ccb())
if (curr->source()->point() == he->source()->point())
break;
Arrangement_2::Ccb_halfedge_circulator first = curr;
points.push_back(curr->source()->point());
//Save the points from the visibility polygon
while (++curr != first)
points.push_back(curr->source()->point());
}
return points;
}
Polygon_2 compute_visibility_from_segment(std::vector<Point_2>& poly, Point_2 a, Point_2 b) {
//check if we need to split the orignal polygon into more polygons
std::vector<std::vector<Point_2>> split_pgns = split_for_vis(a, b, poly);
std::vector<Point_2> points = {};
if (same(poly[0], a) && same(poly[1], b)) {
points.push_back(a);
points.push_back(b);
}
//points.push_back(b);
//compute visibility per split polygon and then combine
for (int k = 0; k < split_pgns.size();k++)
{
//initiliaze variables
int R = 0;
int L = 0;
std::vector<Point_2> current_pgn_points = split_pgns[k];
if (current_pgn_points.size() < 3)
continue;
//This means we are computing visibility for a point and not segment
if (same(current_pgn_points[0], current_pgn_points[1]))
{
//Erase the first point because it is duplicated
current_pgn_points.erase(current_pgn_points.begin());
if (current_pgn_points.size() < 3)
continue;
//compute the visibility using the method
Arrangement_2 env = polygon_to_arrangement(current_pgn_points);
TEV tev(env);
std::vector<Point_2> vis_points =
compute_visibility_from_point(current_pgn_points[0],
env, &tev);
//If the method results a valid polygon
if (vis_points.size() > 0) {
std::vector<Point_2> ordered_points = {};
int viewer = -1;
for (int i = 0; i < vis_points.size(); i++) {
//Find index of viewer
if (vis_points[i] == current_pgn_points[0]) {
viewer = i;
break;
}
}
if (viewer == vis_points.size() - 1)
points.insert(points.end(), vis_points.begin(), vis_points.end() - 1);
else {
points.insert(points.end(), vis_points.begin() + viewer + 1, vis_points.end());
points.insert(points.end(), vis_points.begin(), vis_points.begin() + viewer);
}
}
continue; //skip to the next iteration
}
//Loop through the vertices
for (int i = 1; i < current_pgn_points.size() - 1; i++)
{
if (current_pgn_points[i + 1] == current_pgn_points[1]) {
points.push_back(current_pgn_points[i + 1]);
continue;
}
//Check for the righmost beam
std::tuple<int, int> rmb = find_rightmost_beam(split_pgns[k], i);
R = std::get<0>(rmb);
L = std::get<1>(rmb);
//No proper beam available!
if (R == 0 && L == 0)
{
continue;
}
if (L == i + 1)
{
//add vi1 to result
points.push_back(current_pgn_points[i + 1]);
Point_2 s = empty_point;
//point closest to v0 is a, so the source.
//compute point visibility
Arrangement_2 env = polygon_to_arrangement(poly);
TEV tev(env);
std::vector<Point_2> point_vis = compute_visibility_from_point(current_pgn_points[i + 1], env, &tev);
CGAL::Bounded_side b = CGAL::bounded_side_2(point_vis.begin(), point_vis.end(), current_pgn_points[0]);
if (b != CGAL::ON_UNBOUNDED_SIDE) //a is visible
s = current_pgn_points[0];
else {
//iterate the polygon and find the part of the edge that is inside
for (int i_vis = 0; i_vis < point_vis.size();i_vis++) {
Point_2 curp = point_vis[i_vis];
Point_2 nextp = point_vis[(i_vis + 1) % point_vis.size()];
Point_2 interpoint = point_intersection(Segment_2(current_pgn_points[0], current_pgn_points[1]),
Segment_2(curp, nextp));
if (isset(interpoint) && Segment_2(current_pgn_points[0], interpoint).squared_length() < Segment_2(current_pgn_points[0], s).squared_length())
s = interpoint;
}
}
//is s in LHP(vi1,vi2)?
if (!isset(s) || current_pgn_points.size() <= (i + 2) || in_half_plane({ CGAL::LEFT_TURN, CGAL::COLLINEAR }, current_pgn_points[i + 1], current_pgn_points[i + 2], s))
continue;
else
{
//x is the point where ray svi1 exits P, and vivi1 is the edge in which this happens (update i)
std::tuple<Segment_2, int> sx_and_i = polygon_exits(Ray_2(s, current_pgn_points[i + 1]), current_pgn_points, current_pgn_points[i + 1], i + 1);
Point_2 x = std::get<0>(sx_and_i).target();
if (!same(s, x) && !same(current_pgn_points[i + 1], x))
{
points.push_back(x);
i = std::get<1>(sx_and_i) - 1;
}
}
}
else
{
//Use R and L to find the left most point on vivi1 that we can see
Point_2 q = point_intersection(Ray_2(current_pgn_points[R], current_pgn_points[L]), Segment_2(current_pgn_points[i], current_pgn_points[i + 1]));
points.push_back(q);
points.push_back(current_pgn_points[L]);
//any i between i and L we cannot see, so i = L
i = L - 1;
}
}
}
//remove duplicates
std::vector<Point_2> pure_points = {};
for (int i = 0; i < points.size();i++) {
int next = (i + 1) % points.size();
if (!same(points[i], points[next]))
pure_points.push_back(points[i]);
}
return Polygon_2(pure_points.begin(), pure_points.end());
}
};