/*************************************************************************** DualEdgeTriangulation.cc - description ------------------- copyright : (C) 2004 by Marco Hugentobler email : mhugent@geo.unizh.ch ***************************************************************************/ /*************************************************************************** * * * This program 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. * * * ***************************************************************************/ #include "DualEdgeTriangulation.h" #include <map> #include "Line3D.h" #include "MathUtils.h" #include "qgsgeometry.h" #include "qgslogger.h" #include "qgsvectorfilewriter.h" double leftOfTresh = 0.00000001; DualEdgeTriangulation::~DualEdgeTriangulation() { //remove all the points if ( !mPointVector.isEmpty() ) { for ( int i = 0; i < mPointVector.count(); i++ ) { delete mPointVector[i]; } } //remove all the HalfEdge if ( !mHalfEdge.isEmpty() ) { for ( int i = 0; i < mHalfEdge.count(); i++ ) { delete mHalfEdge[i]; } } } void DualEdgeTriangulation::performConsistencyTest() { QgsDebugMsg( "performing consistency test" ); for ( int i = 0; i < mHalfEdge.count(); i++ ) { int a = mHalfEdge[mHalfEdge[i]->getDual()]->getDual(); int b = mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getNext(); if ( i != a ) { QgsDebugMsg( "warning, first test failed" ); } if ( i != b ) { QgsDebugMsg( "warning, second test failed" ); } } QgsDebugMsg( "consistency test finished" ); } void DualEdgeTriangulation::addLine( Line3D* line, bool breakline ) { int actpoint = -10;//number of the last point, which has been inserted from the line int currentpoint = -10;//number of the point, which is currently inserted from the line if ( line ) { //first, find the first point unsigned int i; line->goToBegin(); for ( i = 0; i < line->getSize(); i++ ) { line->goToNext(); // Use copy ctor since line can be deleted as well as its // associated Node and Point3D actpoint = mDecorator->addPoint( new Point3D( *line->getPoint() ) ); if ( actpoint != -100 ) { i++; break; } } if ( actpoint == -100 )//no point of the line could be inserted { delete line; return; } for ( ; i < line->getSize(); i++ ) { line->goToNext(); currentpoint = mDecorator->addPoint( new Point3D( *line->getPoint() ) ); if ( currentpoint != -100 && actpoint != -100 && currentpoint != actpoint )//-100 is the return value if the point could not be not inserted { insertForcedSegment( actpoint, currentpoint, breakline ); } actpoint = currentpoint; } } delete line; } int DualEdgeTriangulation::addPoint( Point3D* p ) { if ( p ) { // QgsDebugMsg( QString("inserting point %1,%2//%3//%4").arg(mPointVector.count()).arg(p->getX()).arg(p->getY()).arg(p->getZ())); //first update the bounding box if ( mPointVector.isEmpty() )//update bounding box when the first point is inserted { xMin = ( *p ).getX(); yMin = ( *p ).getY(); xMax = ( *p ).getX(); yMax = ( *p ).getY(); } else//update bounding box else { if (( *p ).getX() < xMin ) { xMin = ( *p ).getX(); } else if (( *p ).getX() > xMax ) { xMax = ( *p ).getX(); } if (( *p ).getY() < yMin ) { yMin = ( *p ).getY(); } else if (( *p ).getY() > yMax ) { yMax = ( *p ).getY(); } } //then update mPointVector mPointVector.append( p ); //then update the HalfEdgeStructure if ( mPointVector.count() == 1 )//insert the first point into the triangulation { unsigned int zedge = insertEdge( -10, -10, -1, false, false );//edge pointing from p to the virtual point unsigned int fedge = insertEdge(( int )zedge, ( int )zedge, 0, false, false );//edge pointing from the virtual point to p ( mHalfEdge.at( zedge ) )->setDual(( int )fedge ); ( mHalfEdge.at( zedge ) )->setNext(( int )fedge ); } else if ( mPointVector.count() == 2 )//insert the second point into the triangulation { //test, if it is the same point as the first point if ( p->getX() == mPointVector[0]->getX() && p->getY() == mPointVector[0]->getY() ) { QgsDebugMsg( "second point is the same as the first point, it thus has not been inserted" ); Point3D* p = mPointVector[1]; mPointVector.remove( 1 ); delete p; return -100; } unsigned int sedge = insertEdge( -10, -10, 1, false, false );//edge pointing from point 0 to point 1 unsigned int tedge = insertEdge(( int )sedge, 0, 0, false, false );//edge pointing from point 1 to point 0 unsigned int foedge = insertEdge( -10, 4, 1, false, false );//edge pointing from the virtual point to point 1 unsigned int fiedge = insertEdge(( int )foedge, 1, -1, false, false );//edge pointing from point 2 to the virtual point mHalfEdge.at( sedge )->setDual(( int )tedge ); mHalfEdge.at( sedge )->setNext(( int )fiedge ); mHalfEdge.at( foedge )->setDual(( int )fiedge ); mHalfEdge.at( foedge )->setNext(( int )tedge ); mHalfEdge.at( 0 )->setNext(( int )foedge ); mHalfEdge.at( 1 )->setNext(( int )sedge ); mEdgeInside = 3; } else if ( mPointVector.count() == 3 )//insert the third point into the triangulation { //we first have to decide, if the third point is to the left or to the right of the line through p0 and p1 double number = MathUtils::leftOf( p, mPointVector[0], mPointVector[1] ); if ( number < -leftOfTresh )//p is on the left side { //insert six new edges unsigned int edgea = insertEdge( -10, -10, 2, false, false );//edge pointing from point1 to point2 unsigned int edgeb = insertEdge(( int )edgea, 5, 1, false, false );//edge pointing from point2 to point1 unsigned int edgec = insertEdge( -10, ( int )edgeb, 2, false, false );//edge pointing from the virtual point to p2 unsigned int edged = insertEdge( -10, 2, 0, false, false );//edge pointing from point2 to point0 unsigned int edgee = insertEdge(( int )edged, -10, 2, false, false );//edge pointing from point0 to point2 unsigned int edgef = insertEdge(( int )edgec, 1, -1, false, false );//edge pointing from point2 to the virtual point mHalfEdge.at( edgea )->setDual(( int )edgeb ); mHalfEdge.at( edgea )->setNext(( int )edged ); mHalfEdge.at( edgec )->setDual(( int )edgef ); mHalfEdge.at( edged )->setDual(( int )edgee ); mHalfEdge.at( edgee )->setNext(( int )edgef ); mHalfEdge.at( 5 )->setNext(( int )edgec ); mHalfEdge.at( 1 )->setNext(( int )edgee ); mHalfEdge.at( 2 )->setNext(( int )edgea ); } else if ( number > leftOfTresh )//p is on the right side { //insert six new edges unsigned int edgea = insertEdge( -10, -10, 2, false, false );//edge pointing from p0 to p2 unsigned int edgeb = insertEdge(( int )edgea, 0, 0, false, false );//edge pointing from p2 to p0 unsigned int edgec = insertEdge( -10, ( int )edgeb, 2, false, false );//edge pointing from the virtual point to p2 unsigned int edged = insertEdge( -10, 3, 1, false, false );//edge pointing from p2 to p1 unsigned int edgee = insertEdge(( int )edged, -10, 2, false, false );//edge pointing from p1 to p2 unsigned int edgef = insertEdge(( int )edgec, 4, -1, false, false );//edge pointing from p2 to the virtual point mHalfEdge.at( edgea )->setDual(( int )edgeb ); mHalfEdge.at( edgea )->setNext(( int )edged ); mHalfEdge.at( edgec )->setDual(( int )edgef ); mHalfEdge.at( edged )->setDual(( int )edgee ); mHalfEdge.at( edgee )->setNext(( int )edgef ); mHalfEdge.at( 0 )->setNext(( int )edgec ); mHalfEdge.at( 4 )->setNext(( int )edgee ); mHalfEdge.at( 3 )->setNext(( int )edgea ); } else//p is in a line with p0 and p1 { mPointVector.remove( mPointVector.count() - 1 ); QgsDebugMsg( "error: third point is on the same line as the first and the second point. It thus has not been inserted into the triangulation" ); return -100; } } else if ( mPointVector.count() >= 4 )//insert an arbitrary point into the triangulation { int number = baseEdgeOfTriangle( p ); //point is outside the convex hull---------------------------------------------------- if ( number == -10 ) { unsigned int cwedge = mEdgeOutside;//the last visible edge clockwise from mEdgeOutside unsigned int ccwedge = mEdgeOutside;//the last visible edge counterclockwise from mEdgeOutside //mEdgeOutside is in each case visible mHalfEdge[mHalfEdge[mEdgeOutside]->getNext()]->setPoint( mPointVector.count() - 1 ); //find cwedge and replace the virtual point with the new point when necessary while ( MathUtils::leftOf( mPointVector[( unsigned int ) mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[cwedge]->getNext()]->getDual()]->getNext()]->getPoint()], p, mPointVector[( unsigned int ) mHalfEdge[cwedge]->getPoint()] ) < ( -leftOfTresh ) ) { //set the point number of the necessary edge to the actual point instead of the virtual point mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[cwedge]->getNext()]->getDual()]->getNext()]->getNext()]->setPoint( mPointVector.count() - 1 ); //advance cwedge one edge further clockwise cwedge = ( unsigned int )mHalfEdge[mHalfEdge[mHalfEdge[cwedge]->getNext()]->getDual()]->getNext(); } //build the necessary connections with the virtual point unsigned int edge1 = insertEdge( mHalfEdge[cwedge]->getNext(), -10, mHalfEdge[cwedge]->getPoint(), false, false );//edge pointing from the new point to the last visible point clockwise unsigned int edge2 = insertEdge( mHalfEdge[mHalfEdge[cwedge]->getNext()]->getDual(), -10, -1, false, false );//edge pointing from the last visible point to the virtual point unsigned int edge3 = insertEdge( -10, edge1, mPointVector.count() - 1, false, false );//edge pointing from the virtual point to new point //adjust the other pointers mHalfEdge[mHalfEdge[mHalfEdge[cwedge]->getNext()]->getDual()]->setDual( edge2 ); mHalfEdge[mHalfEdge[cwedge]->getNext()]->setDual( edge1 ); mHalfEdge[edge1]->setNext( edge2 ); mHalfEdge[edge2]->setNext( edge3 ); //find ccwedge and replace the virtual point with the new point when necessary while ( MathUtils::leftOf( mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[ccwedge]->getNext()]->getNext()]->getPoint()], mPointVector[mPointVector.count()-1], mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwedge]->getNext()]->getNext()]->getDual()]->getNext()]->getPoint()] ) < ( -leftOfTresh ) ) { //set the point number of the necessary edge to the actual point instead of the virtual point mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwedge]->getNext()]->getNext()]->getDual()]->setPoint( mPointVector.count() - 1 ); //advance ccwedge one edge further counterclockwise ccwedge = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwedge]->getNext()]->getNext()]->getDual()]->getNext()]->getNext(); } //build the necessary connections with the virtual point unsigned int edge4 = insertEdge( mHalfEdge[mHalfEdge[ccwedge]->getNext()]->getNext(), -10, mPointVector.count() - 1, false, false );//points from the last visible point counterclockwise to the new point unsigned int edge5 = insertEdge( edge3, -10, -1, false, false );//points from the new point to the virtual point unsigned int edge6 = insertEdge( mHalfEdge[mHalfEdge[mHalfEdge[ccwedge]->getNext()]->getNext()]->getDual(), edge4, mHalfEdge[mHalfEdge[ccwedge]->getDual()]->getPoint(), false, false );//points from the virtual point to the last visible point counterclockwise //adjust the other pointers mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwedge]->getNext()]->getNext()]->getDual()]->setDual( edge6 ); mHalfEdge[mHalfEdge[mHalfEdge[ccwedge]->getNext()]->getNext()]->setDual( edge4 ); mHalfEdge[edge4]->setNext( edge5 ); mHalfEdge[edge5]->setNext( edge6 ); mHalfEdge[edge3]->setDual( edge5 ); //now test the HalfEdge at the former convex hull for swappint unsigned int index = ccwedge; unsigned int toswap; while ( true ) { toswap = index; index = mHalfEdge[mHalfEdge[mHalfEdge[index]->getNext()]->getDual()]->getNext(); checkSwap( toswap, 0 ); if ( toswap == cwedge ) { break; } } } //point is inside the convex hull------------------------------------------------------ else if ( number >= 0 ) { int nextnumber = mHalfEdge[number]->getNext(); int nextnextnumber = mHalfEdge[mHalfEdge[number]->getNext()]->getNext(); //insert 6 new HalfEdges for the connections to the vertices of the triangle unsigned int edge1 = insertEdge( -10, nextnumber, mHalfEdge[number]->getPoint(), false, false ); unsigned int edge2 = insertEdge(( int )edge1, -10, mPointVector.count() - 1, false, false ); unsigned int edge3 = insertEdge( -10, nextnextnumber, mHalfEdge[nextnumber]->getPoint(), false, false ); unsigned int edge4 = insertEdge(( int )edge3, ( int )edge1, mPointVector.count() - 1, false, false ); unsigned int edge5 = insertEdge( -10, number, mHalfEdge[nextnextnumber]->getPoint(), false, false ); unsigned int edge6 = insertEdge(( int )edge5, ( int )edge3, mPointVector.count() - 1, false, false ); mHalfEdge.at( edge1 )->setDual(( int )edge2 ); mHalfEdge.at( edge2 )->setNext(( int )edge5 ); mHalfEdge.at( edge3 )->setDual(( int )edge4 ); mHalfEdge.at( edge5 )->setDual(( int )edge6 ); mHalfEdge.at( number )->setNext(( int )edge2 ); mHalfEdge.at( nextnumber )->setNext(( int )edge4 ); mHalfEdge.at( nextnextnumber )->setNext(( int )edge6 ); //check, if there are swaps necessary checkSwap( number, 0 ); checkSwap( nextnumber, 0 ); checkSwap( nextnextnumber, 0 ); } //the point is exactly on an existing edge (the number of the edge is stored in the variable 'mEdgeWithPoint'--------------- else if ( number == -20 ) { int edgea = mEdgeWithPoint; int edgeb = mHalfEdge[mEdgeWithPoint]->getDual(); int edgec = mHalfEdge[edgea]->getNext(); int edged = mHalfEdge[edgec]->getNext(); int edgee = mHalfEdge[edgeb]->getNext(); int edgef = mHalfEdge[edgee]->getNext(); //insert the six new edges int nedge1 = insertEdge( -10, mHalfEdge[edgea]->getNext(), mHalfEdge[edgea]->getPoint(), false, false ); int nedge2 = insertEdge( nedge1, -10, mPointVector.count() - 1, false, false ); int nedge3 = insertEdge( -10, edged, mHalfEdge[edgec]->getPoint(), false, false ); int nedge4 = insertEdge( nedge3, nedge1, mPointVector.count() - 1, false, false ); int nedge5 = insertEdge( -10, edgef, mHalfEdge[edgee]->getPoint(), false, false ); int nedge6 = insertEdge( nedge5, edgeb, mPointVector.count() - 1, false, false ); //adjust the triangular structure mHalfEdge[nedge1]->setDual( nedge2 ); mHalfEdge[nedge2]->setNext( nedge5 ); mHalfEdge[nedge3]->setDual( nedge4 ); mHalfEdge[nedge5]->setDual( nedge6 ); mHalfEdge[edgea]->setPoint( mPointVector.count() - 1 ); mHalfEdge[edgea]->setNext( nedge3 ); mHalfEdge[edgec]->setNext( nedge4 ); mHalfEdge[edgee]->setNext( nedge6 ); mHalfEdge[edgef]->setNext( nedge2 ); //swap edges if necessary checkSwap( edgec, 0 ); checkSwap( edged, 0 ); checkSwap( edgee, 0 ); checkSwap( edgef, 0 ); } else if ( number == -100 || number == -5 )//this means unknown problems or a numerical error occurred in 'baseEdgeOfTriangle' { // QgsDebugMsg("point has not been inserted because of unknown problems"); Point3D* p = mPointVector[mPointVector.count()-1]; mPointVector.remove( mPointVector.count() - 1 ); delete p; return -100; } else if ( number == -25 )//this means that the point has already been inserted in the triangulation { //Take the higher z-Value in case of two equal points Point3D* newPoint = mPointVector[mPointVector.count()-1]; Point3D* existingPoint = mPointVector[mTwiceInsPoint]; existingPoint->setZ( qMax( newPoint->getZ(), existingPoint->getZ() ) ); mPointVector.remove( mPointVector.count() - 1 ); delete newPoint; return mTwiceInsPoint; } } return ( mPointVector.count() - 1 ); } else { QgsDebugMsg( "warning: null pointer" ); return -100; } } int DualEdgeTriangulation::baseEdgeOfPoint( int point ) { unsigned int actedge = mEdgeInside;//starting edge if ( mPointVector.count() < 4 || point == -1 )//at the beginning, mEdgeInside is not defined yet { //first find pointingedge(an edge pointing to p1) for ( int i = 0; i < mHalfEdge.count(); i++ ) { if ( mHalfEdge[i]->getPoint() == point )//we found it { return i; } } } int control = 0; while ( true )//otherwise, start the search { control += 1; if ( control > 1000000 ) { // QgsDebugMsg( "warning, endless loop" ); //use the secure and slow method //qWarning( "******************warning, using the slow method in baseEdgeOfPoint****************************************" ); for ( int i = 0; i < mHalfEdge.count(); i++ ) { if ( mHalfEdge[i]->getPoint() == point && mHalfEdge[mHalfEdge[i]->getNext()]->getPoint() != -1 )//we found it { return i; } } } int frompoint = mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint(); int topoint = mHalfEdge[actedge]->getPoint(); if ( frompoint == -1 || topoint == -1 )//this would cause a crash. Therefore we use the slow method in this case { for ( int i = 0; i < mHalfEdge.count(); i++ ) { if ( mHalfEdge[i]->getPoint() == point && mHalfEdge[mHalfEdge[i]->getNext()]->getPoint() != -1 )//we found it { mEdgeInside = i; return i; } } } double leftofnumber = MathUtils::leftOf( mPointVector[point], mPointVector[mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[actedge]->getPoint()] ); if ( mHalfEdge[actedge]->getPoint() == point && mHalfEdge[mHalfEdge[actedge]->getNext()]->getPoint() != -1 )//we found the edge { mEdgeInside = actedge; return actedge; } else if ( leftofnumber <= 0.0 ) { actedge = mHalfEdge[actedge]->getNext(); } else { actedge = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getDual()]->getNext()]->getNext()]->getDual(); } } } int DualEdgeTriangulation::baseEdgeOfTriangle( Point3D* point ) { unsigned int actedge = mEdgeInside;//start with an edge which does not point to the virtual point (usualy number 3) int counter = 0;//number of consecutive successful left-of-tests int nulls = 0;//number of left-of-tests, which returned 0. 1 means, that the point is on a line, 2 means that it is on an existing point int numinstabs = 0;//number of suspect left-of-tests due to 'leftOfTresh' int runs = 0;//counter for the number of iterations in the loop to prevent an endless loop int firstendp = 0, secendp = 0, thendp = 0, fouendp = 0; //four numbers of endpoints in cases when two left-of-test are 0 while ( true ) { if ( runs > nBaseOfRuns )//prevents endless loops { // QgsDebugMsg("warning, probable endless loop detected"); return -100; } double leftofvalue = MathUtils::leftOf( point, mPointVector[mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[actedge]->getPoint()] ); if ( leftofvalue < ( -leftOfTresh ) )//point is on the left side { counter += 1; if ( counter == 3 )//three successful passes means that we have found the triangle { break; } } else if ( leftofvalue == 0 )//point is exactly in the line of the edge { if ( nulls == 0 ) { //store the numbers of the two endpoints of the line firstendp = mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint(); secendp = mHalfEdge[actedge]->getPoint(); } else if ( nulls == 1 ) { //store the numbers of the two endpoints of the line thendp = mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint(); fouendp = mHalfEdge[actedge]->getPoint(); } counter += 1; mEdgeWithPoint = actedge; nulls += 1; if ( counter == 3 )//three successful passes means that we have found the triangle { break; } } else if ( leftofvalue < leftOfTresh )//numerical problems { counter += 1; numinstabs += 1; if ( counter == 3 )//three successful passes means that we have found the triangle { break; } } else//point is on the right side { actedge = mHalfEdge[actedge]->getDual(); counter = 1; nulls = 0; numinstabs = 0; } actedge = mHalfEdge[actedge]->getNext(); if ( mHalfEdge[actedge]->getPoint() == -1 )//the half edge points to the virtual point { if ( nulls == 1 )//point is exactly on the convex hull { return -20; } mEdgeOutside = ( unsigned int )mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext(); mEdgeInside = mHalfEdge[mHalfEdge[mEdgeOutside]->getDual()]->getNext(); return -10;//the point is outside the convex hull } runs++; } if ( numinstabs > 0 )//we hit an existing point or a numerical instability occurred { // QgsDebugMsg("numerical instability occurred"); mUnstableEdge = actedge; return -5; } if ( nulls == 2 ) { //find out the number of the point, which has already been inserted if ( firstendp == thendp || firstendp == fouendp ) { //firstendp is the number of the point which has been inserted twice mTwiceInsPoint = firstendp; // QgsDebugMsg(QString("point nr %1 already inserted").arg(firstendp)); } else if ( secendp == thendp || secendp == fouendp ) { //secendp is the number of the point which has been inserted twice mTwiceInsPoint = secendp; // QgsDebugMsg(QString("point nr %1 already inserted").arg(secendp)); } return -25;//return the code for a point that is already contained in the triangulation } if ( nulls == 1 )//point is on an existing edge { return -20; } mEdgeInside = actedge; int nr1, nr2, nr3; nr1 = mHalfEdge[actedge]->getPoint(); nr2 = mHalfEdge[mHalfEdge[actedge]->getNext()]->getPoint(); nr3 = mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext()]->getPoint(); double x1 = mPointVector[nr1]->getX(); double y1 = mPointVector[nr1]->getY(); double x2 = mPointVector[nr2]->getX(); double y2 = mPointVector[nr2]->getY(); double x3 = mPointVector[nr3]->getX(); double y3 = mPointVector[nr3]->getY(); //now make sure that always the same edge is returned if ( x1 < x2 && x1 < x3 )//return the edge which points to the point with the lowest x-coordinate { return actedge; } else if ( x2 < x1 && x2 < x3 ) { return mHalfEdge[actedge]->getNext(); } else if ( x3 < x1 && x3 < x2 ) { return mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext(); } //in case two x-coordinates are the same, the edge pointing to the point with the lower y-coordinate is returned else if ( x1 == x2 ) { if ( y1 < y2 ) { return actedge; } else if ( y2 < y1 ) { return mHalfEdge[actedge]->getNext(); } } else if ( x2 == x3 ) { if ( y2 < y3 ) { return mHalfEdge[actedge]->getNext(); } else if ( y3 < y2 ) { return mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext(); } } else if ( x1 == x3 ) { if ( y1 < y3 ) { return actedge; } else if ( y3 < y1 ) { return mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext(); } } return -100;//this means a bug happened } bool DualEdgeTriangulation::calcNormal( double x, double y, Vector3D* result ) { if ( result && mTriangleInterpolator ) { if ( !mTriangleInterpolator->calcNormVec( x, y, result ) ) {return false;} return true; } else { QgsDebugMsg( "warning, null pointer" ); return false; } } bool DualEdgeTriangulation::calcPoint( double x, double y, Point3D* result ) { if ( result && mTriangleInterpolator ) { if ( !mTriangleInterpolator->calcPoint( x, y, result ) ) {return false;} return true; } else { QgsDebugMsg( "warning, null pointer" ); return false; } } bool DualEdgeTriangulation::checkSwap( unsigned int edge, unsigned int recursiveDeep ) { if ( swapPossible( edge ) ) { Point3D* pta = mPointVector[mHalfEdge[edge]->getPoint()]; Point3D* ptb = mPointVector[mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint()]; Point3D* ptc = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[edge]->getNext()]->getNext()]->getPoint()]; Point3D* ptd = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint()]; if ( MathUtils::inCircle( ptd, pta, ptb, ptc ) && recursiveDeep < 100 )//empty circle criterion violated { doSwap( edge, recursiveDeep );//swap the edge (recursive) return true; } } return false; } void DualEdgeTriangulation::doOnlySwap( unsigned int edge ) { unsigned int edge1 = edge; unsigned int edge2 = mHalfEdge[edge]->getDual(); unsigned int edge3 = mHalfEdge[edge]->getNext(); unsigned int edge4 = mHalfEdge[mHalfEdge[edge]->getNext()]->getNext(); unsigned int edge5 = mHalfEdge[mHalfEdge[edge]->getDual()]->getNext(); unsigned int edge6 = mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getNext(); mHalfEdge[edge1]->setNext( edge4 );//set the necessary nexts mHalfEdge[edge2]->setNext( edge6 ); mHalfEdge[edge3]->setNext( edge2 ); mHalfEdge[edge4]->setNext( edge5 ); mHalfEdge[edge5]->setNext( edge1 ); mHalfEdge[edge6]->setNext( edge3 ); mHalfEdge[edge1]->setPoint( mHalfEdge[edge3]->getPoint() );//change the points to which edge1 and edge2 point mHalfEdge[edge2]->setPoint( mHalfEdge[edge5]->getPoint() ); } void DualEdgeTriangulation::doSwap( unsigned int edge, unsigned int recursiveDeep ) { unsigned int edge1 = edge; unsigned int edge2 = mHalfEdge[edge]->getDual(); unsigned int edge3 = mHalfEdge[edge]->getNext(); unsigned int edge4 = mHalfEdge[mHalfEdge[edge]->getNext()]->getNext(); unsigned int edge5 = mHalfEdge[mHalfEdge[edge]->getDual()]->getNext(); unsigned int edge6 = mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getNext(); mHalfEdge[edge1]->setNext( edge4 );//set the necessary nexts mHalfEdge[edge2]->setNext( edge6 ); mHalfEdge[edge3]->setNext( edge2 ); mHalfEdge[edge4]->setNext( edge5 ); mHalfEdge[edge5]->setNext( edge1 ); mHalfEdge[edge6]->setNext( edge3 ); mHalfEdge[edge1]->setPoint( mHalfEdge[edge3]->getPoint() );//change the points to which edge1 and edge2 point mHalfEdge[edge2]->setPoint( mHalfEdge[edge5]->getPoint() ); recursiveDeep++; checkSwap( edge3, recursiveDeep ); checkSwap( edge6, recursiveDeep ); checkSwap( edge4, recursiveDeep ); checkSwap( edge5, recursiveDeep ); } #if 0 void DualEdgeTriangulation::draw( QPainter* p, double xlowleft, double ylowleft, double xupright, double yupright, double width, double height ) const { //if mPointVector is empty, there is nothing to do if ( mPointVector.isEmpty() ) { return; } p->setPen( mEdgeColor ); bool* control = new bool[mHalfEdge.count()];//controllarray that no edge is painted twice bool* control2 = new bool[mHalfEdge.count()];//controllarray for the flat triangles for ( unsigned int i = 0; i <= mHalfEdge.count() - 1; i++ ) { control[i] = false; control2[i] = false; } if ((( xupright - xlowleft ) / width ) > (( yupright - ylowleft ) / height ) ) { double lowerborder = -( height * ( xupright - xlowleft ) / width - yupright );//real world coordinates of the lower widget border. This is useful to know because of the HalfEdge bounding box test for ( unsigned int i = 0; i < mHalfEdge.count() - 1; i++ ) { if ( mHalfEdge[i]->getPoint() == -1 || mHalfEdge[mHalfEdge[i]->getDual()]->getPoint() == -1 ) {continue;} //check, if the edge belongs to a flat triangle, remove this later if ( !control2[i] ) { double p1, p2, p3; if ( mHalfEdge[i]->getPoint() != -1 && mHalfEdge[mHalfEdge[i]->getNext()]->getPoint() != -1 && mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint() != -1 ) { p1 = mPointVector[mHalfEdge[i]->getPoint()]->getZ(); p2 = mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getZ(); p3 = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getZ(); if ( p1 == p2 && p2 == p3 && halfEdgeBBoxTest( i, xlowleft, lowerborder, xupright, yupright ) && halfEdgeBBoxTest( mHalfEdge[i]->getNext(), xlowleft, lowerborder, xupright, yupright ) && halfEdgeBBoxTest( mHalfEdge[mHalfEdge[i]->getNext()]->getNext(), xlowleft, lowerborder, xupright, yupright ) )//draw the triangle { QPointArray pa( 3 ); pa.setPoint( 0, ( mPointVector[mHalfEdge[i]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[i]->getPoint()]->getY() ) / ( xupright - xlowleft )*width ); pa.setPoint( 1, ( mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getY() ) / ( xupright - xlowleft )*width ); pa.setPoint( 2, ( mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getY() ) / ( xupright - xlowleft )*width ); QColor c( 255, 0, 0 ); p->setBrush( c ); p->drawPolygon( pa ); } } control2[i] = true; control2[mHalfEdge[i]->getNext()] = true; control2[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()] = true; }//end of the section, which has to be removed later if ( control[i] )//check, if edge has already been drawn {continue;} //draw the edge; if ( halfEdgeBBoxTest( i, xlowleft, lowerborder, xupright, yupright ) )//only draw the halfedge if its bounding box intersects the painted area { if ( mHalfEdge[i]->getBreak() )//change the color it the edge is a breakline { p->setPen( mBreakEdgeColor ); } else if ( mHalfEdge[i]->getForced() )//change the color if the edge is forced { p->setPen( mForcedEdgeColor ); } p->drawLine(( mPointVector[mHalfEdge[i]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[i]->getPoint()]->getY() ) / ( xupright - xlowleft )*width, ( mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()]->getY() ) / ( xupright - xlowleft )*width ); if ( mHalfEdge[i]->getForced() ) { p->setPen( mEdgeColor ); } } control[i] = true; control[mHalfEdge[i]->getDual()] = true; } } else { double rightborder = width * ( yupright - ylowleft ) / height + xlowleft;//real world coordinates of the right widget border. This is useful to know because of the HalfEdge bounding box test for ( unsigned int i = 0; i < mHalfEdge.count() - 1; i++ ) { if ( mHalfEdge[i]->getPoint() == -1 || mHalfEdge[mHalfEdge[i]->getDual()]->getPoint() == -1 ) {continue;} //check, if the edge belongs to a flat triangle, remove this section later if ( !control2[i] ) { double p1, p2, p3; if ( mHalfEdge[i]->getPoint() != -1 && mHalfEdge[mHalfEdge[i]->getNext()]->getPoint() != -1 && mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint() != -1 ) { p1 = mPointVector[mHalfEdge[i]->getPoint()]->getZ(); p2 = mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getZ(); p3 = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getZ(); if ( p1 == p2 && p2 == p3 && halfEdgeBBoxTest( i, xlowleft, ylowleft, rightborder, yupright ) && halfEdgeBBoxTest( mHalfEdge[i]->getNext(), xlowleft, ylowleft, rightborder, yupright ) && halfEdgeBBoxTest( mHalfEdge[mHalfEdge[i]->getNext()]->getNext(), xlowleft, ylowleft, rightborder, yupright ) )//draw the triangle { QPointArray pa( 3 ); pa.setPoint( 0, ( mPointVector[mHalfEdge[i]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[i]->getPoint()]->getY() ) / ( yupright - ylowleft )*height ); pa.setPoint( 1, ( mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getY() ) / ( yupright - ylowleft )*height ); pa.setPoint( 2, ( mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getY() ) / ( yupright - ylowleft )*height ); QColor c( 255, 0, 0 ); p->setBrush( c ); p->drawPolygon( pa ); } } control2[i] = true; control2[mHalfEdge[i]->getNext()] = true; control2[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()] = true; }//end of the section, which has to be removed later if ( control[i] )//check, if edge has already been drawn {continue;} //draw the edge if ( halfEdgeBBoxTest( i, xlowleft, ylowleft, rightborder, yupright ) )//only draw the edge if its bounding box intersects with the painted area { if ( mHalfEdge[i]->getBreak() )//change the color if the edge is a breakline { p->setPen( mBreakEdgeColor ); } else if ( mHalfEdge[i]->getForced() )//change the color if the edge is forced { p->setPen( mForcedEdgeColor ); } p->drawLine(( mPointVector[mHalfEdge[i]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[i]->getPoint()]->getY() ) / ( yupright - ylowleft )*height, ( mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()]->getY() ) / ( yupright - ylowleft )*height ); if ( mHalfEdge[i]->getForced() ) { p->setPen( mEdgeColor ); } } control[i] = true; control[mHalfEdge[i]->getDual()] = true; } } delete[] control; delete[] control2; } #endif int DualEdgeTriangulation::getOppositePoint( int p1, int p2 ) { //first find a half edge which points to p2 int firstedge = baseEdgeOfPoint( p2 ); //then find the edge which comes from p1 or print an error message if there isn't any int theedge = -10; int nextnextedge = firstedge; int edge, nextedge; do { edge = mHalfEdge[nextnextedge]->getDual(); if ( mHalfEdge[edge]->getPoint() == p1 ) { theedge = nextnextedge; break; }//we found the edge nextedge = mHalfEdge[edge]->getNext(); nextnextedge = mHalfEdge[nextedge]->getNext(); } while ( nextnextedge != firstedge ); if ( theedge == -10 )//there is no edge between p1 and p2 { QgsDebugMsg( QString( "warning, error: the points are: %1 and %2" ).arg( p1 ).arg( p2 ) ); return -10; } //finally find the opposite point return mHalfEdge[mHalfEdge[mHalfEdge[theedge]->getDual()]->getNext()]->getPoint(); } QList<int>* DualEdgeTriangulation::getSurroundingTriangles( int pointno ) { int firstedge = baseEdgeOfPoint( pointno ); if ( firstedge == -1 )//an error occurred { return nullptr; } QList<int>* vlist = new QList<int>();//create the value list on the heap int actedge = firstedge; int edge, nextedge, nextnextedge; do { edge = mHalfEdge[actedge]->getDual(); vlist->append( mHalfEdge[edge]->getPoint() );//add the number of the endpoint of the first edge to the value list nextedge = mHalfEdge[edge]->getNext(); vlist->append( mHalfEdge[nextedge]->getPoint() );//add the number of the endpoint of the second edge to the value list nextnextedge = mHalfEdge[nextedge]->getNext(); vlist->append( mHalfEdge[nextnextedge]->getPoint() );//add the number of endpoint of the third edge to the value list if ( mHalfEdge[nextnextedge]->getBreak() )//add, whether the third edge is a breakline or not { vlist->append( -10 ); } else { vlist->append( -20 ); } actedge = nextnextedge; } while ( nextnextedge != firstedge ); return vlist; } bool DualEdgeTriangulation::getTriangle( double x, double y, Point3D* p1, int* n1, Point3D* p2, int* n2, Point3D* p3, int* n3 ) { if ( mPointVector.size() < 3 ) { return false; } if ( p1 && p2 && p3 ) { Point3D point( x, y, 0 ); int edge = baseEdgeOfTriangle( &point ); if ( edge == -10 )//the point is outside the convex hull { QgsDebugMsg( "edge outside the convex hull" ); return false; } else if ( edge >= 0 )//the point is inside the convex hull { int ptnr1 = mHalfEdge[edge]->getPoint(); int ptnr2 = mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint(); int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[edge]->getNext()]->getNext()]->getPoint(); p1->setX( mPointVector[ptnr1]->getX() ); p1->setY( mPointVector[ptnr1]->getY() ); p1->setZ( mPointVector[ptnr1]->getZ() ); p2->setX( mPointVector[ptnr2]->getX() ); p2->setY( mPointVector[ptnr2]->getY() ); p2->setZ( mPointVector[ptnr2]->getZ() ); p3->setX( mPointVector[ptnr3]->getX() ); p3->setY( mPointVector[ptnr3]->getY() ); p3->setZ( mPointVector[ptnr3]->getZ() ); ( *n1 ) = ptnr1; ( *n2 ) = ptnr2; ( *n3 ) = ptnr3; return true; } else if ( edge == -20 )//the point is exactly on an edge { int ptnr1 = mHalfEdge[mEdgeWithPoint]->getPoint(); int ptnr2 = mHalfEdge[mHalfEdge[mEdgeWithPoint]->getNext()]->getPoint(); int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[mEdgeWithPoint]->getNext()]->getNext()]->getPoint(); if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 ) { return false; } p1->setX( mPointVector[ptnr1]->getX() ); p1->setY( mPointVector[ptnr1]->getY() ); p1->setZ( mPointVector[ptnr1]->getZ() ); p2->setX( mPointVector[ptnr2]->getX() ); p2->setY( mPointVector[ptnr2]->getY() ); p2->setZ( mPointVector[ptnr2]->getZ() ); p3->setX( mPointVector[ptnr3]->getX() ); p3->setY( mPointVector[ptnr3]->getY() ); p3->setZ( mPointVector[ptnr3]->getZ() ); ( *n1 ) = ptnr1; ( *n2 ) = ptnr2; ( *n3 ) = ptnr3; return true; } else if ( edge == -25 )//x and y are the coordinates of an existing point { int edge1 = baseEdgeOfPoint( mTwiceInsPoint ); int edge2 = mHalfEdge[edge1]->getNext(); int edge3 = mHalfEdge[edge2]->getNext(); int ptnr1 = mHalfEdge[edge1]->getPoint(); int ptnr2 = mHalfEdge[edge2]->getPoint(); int ptnr3 = mHalfEdge[edge3]->getPoint(); p1->setX( mPointVector[ptnr1]->getX() ); p1->setY( mPointVector[ptnr1]->getY() ); p1->setZ( mPointVector[ptnr1]->getZ() ); p2->setX( mPointVector[ptnr2]->getX() ); p2->setY( mPointVector[ptnr2]->getY() ); p2->setZ( mPointVector[ptnr2]->getZ() ); p3->setX( mPointVector[ptnr3]->getX() ); p3->setY( mPointVector[ptnr3]->getY() ); p3->setZ( mPointVector[ptnr3]->getZ() ); ( *n1 ) = ptnr1; ( *n2 ) = ptnr2; ( *n3 ) = ptnr3; return true; } else if ( edge == -5 )//numerical problems in 'baseEdgeOfTriangle' { int ptnr1 = mHalfEdge[mUnstableEdge]->getPoint(); int ptnr2 = mHalfEdge[mHalfEdge[mUnstableEdge]->getNext()]->getPoint(); int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[mUnstableEdge]->getNext()]->getNext()]->getPoint(); if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 ) { return false; } p1->setX( mPointVector[ptnr1]->getX() ); p1->setY( mPointVector[ptnr1]->getY() ); p1->setZ( mPointVector[ptnr1]->getZ() ); p2->setX( mPointVector[ptnr2]->getX() ); p2->setY( mPointVector[ptnr2]->getY() ); p2->setZ( mPointVector[ptnr2]->getZ() ); p3->setX( mPointVector[ptnr3]->getX() ); p3->setY( mPointVector[ptnr3]->getY() ); p3->setZ( mPointVector[ptnr3]->getZ() ); ( *n1 ) = ptnr1; ( *n2 ) = ptnr2; ( *n3 ) = ptnr3; return true; } else//problems { QgsDebugMsg( QString( "problem: the edge is: %1" ).arg( edge ) ); return false; } } else { QgsDebugMsg( "warning, null pointer" ); return false; } } bool DualEdgeTriangulation::getTriangle( double x, double y, Point3D* p1, Point3D* p2, Point3D* p3 ) { if ( mPointVector.size() < 3 ) { return false; } if ( p1 && p2 && p3 ) { Point3D point( x, y, 0 ); int edge = baseEdgeOfTriangle( &point ); if ( edge == -10 )//the point is outside the convex hull { QgsDebugMsg( "edge outside the convex hull" ); return false; } else if ( edge >= 0 )//the point is inside the convex hull { int ptnr1 = mHalfEdge[edge]->getPoint(); int ptnr2 = mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint(); int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[edge]->getNext()]->getNext()]->getPoint(); p1->setX( mPointVector[ptnr1]->getX() ); p1->setY( mPointVector[ptnr1]->getY() ); p1->setZ( mPointVector[ptnr1]->getZ() ); p2->setX( mPointVector[ptnr2]->getX() ); p2->setY( mPointVector[ptnr2]->getY() ); p2->setZ( mPointVector[ptnr2]->getZ() ); p3->setX( mPointVector[ptnr3]->getX() ); p3->setY( mPointVector[ptnr3]->getY() ); p3->setZ( mPointVector[ptnr3]->getZ() ); return true; } else if ( edge == -20 )//the point is exactly on an edge { int ptnr1 = mHalfEdge[mEdgeWithPoint]->getPoint(); int ptnr2 = mHalfEdge[mHalfEdge[mEdgeWithPoint]->getNext()]->getPoint(); int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[mEdgeWithPoint]->getNext()]->getNext()]->getPoint(); if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 ) { return false; } p1->setX( mPointVector[ptnr1]->getX() ); p1->setY( mPointVector[ptnr1]->getY() ); p1->setZ( mPointVector[ptnr1]->getZ() ); p2->setX( mPointVector[ptnr2]->getX() ); p2->setY( mPointVector[ptnr2]->getY() ); p2->setZ( mPointVector[ptnr2]->getZ() ); p3->setX( mPointVector[ptnr3]->getX() ); p3->setY( mPointVector[ptnr3]->getY() ); p3->setZ( mPointVector[ptnr3]->getZ() ); return true; } else if ( edge == -25 )//x and y are the coordinates of an existing point { int edge1 = baseEdgeOfPoint( mTwiceInsPoint ); int edge2 = mHalfEdge[edge1]->getNext(); int edge3 = mHalfEdge[edge2]->getNext(); int ptnr1 = mHalfEdge[edge1]->getPoint(); int ptnr2 = mHalfEdge[edge2]->getPoint(); int ptnr3 = mHalfEdge[edge3]->getPoint(); if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 ) { return false; } p1->setX( mPointVector[ptnr1]->getX() ); p1->setY( mPointVector[ptnr1]->getY() ); p1->setZ( mPointVector[ptnr1]->getZ() ); p2->setX( mPointVector[ptnr2]->getX() ); p2->setY( mPointVector[ptnr2]->getY() ); p2->setZ( mPointVector[ptnr2]->getZ() ); p3->setX( mPointVector[ptnr3]->getX() ); p3->setY( mPointVector[ptnr3]->getY() ); p3->setZ( mPointVector[ptnr3]->getZ() ); return true; } else if ( edge == -5 )//numerical problems in 'baseEdgeOfTriangle' { int ptnr1 = mHalfEdge[mUnstableEdge]->getPoint(); int ptnr2 = mHalfEdge[mHalfEdge[mUnstableEdge]->getNext()]->getPoint(); int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[mUnstableEdge]->getNext()]->getNext()]->getPoint(); if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 ) { return false; } p1->setX( mPointVector[ptnr1]->getX() ); p1->setY( mPointVector[ptnr1]->getY() ); p1->setZ( mPointVector[ptnr1]->getZ() ); p2->setX( mPointVector[ptnr2]->getX() ); p2->setY( mPointVector[ptnr2]->getY() ); p2->setZ( mPointVector[ptnr2]->getZ() ); p3->setX( mPointVector[ptnr3]->getX() ); p3->setY( mPointVector[ptnr3]->getY() ); p3->setZ( mPointVector[ptnr3]->getZ() ); return true; } else//problems { QgsDebugMsg( QString( "problems: the edge is: %1" ).arg( edge ) ); return false; } } else { QgsDebugMsg( "warning, null pointer" ); return false; } } unsigned int DualEdgeTriangulation::insertEdge( int dual, int next, int point, bool mbreak, bool forced ) { HalfEdge* edge = new HalfEdge( dual, next, point, mbreak, forced ); mHalfEdge.append( edge ); return mHalfEdge.count() - 1; } int DualEdgeTriangulation::insertForcedSegment( int p1, int p2, bool breakline ) { if ( p1 == p2 ) { return 0; } //list with (half of) the crossed edges QList<int> crossedEdges; //an edge pointing to p1 int pointingedge = 0; pointingedge = baseEdgeOfPoint( p1 ); if ( pointingedge == -1 ) { return -100;//return an error code } //go around p1 and find out, if the segment already exists and if not, which is the first cutted edge int actedge = mHalfEdge[pointingedge]->getDual(); //number to prevent endless loops int control = 0; while ( true )//if it's an endless loop, something went wrong { control += 1; if ( control > 17000 ) { QgsDebugMsg( "warning, endless loop" ); return -100;//return an error code } if ( mHalfEdge[actedge]->getPoint() == -1 )//actedge points to the virtual point { actedge = mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext()]->getDual(); continue; } //test, if actedge is already the forced edge if ( mHalfEdge[actedge]->getPoint() == p2 ) { mHalfEdge[actedge]->setForced( true ); mHalfEdge[actedge]->setBreak( breakline ); mHalfEdge[mHalfEdge[actedge]->getDual()]->setForced( true ); mHalfEdge[mHalfEdge[actedge]->getDual()]->setBreak( breakline ); return actedge; } //test, if the forced segment is a multiple of actedge and if the direction is the same else if ( /*lines are parallel*/( mPointVector[p2]->getY() - mPointVector[p1]->getY() ) / ( mPointVector[mHalfEdge[actedge]->getPoint()]->getY() - mPointVector[p1]->getY() ) == ( mPointVector[p2]->getX() - mPointVector[p1]->getX() ) / ( mPointVector[mHalfEdge[actedge]->getPoint()]->getX() - mPointVector[p1]->getX() ) && (( mPointVector[p2]->getY() - mPointVector[p1]->getY() ) >= 0 ) == (( mPointVector[mHalfEdge[actedge]->getPoint()]->getY() - mPointVector[p1]->getY() ) > 0 ) && (( mPointVector[p2]->getX() - mPointVector[p1]->getX() ) >= 0 ) == (( mPointVector[mHalfEdge[actedge]->getPoint()]->getX() - mPointVector[p1]->getX() ) > 0 ) ) { //mark actedge and Dual(actedge) as forced, reset p1 and start the method from the beginning mHalfEdge[actedge]->setForced( true ); mHalfEdge[actedge]->setBreak( breakline ); mHalfEdge[mHalfEdge[actedge]->getDual()]->setForced( true ); mHalfEdge[mHalfEdge[actedge]->getDual()]->setBreak( breakline ); int a = insertForcedSegment( mHalfEdge[actedge]->getPoint(), p2, breakline ); return a; } //test, if the forced segment intersects Next(actedge) if ( mHalfEdge[mHalfEdge[actedge]->getNext()]->getPoint() == -1 )//intersection with line to the virtual point makes no sense { actedge = mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext()]->getDual(); continue; } else if ( MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[mHalfEdge[mHalfEdge[actedge]->getNext()]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getNext()]->getDual()]->getPoint()] ) ) { if ( mHalfEdge[mHalfEdge[actedge]->getNext()]->getForced() && mForcedCrossBehaviour == Triangulation::SnappingType_VERTICE )//if the crossed edge is a forced edge, we have to snap the forced line to the next node { Point3D crosspoint; int p3, p4; p3 = mHalfEdge[mHalfEdge[actedge]->getNext()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getNext()]->getDual()]->getPoint(); MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p4], &crosspoint ); double dista = sqrt(( crosspoint.getX() - mPointVector[p3]->getX() ) * ( crosspoint.getX() - mPointVector[p3]->getX() ) + ( crosspoint.getY() - mPointVector[p3]->getY() ) * ( crosspoint.getY() - mPointVector[p3]->getY() ) ); double distb = sqrt(( crosspoint.getX() - mPointVector[p4]->getX() ) * ( crosspoint.getX() - mPointVector[p4]->getX() ) + ( crosspoint.getY() - mPointVector[p4]->getY() ) * ( crosspoint.getY() - mPointVector[p4]->getY() ) ); if ( dista <= distb ) { insertForcedSegment( p1, p3, breakline ); int e = insertForcedSegment( p3, p2, breakline ); return e; } else if ( distb <= dista ) { insertForcedSegment( p1, p4, breakline ); int e = insertForcedSegment( p4, p2, breakline ); return e; } } else if ( mHalfEdge[mHalfEdge[actedge]->getNext()]->getForced() && mForcedCrossBehaviour == Triangulation::INSERT_VERTICE )//if the crossed edge is a forced edge, we have to insert a new vertice on this edge { Point3D crosspoint; int p3, p4; p3 = mHalfEdge[mHalfEdge[actedge]->getNext()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getNext()]->getDual()]->getPoint(); MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p4], &crosspoint ); double distpart = sqrt(( crosspoint.getX() - mPointVector[p4]->getX() ) * ( crosspoint.getX() - mPointVector[p4]->getX() ) + ( crosspoint.getY() - mPointVector[p4]->getY() ) * ( crosspoint.getY() - mPointVector[p4]->getY() ) ); double disttot = sqrt(( mPointVector[p3]->getX() - mPointVector[p4]->getX() ) * ( mPointVector[p3]->getX() - mPointVector[p4]->getX() ) + ( mPointVector[p3]->getY() - mPointVector[p4]->getY() ) * ( mPointVector[p3]->getY() - mPointVector[p4]->getY() ) ); float frac = distpart / disttot; if ( frac == 0 || frac == 1 )//just in case MathUtils::lineIntersection does not work as expected { if ( frac == 0 ) { //mark actedge and Dual(actedge) as forced, reset p1 and start the method from the beginning mHalfEdge[actedge]->setForced( true ); mHalfEdge[actedge]->setBreak( breakline ); mHalfEdge[mHalfEdge[actedge]->getDual()]->setForced( true ); mHalfEdge[mHalfEdge[actedge]->getDual()]->setBreak( breakline ); int a = insertForcedSegment( p4, p2, breakline ); return a; } else if ( frac == 1 ) { //mark actedge and Dual(actedge) as forced, reset p1 and start the method from the beginning mHalfEdge[actedge]->setForced( true ); mHalfEdge[actedge]->setBreak( breakline ); mHalfEdge[mHalfEdge[actedge]->getDual()]->setForced( true ); mHalfEdge[mHalfEdge[actedge]->getDual()]->setBreak( breakline ); if ( p3 != p2 ) { int a = insertForcedSegment( p3, p2, breakline ); return a; } else { return actedge; } } } else { int newpoint = splitHalfEdge( mHalfEdge[actedge]->getNext(), frac ); insertForcedSegment( p1, newpoint, breakline ); int e = insertForcedSegment( newpoint, p2, breakline ); return e; } } //add the first HalfEdge to the list of crossed edges crossedEdges.append( mHalfEdge[actedge]->getNext() ); break; } actedge = mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext()]->getDual(); } //we found the first edge, terminated the method or called the method with other points. Lets search for all the other crossed edges while ( true )//if its an endless loop, something went wrong. { if ( MathUtils::lineIntersection( mPointVector[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint()], mPointVector[p1], mPointVector[p2] ) ) { if ( mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getForced() && mForcedCrossBehaviour == Triangulation::SnappingType_VERTICE )//if the crossed edge is a forced edge and mForcedCrossBehaviour is SnappingType_VERTICE, we have to snap the forced line to the next node { Point3D crosspoint; int p3, p4; p3 = mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint(); MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p4], &crosspoint ); double dista = sqrt(( crosspoint.getX() - mPointVector[p3]->getX() ) * ( crosspoint.getX() - mPointVector[p3]->getX() ) + ( crosspoint.getY() - mPointVector[p3]->getY() ) * ( crosspoint.getY() - mPointVector[p3]->getY() ) ); double distb = sqrt(( crosspoint.getX() - mPointVector[p4]->getX() ) * ( crosspoint.getX() - mPointVector[p4]->getX() ) + ( crosspoint.getY() - mPointVector[p4]->getY() ) * ( crosspoint.getY() - mPointVector[p4]->getY() ) ); if ( dista <= distb ) { insertForcedSegment( p1, p3, breakline ); int e = insertForcedSegment( p3, p2, breakline ); return e; } else if ( distb <= dista ) { insertForcedSegment( p1, p4, breakline ); int e = insertForcedSegment( p4, p2, breakline ); return e; } } else if ( mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getForced() && mForcedCrossBehaviour == Triangulation::INSERT_VERTICE )//if the crossed edge is a forced edge, we have to insert a new vertice on this edge { Point3D crosspoint; int p3, p4; p3 = mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint(); MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p4], &crosspoint ); double distpart = sqrt(( crosspoint.getX() - mPointVector[p3]->getX() ) * ( crosspoint.getX() - mPointVector[p3]->getX() ) + ( crosspoint.getY() - mPointVector[p3]->getY() ) * ( crosspoint.getY() - mPointVector[p3]->getY() ) ); double disttot = sqrt(( mPointVector[p3]->getX() - mPointVector[p4]->getX() ) * ( mPointVector[p3]->getX() - mPointVector[p4]->getX() ) + ( mPointVector[p3]->getY() - mPointVector[p4]->getY() ) * ( mPointVector[p3]->getY() - mPointVector[p4]->getY() ) ); float frac = distpart / disttot; if ( frac == 0 || frac == 1 ) { break;//seems that a roundoff error occurred. We found the endpoint } int newpoint = splitHalfEdge( mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext(), frac ); insertForcedSegment( p1, newpoint, breakline ); int e = insertForcedSegment( newpoint, p2, breakline ); return e; } crossedEdges.append( mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext() ); continue; } else if ( MathUtils::lineIntersection( mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getPoint()], mPointVector[p1], mPointVector[p2] ) ) { if ( mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getForced() && mForcedCrossBehaviour == Triangulation::SnappingType_VERTICE )//if the crossed edge is a forced edge and mForcedCrossBehaviour is SnappingType_VERTICE, we have to snap the forced line to the next node { Point3D crosspoint; int p3, p4; p3 = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getPoint(); MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p4], &crosspoint ); double dista = sqrt(( crosspoint.getX() - mPointVector[p3]->getX() ) * ( crosspoint.getX() - mPointVector[p3]->getX() ) + ( crosspoint.getY() - mPointVector[p3]->getY() ) * ( crosspoint.getY() - mPointVector[p3]->getY() ) ); double distb = sqrt(( crosspoint.getX() - mPointVector[p4]->getX() ) * ( crosspoint.getX() - mPointVector[p4]->getX() ) + ( crosspoint.getY() - mPointVector[p4]->getY() ) * ( crosspoint.getY() - mPointVector[p4]->getY() ) ); if ( dista <= distb ) { insertForcedSegment( p1, p3, breakline ); int e = insertForcedSegment( p3, p2, breakline ); return e; } else if ( distb <= dista ) { insertForcedSegment( p1, p4, breakline ); int e = insertForcedSegment( p4, p2, breakline ); return e; } } else if ( mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getForced() && mForcedCrossBehaviour == Triangulation::INSERT_VERTICE )//if the crossed edge is a forced edge, we have to insert a new vertice on this edge { Point3D crosspoint; int p3, p4; p3 = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getPoint(); MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p4], &crosspoint ); double distpart = sqrt(( crosspoint.getX() - mPointVector[p3]->getX() ) * ( crosspoint.getX() - mPointVector[p3]->getX() ) + ( crosspoint.getY() - mPointVector[p3]->getY() ) * ( crosspoint.getY() - mPointVector[p3]->getY() ) ); double disttot = sqrt(( mPointVector[p3]->getX() - mPointVector[p4]->getX() ) * ( mPointVector[p3]->getX() - mPointVector[p4]->getX() ) + ( mPointVector[p3]->getY() - mPointVector[p4]->getY() ) * ( mPointVector[p3]->getY() - mPointVector[p4]->getY() ) ); float frac = distpart / disttot; if ( frac == 0 || frac == 1 ) { break;//seems that a roundoff error occurred. We found the endpoint } int newpoint = splitHalfEdge( mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext(), frac ); insertForcedSegment( p1, newpoint, breakline ); int e = insertForcedSegment( newpoint, p2, breakline ); return e; } crossedEdges.append( mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext() ); continue; } else//forced edge terminates { break; } } //set the flags 'forced' and 'break' to false for every edge and dualedge of 'crossEdges' QList<int>::const_iterator iter; for ( iter = crossedEdges.constBegin(); iter != crossedEdges.constEnd(); ++iter ) { mHalfEdge[( *( iter ) )]->setForced( false ); mHalfEdge[( *( iter ) )]->setBreak( false ); mHalfEdge[mHalfEdge[( *( iter ) )]->getDual()]->setForced( false ); mHalfEdge[mHalfEdge[( *( iter ) )]->getDual()]->setBreak( false ); } //crossed edges is filled, now the two polygons to be retriangulated can be build QList<int> freelist = crossedEdges;//copy the list with the crossed edges to remove the edges already reused //create the left polygon as a list of the numbers of the halfedges QList<int> leftPolygon; QList<int> rightPolygon; //insert the forced edge and enter the corresponding halfedges as the first edges in the left and right polygons. The nexts and points are set later because of the algorithm to build two polygons from 'crossedEdges' int firstedge = freelist.first();//edge pointing from p1 to p2 mHalfEdge[firstedge]->setForced( true ); mHalfEdge[firstedge]->setBreak( breakline ); leftPolygon.append( firstedge ); int dualfirstedge = mHalfEdge[freelist.first()]->getDual();//edge pointing from p2 to p1 mHalfEdge[dualfirstedge]->setForced( true ); mHalfEdge[dualfirstedge]->setBreak( breakline ); rightPolygon.append( dualfirstedge ); freelist.pop_front();//delete the first entry from the freelist //finish the polygon on the left side int actpointl = p2; QList<int>::const_iterator leftiter; //todo: is there a better way to set an iterator to the last list element? leftiter = crossedEdges.constEnd(); --leftiter; while ( true ) { int newpoint = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[( *leftiter )]->getDual()]->getNext()]->getNext()]->getPoint(); if ( newpoint != actpointl ) { //insert the edge into the leftPolygon actpointl = newpoint; int theedge = mHalfEdge[mHalfEdge[mHalfEdge[( *leftiter )]->getDual()]->getNext()]->getNext(); leftPolygon.append( theedge ); } if ( leftiter == crossedEdges.constBegin() ) {break;} --leftiter; } //insert the last element into leftPolygon leftPolygon.append( mHalfEdge[crossedEdges.first()]->getNext() ); //finish the polygon on the right side QList<int>::const_iterator rightiter; int actpointr = p1; for ( rightiter = crossedEdges.constBegin(); rightiter != crossedEdges.constEnd(); ++rightiter ) { int newpoint = mHalfEdge[mHalfEdge[mHalfEdge[( *rightiter )]->getNext()]->getNext()]->getPoint(); if ( newpoint != actpointr ) { //insert the edge into the right polygon actpointr = newpoint; int theedge = mHalfEdge[mHalfEdge[( *rightiter )]->getNext()]->getNext(); rightPolygon.append( theedge ); } } //insert the last element into rightPolygon rightPolygon.append( mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext() ); mHalfEdge[rightPolygon.last()]->setNext( dualfirstedge );//set 'Next' of the last edge to dualfirstedge //set the necessary nexts of leftPolygon(exept the first) int actedgel = leftPolygon[1]; leftiter = leftPolygon.constBegin(); leftiter += 2; for ( ; leftiter != leftPolygon.constEnd(); ++leftiter ) { mHalfEdge[actedgel]->setNext(( *leftiter ) ); actedgel = ( *leftiter ); } //set all the necessary nexts of rightPolygon int actedger = rightPolygon[1]; rightiter = rightPolygon.constBegin(); rightiter += 2; for ( ; rightiter != rightPolygon.constEnd(); ++rightiter ) { mHalfEdge[actedger]->setNext(( *rightiter ) ); actedger = ( *( rightiter ) ); } //setNext and setPoint for the forced edge because this would disturb the building of 'leftpoly' and 'rightpoly' otherwise mHalfEdge[leftPolygon.first()]->setNext(( *( ++( leftiter = leftPolygon.begin() ) ) ) ); mHalfEdge[leftPolygon.first()]->setPoint( p2 ); mHalfEdge[leftPolygon.last()]->setNext( firstedge ); mHalfEdge[rightPolygon.first()]->setNext(( *( ++( rightiter = rightPolygon.begin() ) ) ) ); mHalfEdge[rightPolygon.first()]->setPoint( p1 ); mHalfEdge[rightPolygon.last()]->setNext( dualfirstedge ); triangulatePolygon( &leftPolygon, &freelist, firstedge ); triangulatePolygon( &rightPolygon, &freelist, dualfirstedge ); //optimisation of the new edges for ( iter = crossedEdges.begin(); iter != crossedEdges.end(); ++iter ) { checkSwap(( *( iter ) ), 0 ); } return leftPolygon.first(); } void DualEdgeTriangulation::setForcedCrossBehaviour( Triangulation::forcedCrossBehaviour b ) { mForcedCrossBehaviour = b; } void DualEdgeTriangulation::setEdgeColor( int r, int g, int b ) { mEdgeColor.setRgb( r, g, b ); } void DualEdgeTriangulation::setForcedEdgeColor( int r, int g, int b ) { mForcedEdgeColor.setRgb( r, g, b ); } void DualEdgeTriangulation::setBreakEdgeColor( int r, int g, int b ) { mBreakEdgeColor.setRgb( r, g, b ); } void DualEdgeTriangulation::setTriangleInterpolator( TriangleInterpolator* interpolator ) { mTriangleInterpolator = interpolator; } void DualEdgeTriangulation::eliminateHorizontalTriangles() { QgsDebugMsg( "am in eliminateHorizontalTriangles" ); double minangle = 0;//minimum angle for swapped triangles. If triangles generated by a swap would have a minimum angle (in degrees) below that value, the swap will not be done. while ( true ) { bool swapped = false;//flag which allows exiting the loop bool* control = new bool[mHalfEdge.count()];//controlarray for ( int i = 0; i <= mHalfEdge.count() - 1; i++ ) { control[i] = false; } for ( int i = 0; i <= mHalfEdge.count() - 1; i++ ) { if ( control[i] )//edge has already been examined { continue; } int e1, e2, e3;//numbers of the three edges e1 = i; e2 = mHalfEdge[e1]->getNext(); e3 = mHalfEdge[e2]->getNext(); int p1, p2, p3;//numbers of the three points p1 = mHalfEdge[e1]->getPoint(); p2 = mHalfEdge[e2]->getPoint(); p3 = mHalfEdge[e3]->getPoint(); //skip the iteration, if one point is the virtual point if ( p1 == -1 || p2 == -1 || p3 == -1 ) { control[e1] = true; control[e2] = true; control[e3] = true; continue; } double el1, el2, el3;//elevations of the points el1 = mPointVector[p1]->getZ(); el2 = mPointVector[p2]->getZ(); el3 = mPointVector[p3]->getZ(); if ( el1 == el2 && el2 == el3 )//we found a horizonal triangle { //swap edges if it is possible, if it would remove the horizontal triangle and if the minimum angle generated by the swap is high enough if ( swapPossible(( uint )e1 ) && mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[e1]->getDual()]->getNext()]->getPoint()]->getZ() != el1 && swapMinAngle( e1 ) > minangle ) { doOnlySwap(( uint )e1 ); swapped = true; } else if ( swapPossible(( uint )e2 ) && mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[e2]->getDual()]->getNext()]->getPoint()]->getZ() != el2 && swapMinAngle( e2 ) > minangle ) { doOnlySwap(( uint )e2 ); swapped = true; } else if ( swapPossible(( uint )e3 ) && mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[e3]->getDual()]->getNext()]->getPoint()]->getZ() != el3 && swapMinAngle( e3 ) > minangle ) { doOnlySwap(( uint )e3 ); swapped = true; } control[e1] = true; control[e2] = true; control[e3] = true; continue; } else//no horizontal triangle, go to the next one { control[e1] = true; control[e2] = true; control[e3] = true; continue; } } if ( !swapped ) { delete[] control; break; } delete[] control; } QgsDebugMsg( "end of method" ); } void DualEdgeTriangulation::ruppertRefinement() { //minimum angle double mintol = 17;//refinement stops after the minimum angle reached this tolerance //data structures std::map<int, double> edge_angle;//search tree with the edge number as key std::multimap<double, int> angle_edge;//multimap (map with not unique keys) with angle as key QSet<int> dontexamine;//search tree containing the edges which do not have to be examined (because of numerical problems) //first, go through all the forced edges and subdivide if they are encroached by a point bool stop = false;//flag to ensure that the for-loop is repeated until no half edge is split any more while ( !stop ) { stop = true; int nhalfedges = mHalfEdge.count(); for ( int i = 0; i < nhalfedges - 1; i++ ) { int next = mHalfEdge[i]->getNext(); int nextnext = mHalfEdge[next]->getNext(); if ( mHalfEdge[next]->getPoint() != -1 && ( mHalfEdge[i]->getForced() || mHalfEdge[mHalfEdge[mHalfEdge[i]->getDual()]->getNext()]->getPoint() == -1 ) )//check for encroached points on forced segments and segments on the inner side of the convex hull, but don't consider edges on the outer side of the convex hull { if ( !(( mHalfEdge[next]->getForced() || edgeOnConvexHull( next ) ) || ( mHalfEdge[nextnext]->getForced() || edgeOnConvexHull( nextnext ) ) ) )//don't consider triangles where all three edges are forced edges or hull edges { //test for encroachment while ( MathUtils::inDiametral( mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()], mPointVector[mHalfEdge[i]->getPoint()], mPointVector[mHalfEdge[next]->getPoint()] ) ) { //split segment int pointno = splitHalfEdge( i, 0.5 ); Q_UNUSED( pointno ); stop = false; } } } } } //examine the triangulation for angles below the minimum and insert the edges into angle_edge and edge_angle, except the small angle is between forced segments or convex hull edges double angle;//angle between edge i and the consecutive edge int p1, p2, p3;//numbers of the triangle points for ( int i = 0; i < mHalfEdge.count() - 1; i++ ) { p1 = mHalfEdge[mHalfEdge[i]->getDual()]->getPoint(); p2 = mHalfEdge[i]->getPoint(); p3 = mHalfEdge[mHalfEdge[i]->getNext()]->getPoint(); if ( p1 == -1 || p2 == -1 || p3 == -1 )//don't consider triangles with the virtual point { continue; } angle = MathUtils::angle( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p2] ); bool twoforcededges;//flag to decide, if edges should be added to the maps. Do not add them if true if (( mHalfEdge[i]->getForced() || edgeOnConvexHull( i ) ) && ( mHalfEdge[mHalfEdge[i]->getNext()]->getForced() || edgeOnConvexHull( mHalfEdge[i]->getNext() ) ) ) { twoforcededges = true; } else { twoforcededges = false; } if ( angle < mintol && !twoforcededges ) { edge_angle.insert( std::make_pair( i, angle ) ); angle_edge.insert( std::make_pair( angle, i ) ); } } //debugging: print out all the angles below the minimum for a test for ( std::multimap<double, int>::const_iterator it = angle_edge.begin(); it != angle_edge.end(); ++it ) { QgsDebugMsg( QString( "angle: %1" ).arg( it->first ) ); } double minangle = 0;//actual minimum angle int minedge;//first edge adjacent to the minimum angle int minedgenext; int minedgenextnext; Point3D circumcenter; while ( !edge_angle.empty() ) { minangle = angle_edge.begin()->first; QgsDebugMsg( QString( "minangle: %1" ).arg( minangle ) ); minedge = angle_edge.begin()->second; minedgenext = mHalfEdge[minedge]->getNext(); minedgenextnext = mHalfEdge[minedgenext]->getNext(); //calculate the circumcenter if ( !MathUtils::circumcenter( mPointVector[mHalfEdge[minedge]->getPoint()], mPointVector[mHalfEdge[minedgenext]->getPoint()], mPointVector[mHalfEdge[minedgenextnext]->getPoint()], &circumcenter ) ) { QgsDebugMsg( "warning, calculation of circumcenter failed" ); //put all three edges to dontexamine and remove them from the other maps dontexamine.insert( minedge ); edge_angle.erase( minedge ); std::multimap<double, int>::iterator minedgeiter = angle_edge.find( minangle ); while ( minedgeiter->second != minedge ) { ++minedgeiter; } angle_edge.erase( minedgeiter ); continue; } if ( !pointInside( circumcenter.getX(), circumcenter.getY() ) ) { //put all three edges to dontexamine and remove them from the other maps QgsDebugMsg( QString( "put circumcenter %1//%2 on dontexamine list because it is outside the convex hull" ) .arg( circumcenter.getX() ).arg( circumcenter.getY() ) ); dontexamine.insert( minedge ); edge_angle.erase( minedge ); std::multimap<double, int>::iterator minedgeiter = angle_edge.find( minangle ); while ( minedgeiter->second != minedge ) { ++minedgeiter; } angle_edge.erase( minedgeiter ); continue; } /*******find out, if any forced segment or convex hull segment is in the influence region of the circumcenter. In this case, split the segment********************/ bool encroached = false; #if 0 //slow version int numhalfedges = mHalfEdge.count();//begin slow version for ( int i = 0; i < numhalfedges; i++ ) { if ( mHalfEdge[i]->getForced() || edgeOnConvexHull( i ) ) { if ( MathUtils::inDiametral( mPointVector[mHalfEdge[i]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()], &circumcenter ) ) { encroached = true; //split segment QgsDebugMsg( "segment split" ); int pointno = splitHalfEdge( i, 0.5 ); //update dontexmine, angle_edge, edge_angle int pointingedge = baseEdgeOfPoint( pointno ); int actedge = pointingedge; int ed1, ed2, ed3;//numbers of the three edges int pt1, pt2, pt3;//numbers of the three points double angle1, angle2, angle3; do { ed1 = mHalfEdge[actedge]->getDual(); pt1 = mHalfEdge[ed1]->getPoint(); ed2 = mHalfEdge[ed1]->getNext(); pt2 = mHalfEdge[ed2]->getPoint(); ed3 = mHalfEdge[ed2]->getNext(); pt3 = mHalfEdge[ed3]->getPoint(); actedge = ed3; if ( pt1 == -1 || pt2 == -1 || pt3 == -1 )//don't consider triangles with the virtual point { continue; } angle1 = MathUtils::angle( mPointVector[pt3], mPointVector[pt1], mPointVector[pt2], mPointVector[pt1] ); angle2 = MathUtils::angle( mPointVector[pt1], mPointVector[pt2], mPointVector[pt3], mPointVector[pt2] ); angle3 = MathUtils::angle( mPointVector[pt2], mPointVector[pt3], mPointVector[pt1], mPointVector[pt3] ); //don't put the edges on the maps if two segments are forced or on a hull bool twoforcededges1, twoforcededges2, twoforcededges3;//flag to indicate, if angle1, angle2 and angle3 are between forced edges or hull edges if (( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) && ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) ) { twoforcededges1 = true; } else { twoforcededges1 = false; } if (( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) && ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) ) { twoforcededges2 = true; } else { twoforcededges2 = false; } if (( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) && ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) ) { twoforcededges3 = true; } else { twoforcededges3 = false; } //update the settings related to ed1 QSet<int>::iterator ed1iter = dontexamine.find( ed1 ); if ( ed1iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed1iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed1 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed1 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed1 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle1 < mintol && !twoforcededges1 ) { edge_angle.insert( std::make_pair( ed1, angle1 ) ); angle_edge.insert( std::make_pair( angle1, ed1 ) ); } //update the settings related to ed2 QSet<int>::iterator ed2iter = dontexamine.find( ed2 ); if ( ed2iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed2iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed2 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed2 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed2 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle2 < mintol && !twoforcededges2 ) { edge_angle.insert( std::make_pair( ed2, angle2 ) ); angle_edge.insert( std::make_pair( angle2, ed2 ) ); } //update the settings related to ed3 QSet<int>::iterator ed3iter = dontexamine.find( ed3 ); if ( ed3iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed3iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed3 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed3 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed3 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle3 < mintol && !twoforcededges3 ) { edge_angle.insert( std::make_pair( ed3, angle3 ) ); angle_edge.insert( std::make_pair( angle3, ed3 ) ); } } while ( actedge != pointingedge ); } } } #endif //end slow version //fast version. Maybe this does not work QSet<int> influenceedges;//begin fast method int baseedge = baseEdgeOfTriangle( &circumcenter ); if ( baseedge == -5 )//a numerical instability occurred or the circumcenter already exists in the triangulation { //delete minedge from edge_angle and minangle from angle_edge edge_angle.erase( minedge ); std::multimap<double, int>::iterator minedgeiter = angle_edge.find( minangle ); while ( minedgeiter->second != minedge ) { ++minedgeiter; } angle_edge.erase( minedgeiter ); continue; } else if ( baseedge == -25 )//circumcenter already exists in the triangulation { //delete minedge from edge_angle and minangle from angle_edge edge_angle.erase( minedge ); std::multimap<double, int>::iterator minedgeiter = angle_edge.find( minangle ); while ( minedgeiter->second != minedge ) { ++minedgeiter; } angle_edge.erase( minedgeiter ); continue; } else if ( baseedge == -20 ) { baseedge = mEdgeWithPoint; } evaluateInfluenceRegion( &circumcenter, baseedge, influenceedges ); evaluateInfluenceRegion( &circumcenter, mHalfEdge[baseedge]->getNext(), influenceedges ); evaluateInfluenceRegion( &circumcenter, mHalfEdge[mHalfEdge[baseedge]->getNext()]->getNext(), influenceedges ); for ( QSet<int>::iterator it = influenceedges.begin(); it != influenceedges.end(); ++it ) { if (( mHalfEdge[*it]->getForced() || edgeOnConvexHull( *it ) ) && MathUtils::inDiametral( mPointVector[mHalfEdge[*it]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[*it]->getDual()]->getPoint()], &circumcenter ) ) { //split segment QgsDebugMsg( "segment split" ); int pointno = splitHalfEdge( *it, 0.5 ); encroached = true; //update dontexmine, angle_edge, edge_angle int pointingedge = baseEdgeOfPoint( pointno ); int actedge = pointingedge; int ed1, ed2, ed3;//numbers of the three edges int pt1, pt2, pt3;//numbers of the three points double angle1, angle2, angle3; do { ed1 = mHalfEdge[actedge]->getDual(); pt1 = mHalfEdge[ed1]->getPoint(); ed2 = mHalfEdge[ed1]->getNext(); pt2 = mHalfEdge[ed2]->getPoint(); ed3 = mHalfEdge[ed2]->getNext(); pt3 = mHalfEdge[ed3]->getPoint(); actedge = ed3; if ( pt1 == -1 || pt2 == -1 || pt3 == -1 )//don't consider triangles with the virtual point { continue; } angle1 = MathUtils::angle( mPointVector[pt3], mPointVector[pt1], mPointVector[pt2], mPointVector[pt1] ); angle2 = MathUtils::angle( mPointVector[pt1], mPointVector[pt2], mPointVector[pt3], mPointVector[pt2] ); angle3 = MathUtils::angle( mPointVector[pt2], mPointVector[pt3], mPointVector[pt1], mPointVector[pt3] ); //don't put the edges on the maps if two segments are forced or on a hull bool twoforcededges1, twoforcededges2, twoforcededges3;//flag to decide, if edges should be added to the maps. Do not add them if true if (( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) && ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) ) { twoforcededges1 = true; } else { twoforcededges1 = false; } if (( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) && ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) ) { twoforcededges2 = true; } else { twoforcededges2 = false; } if (( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) && ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) ) { twoforcededges3 = true; } else { twoforcededges3 = false; } //update the settings related to ed1 QSet<int>::iterator ed1iter = dontexamine.find( ed1 ); if ( ed1iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed1iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed1 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed1 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed1 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle1 < mintol && !twoforcededges1 ) { edge_angle.insert( std::make_pair( ed1, angle1 ) ); angle_edge.insert( std::make_pair( angle1, ed1 ) ); } //update the settings related to ed2 QSet<int>::iterator ed2iter = dontexamine.find( ed2 ); if ( ed2iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed2iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed2 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed2 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed2 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle2 < mintol && !twoforcededges2 ) { edge_angle.insert( std::make_pair( ed2, angle2 ) ); angle_edge.insert( std::make_pair( angle2, ed2 ) ); } //update the settings related to ed3 QSet<int>::iterator ed3iter = dontexamine.find( ed3 ); if ( ed3iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed3iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed3 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed3 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed3 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle3 < mintol && !twoforcededges3 ) { edge_angle.insert( std::make_pair( ed3, angle3 ) ); angle_edge.insert( std::make_pair( angle3, ed3 ) ); } } while ( actedge != pointingedge ); } } //end fast method if ( encroached ) { continue; } /*******otherwise, try to add the circumcenter to the triangulation************************************************************************************************/ Point3D* p = new Point3D(); mDecorator->calcPoint( circumcenter.getX(), circumcenter.getY(), p ); int pointno = mDecorator->addPoint( p ); if ( pointno == -100 || pointno == mTwiceInsPoint ) { if ( pointno == -100 ) { QgsDebugMsg( QString( "put circumcenter %1//%2 on dontexamine list because of numerical instabilities" ) .arg( circumcenter.getX() ).arg( circumcenter.getY() ) ); } else if ( pointno == mTwiceInsPoint ) { QgsDebugMsg( QString( "put circumcenter %1//%2 on dontexamine list because it is already inserted" ) .arg( circumcenter.getX() ).arg( circumcenter.getY() ) ); //test, if the point is present in the triangulation bool flag = false; for ( int i = 0; i < mPointVector.count(); i++ ) { if ( mPointVector[i]->getX() == circumcenter.getX() && mPointVector[i]->getY() == circumcenter.getY() ) { flag = true; } } if ( !flag ) { QgsDebugMsg( "point is not present in the triangulation" ); } } //put all three edges to dontexamine and remove them from the other maps dontexamine.insert( minedge ); edge_angle.erase( minedge ); std::multimap<double, int>::iterator minedgeiter = angle_edge.lower_bound( minangle ); while ( minedgeiter->second != minedge ) { ++minedgeiter; } angle_edge.erase( minedgeiter ); continue; } else//insertion successful { QgsDebugMsg( "circumcenter added" ); //update the maps //go around the inserted point and make changes for every half edge int pointingedge = baseEdgeOfPoint( pointno ); int actedge = pointingedge; int ed1, ed2, ed3;//numbers of the three edges int pt1, pt2, pt3;//numbers of the three points double angle1, angle2, angle3; do { ed1 = mHalfEdge[actedge]->getDual(); pt1 = mHalfEdge[ed1]->getPoint(); ed2 = mHalfEdge[ed1]->getNext(); pt2 = mHalfEdge[ed2]->getPoint(); ed3 = mHalfEdge[ed2]->getNext(); pt3 = mHalfEdge[ed3]->getPoint(); actedge = ed3; if ( pt1 == -1 || pt2 == -1 || pt3 == -1 )//don't consider triangles with the virtual point { continue; } angle1 = MathUtils::angle( mPointVector[pt3], mPointVector[pt1], mPointVector[pt2], mPointVector[pt1] ); angle2 = MathUtils::angle( mPointVector[pt1], mPointVector[pt2], mPointVector[pt3], mPointVector[pt2] ); angle3 = MathUtils::angle( mPointVector[pt2], mPointVector[pt3], mPointVector[pt1], mPointVector[pt3] ); //todo: put all three edges on the dontexamine list if two edges are forced or convex hull edges bool twoforcededges1, twoforcededges2, twoforcededges3; if (( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) && ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) ) { twoforcededges1 = true; } else { twoforcededges1 = false; } if (( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) && ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) ) { twoforcededges2 = true; } else { twoforcededges2 = false; } if (( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) && ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) ) { twoforcededges3 = true; } else { twoforcededges3 = false; } //update the settings related to ed1 QSet<int>::iterator ed1iter = dontexamine.find( ed1 ); if ( ed1iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed1iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed1 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed1 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed1 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle1 < mintol && !twoforcededges1 ) { edge_angle.insert( std::make_pair( ed1, angle1 ) ); angle_edge.insert( std::make_pair( angle1, ed1 ) ); } //update the settings related to ed2 QSet<int>::iterator ed2iter = dontexamine.find( ed2 ); if ( ed2iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed2iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed2 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed2 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed2 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle2 < mintol && !twoforcededges2 ) { edge_angle.insert( std::make_pair( ed2, angle2 ) ); angle_edge.insert( std::make_pair( angle2, ed2 ) ); } //update the settings related to ed3 QSet<int>::iterator ed3iter = dontexamine.find( ed3 ); if ( ed3iter != dontexamine.end() ) { //edge number is on dontexamine list dontexamine.erase( ed3iter ); } else { //test, if it is on edge_angle and angle_edge and erase them if yes std::map<int, double>::iterator tempit1; tempit1 = edge_angle.find( ed3 ); if ( tempit1 != edge_angle.end() ) { //erase the entries double angle = tempit1->second; edge_angle.erase( ed3 ); std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle ); while ( tempit2->second != ed3 ) { ++tempit2; } angle_edge.erase( tempit2 ); } } if ( angle3 < mintol && !twoforcededges3 ) { edge_angle.insert( std::make_pair( ed3, angle3 ) ); angle_edge.insert( std::make_pair( angle3, ed3 ) ); } } while ( actedge != pointingedge ); } } #if 0 //debugging: print out all edge of dontexamine for ( QSet<int>::iterator it = dontexamine.begin(); it != dontexamine.end(); ++it ) { QgsDebugMsg( QString( "edge nr. %1 is in dontexamine" ).arg( *it ) ); } #endif } bool DualEdgeTriangulation::swapPossible( unsigned int edge ) { //test, if edge belongs to a forced edge if ( mHalfEdge[edge]->getForced() ) { return false; } //test, if the edge is on the convex hull or is connected to the virtual point if ( mHalfEdge[edge]->getPoint() == -1 || mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint() == -1 || mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint() == -1 || mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint() == -1 ) { return false; } //then, test, if the edge is in the middle of a not convex quad Point3D* pta = mPointVector[mHalfEdge[edge]->getPoint()]; Point3D* ptb = mPointVector[mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint()]; Point3D* ptc = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[edge]->getNext()]->getNext()]->getPoint()]; Point3D* ptd = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint()]; if ( MathUtils::leftOf( ptc, pta, ptb ) > leftOfTresh ) { return false; } else if ( MathUtils::leftOf( ptd, ptb, ptc ) > leftOfTresh ) { return false; } else if ( MathUtils::leftOf( pta, ptc, ptd ) > leftOfTresh ) { return false; } else if ( MathUtils::leftOf( ptb, ptd, pta ) > leftOfTresh ) { return false; } return true; } void DualEdgeTriangulation::triangulatePolygon( QList<int>* poly, QList<int>* free, int mainedge ) { if ( poly && free ) { if ( poly->count() == 3 )//polygon is already a triangle { return; } //search for the edge pointing on the closest point(distedge) and for the next(nextdistedge) QList<int>::const_iterator iterator = ++( poly->constBegin() );//go to the second edge double distance = MathUtils::distPointFromLine( mPointVector[mHalfEdge[( *iterator )]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[mainedge]->getPoint()] ); int distedge = ( *iterator ); int nextdistedge = mHalfEdge[( *iterator )]->getNext(); ++iterator; while ( iterator != --( poly->constEnd() ) ) { if ( MathUtils::distPointFromLine( mPointVector[mHalfEdge[( *iterator )]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[mainedge]->getPoint()] ) < distance ) { distedge = ( *iterator ); nextdistedge = mHalfEdge[( *iterator )]->getNext(); distance = MathUtils::distPointFromLine( mPointVector[mHalfEdge[( *iterator )]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[mainedge]->getPoint()] ); } ++iterator; } if ( nextdistedge == ( *( --poly->end() ) ) )//the nearest point is connected to the endpoint of mainedge { int inserta = free->first();//take an edge from the freelist int insertb = mHalfEdge[inserta]->getDual(); free->pop_front(); mHalfEdge[inserta]->setNext(( poly->at( 1 ) ) ); mHalfEdge[inserta]->setPoint( mHalfEdge[mainedge]->getPoint() ); mHalfEdge[insertb]->setNext( nextdistedge ); mHalfEdge[insertb]->setPoint( mHalfEdge[distedge]->getPoint() ); mHalfEdge[distedge]->setNext( inserta ); mHalfEdge[mainedge]->setNext( insertb ); QList<int> polya; for ( iterator = ( ++( poly->constBegin() ) ); ( *iterator ) != nextdistedge; ++iterator ) { polya.append(( *iterator ) ); } polya.prepend( inserta ); #if 0 //print out all the elements of polya for a test for ( iterator = polya.begin(); iterator != polya.end(); ++iterator ) { QgsDebugMsg( *iterator ); } #endif triangulatePolygon( &polya, free, inserta ); } else if ( distedge == ( *( ++poly->begin() ) ) )//the nearest point is connected to the beginpoint of mainedge { int inserta = free->first();//take an edge from the freelist int insertb = mHalfEdge[inserta]->getDual(); free->pop_front(); mHalfEdge[inserta]->setNext(( poly->at( 2 ) ) ); mHalfEdge[inserta]->setPoint( mHalfEdge[distedge]->getPoint() ); mHalfEdge[insertb]->setNext( mainedge ); mHalfEdge[insertb]->setPoint( mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint() ); mHalfEdge[distedge]->setNext( insertb ); mHalfEdge[( *( --poly->end() ) )]->setNext( inserta ); QList<int> polya; iterator = poly->constBegin(); iterator += 2; while ( iterator != poly->constEnd() ) { polya.append(( *iterator ) ); ++iterator; } polya.prepend( inserta ); triangulatePolygon( &polya, free, inserta ); } else//the nearest point is not connected to an endpoint of mainedge { int inserta = free->first();//take an edge from the freelist int insertb = mHalfEdge[inserta]->getDual(); free->pop_front(); int insertc = free->first(); int insertd = mHalfEdge[insertc]->getDual(); free->pop_front(); mHalfEdge[inserta]->setNext(( poly->at( 1 ) ) ); mHalfEdge[inserta]->setPoint( mHalfEdge[mainedge]->getPoint() ); mHalfEdge[insertb]->setNext( insertd ); mHalfEdge[insertb]->setPoint( mHalfEdge[distedge]->getPoint() ); mHalfEdge[insertc]->setNext( nextdistedge ); mHalfEdge[insertc]->setPoint( mHalfEdge[distedge]->getPoint() ); mHalfEdge[insertd]->setNext( mainedge ); mHalfEdge[insertd]->setPoint( mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint() ); mHalfEdge[distedge]->setNext( inserta ); mHalfEdge[mainedge]->setNext( insertb ); mHalfEdge[( *( --poly->end() ) )]->setNext( insertc ); //build two new polygons for recursive triangulation QList<int> polya; QList<int> polyb; for ( iterator = ++( poly->constBegin() ); ( *iterator ) != nextdistedge; ++iterator ) { polya.append(( *iterator ) ); } polya.prepend( inserta ); while ( iterator != poly->constEnd() ) { polyb.append(( *iterator ) ); ++iterator; } polyb.prepend( insertc ); triangulatePolygon( &polya, free, inserta ); triangulatePolygon( &polyb, free, insertc ); } } else { QgsDebugMsg( "warning, null pointer" ); } } bool DualEdgeTriangulation::pointInside( double x, double y ) { Point3D point( x, y, 0 ); unsigned int actedge = mEdgeInside;//start with an edge which does not point to the virtual point int counter = 0;//number of consecutive successful left-of-tests int nulls = 0;//number of left-of-tests, which returned 0. 1 means, that the point is on a line, 2 means that it is on an existing point int numinstabs = 0;//number of suspect left-of-tests due to 'leftOfTresh' int runs = 0;//counter for the number of iterations in the loop to prevent an endless loop while ( true ) { if ( runs > nBaseOfRuns )//prevents endless loops { QgsDebugMsg( QString( "warning, instability detected: Point coordinates: %1//%2" ).arg( x ).arg( y ) ); return false; } if ( MathUtils::leftOf( &point, mPointVector[mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[actedge]->getPoint()] ) < ( -leftOfTresh ) )//point is on the left side { counter += 1; if ( counter == 3 )//three successful passes means that we have found the triangle { break; } } else if ( MathUtils::leftOf( &point, mPointVector[mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[actedge]->getPoint()] ) == 0 )//point is exactly in the line of the edge { counter += 1; mEdgeWithPoint = actedge; nulls += 1; if ( counter == 3 )//three successful passes means that we have found the triangle { break; } } else if ( MathUtils::leftOf( &point, mPointVector[mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[actedge]->getPoint()] ) < leftOfTresh )//numerical problems { counter += 1; numinstabs += 1; if ( counter == 3 )//three successful passes means that we have found the triangle { break; } } else//point is on the right side { actedge = mHalfEdge[actedge]->getDual(); counter = 1; nulls = 0; numinstabs = 0; } actedge = mHalfEdge[actedge]->getNext(); if ( mHalfEdge[actedge]->getPoint() == -1 )//the half edge points to the virtual point { if ( nulls == 1 )//point is exactly on the convex hull { return true; } mEdgeOutside = ( unsigned int )mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext(); return false;//the point is outside the convex hull } runs++; } if ( nulls == 2 )//we hit an existing point { return true; } if ( numinstabs > 0 )//a numerical instability occurred { QgsDebugMsg( "numerical instabilities" ); return true; } if ( nulls == 1 )//point is on an existing edge { return true; } mEdgeInside = actedge; return true; } #if 0 bool DualEdgeTriangulation::readFromTAFF( QString filename ) { QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );//change the cursor QFile file( filename );//the file to be read file.open( IO_Raw | IO_ReadOnly ); QBuffer buffer( file.readAll() );//the buffer to copy the file to file.close(); QTextStream textstream( &buffer ); buffer.open( IO_ReadOnly ); QString buff; int numberofhalfedges; int numberofpoints; //edge section while ( buff.mid( 0, 4 ) != "TRIA" )//search for the TRIA-section { buff = textstream.readLine(); } while ( buff.mid( 0, 4 ) != "NEDG" ) { buff = textstream.readLine(); } numberofhalfedges = buff.section( ' ', 1, 1 ).toInt(); mHalfEdge.resize( numberofhalfedges ); while ( buff.mid( 0, 4 ) != "DATA" )//search for the data section { textstream >> buff; } int nr1, nr2, dual1, dual2, point1, point2, next1, next2, fo1, fo2, b1, b2; bool forced1, forced2, break1, break2; //import all the DualEdges QProgressBar* edgebar = new QProgressBar();//use a progress dialog so that it is not boring for the user edgebar->setCaption( "Reading edges..." ); edgebar->setTotalSteps( numberofhalfedges / 2 ); edgebar->setMinimumWidth( 400 ); edgebar->move( 500, 500 ); edgebar->show(); for ( int i = 0; i < numberofhalfedges / 2; i++ ) { if ( i % 1000 == 0 ) { edgebar->setProgress( i ); } textstream >> nr1; textstream >> point1; textstream >> next1; textstream >> fo1; if ( fo1 == 0 ) { forced1 = false; } else { forced1 = true; } textstream >> b1; if ( b1 == 0 ) { break1 = false; } else { break1 = true; } textstream >> nr2; textstream >> point2; textstream >> next2; textstream >> fo2; if ( fo2 == 0 ) { forced2 = false; } else { forced2 = true; } textstream >> b2; if ( b2 == 0 ) { break2 = false; } else { break2 = true; } HalfEdge* hf1 = new HalfEdge(); hf1->setDual( nr2 ); hf1->setNext( next1 ); hf1->setPoint( point1 ); hf1->setBreak( break1 ); hf1->setForced( forced1 ); HalfEdge* hf2 = new HalfEdge(); hf2->setDual( nr1 ); hf2->setNext( next2 ); hf2->setPoint( point2 ); hf2->setBreak( break2 ); hf2->setForced( forced2 ); // QgsDebugMsg( QString( "inserting half edge pair %1" ).arg( i ) ); mHalfEdge.insert( nr1, hf1 ); mHalfEdge.insert( nr2, hf2 ); } edgebar->setProgress( numberofhalfedges / 2 ); delete edgebar; //set mEdgeInside to a reasonable value for ( int i = 0; i < numberofhalfedges; i++ ) { int a, b, c, d; a = mHalfEdge[i]->getPoint(); b = mHalfEdge[mHalfEdge[i]->getDual()]->getPoint(); c = mHalfEdge[mHalfEdge[i]->getNext()]->getPoint(); d = mHalfEdge[mHalfEdge[mHalfEdge[i]->getDual()]->getNext()]->getPoint(); if ( a != -1 && b != -1 && c != -1 && d != -1 ) { mEdgeInside = i; break; } } //point section while ( buff.mid( 0, 4 ) != "POIN" ) { buff = textstream.readLine(); QgsDebugMsg( buff ); } while ( buff.mid( 0, 4 ) != "NPTS" ) { buff = textstream.readLine(); QgsDebugMsg( buff ); } numberofpoints = buff.section( ' ', 1, 1 ).toInt(); mPointVector.resize( numberofpoints ); while ( buff.mid( 0, 4 ) != "DATA" ) { textstream >> buff; } QProgressBar* pointbar = new QProgressBar(); pointbar->setCaption( "Reading points..." ); pointbar->setTotalSteps( numberofpoints ); pointbar->setMinimumWidth( 400 ); pointbar->move( 500, 500 ); pointbar->show(); double x, y, z; for ( int i = 0; i < numberofpoints; i++ ) { if ( i % 1000 == 0 ) { pointbar->setProgress( i ); } textstream >> x; textstream >> y; textstream >> z; Point3D* p = new Point3D( x, y, z ); // QgsDebugMsg( QString( "inserting point %1" ).arg( i ) ); mPointVector.insert( i, p ); if ( i == 0 ) { xMin = x; xMax = x; yMin = y; yMax = y; } else { //update the bounding box if ( x < xMin ) { xMin = x; } else if ( x > xMax ) { xMax = x; } if ( y < yMin ) { yMin = y; } else if ( y > yMax ) { yMax = y; } } } pointbar->setProgress( numberofpoints ); delete pointbar; QApplication::restoreOverrideCursor(); } bool DualEdgeTriangulation::saveToTAFF( QString filename ) const { QFile outputfile( filename ); if ( !outputfile.open( IO_WriteOnly ) ) { QMessageBox::warning( 0, "warning", "File could not be written", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton ); return false; } QTextStream outstream( &outputfile ); outstream.precision( 9 ); //export the edges. Attention, dual edges must be adjacent in the TAFF-file outstream << "TRIA" << std::endl << std::flush; outstream << "NEDG " << mHalfEdge.count() << std::endl << std::flush; outstream << "PANO 1" << std::endl << std::flush; outstream << "DATA "; bool* cont = new bool[mHalfEdge.count()]; for ( unsigned int i = 0; i <= mHalfEdge.count() - 1; i++ ) { cont[i] = false; } for ( unsigned int i = 0; i < mHalfEdge.count(); i++ ) { if ( cont[i] ) { continue; } int dual = mHalfEdge[i]->getDual(); outstream << i << " " << mHalfEdge[i]->getPoint() << " " << mHalfEdge[i]->getNext() << " " << mHalfEdge[i]->getForced() << " " << mHalfEdge[i]->getBreak() << " "; outstream << dual << " " << mHalfEdge[dual]->getPoint() << " " << mHalfEdge[dual]->getNext() << " " << mHalfEdge[dual]->getForced() << " " << mHalfEdge[dual]->getBreak() << " "; cont[i] = true; cont[dual] = true; } outstream << std::endl << std::flush; outstream << std::endl << std::flush; delete[] cont; //export the points to the file outstream << "POIN" << std::endl << std::flush; outstream << "NPTS " << getNumberOfPoints() << std::endl << std::flush; outstream << "PATT 3" << std::endl << std::flush; outstream << "DATA "; for ( int i = 0; i < getNumberOfPoints(); i++ ) { Point3D* p = mPointVector[i]; outstream << p->getX() << " " << p->getY() << " " << p->getZ() << " "; } outstream << std::endl << std::flush; outstream << std::endl << std::flush; return true; } #endif //0 bool DualEdgeTriangulation::swapEdge( double x, double y ) { Point3D p( x, y, 0 ); int edge1 = baseEdgeOfTriangle( &p ); if ( edge1 >= 0 ) { int edge2, edge3; Point3D* point1; Point3D* point2; Point3D* point3; edge2 = mHalfEdge[edge1]->getNext(); edge3 = mHalfEdge[edge2]->getNext(); point1 = getPoint( mHalfEdge[edge1]->getPoint() ); point2 = getPoint( mHalfEdge[edge2]->getPoint() ); point3 = getPoint( mHalfEdge[edge3]->getPoint() ); if ( point1 && point2 && point3 ) { //find out the closest edge to the point and swap this edge double dist1, dist2, dist3; dist1 = MathUtils::distPointFromLine( &p, point3, point1 ); dist2 = MathUtils::distPointFromLine( &p, point1, point2 ); dist3 = MathUtils::distPointFromLine( &p, point2, point3 ); if ( dist1 <= dist2 && dist1 <= dist3 ) { //qWarning("edge "+QString::number(edge1)+" is closest"); if ( swapPossible( edge1 ) ) { doOnlySwap( edge1 ); } } else if ( dist2 <= dist1 && dist2 <= dist3 ) { //qWarning("edge "+QString::number(edge2)+" is closest"); if ( swapPossible( edge2 ) ) { doOnlySwap( edge2 ); } } else if ( dist3 <= dist1 && dist3 <= dist2 ) { //qWarning("edge "+QString::number(edge3)+" is closest"); if ( swapPossible( edge3 ) ) { doOnlySwap( edge3 ); } } return true; } else { // QgsDebugMsg("warning: null pointer"); return false; } } else { // QgsDebugMsg("Edge number negative"); return false; } } QList<int>* DualEdgeTriangulation::getPointsAroundEdge( double x, double y ) { Point3D p( x, y, 0 ); int p1, p2, p3, p4; int edge1 = baseEdgeOfTriangle( &p ); if ( edge1 >= 0 ) { int edge2, edge3; Point3D* point1; Point3D* point2; Point3D* point3; edge2 = mHalfEdge[edge1]->getNext(); edge3 = mHalfEdge[edge2]->getNext(); point1 = getPoint( mHalfEdge[edge1]->getPoint() ); point2 = getPoint( mHalfEdge[edge2]->getPoint() ); point3 = getPoint( mHalfEdge[edge3]->getPoint() ); if ( point1 && point2 && point3 ) { double dist1, dist2, dist3; dist1 = MathUtils::distPointFromLine( &p, point3, point1 ); dist2 = MathUtils::distPointFromLine( &p, point1, point2 ); dist3 = MathUtils::distPointFromLine( &p, point2, point3 ); if ( dist1 <= dist2 && dist1 <= dist3 ) { p1 = mHalfEdge[edge1]->getPoint(); p2 = mHalfEdge[mHalfEdge[edge1]->getNext()]->getPoint(); p3 = mHalfEdge[mHalfEdge[edge1]->getDual()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[edge1]->getDual()]->getNext()]->getPoint(); } else if ( dist2 <= dist1 && dist2 <= dist3 ) { p1 = mHalfEdge[edge2]->getPoint(); p2 = mHalfEdge[mHalfEdge[edge2]->getNext()]->getPoint(); p3 = mHalfEdge[mHalfEdge[edge2]->getDual()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[edge2]->getDual()]->getNext()]->getPoint(); } else if ( dist3 <= dist1 && dist3 <= dist2 ) { p1 = mHalfEdge[edge3]->getPoint(); p2 = mHalfEdge[mHalfEdge[edge3]->getNext()]->getPoint(); p3 = mHalfEdge[mHalfEdge[edge3]->getDual()]->getPoint(); p4 = mHalfEdge[mHalfEdge[mHalfEdge[edge3]->getDual()]->getNext()]->getPoint(); } QList<int>* list = new QList<int>(); list->append( p1 ); list->append( p2 ); list->append( p3 ); list->append( p4 ); return list; } else { QgsDebugMsg( "warning: null pointer" ); return nullptr; } } else { QgsDebugMsg( "Edge number negative" ); return nullptr; } } bool DualEdgeTriangulation::saveAsShapefile( const QString& fileName ) const { QString shapeFileName = fileName; QgsFields fields; fields.append( QgsField( "type", QVariant::String, "String" ) ); // add the extension if not present if ( shapeFileName.indexOf( ".shp" ) == -1 ) { shapeFileName += ".shp"; } //delete already existing files if ( QFile::exists( shapeFileName ) ) { if ( !QgsVectorFileWriter::deleteShapeFile( shapeFileName ) ) { return false; } } QgsVectorFileWriter writer( shapeFileName, "Utf-8", fields, Qgis::WKBLineString ); if ( writer.hasError() != QgsVectorFileWriter::NoError ) { return false; } bool *alreadyVisitedEdges = new bool[mHalfEdge.size()]; if ( !alreadyVisitedEdges ) { QgsDebugMsg( "out of memory" ); return false; } for ( int i = 0; i < mHalfEdge.size(); ++i ) { alreadyVisitedEdges[i] = false; } for ( int i = 0; i < mHalfEdge.size(); ++i ) { HalfEdge* currentEdge = mHalfEdge[i]; if ( currentEdge->getPoint() != -1 && mHalfEdge[currentEdge->getDual()]->getPoint() != -1 && !alreadyVisitedEdges[currentEdge->getDual()] ) { QgsFeature edgeLineFeature; //geometry Point3D* p1 = mPointVector[currentEdge->getPoint()]; Point3D* p2 = mPointVector[mHalfEdge[currentEdge->getDual()]->getPoint()]; QgsPolyline lineGeom; lineGeom.push_back( QgsPoint( p1->getX(), p1->getY() ) ); lineGeom.push_back( QgsPoint( p2->getX(), p2->getY() ) ); QgsGeometry* geom = QgsGeometry::fromPolyline( lineGeom ); edgeLineFeature.setGeometry( *geom ); delete geom; edgeLineFeature.initAttributes( 1 ); //attributes QString attributeString; if ( currentEdge->getForced() ) { if ( currentEdge->getBreak() ) { attributeString = "break line"; } else { attributeString = "structure line"; } } edgeLineFeature.setAttribute( 0, attributeString ); writer.addFeature( edgeLineFeature ); } alreadyVisitedEdges[i] = true; } delete [] alreadyVisitedEdges; return true; } double DualEdgeTriangulation::swapMinAngle( int edge ) const { Point3D* p1 = getPoint( mHalfEdge[edge]->getPoint() ); Point3D* p2 = getPoint( mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint() ); Point3D* p3 = getPoint( mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint() ); Point3D* p4 = getPoint( mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint() ); //search for the minimum angle (it is important, which directions the lines have!) double minangle; double angle1 = MathUtils::angle( p1, p2, p4, p2 ); minangle = angle1; double angle2 = MathUtils::angle( p3, p2, p4, p2 ); if ( angle2 < minangle ) { minangle = angle2; } double angle3 = MathUtils::angle( p2, p3, p4, p3 ); if ( angle3 < minangle ) { minangle = angle3; } double angle4 = MathUtils::angle( p3, p4, p2, p4 ); if ( angle4 < minangle ) { minangle = angle4; } double angle5 = MathUtils::angle( p2, p4, p1, p4 ); if ( angle5 < minangle ) { minangle = angle5; } double angle6 = MathUtils::angle( p4, p1, p2, p1 ); if ( angle6 < minangle ) { minangle = angle6; } return minangle; } int DualEdgeTriangulation::splitHalfEdge( int edge, float position ) { //just a short test if position is between 0 and 1 if ( position < 0 || position > 1 ) { QgsDebugMsg( "warning, position is not between 0 and 1" ); } //create the new point on the heap Point3D* p = new Point3D( mPointVector[mHalfEdge[edge]->getPoint()]->getX()*position + mPointVector[mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint()]->getX()*( 1 - position ), mPointVector[mHalfEdge[edge]->getPoint()]->getY()*position + mPointVector[mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint()]->getY()*( 1 - position ), 0 ); //calculate the z-value of the point to insert Point3D zvaluepoint; mDecorator->calcPoint( p->getX(), p->getY(), &zvaluepoint ); p->setZ( zvaluepoint.getZ() ); //insert p into mPointVector if ( mPointVector.count() >= mPointVector.size() ) { mPointVector.resize( mPointVector.count() + 1 ); } QgsDebugMsg( QString( "inserting point nr. %1, %2//%3//%4" ).arg( mPointVector.count() ).arg( p->getX() ).arg( p->getY() ).arg( p->getZ() ) ); mPointVector.insert( mPointVector.count(), p ); //insert the six new halfedges int dualedge = mHalfEdge[edge]->getDual(); int edge1 = insertEdge( -10, -10, mPointVector.count() - 1, false, false ); int edge2 = insertEdge( edge1, mHalfEdge[mHalfEdge[edge]->getNext()]->getNext(), mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint(), false, false ); int edge3 = insertEdge( -10, mHalfEdge[mHalfEdge[dualedge]->getNext()]->getNext(), mHalfEdge[mHalfEdge[dualedge]->getNext()]->getPoint(), false, false ); int edge4 = insertEdge( edge3, dualedge, mPointVector.count() - 1, false, false ); int edge5 = insertEdge( -10, mHalfEdge[edge]->getNext(), mHalfEdge[edge]->getPoint(), mHalfEdge[edge]->getBreak(), mHalfEdge[edge]->getForced() ); int edge6 = insertEdge( edge5, edge3, mPointVector.count() - 1, mHalfEdge[dualedge]->getBreak(), mHalfEdge[dualedge]->getForced() ); mHalfEdge[edge1]->setDual( edge2 ); mHalfEdge[edge1]->setNext( edge5 ); mHalfEdge[edge3]->setDual( edge4 ); mHalfEdge[edge5]->setDual( edge6 ); //adjust the already existing halfedges mHalfEdge[mHalfEdge[edge]->getNext()]->setNext( edge1 ); mHalfEdge[mHalfEdge[dualedge]->getNext()]->setNext( edge4 ); mHalfEdge[edge]->setNext( edge2 ); mHalfEdge[edge]->setPoint( mPointVector.count() - 1 ); mHalfEdge[mHalfEdge[edge3]->getNext()]->setNext( edge6 ); //test four times recursively for swapping checkSwap( mHalfEdge[edge5]->getNext(), 0 ); checkSwap( mHalfEdge[edge2]->getNext(), 0 ); checkSwap( mHalfEdge[dualedge]->getNext(), 0 ); checkSwap( mHalfEdge[edge3]->getNext(), 0 ); mDecorator->addPoint( new Point3D( p->getX(), p->getY(), 0 ) );//dirty hack to enforce update of decorators return mPointVector.count() - 1; } bool DualEdgeTriangulation::edgeOnConvexHull( int edge ) { return ( mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint() == -1 || mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint() == -1 ); } void DualEdgeTriangulation::evaluateInfluenceRegion( Point3D* point, int edge, QSet<int> &set ) { if ( set.find( edge ) == set.end() ) { set.insert( edge ); } else//prevent endless loops { return; } if ( !mHalfEdge[edge]->getForced() && !edgeOnConvexHull( edge ) ) { //test, if point is in the circle through both endpoints of edge and the endpoint of edge->dual->next->point if ( MathUtils::inCircle( point, mPointVector[mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint()], mPointVector[mHalfEdge[edge]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint()] ) ) { evaluateInfluenceRegion( point, mHalfEdge[mHalfEdge[edge]->getDual()]->getNext(), set ); evaluateInfluenceRegion( point, mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getNext(), set ); } } }