ArtGallery.cpp
#pragma once
#include "pch.h"
#include "ArrangementFunctions.h"
#include "ArtGallery.h"
#include "Convex_expansion_visibility_2_temp.h"
#include "IOHandling.h"
#include "IPSolver.h"
#include "MikkelVisibility.h"
#include "PointFunctions.h"
#include "Visibility.h"
#include "WeakVisDecomp.h"
typedef Convex_expansion_visibility_2 CEV;
class ArtGalleryImpl {
public:
ArtGallery* wrapper;
IPSolver IP;
//vector<Vertex_handle> vertexHandles;
//Save reflex details, used for splits etc...
vector<pair<Vertex_handle, Vertex_handle>> reflexNeighbours = {};
vector<Vertex_handle> reflexHandles = {};
vector<pair<Vertex_handle, Vertex_handle>> chords = {}; //chords between reflex vertices that can see eachother!
//Visibility
unique_ptr<Visibility> vis;
shared_ptr<WeakVisNode> weakVisRoot;
int maxGranularity = pow(2, 6); //default value?
ArtGalleryImpl(ArtGallery* wrapper) {
vis = unique_ptr<Visibility>(new Visibility());
this->wrapper = wrapper;
//Make sure thePolygon is filled
IOHandling::GetTestPolygon(wrapper->testPolygonID, wrapper->currentSize, wrapper->inTestMode, vis->polygonBoundary);
IOHandling::SetDimensions(vis->polygonBoundary);
vis->attach(&IP, wrapper->criticalThreshold);
IOHandling::GetTestPolygon(wrapper->testPolygonID, wrapper->currentSize, wrapper->inTestMode, vis->thePolygon);
//Identify reflex vertices
//use do/while for circular loop
//The polygon is a "hole" in the unbounded face of the arrangement, thus a clockwise inner_ccb
auto eit = *vis->thePolygon.unbounded_face()->inner_ccbs_begin();
do {
//Assign ids to vertices (this is their polygonal ID, used for the shortest path map later!
eit->source()->data().isOriginal = true;
//Left turn, because the boundary is clockwise...
if (CGAL::orientation(eit->prev()->source()->point(), eit->prev()->target()->point(), eit->target()->point()) == CGAL::LEFT_TURN) {
//eit->source() is a reflex vertex...
eit->source()->data().isReflex = true;
reflexHandles.push_back(eit->source());
reflexNeighbours.push_back(
make_pair(eit->prev()->source(), eit->target()
));
}
} while (++eit != *(vis->thePolygon.unbounded_face()->inner_ccbs_begin()));
}
bool initialize() {
auto timeBegin = IOHandling::get_cpu_time();
Arrangement_2 theRotatedPolygon = rotateArrangement(vis->thePolygon);
//Shoot orthogonal rays
for (size_t i = 0; i < reflexHandles.size(); i++) {
Point_2 prevPoint = reflexNeighbours[i].first->point();
Point_2 reflexPoint = reflexHandles[i]->point();
Point_2 nextPoint = reflexNeighbours[i].second->point();
bool goUp, goDown, goRight, goLeft;
goUp = goDown = goRight = goLeft = true;
auto vit = reflexHandles[i]->incident_halfedges();
do {
//check for verticalities, because CGAL's shoot_up/shoot_down bugs out otherwise...
//target is our reflex vertex...
if (vit->curve().is_vertical()) {
if (vit->source()->point().y() > reflexPoint.y())
goUp = false;
else
goDown = false;
}
else if (vit->source()->point().y() == vit->target()->point().y()) {
if (vit->source()->point().x() > reflexPoint.x())
goRight = false;
else
goLeft = false;
}
} while (++vit != reflexHandles[i]->incident_halfedges());
vector<Point_2> newVertices = shootRayUpDown(vis->thePolygon, reflexPoint, goUp, goDown);
vector<Point_2> rVertices = shootRayUpDown(theRotatedPolygon, rotatePointRight(reflexPoint), goLeft, goRight);
for (auto &rVertex : rVertices)
newVertices.push_back(rotatePointLeft(rVertex));
for (auto newVertex : newVertices)
{
//check if the point is contained inside the polygon...
//(if it is to the right of one of the two incident reflex segments its okay (right because we found these edges going clockwise))
if (CGAL::orientation(prevPoint, reflexPoint, newVertex) == CGAL::RIGHT_TURN ||
CGAL::orientation(reflexPoint, nextPoint, newVertex) == CGAL::RIGHT_TURN) {
Arrangement_2::X_monotone_curve_2 toInsert(reflexPoint, newVertex);
/*if (toInsert.is_directed_right()) {
vis->thePolygon.insert_at_left
}*/
//TODO: improve insert?
CGAL::insert(vis->thePolygon, Segment_2(reflexPoint, newVertex));
//the reflex vertex is the starting point
//insert into both arrangements
CGAL::insert(theRotatedPolygon, Segment_2(rotatePointRight(reflexPoint), rotatePointRight(newVertex)));
}
}
}
auto timeEnd = IOHandling::get_cpu_time();
chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(timeEnd - timeBegin);
wrapper->preprocessingTime += time_span.count();
timeBegin = IOHandling::get_cpu_time();
//compute all visibilities that we still have to
for (auto vit = vis->thePolygon.vertices_begin(); vit != vis->thePolygon.vertices_end(); ++vit)
if(!vit->data().created)
vis->prepareGuard(vit, FaceGuard());
for (auto vit = vis->thePolygon.vertices_begin(); vit != vis->thePolygon.vertices_end(); ++vit) {
if (!vit->data().created) {
vit->data().created = true;
vis->updateVisibilities(vit);
}
}
for (auto fit = vis->thePolygon.faces_begin(); fit != vis->thePolygon.faces_end(); ++fit)
if (fit->has_outer_ccb() && !fit->data().created)
vis->prepareGuard(fit, FaceGuard());
for (auto fit = vis->thePolygon.faces_begin(); fit != vis->thePolygon.faces_end(); ++fit) {
if (fit->has_outer_ccb() && !fit->data().created) {
fit->data().created = true;
vis->updateVisibilities(fit);
}
}
timeEnd = IOHandling::get_cpu_time();
time_span = chrono::duration_cast<chrono::duration<double>>(timeEnd - timeBegin);
wrapper->processingTime += time_span.count();
//Compute chords for splits!
for (auto vit = reflexHandles.begin(); vit != reflexHandles.end(); ++vit) {
//for every other reflex vertex
for (auto vit2 = vit + 1; vit2 != reflexHandles.end(); ++vit2) {
//if they see eachother: save reflex chord
if (vis->seesWitness(*vit, *vit2))
chords.push_back(make_pair(*vit, *vit2));
}
}
string fileString;
if(wrapper->inTestMode)
fileString = to_string(wrapper->currentSize) + "-" + to_string(wrapper->testPolygonID) + "/" + wrapper->initSVGString;
else
fileString = testPolygonNames[wrapper->testPolygonID] + "/" + wrapper->initSVGString;
//returns true if not in Drawmode. Otherwise draws polygon and returns result
return !wrapper->inDrawMode || IOHandling::DrawArtGallery(vis->thePolygon, fileString, IP);
}
bool preProcess() {
auto timeBegin = IOHandling::get_cpu_time();
//Set-up weak visibility decomp O(n^2)?)
auto eit = *vis->thePolygon.unbounded_face()->inner_ccbs_begin(); //random edge
WeakVisNode::weakVisCounter = 0;
weakVisRoot = shared_ptr<WeakVisNode>(new WeakVisNode(vis->thePolygon, vis->thePolygon, 0, eit->twin(), wrapper->useWeakVis));
//build the weak visibility vector for constant look-up
vis->weakVisNodes.push_back(weakVisRoot);
vector<shared_ptr<WeakVisNode>> rootSubTree = weakVisRoot->subTree();
vis->weakVisNodes.insert(vis->weakVisNodes.end(), rootSubTree.begin(), rootSubTree.end());
auto timeEnd = IOHandling::get_cpu_time();
chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(timeEnd - timeBegin);
wrapper->preprocessingTime += time_span.count();
string fileString;
if (wrapper->inTestMode)
fileString = to_string(wrapper->currentSize) + "-" + to_string(wrapper->testPolygonID) + "/" + wrapper->decompSVGString;
else
fileString = testPolygonNames[wrapper->testPolygonID] + "/" + wrapper->decompSVGString;
//returns true if not inDrawMode. Otherwise draws polygon and returns result
return !wrapper->inDrawMode || IOHandling::DrawDecomposition(vis->thePolygon, weakVisRoot, fileString);
}
bool angularSplit(Face_handle& toSplit, int raysStart, bool preferIncident) {
//choose reflex vertices in random order
vector<int> indices(reflexHandles.size());
iota(begin(indices), end(indices), 0);
random_shuffle(indices.begin(), indices.end());
bool incidentFound = false;
for (auto it = indices.begin(); it != indices.end() - 1 && !incidentFound; it++) {
if (vis->seesWitness(toSplit, reflexHandles[*it])) {
auto eit = toSplit->outer_ccb();
do {
if (eit->source()->data().id == reflexHandles[*it]->data().id) {
//we are the indicent vertex!
iter_swap(it, indices.end() - 1);
incidentFound = true;
}
} while (++eit != toSplit->outer_ccb() && !incidentFound);
}
}
if(incidentFound && !preferIncident && indices.size() > 1)
indices.pop_back();
int maximumGranularity = maxGranularity;
int numberOfRays = raysStart;
while (numberOfRays <= maximumGranularity) {
bool seenByAReflex = false;
for (auto it = indices.begin(); it != indices.end(); it++)
{
if (vis->seesWitness(toSplit, reflexHandles[*it])) {
seenByAReflex = true;
//using the current granularity, try to find a reflex vertex that has at least two intersections!
Segment_2 firstIntersection;
int firstIntersectionID = 0;
//First shoot up
bool foundIntersection = properIntersectFace(toSplit, getRay(numberOfRays, 0, reflexHandles[*it]->point()), firstIntersection);
int low = 0;
int high = numberOfRays - 1;
int mid;
//binary search for intersection
while (!foundIntersection && low <= high) {
mid = (low + high) / 2;
Ray_2 midRay = getRay(numberOfRays, mid, reflexHandles[*it]->point());
foundIntersection = properIntersectFace(toSplit, midRay, firstIntersection);
if (foundIntersection) {
firstIntersectionID = mid;
break; //done
}
//Check if we are right or left
auto eit = toSplit->outer_ccb();
CGAL::Orientation orCheck;
do {
orCheck = midRay.supporting_line().oriented_side(eit->source()->point());
eit++;
} while (orCheck == CGAL::COLLINEAR); //if we are collinear check another point :(
//Are we left of the line?
if (orCheck == CGAL::LEFT_TURN)
high = mid - 1;
else
low = mid + 1;
}
if (foundIntersection) {
vector<Segment_2> intersections;
vector<int> intersectionRayIDs;
//look left of firstIntersectionID
int rayID = (firstIntersectionID + (numberOfRays - 1)) % numberOfRays; //decrement one "on the clock"
Segment_2 nextIntersection;
Ray_2 nextRay = getRay(numberOfRays, rayID, reflexHandles[*it]->point());
bool weIntersect = properIntersectFace(toSplit, nextRay, nextIntersection);
while (weIntersect){
intersections.push_back(nextIntersection);
intersectionRayIDs.push_back(rayID);
rayID = (rayID + (numberOfRays - 1)) % numberOfRays; //decrement one "on the clock"
nextRay = getRay(numberOfRays, rayID, reflexHandles[*it]->point());
weIntersect = properIntersectFace(toSplit, nextRay, nextIntersection);
}
reverse(intersections.begin(), intersections.end()); //reverse the ones we found so far, they are in the wrong order
reverse(intersectionRayIDs.begin(), intersectionRayIDs.end());
intersections.push_back(firstIntersection); //add the first one
intersectionRayIDs.push_back(firstIntersectionID);
//look right of firstIntersectionID
rayID = (firstIntersectionID + 1) % numberOfRays; //increment one "on the clock"
nextRay = getRay(numberOfRays, rayID, reflexHandles[*it]->point());
weIntersect = properIntersectFace(toSplit, nextRay, nextIntersection);
while (weIntersect) {
intersectionRayIDs.push_back(rayID);
intersections.push_back(nextIntersection);
rayID = (rayID + 1) % numberOfRays;
nextRay = getRay(numberOfRays, rayID, reflexHandles[*it]->point());
weIntersect = properIntersectFace(toSplit, nextRay, nextIntersection);
}
if (intersections.size() > 1) {
int middle = intersections.size() / 2; //integer division rounds down
Segment_2 middleSegment;
bool foundIt = true;
//If we are odd we take the middle one (most central)
//If we are even, we shoot the middle ray in the next level of granularity, so we double number of rays
if (intersections.size() % 2 > 0)
middleSegment = intersections[middle];
else
foundIt = properIntersectFace(toSplit, getRay(numberOfRays * 2, intersectionRayIDs[middle] * 2 - 1, reflexHandles[*it]->point()), middleSegment);
if (numberOfRays > wrapper->currentGranularity)
wrapper->currentGranularity = numberOfRays;
wrapper->angularSplits++;
vector<Vertex_handle> sources = {};
vector<Vertex_handle> targets = {};
for (auto &intersection : intersections) {
sources.push_back(splitFaceEdge(vis->thePolygon, intersection.source(), toSplit));
targets.push_back(splitFaceEdge(vis->thePolygon, intersection.target(), toSplit));
}
for (size_t i = 0; i < sources.size(); i++) {
vis->thePolygon.insert_at_vertices(intersections[i], sources[i], targets[i]);
}
return true;
}
}
}
}
if (!seenByAReflex)
cout << "Why????whywhyhw";
numberOfRays = numberOfRays * 2;
}
return false;
}
void squareSplit(Face_handle& toSplit) {
Arrangement_2 onlyFace;
vector<Point_2> facePts;
//Take necessary info
auto eit = toSplit->outer_ccb();
do {
facePts.push_back(eit->source()->point());
CGAL::insert(onlyFace, eit->curve());
} while (++eit != toSplit->outer_ccb());
Arrangement_2 rotatedFace = rotateArrangement(onlyFace);
//Find middle of face and insert as vertex
auto bbox = CGAL::bounding_box(facePts.begin(), facePts.end());
//otherwise we use center of bounding box
Point_2 middle = Point_2(bbox.xmin() + (bbox.xmax() - bbox.xmin())/2, bbox.ymin() + (bbox.ymax() - bbox.ymin())/2);
Vertex_handle midvertex = splitFaceEdge(vis->thePolygon, middle, toSplit);
vector<Point_2> newPoints;
vector<Point_2> horPoints = shootRayUpDown(rotatedFace, rotatePointRight(middle));
//Rotate them back
for (auto horPoint : horPoints)
newPoints.push_back(rotatePointLeft(horPoint));
vector<Point_2> verPoints = shootRayUpDown(onlyFace, middle);
newPoints.insert(newPoints.end(), verPoints.begin(), verPoints.end());
vector<Vertex_handle> newVertices;
for (auto& pit : newPoints) {
if (middle == pit)
continue;
else
newVertices.push_back(splitFaceEdge(vis->thePolygon, pit, toSplit));
}
for (auto& vit : newVertices)
vis->thePolygon.insert_at_vertices(Segment_2(middle, vit->point()), midvertex, vit);
wrapper->squareSplits++;
}
bool extensionSplit(Face_handle& toSplit) {
//we will choose randomly!
vector<int> indices(reflexHandles.size());
iota(begin(indices), end(indices), 0);
random_shuffle(indices.begin(), indices.end());
for (auto it = indices.begin(); it != indices.end(); it++)
{
if (vis->seesWitness(toSplit, reflexHandles[*it])) {
//try to split using both reflex extensions if necessary
Segment_2 intersections;
//Because of the OR we only check the second one if we actually need to!
if (properIntersectFace(toSplit, Ray_2(reflexNeighbours[*it].first->point(), reflexHandles[*it]->point()), intersections))
{
//we have found some intersections we can use
vis->thePolygon.insert_at_vertices(
intersections,
splitFaceEdge(vis->thePolygon, intersections.source(), toSplit),
splitFaceEdge(vis->thePolygon, intersections.target(), toSplit)
);
wrapper->extensionSplits++;
return true;
}
else if (properIntersectFace(toSplit, Ray_2(reflexNeighbours[*it].second->point(), reflexHandles[*it]->point()), intersections)) {
vis->thePolygon.insert_at_vertices(
intersections,
splitFaceEdge(vis->thePolygon, intersections.source(), toSplit),
splitFaceEdge(vis->thePolygon, intersections.target(), toSplit)
);
wrapper->extensionSplits++;
return true;
}
}
}
return false;
}
bool chordSplit(Face_handle& toSplit) {
//choose chords in random order
vector<int> indices(chords.size());
iota(begin(indices), end(indices), 0);
random_shuffle(indices.begin(), indices.end());
for (auto it = indices.begin(); it != indices.end(); it++)
{
if (vis->seesWitness(toSplit, chords[*it].first) && vis->seesWitness(toSplit, chords[*it].second)) {
//try to split using chord
Segment_2 intersections;
if (properIntersectFace(toSplit, Ray_2(chords[*it].first->point(), chords[*it].second->point()), intersections))
{
//we have found some intersections we can use
vis->thePolygon.insert_at_vertices(
intersections,
splitFaceEdge(vis->thePolygon, intersections.source(), toSplit),
splitFaceEdge(vis->thePolygon, intersections.target(), toSplit)
);
wrapper->chordSplits++;
return true;
}
}
}
return false;
}
bool vislineSplit(Face_handle& toSplit, bool isGuard) {
vector<Vertex_handle> candidates;
//identify split options
if (isGuard) {
for (auto& sv : toSplit->data().seenVertices) {
if (!vis->seesWitness(vis->allVertices[sv.first], toSplit))
{
bool onlyUs = true;
//we see him but he does not see us (good news)
//are we the only one that sees him?
for (auto& vs : IP.vertexSolution)
{
if (vis->seesWitness(vs, vis->allVertices[sv.first]))
{
onlyUs = false;
break;
}
}
if (onlyUs) {
for (auto& fs : IP.faceSolution)
{
if (fs->data().id != toSplit->data().id && vis->seesWitness(fs, vis->allVertices[sv.first]))
{
onlyUs = false;
break;
}
}
}
if (onlyUs) //okay we satisfy all conditions
candidates.push_back(vis->allVertices[sv.first]);
}
}
}
else{
//we want vertex guards that we can see (only those are interesting)
for (auto& vs : IP.vertexSolution) {
if (vis->seesWitness(toSplit, vs)) {
vector<Vertex_handle> seenFVertices = {};
auto eit = toSplit->outer_ccb();
do {
if (vis->seesWitness(vs, eit->source()))
seenFVertices.push_back(eit->source());
} while (++eit != toSplit->outer_ccb());
if (seenFVertices.size() > 2 || (seenFVertices.size() == 2 && !Line_2(vs->point(), seenFVertices[0]->point()).has_on(seenFVertices[1]->point())))
candidates.push_back(vs);
}
}
}
if (candidates.size() > 0) {
//lets go
//int rI = rand() % candidates.size();
random_shuffle(candidates.begin(), candidates.end());
vector<pair<Vertex_handle, Vertex_handle>> newVertices;
for (auto &candidate : candidates) {
for (auto pedge = vis->pointvisPolygons[candidate->data().id].edges_begin(); pedge != vis->pointvisPolygons[candidate->data().id].edges_end(); pedge++)
{
Segment_2 inter;
if(properIntersectFace(toSplit, *pedge, inter))
newVertices.push_back(make_pair(splitFaceEdge(vis->thePolygon, inter.source(), toSplit), splitFaceEdge(vis->thePolygon, inter.target(), toSplit)));
}
if (!newVertices.empty())
break;
}
if (newVertices.empty())
return false;
for (auto& newV : newVertices)
vis->thePolygon.insert_at_vertices(Segment_2(newV.first->point(), newV.second->point()), newV.first, newV.second);
wrapper->vislineSplits++;
return true;
}
return false;
}
bool iterations() {
auto timeBegin = IOHandling::get_cpu_time();
auto timePrev = timeBegin;
wrapper->intermediateSteps = 0;
do {
//split faces if any
for (auto fit = IP.bothFaces.begin(); fit != IP.bothFaces.end(); ++fit)
{
FaceGuard papa = (*fit)->data();
bool isGuard = find(IP.unseenFaces.begin(), IP.unseenFaces.end(), *fit) == IP.unseenFaces.end();
if ((*fit)->data().constraintAdded)
IP.model.remove(IP.faceConstraints[papa.id]);
//force it not to see anything
IloExpr expr(IP.env);
expr += IP.faceguardVar[papa.id] + IP.facewitnessVar[papa.id];
IloConstraint c(expr == 0);
IP.model.add(c);
int reflexCount = 0;
//Check some things for split types...
auto eit = (*fit)->outer_ccb();
do {
if (eit->source()->data().isReflex)
reflexCount++;
} while (++eit != (*fit)->outer_ccb());
if (reflexCount > 1 || wrapper->doingP5) //P5 = only squaresplitz
{
//Do square split
squareSplit(*fit);
}
else {
int dice = rand() % 10 + 1;
bool splitDone = false;
if (dice <= 2) {
//20% chance of extension split
splitDone = extensionSplit(*fit);
}
else if (dice <= 4) {
//10% chance of chord split
splitDone = chordSplit(*fit);
}
else if (dice <= 6) {
//50% of visline split
splitDone = vislineSplit(*fit, isGuard);
}
if (!splitDone) { //otherwise do angular split!
int raysStart = 16;
splitDone = angularSplit(*fit, raysStart, false);
//splitDone = true;
//squareSplit(*fit);
//try chord and extension first before increasing gran gran
if (!splitDone)
splitDone = extensionSplit(*fit);
if (!splitDone)
splitDone = chordSplit(*fit);
while (!splitDone) {
//here we either mark as unsplittable and use bigIP to continue
raysStart = maxGranularity;
//or change maxGran here
maxGranularity = maxGranularity * 16;
splitDone = angularSplit(*fit, raysStart, false);
}
}
}
//(*fit) is now a new face
(*fit)->set_data(FaceGuard());
//now we are done splitting...
for (auto nvit = vis->thePolygon.vertices_begin(); nvit != vis->thePolygon.vertices_end(); nvit++)
if (!nvit->data().created)
vis->prepareGuard(nvit, papa);
for (auto nvit = vis->thePolygon.vertices_begin(); nvit != vis->thePolygon.vertices_end(); nvit++) {
if (!nvit->data().created) {
nvit->data().created = true;
vis->updateVisibilities(nvit);
}
}
//handle all new faces and vertices
for (auto nfit = vis->thePolygon.faces_begin(); nfit != vis->thePolygon.faces_end(); nfit++)
if (!nfit->data().created && nfit->has_outer_ccb())
vis->prepareGuard(nfit, papa);
int nfaces = 0;
for (auto nfit = vis->thePolygon.faces_begin(); nfit != vis->thePolygon.faces_end(); nfit++) {
if (!nfit->data().created && nfit->has_outer_ccb()) {
nfaces++;
nfit->data().created = true;
vis->updateVisibilities(nfit);
}
}
}
//Critical loop!
bool allAreSeen = true;
bool preferGuards = (wrapper->intermediateSteps % 2) == 0;
do {
//Find next solution
IP.findSolution(vis->thePolygon, preferGuards, wrapper->doingP5);
if (wrapper->criticalThreshold < 100)
allAreSeen = vis->verifySolution();
} while (!allAreSeen);
string fileString;
string fileStringCrit;
string fileStringFace;
if (wrapper->inDrawMode) {
if (wrapper->inTestMode) {
fileString = to_string(wrapper->currentSize) + "-" + to_string(wrapper->testPolygonID) + "/" + wrapper->intermediateSVGString + to_string(wrapper->intermediateSteps);
fileStringCrit = to_string(wrapper->currentSize) + "-" + to_string(wrapper->testPolygonID) + "/" + wrapper->criticalSVGString + to_string(wrapper->intermediateSteps);
fileStringFace = to_string(wrapper->currentSize) + "-" + to_string(wrapper->testPolygonID) + "/face_visibility - " + to_string(wrapper->intermediateSteps) + "-";
}
else {
fileString = testPolygonNames[wrapper->testPolygonID] + "/" + wrapper->intermediateSVGString + to_string(wrapper->intermediateSteps);
fileStringCrit = testPolygonNames[wrapper->testPolygonID] + "/" + wrapper->criticalSVGString + to_string(wrapper->intermediateSteps);
fileStringFace = testPolygonNames[wrapper->testPolygonID] + "/face_visibility - " + to_string(wrapper->intermediateSteps) + "-";
}
//Draw necessary things
IOHandling::DrawCritical(vis->thePolygon, fileStringCrit);
IOHandling::DrawArtGallery(vis->thePolygon, fileString, IP);
}
auto timeEnd = IOHandling::get_cpu_time();
chrono::duration<double> time_span2 = chrono::duration_cast<chrono::duration<double>>(timeEnd - timeBegin);
//Are we P5 (irrational polygon)
if (wrapper->doingP5) {
//track cumalative time
chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(timeEnd - timePrev);
wrapper->p5Times.push_back(time_span.count());
timePrev = timeEnd;
//track Hausdorff.
vector<Point_2> currentSolution;
for (auto& vertex : IP.vertexSolution)
currentSolution.push_back(vertex->point());
for (auto& face : IP.faceSolution)
{
auto eit = face->outer_ccb();
do {
currentSolution.push_back(eit->source()->point());
} while (++eit != face->outer_ccb());
}
//calculate Hausdorff and save...
wrapper->hausdorffDistances.push_back(Hausdorff(p5Solution, currentSolution));
if (time_span2.count() >= wrapper->maxP5Time)
break; //stop iterating!
}
else
if (time_span2.count() >= 500)
break;
//print summary
if (wrapper->inDrawMode) {
cout << "----------- ITERATION " << wrapper->intermediateSteps << "\n";
/*cout << "WeakVisLookups so far: " << vis->weakvisLookups << "\n";
cout << "\n";*/
int j = 0;
for (auto fit = IP.faceSolution.begin(); fit != IP.faceSolution.end(); fit++) {
/* for (int i = 0; i < vis->weakVisibility.vis_polygons.size(); i++)
IOHandling::DrawWeakVis(weakVisibility, "100-25/faceguardvis-" + to_string(wrapper->intermediateSteps) + "-" + to_string(i),
faceToPolygon(f), Arrangement_2(), i);*/
//draw the weakvispolygon
/*IOHandling::DrawWeakVis(
vis->weakVisibility, fileStringFace + to_string(j),
faceToPolygon(*fit), vis->facevisPolygons[(*fit)->data().id].container());*/
j++;
}
}
//else
//cout << " " << wrapper->intermediateSteps << " ";
//cout << "Number of vertices: " << vis->thePolygon.number_of_vertices() << " ";
wrapper->intermediateSteps++;
} while (wrapper->intermediateSteps < wrapper->maxIterations && IP.bothFaces.size() > 0);
auto timeEnd = IOHandling::get_cpu_time();
chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(timeEnd - timeBegin);
wrapper->processingTime += time_span.count();
//General information
wrapper->solutionSize = IP.vertexSolution.size();
wrapper->facesAtEnd = vis->thePolygon.number_of_faces() - 1; //no unbounded face
wrapper->verticesAtEnd = vis->thePolygon.number_of_vertices();
//Count critical witnesses
for (auto vit = vis->thePolygon.vertices_begin(); vit != vis->thePolygon.vertices_end(); vit++)
if (vit->data().isCritical)
wrapper->criticalVerticesAtEnd++;
for (auto fit = vis->thePolygon.faces_begin(); fit != vis->thePolygon.faces_end(); fit++)
if (fit->data().isCritical)
wrapper->criticalFacesAtEnd++;
//Decomp information
wrapper->decompositionSize = weakVisRoot->subTreeSize() + 1; //this function recursively calculates subtreesize.
wrapper->maxDecompVertices = weakVisRoot->maxVertices();
wrapper->maxDecompReflexVertices = weakVisRoot->maxReflexVertices();
//Visibility computations
wrapper->constantLookups = vis->constantLookups;
wrapper->faceVisibilitiesComputed = vis->faceVisibilitiesComputed;
wrapper->pointVisibilitiesComputed = vis->pointVisibilitiesComputed;
wrapper->weakvisLookups = vis->weakvisLookups;
cout << "Clearing ILO memory\n";
IP.pointConstraints.end();
IP.faceConstraints.end();
IP.pointExpr.end();
IP.faceExpr.end();
IP.faceguardVar.end();
IP.pointguardVar.end();
IP.facewitnessVar.end();
IP.model.end();
IP.env.end();
vis->polygonBoundary.clear();
vis->thePolygon.clear();
return true;
}
};
ArtGallery::ArtGallery(int tId, int maxIterations, int criticalThreshold, bool useWeakVis, bool inTestMode, bool inDrawMode, int currentSize) {
srand((unsigned int)time(0));
this->inTestMode = inTestMode;
this->currentSize = currentSize;
this->maxIterations = maxIterations;
this->criticalThreshold = criticalThreshold;
this->useWeakVis = useWeakVis;
this->testPolygonID = tId;
this->inDrawMode = inDrawMode;
this->implementation = AGPTR(new ArtGalleryImpl(this));
//this->implementation = ArtGalleryImpl(this);
}
bool ArtGallery::initialize() {
return implementation->initialize();
}
bool ArtGallery::preProcess() {
return implementation->preProcess();
}
bool ArtGallery::iterations() {
if (testPolygonID == 3 && currentSize == 1000 && !inDrawMode)
return true;
if (testPolygonID == 7 && currentSize == 1000 && !inDrawMode)
return true;
if (testPolygonID == 15 && currentSize == 1000 && !inDrawMode)
return true;
if (testPolygonID == 17 && currentSize == 1000 && !inDrawMode)
return true;
if (testPolygonID == 25 && currentSize == 1000 && !inDrawMode)
return true;
if (testPolygonID == 25 && currentSize == 100 && !inDrawMode)
return true;
if (testPolygonID == 18 && currentSize == 500)
return true;
implementation->iterations();
return true;
}
ArtGallery::~ArtGallery() {
//this->implementation->~ArtGalleryImpl();
}