/* ---- This file is part of SECONDO. Copyright (C) 2009, University in Hagen, Faculty of Mathematics and Computer Science, Database Systems for New Applications. SECONDO 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 2 of the License, or (at your option) any later version. SECONDO 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 SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}] //paragraph [10] Footnote: [{\footnote{] [}}] //[TOC] [\tableofcontents] [TOC] 0 Overview 1 Includes and defines */ #ifndef _COARSENING_CPP #define _COARSENING_CPP #include "Coarsening.h" using namespace std; namespace p2d { /* 1 Class CoarseningGraph */ /* 1.1 Constructor and destructor */ CoarseningGraph::CoarseningGraph() { } CoarseningGraph::~CoarseningGraph() { } /* 1.1 ~computeGraph~ */ void CoarseningGraph::computeGraph(/*const*/Region2& r) { Reg2GridHalfSegment gs; for (int i = 0; i < r.Size(); i++) { r.getgridCoordinates()->Get(i, gs); if (gs.IsLeftDomPoint() && ((gs.GetLeftPointX() != gs.GetRightPointX()) || (gs.GetLeftPointY() != gs.GetRightPointY()))) { int absX = abs(gs.GetLeftPointX() - gs.GetRightPointX()); int absY = abs(gs.GetLeftPointY() - gs.GetRightPointY()); if ((absX + absY) == 1) { //the segment starts and ends in adjacent grid points. Vertex* v1 = insert(gs.GetLeftPointX(), gs.GetLeftPointY()); Vertex* v2 = insert(gs.GetRightPointX(), gs.GetRightPointY()); if (v1->addEdge(v2)){ v2->addEdge(v1); } } else { //the start- and end-point of the segment are not adjacent, the segment //runs through a number of grid-points. For each interesting points //a vertex has to be created. computeGraphBetween(gs.GetLeftPointX(), gs.GetLeftPointY(), gs.GetRightPointX(), gs.GetRightPointY()); } } } } /* 1.1 ~computeGraphBetween~ */ void CoarseningGraph::computeGraphBetween(int lx, int ly, int rx, int ry) { Vertex left(lx, ly); Vertex right(rx, ry); if (left != right) { if (left < right) { //nothing to do } else { Vertex temp(left); left = right; right = temp; } } else { //start- and end-points are equal, there is no need for a nother vertex. return; } int x = left.getX(); int y = left.getY(); if ((x!=right.getX()) && ((y != right.getY()))){ Vertex* v1 = insert(left.getX(), left.getY()); mpq_class num = left.getY() - right.getY(); mpq_class den = left.getX() - right.getX(); mpq_class slope = num / den; while ((x != right.getX()) && (y != right.getY())) { //the segment runs through some grids in both directions // the segment intersects the vertical line in (x+1) in ~yValue~. mpq_class yValue = ((slope * (x + 1)) + right.getY() - (slope * right.getX())); int newY; // gets the y-value of the next vertex if (cmp(y, yValue)<0){ if (cmp(slope, 0)>0){ //ascending segment //yValue is above y and the right point has not been reached. For the next //vertex, yValue is rounded up to the next integer. newY = (int) ((ceil_mpq(yValue)).get_d()); } else { //horizontal or descending segment newY = y; } while (y < newY) { //(newY-y) new vertices above y and the corresponding edges //have to be created. Vertex*v2 = insert(x, y + 1); if (v1->addEdge(v2)){ v2->addEdge(v1); } v1 = v2; y++; } //create a new Vertex right of the vertex (x, newY) incl. the corresponding //edges Vertex* v2 = insert(x + 1, y); if (v1->addEdge(v2)){ v2->addEdge(v1); } v1 = v2; } else { //for more info see if-branch if (cmp (slope, 0)<=0) { newY = (int)((floor_mpq(yValue)).get_d()); } else { newY = y; } while (y > newY) { Vertex* v2 = insert(x, y - 1); if(v1->addEdge(v2)){ v2->addEdge(v1); } v1 = v2; y--; } Vertex* v2 = insert(x + 1, y); if (v1->addEdge(v2)){ v2->addEdge(v1); } v1 = v2; } x++; } } if (x != right.getX()) { //the segment runs through some grid which have all the same y-value, //the coarse segment will be horizontal line Vertex* first = insert(x, y); x++; while (x <= right.getX()) { Vertex* second = insert(x, y); if(first->addEdge(second)){ second->addEdge(first); } first = second; x++; } } if (y != right.getY()) { //the segment runs through some grid which have all the same x-value, //the coarse segment will be vertical line Vertex* first = insert(x, y); y++; while (y <= right.getY()) { Vertex* second = insert(x, y); if (first->addEdge(second)){ second->addEdge(first); } first = second; y++; } } } /* 1.1 ~calculateBoundary~ */ void CoarseningGraph::calculateBoundary(Region& result) { result.Clear(); if (vertices.size() < 4) { //a region needs at least 4 nodes a coarse region has only 90 degree angles result.SetDefined(true); return; } //removes nodes without an edge removeIsleNodes(); //compute boundary result.SetDefined(true); Region tmpRegion(0); while (vertices.size() >= 4) { //there are enough vertices to create another cycle try { tmpRegion.Clear(); tmpRegion.StartBulkLoad(); //create next cycle, which becomes an outercycle or a hole bool lastInsideAbove = false; bool insideAbove = false; Vertex* firstVertex = *(vertices.begin()); while (firstVertex->getNoOfEdges()==0){ removeIsleNode(firstVertex); firstVertex = *(vertices.begin()); } if (vertices.size()>=4){ Vertex* last = firstVertex; Direction lastDirection = noDirection; Direction dir = noDirection; Vertex* next; int firstX = last->getX(); //the x-value of the first vertex int firstY = last->getY(); //the y-value of the first vertex HalfSegment* hs; int edgeNo = 0; Point* lp = new Point(true, last->getX(), last->getY()); Point* rp = NULL; do { last->getNextVertex(&next, dir, insideAbove); if (lastDirection == noDirection) { //last contains the first vertex of the cycle lastDirection = dir; } if (lastDirection != dir) { //~next~ goes in another direction than ~lastDirection~ //a new endpoint ~rp~ for the next halfsegment has to be created and the //next segment extends in the direction ~dir~ rp = new Point(true, last->getX(), last->getY()); lastDirection = dir; } if (rp != NULL) { // a new halfsegment has to be created. if (*lp < *rp) { hs = new HalfSegment(true, *lp, *rp); hs->attr.edgeno = edgeNo; hs->attr.insideAbove = lastInsideAbove; tmpRegion += *hs; hs->SetLeftDomPoint(false); tmpRegion += *hs; edgeNo++; } else { hs = new HalfSegment(true, *rp, *lp); hs->attr.edgeno = edgeNo; hs->attr.insideAbove = lastInsideAbove; tmpRegion += *hs; hs->SetLeftDomPoint(false); tmpRegion += *hs; edgeNo++; } lastInsideAbove = insideAbove; lp = rp; rp = NULL; } next->removeEdge(last); last->removeEdge(next); if ((*last != *firstVertex) && (last->getNoOfEdges() ==0)){ removeIsleNode(last); } last = next; } while (*last != *firstVertex); rp = new Point(true, firstX, firstY); hs = new HalfSegment(true, *rp, *lp); hs->attr.edgeno = edgeNo; hs->attr.insideAbove = true; tmpRegion += *hs; hs->SetLeftDomPoint(false); tmpRegion += *hs; edgeNo++; if (last->getNoOfEdges() ==0){ removeIsleNode(last); } //build region tmpRegion.EndBulkLoad(); if (tmpRegion.IsDefined()) { if (result.Size() == 0) { //~tmpRegion~ was the first cycle result = tmpRegion; } else { //there are already some cycles in ~result~ if (tmpRegion.Inside(result)) { //~tmpRegion~ is within ~result~ and becomes a hole in ~result~ Region res(0); result.Minus(tmpRegion, res); result = res; } else { //~tmpRegion~ and ~result~ are merged Region res(0); result.Union(tmpRegion, res); result = res; } } } } } catch (exception& e) { removeIsleNodes(); } } //remove the remaining vertices and edges clear(); } /* 1.1 ~calculateBoundary2~ */ void CoarseningGraph::calculateBoundary2(Region2& result, int scalefactor) { result.Clear(); if (vertices.size() < 4) { //a region needs at least 4 nodes a coarse region has only 90 degree angles result.SetDefined(true); return; } //removes nodes without an edge removeIsleNodes(); //compute boundary result.SetDefined(true); Line2 tmpLine(0); tmpLine.Clear(); tmpLine.StartBulkLoad(); while (vertices.size() >= 4) { //there are enough vertices to create another cycle try { //create next cycle, which becomes an outercycle or a hole //bool lastInsideAbove = false; bool insideAbove = false; Vertex* firstVertex = *(vertices.begin()); while (firstVertex->getNoOfEdges()==0){ removeIsleNode(firstVertex); firstVertex = *(vertices.begin()); } if (vertices.size()>=4){ Vertex* last = firstVertex; Direction lastDirection = noDirection; Direction dir = noDirection; Vertex* next; int firstX = last->getX(); //the x-value of the first vertex int firstY = last->getY(); //the y-value of the first vertex int edgeNo = 0; mpq_class zero(0); Point2* lp = new Point2(true, last->getX(), last->getY(), zero, zero); Point2* rp = NULL; do { last->getNextVertex(&next, dir, insideAbove); if (next == NULL) { //throw exception(); } if (lastDirection == noDirection) { //last contains the first vertex of the cycle lastDirection = dir; } if (lastDirection != dir) { //~next~ goes in another direction than ~lastDirection~ //a new endpoint ~rp~ for the next halfsegment has to be created and the //next segment extends in the direction ~dir~ rp = new Point2(true, last->getX(), last->getY(), zero, zero); lastDirection = dir; } if (rp != NULL) { // a new halfsegment has to be created. if (*lp < *rp) { tmpLine.addSegment(true, lp, rp, edgeNo); tmpLine.addSegment(false, lp, rp, edgeNo); edgeNo++; } else { tmpLine.addSegment(true, rp, lp, edgeNo); tmpLine.addSegment(false, rp, lp, edgeNo); edgeNo++; } lp = rp; rp = NULL; } next->removeEdge(last); last->removeEdge(next); if ((*last != *firstVertex) && (last->getNoOfEdges() ==0)){ removeIsleNode(last); } last = next; } while (*last != *firstVertex); rp = new Point2(true, firstX, firstY, zero, zero); tmpLine.addSegment(true, rp, lp, edgeNo); tmpLine.addSegment(false, rp, lp, edgeNo); edgeNo++; if (last->getNoOfEdges() ==0){ removeIsleNode(last); } } } catch (exception& e) { removeIsleNodes(); } } tmpLine.EndBulkLoad(); p2d::BuildRegion(tmpLine, result, scalefactor); //remove the remaining vertices and edges clear(); } /* 1.1 ~insert~ */ Vertex* CoarseningGraph::insert(int x, int y) { Vertex* v = new Vertex(x, y); pair::iterator, bool> pair1 = vertices.insert(v); return *(pair1.first); } /* 1.1 ~Print~ */ void CoarseningGraph::Print() const { for (set::iterator i = vertices.begin(); i != vertices.end(); i++) { (*i)->Print(); } } /* 1.1 ~clear~ */ void CoarseningGraph::clear() { set::iterator it = vertices.begin(); while (it != vertices.end()) { Vertex* v = *it; v->removeEdges(); vertices.erase(it); delete v; it++; } } /* 1.1 ~removeIsleNodes~ */ void CoarseningGraph::removeIsleNodes() { set::iterator current = vertices.begin(); while (current != vertices.end()) { Vertex* curVertex = *current; if (curVertex->getNoOfEdges()==0){ vertices.erase(vertices.find(curVertex)); } current++; } } /* 1.1 ~removeIsleNode~ */ void CoarseningGraph::removeIsleNode(Vertex* v) { if (v->getNoOfEdges() == 0) { vertices.erase(vertices.find(v)); delete v; } } /* 1 Class Vertex */ /* 1.1 Constructor and destructor */ Vertex::Vertex(int a, int b) : x(a), y(b){ } Vertex::Vertex(const Vertex& v) : x(v.x), y(v.y), edgeSet(v.edgeSet) { } Vertex::~Vertex() {}; /* 1.1 ~=~ */ Vertex& Vertex::operator=(const Vertex& v) { x = v.getX(); y = v.getY(); edgeSet = v.getEdges(); return *this; } /* 1.1 ~!=~ */ bool Vertex::operator!=(const Vertex& v) const { if (x != v.getX()) { return true; } if (y != v.getY()) { return true; } return false; } /* 1.1 ~$<$~ */ bool Vertex::operator<(const Vertex& v) const { if (x < v.getX()) { return true; } if (x == v.getX() && y < v.getY()) { return true; } return false; } /* 1.1 ~addEdge~ */ bool Vertex::addEdge(Vertex* v) { set::iterator it = (edgeSet.find(v)); if (it == edgeSet.end()){ // edgeSet.insert(v); return true; } else { edgeSet.erase(it); v->removeEdge(this); return false; } } /* 1.1 ~getEdges~ */ set Vertex::getEdges() const { set edges; for (set::iterator i = edgeSet.begin(); i != edgeSet.end(); i++) { edges.insert(*i); } return edges; } /* 1.1 ~removeEdge~ */ void Vertex::removeEdge(Vertex* v) { set::iterator it1 = edgeSet.begin(); while ((it1 != edgeSet.end()) && (*v != *(*(it1)))) { it1++; } if (it1 == edgeSet.end()) { cerr << "error: vertex"; Print(); cerr << endl << " has no edge to "; v->print(); assert(false); } else { edgeSet.erase(it1); } } /* 1.1 ~removeEdges~ */ void Vertex::removeEdges() { for (set::iterator it = edgeSet.begin(); it != edgeSet.end(); it++) { Vertex* v = *it; v->removeEdge(this); edgeSet.erase(it); } } /* 1.1 ~getNextVertex~ */ void Vertex::getNextVertex(Vertex** next, Direction& d, bool& insideAbove) { switch (d) { case noDirection: { if (hasEdgePointingToTheLeft(next)) { d = left; insideAbove = !insideAbove; } else { if (hasEdgePointingUpwards(next)) { d = up; } else { if (hasEdgePointingToTheRight(next)) { d = right; insideAbove = !insideAbove; } } } break; } case up: { if (hasEdgePointingToTheLeft(next)) { d = left; insideAbove = !insideAbove; return; } if (hasEdgePointingUpwards(next)) { return; } if (hasEdgePointingToTheRight(next)) { d = right; } break; } case down: { if (hasEdgePointingToTheRight(next)) { d = right; insideAbove = !insideAbove; return; } if (hasEdgePointingDownwards(next)) { return; } if (hasEdgePointingToTheLeft(next)) { d = left; } break; } case left: { if (hasEdgePointingDownwards(next)) { d = down; return; } if (hasEdgePointingToTheLeft(next)) { return; } if (hasEdgePointingUpwards(next)) { d = up; insideAbove = !insideAbove; } break; } case right: { if (hasEdgePointingUpwards(next)) { d = up; return; } if (hasEdgePointingToTheRight(next)) { return; } if (hasEdgePointingDownwards(next)) { d = down; insideAbove = !insideAbove; } break; } default: { assert(false); } } } /* 1.1 ~hasEdgePointingUpwards~ */ bool Vertex::hasEdgePointingUpwards(Vertex** next) { bool found = false; *next = NULL; set::iterator it1 = edgeSet.begin(); while ((it1 != edgeSet.end()) && !found) { if (isBelow(*(*it1))) { *next = *it1; found = true; } else { it1++; } } return found; } /* 1.1 ~hasEdgePointingDownwards~ */ bool Vertex::hasEdgePointingDownwards(Vertex** next) { bool found = false; *next = NULL; set::iterator it1 = edgeSet.begin(); while ((it1 != edgeSet.end()) && !found) { if (isAbove(*(*it1))) { *next = *it1; found = true; } else { it1++; } } return found; } /* 1.1 ~hasEdgePointingToTheLeft~ */ bool Vertex::hasEdgePointingToTheLeft(Vertex** next) { bool found = false; *next = NULL; set::iterator it1 = edgeSet.begin(); while ((it1 != edgeSet.end()) && !found) { if (isRightOf(*(*it1))) { *next = *it1; found = true; } else { it1++; } } return found; } /* 1.1 ~hasEdgePointingToTheRight~ */ bool Vertex::hasEdgePointingToTheRight(Vertex** next) { bool found = false; *next = NULL; set::iterator it1 = edgeSet.begin(); while ((it1 != edgeSet.end()) && !found) { if (isLeftOf(*(*it1))) { *next = *it1; found = true; } else { it1++; } } return found; } /* 1.1 ~isBelow~ */ bool Vertex::isBelow(const Vertex& v) { if ((x == v.getX()) && (y < v.getY())) { return true; } return false; } /* 1.1 ~isAbove~ */ bool Vertex::isAbove(const Vertex& v) { if ((x == v.getX()) && (y > v.getY())) { return true; } return false; } /* 1.1 ~isRightOf~ */ bool Vertex::isRightOf(const Vertex& v) { if ((y == v.getY()) && (x > v.getX())) { return true; } return false; } /* 1.1 ~isLeftOf~ */ bool Vertex::isLeftOf(const Vertex& v) { if ((y == v.getY()) && (x < v.getX())) { return true; } return false; } /* 1.1 ~Print~ */ void Vertex::print() const { cout << " ( " << x << ", " << y << " ) "; } void Vertex::Print() const { cout << "( " << x << ", " << y << " ) with " << edgeSet.size() << " edges to:" << endl; for (set::iterator i = edgeSet.begin(); i != edgeSet.end(); i++) { (*i)->print(); } cout << endl << "-----------------------------" << endl; } /* 1 Struct CMPVertex */ /* 1.1 ~operator()~ */ bool CmpVertex::operator()(Vertex* v1, Vertex* v2) const { return ((*v1) < (*v2)); } /* 1 ~coarseRegion2~ */ void coarseRegion2(/*const*/Region2& r, Region& result) { //faces CoarseningGraph g1; Region2 faces2(0); r.getFaces(faces2); g1.computeGraph(faces2); ::Region faces(0); g1.calculateBoundary(faces); //holes CoarseningGraph g2; Region2 holes2(0); r.getHoles(holes2); g2.computeGraph(holes2); ::Region holes(0); g2.calculateBoundary(holes); result.Clear(); faces.Minus(holes, result); } /* 1 ~coarseRegion2b~ */ void coarseRegion2b(/*const*/Region2& r, Region& result) { //faces CoarseningGraph g1; Region2 faces(0); r.getFaces(faces); g1.computeGraph(faces); Region2 tmpFaces(0); g1.calculateBoundary2(faces, r.GetScaleFactor()); //holes CoarseningGraph g2; Region2 holes(0); r.getHoles(holes); g2.computeGraph(holes); //Region2 tmpHoles(0); g2.calculateBoundary2(holes, r.GetScaleFactor()); Region2 tmpResult(0); SetOp(faces, holes, tmpResult, difference_op); createRegion(tmpResult, result); } /* 1 ~createRegion~ */ void createRegion(Region2& s, Region& r){ r.Clear(); if (s.IsDefined()){ r.SetDefined(true); } else { r.SetDefined(false); return; } r.StartBulkLoad(); Reg2GridHalfSegment gs; Reg2PrecHalfSegment ps; int edgeNo = 0; for (int i = 0; i< s.Size(); i++){ s.getgridCoordinates()->Get(i, gs); if (gs.IsLeftDomPoint()){ Point lp(true, gs.GetLeftPointX(), gs.GetLeftPointY()); Point rp(true, gs.GetRightPointX(), gs.GetRightPointY()); HalfSegment hs(true, lp, rp); hs.attr.edgeno = edgeNo; hs.attr.insideAbove = gs.attr.insideAbove; r += hs; hs.SetLeftDomPoint(false); r += hs; edgeNo++; } } r.EndBulkLoad(); } } //end of namespace p2d #endif/* _COARSENING_CPP*/