/* see ConvexHullTreeNode.h for documentation \tableofcontents */ #include "RegionInterpolator.h" using namespace std; namespace RegionInterpol { /* 1 Constructors and Destructor */ ConvexHullTreeNode :: ConvexHullTreeNode() { level=0;; hole=false; myParent=NULL; m_HashCode=0; setDirtyHash(); } ConvexHullTreeNode :: ConvexHullTreeNode(LineWA linelistParam[], int linelistlength, RegionTreeNode* myParent, int level=0, bool isHole=false) { ConvexHullTreeNode(); LineWA *tmplist, *childlist; vector convhull; int index1, index2, length, lastindex, noiterations; int indexll1, indexll2; this->level = level; this->hole = isHole; this->myParent = myParent; if ((level == 0 && !isHole) || (level == 1 && isHole)) { double area = Utils :: getArea(linelistParam, linelistlength); #ifdef DECHTN cout << area << endl; #endif if (area < 0) { #ifdef DECHTN cout<<"drehe"<= 0; a--) { lastindex = Utils :: indexOf(convhull, linelistParam[a]); if (lastindex != -1) break; } if (lastindex > index1) { for (int a=index1; a <= lastindex; a++) { insertLine(convhull[a]); } } else { for (unsigned int a=index1; a < convhull.size(); a++) { insertLine(convhull[a]); } for (int a = 0; a <= lastindex; a++) { insertLine(convhull[a]); } } delete[] tmplist; // Check lines in convex hull with lines in line list. Whenever two points // which are neighbours in the convex hull are not neighbours in the line // list, create a child node from the points between them. noiterations = this->getNrLines(); index1 = 0; indexll1 = 0; while ( !(linelistParam[indexll1].equals(getLine(index1))) ) { indexll1++; } for (int a = 0; a < noiterations; a++) { index2 = index1+1; indexll2 = indexll1+1; while ( !(linelistParam[indexll2 % linelistlength]. equals(getLine(index2 % noiterations))) ) { indexll2++; } if ((indexll2 != indexll1 + 1) && (((level == 0) && !isHole) || ((level == 1) && isHole) || ((indexll2 != linelistlength) && (indexll1 != linelistlength - 1))) && (indexll2 != indexll1 - 1)) { // create child node length = indexll2 - indexll1 + 1; childlist = new LineWA[length]; for (int b = 0; b < length; b++) { if ((b + indexll1) < linelistlength) { childlist[length-b-1] = linelistParam[b + indexll1]; } else { childlist[length-b-1] = linelistParam[b+indexll1-linelistlength]; } } insertChild(index1, new ConvexHullTreeNode(childlist, length, this, level + 1, hole)); } index1 = index2; indexll1 = indexll2; } this->dirtyHash=true; } ConvexHullTreeNode :: ~ConvexHullTreeNode() { myParent = NULL; } /* 1 Get functions 1.1 getLevel() */ int ConvexHullTreeNode :: getLevel() { return (level); } /* 1.1 isHole() */ bool ConvexHullTreeNode :: isHole() { return(hole); } /* 1.1 getNrLines() */ int ConvexHullTreeNode :: getNrLines() { return(linelist.size()); } /* 1.1 getCHLine() */ CHLine ConvexHullTreeNode :: getCHLine(int i) { return(linelist[i]); } /* 1.1 getCenter() */ LineWA ConvexHullTreeNode :: getCenter() { double resx = 0; double resy = 0; for(unsigned int i = 0; i < linelist.size(); i++) { resx += linelist.at(i).getX(); resy += linelist.at(i).getY(); } resx = resx / (linelist.size()); resy = resy / (linelist.size()); LineWA res(resx,resy); return res; } /* 1.1 getSteinerPoint() */ LineWA ConvexHullTreeNode :: getSteinerPoint() { double resx = 0; double resy = 0; for(unsigned int i = 0; i < linelist.size(); i++) { CHLine curr = linelist.at(i); CHLine prev = linelist.at((i - 1 + linelist.size()) % linelist.size()); CHLine next = linelist.at((i + 1) % linelist.size()); double angle = Utils :: getAngleRad(curr.getX(), curr.getY(), prev.getX(), prev.getY(), next.getX(), next.getY()); double weight = 0.5 - (angle / 2 / M_PI); resx += (int)(linelist.at(i).getX() * weight); resy += (int)(linelist.at(i).getY() * weight); } LineWA res(resx, resy); return res; } /* 1.1 getLines() */ vector ConvexHullTreeNode :: getLines() { vector listoflines, tmplist; CHLine tmpline; int nolines, nolines2; nolines = linelist.size(); for (int a = 0; a < nolines; a++) { tmpline = linelist.at(a); listoflines.insert(listoflines.begin(), 1, tmpline); if (tmpline.getChild() != NULL) { tmplist = tmpline.getChild()->getLines(); nolines2 = tmplist.size() - 1; for (int b = 1; b < nolines2; b++) { listoflines.insert(listoflines.begin(), 1, tmplist.at(b)); } } } return (listoflines); } /* 1.1 getOutLine() */ vector ConvexHullTreeNode::getOutLine() { vector result ; for(unsigned int i = 0; i < linelist.size(); i++) { result.push_back( (LineWA) linelist.at(i)); } return(result); } /* 1.1 getChildren() */ vector ConvexHullTreeNode :: getChildren() { CHLine line; vector result; for (int a = 0; a < this->getNrLines(); a++) { line = this->getCHLine(a); if (line.getChild() != NULL) { result.push_back(line.getChild()); } } return(result); } /* 1.1 getParentNode() */ RegionTreeNode *ConvexHullTreeNode :: getParentNode() { return(this->myParent); } /* 1.1 getLineForChild() */ vector ConvexHullTreeNode :: getLineForChild(ConvexHullTreeNode *child) { int length; CHLine line; vector result(2); length = linelist.size(); for (int a = 0; a < length; a++) { line = linelist[a]; if (line.getChild() != NULL && line.getChild()->equals(child)) { result[0] = (LineWA*) &linelist[a]; if (a != length - 1) { result[1] = (LineWA*) &linelist[a + 1]; } else { result[1] = (LineWA*) &linelist[0]; } return(result); } } return(result); } /* 1.1 isDirtyHash() */ bool ConvexHullTreeNode :: isDirtyHash() { return(dirtyHash); } /* 1 Set functions 1.1 setParent() */ void ConvexHullTreeNode :: setParent(RegionTreeNode *_myParent) { myParent = _myParent; myParent->setDirtyHash(); } /* 1.1 setLevel() */ void ConvexHullTreeNode :: setLevel(int lev) { level = lev; vector children = this->getChildren(); for(unsigned int i = 0; i < children.size(); i++) { children.at(i)->setLevel(lev + 1); } //delete children; setDirtyHash(); } /* 1.1 setHole() */ void ConvexHullTreeNode :: setHole(bool _isHole) { hole = _isHole; vector children = this->getChildren(); for(unsigned int i = 0; i < children.size(); i++) { children.at(i)->setHole(_isHole); } //delete children;; setDirtyHash(); } /* 1.1 setDirtyHash() */ void ConvexHullTreeNode :: setDirtyHash() { dirtyHash = true; if(myParent != NULL) { myParent->setDirtyHash(); } } /* 1 Overrides 1.1 hashCode() */ unsigned int ConvexHullTreeNode :: hashCode() { assert( !( !isDirtyHash() && m_HashCode == 0)); if(isDirtyHash()) { calculateHashCode(); } return(m_HashCode); } /* 1.1 calculateHashCode() */ void ConvexHullTreeNode::calculateHashCode() { unsigned int start = 5132; unsigned int multi = 312; unsigned int res = start; vector tmp = this->getLines(); for (unsigned int i = 0; i < tmp.size(); i++) { res += (unsigned int)(res+tmp[i].getX() * multi + tmp[i].getY() * multi); } res += level * 201; if(hole) res += 113; m_HashCode = res; dirtyHash = false; } /* 1.1 equals() */ bool ConvexHullTreeNode :: equals(RegionTreeNode* other) { if(other->hashCode() != this->hashCode()) { return(false); } if(dynamic_cast(other)) { bool res = true; ConvexHullTreeNode *tmp = (ConvexHullTreeNode*) other; vector tmp1 = this->getLines(); vector tmp2 = tmp->getLines(); if(tmp1.size() != tmp2.size()) return false; for(unsigned int i = 0; i < tmp1.size(); i++) { if(tmp1[i].getX() != tmp2[i].getX()) res = false; if(tmp1[i].getY() != tmp2[i].getY()) res = false; } return(res); } else { return(false); } } /* 1 Operators 1.1 $<<$ */ ostream & operator << (ostream& s, ConvexHullTreeNode chtn) { if(chtn.getLevel() == 0) { if(chtn.isHole()) { s << "CHTN is hole" << endl; s << "Hash: " << chtn.hashCode() << endl; } else { s << "CHTN is not a hole" << endl; s << "Hash: " << chtn.hashCode() << endl; } for(int i = 0; i < chtn.getNrLines(); i++) { s << "I" << setw(3) << setfill('-') << i << setfill(' ') << ": " << chtn.getCHLine(i); if(chtn.getCHLine(i).getChild() != NULL) { s << *(chtn.getCHLine(i).getChild()); } } s << endl; } else { s << "I" << setw(3 * chtn.getLevel() - 1) << setfill('-') << "" << setw(3) << chtn.hashCode() << endl; for(int i = 0; i < chtn.getNrLines(); i++) { s << "I" << setw(3 * chtn.getLevel() - 1) << setfill('-') << "" << setw(3) << i << setfill(' ') << ": " << chtn.getCHLine(i); s << setfill(' '); if(chtn.getCHLine(i).getChild() != NULL) { s << *(chtn.getCHLine(i).getChild()); } } } return s; } /* 1 Private Methods 1.1 insertChild() */ void ConvexHullTreeNode :: insertChild(int lineindex, ConvexHullTreeNode *child) { CHLine *line= &linelist.at(lineindex); line->setChild(child); } /* 1.1 insertLine() */ int ConvexHullTreeNode :: insertLine(LineWA* line) { CHLine newline = (CHLine)line; linelist.insert(linelist.end(), newline); return(linelist.size() - 1); } /* 1.1 getLine() */ LineWA* ConvexHullTreeNode :: getLine(int index) { return(&linelist.at(index)); } /* 1.1 getSplitLine() */ vector* ConvexHullTreeNode :: getSplitLine(ConvexHullTreeNode *ref1, ConvexHullTreeNode *ref2) { LineWA p1 = ref1->getCenter(); LineWA p2 = ref2->getCenter(); vector pdist1; vector pdist2; vector *res =new vector; vector ref1lines = ref1->getLines(); vector ref2lines = ref2->getLines(); for (unsigned int i = 0; i < ref1lines.size(); i++) { double dist = Utils :: getRectangularDistance(&p1, &p2, (LineWA*) &ref1lines[i]); if( !isnan(dist)) pdist1.push_back(LineDist( (LineWA*) &ref1lines[i], dist)); } for (unsigned int i = 0; i < ref2lines.size(); i++) { double dist = Utils :: getRectangularDistance(&p1, &p2, (LineWA*) &ref2lines[i]); if(!isnan(dist)) pdist2.push_back( LineDist( (LineWA*) &ref2lines[i], dist)); } sort(pdist1.begin(), pdist1.end()); sort(pdist2.begin(), pdist2.end()); while(pdist1.size() > 1 || pdist2.size() > 1) { if(pdist1.size() == 0 || pdist2.size() == 0) { return(res); } LineDist tmp1 = pdist1[0]; LineDist tmp2 = pdist2[0]; vector *inter1=Utils::getIntersections(new LineWA(tmp1.getX(), tmp1.getY()), new LineWA(tmp2.getX(), tmp2.getY()), &ref1lines); vector *inter2=Utils::getIntersections(new LineWA(tmp1.getX(), tmp1.getY()), new LineWA(tmp2.getX(), tmp2.getY()), &ref2lines); if(inter1->size() <= 2 && inter2->size() <= 2) res->push_back(new LineWA((tmp1.getX() + tmp2.getX()) / 2.0, (tmp1.getY() + tmp2.getY()) / 2.0)); if(tmp1.getDistance() > tmp2.getDistance()) { if(pdist2.size() > 1) { pdist2.erase(pdist2.begin()); } else { while(pdist1.size() > 1) { tmp1=pdist1[0]; tmp2=pdist2[0]; if(((Utils :: getIntersections(new LineWA(tmp1.getX(), tmp1.getY()), new LineWA(tmp2.getX(), tmp2.getY()), &ref1lines)->size()) <= 2) &&(Utils :: getIntersections(new LineWA(tmp1.getX(), tmp1.getY()), new LineWA(tmp2.getX(), tmp2.getY()), &ref2lines)->size()) <= 2) { res->push_back(new LineWA((tmp1.getX()+tmp2.getX())/2.0, (tmp1.getY() + tmp2.getY()) / 2.0)); } pdist1.erase(pdist1.begin()); } } } else { if(pdist1.size() > 1) { pdist1.erase(pdist1.begin()); } else { while(pdist2.size() > 1) { tmp1 = pdist1[0]; tmp2 = pdist2[0]; res->push_back(new LineWA((tmp1.getX()+tmp2.getX())/2.0, (tmp1.getY()+tmp2.getY())/2.0)); pdist2.erase(pdist2.begin()); } } } } if(pdist1.size()==0 || pdist2.size()==0) { return(new vector); } LineDist tmp1 = pdist1[0]; LineDist tmp2 = pdist2[0]; if(((Utils :: getIntersections(new LineWA(tmp1.getX(), tmp1.getY()), new LineWA(tmp2.getX(), tmp2.getY()), &ref1lines)->size()) <= 2) && (Utils :: getIntersections(new LineWA(tmp1.getX(), tmp1.getY()), new LineWA(tmp2.getX(), tmp2.getY()), &ref2lines)->size()) <= 2) { res->push_back(new LineWA((tmp1.getX() + tmp2.getX()) / 2.0, (tmp1.getY() + tmp2.getY()) / 2.0)); } double sumLinex = 0; double sumLiney = 0; for(unsigned int i = 0; i < res->size(); i++) { sumLinex += res->at(i)->getX(); sumLiney += res->at(i)->getY(); } LineWA centerLine = LineWA(sumLinex/(res->size()), sumLiney/(res->size())); double sumRefx = 0; double sumRefy = 0; for(unsigned int i = 0; i < ref1lines.size(); i++) { sumRefx += ref1lines[i].getX(); sumRefy += ref1lines[i].getY(); } for(unsigned int i = 0; i < ref2lines.size(); i++) { sumRefx += ref2lines[i].getX(); sumRefy += ref2lines[i].getY(); } LineWA centerRef = LineWA(sumRefx / (ref1lines.size() + ref2lines.size()), sumRefy / (ref1lines.size() + ref2lines.size())); double scaleVector = abs(Utils :: getArea(getLines())) / (abs(Utils :: getArea(ref1lines)) + abs(Utils :: getArea(ref2lines))); double distLine = sqrt((centerLine.getX() - (res->at(0))->getX()) * (centerLine.getX() - (res->at(0))->getX()) + (centerLine.getY() - (res->at(0))->getY()) * (centerLine.getY() - (res->at(0))->getY())); distLine = max(distLine, sqrt((centerLine.getX() - (res->at(res->size() - 1))->getX()) * (centerLine.getX() - (res->at(res->size() - 1))->getX()) + (centerLine.getY() - (res->at(res->size() - 1))->getY()) * (centerLine.getY() - (res->at(res->size() - 1))->getY()))); double thismaxdist = 0; LineWA centerThis = getCenter(); vector thisLines = getLines(); for(unsigned int i = 0; i< thisLines.size(); i++) { thismaxdist = max(thismaxdist, sqrt((thisLines[i].getX() - centerThis.getX()) * (thisLines[i].getX() - centerThis.getX()) + (thisLines[i].getY() - centerThis.getY()) * (thisLines[i].getY() - centerThis.getY()))); } double scale = thismaxdist / distLine * 1.05; for(unsigned int i = 0; i < res->size(); i++) { res->at(i)->setX(centerThis.getX() + (centerLine.getX() - centerRef.getX()) * scaleVector + (res->at(i)->getX() - centerLine.getX()) * scale); res->at(i)->setY(centerThis.getY() + (centerLine.getY() - centerRef.getY()) * scaleVector + (res->at(i)->getY() - centerLine.getY()) * scale); } return res; } vector > *ConvexHullTreeNode :: getSplitNodes( vector *splitLine) { if(splitLine == NULL || splitLine->size() == 0) return(NULL); vector > *res = new vector > (2); int lowIndexLine, highIndexLine, lowIndexPoly, highIndexPoly; vector IntersectionPoints; vector IntersectionIndexPoly; vector IntersectionIndexLine; vector polyLine = getLines(); for(unsigned int i = 0; i < polyLine.size(); i++) { for(unsigned int j = 0; j < (splitLine->size() - 1); j++) { LineWA *inters = Utils :: getIntersection( (LineWA*) &(polyLine[i]), (LineWA*) &(polyLine[(i + 1)%polyLine.size()]), splitLine->at(j),splitLine->at(j + 1)); if(inters != NULL) { IntersectionPoints.push_back(inters); IntersectionIndexPoly.push_back(i); IntersectionIndexLine.push_back(j); } } } if(IntersectionPoints.size() != 2) { return(NULL); } else { if(IntersectionIndexPoly[0] > IntersectionIndexPoly[1]) { lowIndexPoly = IntersectionIndexPoly[1]; highIndexPoly = IntersectionIndexPoly[0]; } else { lowIndexPoly = IntersectionIndexPoly[0]; highIndexPoly = IntersectionIndexPoly[1]; } if(IntersectionIndexLine[0] > IntersectionIndexLine[1]) { lowIndexLine = IntersectionIndexLine[1]; highIndexLine = IntersectionIndexLine[0]; } else { lowIndexLine = IntersectionIndexLine[0]; highIndexLine = IntersectionIndexLine[1]; } res->at(0).resize(polyLine.size() - highIndexPoly + lowIndexPoly + highIndexLine - lowIndexLine + 2); res->at(1).resize(highIndexPoly - lowIndexPoly + highIndexLine - lowIndexLine + 2); int index1 = 0; int index2 = 0; for(int i = 0; i <= lowIndexPoly; i++ ) { res->at(0)[index1++] = polyLine[i]; } for(int i = highIndexPoly; i > lowIndexPoly; i--) { res->at(1)[index2++] = polyLine[i]; } int indexindex = -1; for(unsigned int i = 0; i < IntersectionIndexPoly.size(); i++) { if(IntersectionIndexPoly[i] == lowIndexPoly) { indexindex = i; break; } } res->at(0)[index1++] = IntersectionPoints[indexindex]; res->at(1)[index2++] = IntersectionPoints[indexindex]; if(IntersectionIndexLine[indexindex] == lowIndexLine) { for(int i = lowIndexLine + 1; i <= highIndexLine; i++) { res->at(0)[index1++] = splitLine->at(i); res->at(1)[index2++] = splitLine->at(i); } } else { for(int i = highIndexLine; i > lowIndexLine; i--) { res->at(0)[index1++] = splitLine->at(i); res->at(1)[index2++] = splitLine->at(i); } } res->at(0)[index1++] = IntersectionPoints[(indexindex - 1) * -1]; res->at(1)[index2++] = IntersectionPoints[(indexindex - 1) * -1]; for(unsigned int i = highIndexPoly + 1; i < polyLine.size(); i++) { res->at(0)[index1++] = polyLine[i]; } #ifdef DECHTN cout<<"ResultNode1"<at(0).size();i++) { cout<at(0)[i]; } cout<<"ResultNode2"<at(1).size();i++) { cout<at(1)[i]; } if(res->at(0)[0].equals(&res->at(0).back())) { return(NULL); } #endif if(res->at(1)[0].equals(&res->at(1).back())) { return(NULL); } } return(res); } }