void LinkStatusWidget::initLines(){ lines.clear(); int lineLeft=this->left_left+this->left_width+this->left_space; int lineRight=this->width()-this->right_right; int centerHeight=this->right_top+this->right_height+this->right_space/2; QPoint p_left_left(lineLeft,centerHeight); QPoint p_left_right(lineRight,centerHeight); QLine line_1(p_left_left,p_left_right); int lineRightRight=this->width()-this->right_right+this->right_space; int lineRightTop=centerHeight- this->right_space/2-this->right_height/2; int lineRightBottom= centerHeight+this->right_space/2+this->right_height/2; QPoint p_right_top_left(lineRightRight,lineRightTop); QPoint p_right_top_right(lineRightRight,lineRightBottom); QLine line_2(p_right_top_left,p_right_top_right); lines.append(line_1); lines.append(line_2); }
// // removes the given vertex and retriangulates the hole which would be made // // The method returns true if the vertex has been removed and false if the vertex has been retained. // bool MeshEx::removeVertexAndReTriangulateNeighbourhood( Vertex *v ) { std::vector<MeshEx::Edge *> boundaryEdges; // boundary edges which form the polygon which has to be triangulated std::vector<MeshEx::Edge *> criticalEdges; // edges which are not only connected to other vertices of the vertexring through boundary edges std::map<MeshEx::Vertex *, EdgeInfoHelper> boundaryRing; // maps incomming and outgoing edge to each vertex of the boundary vertex-ring // gather and prepare information ------------------------------------------------ for( std::vector<Triangle *>::iterator it = v->triangleRing.begin(); it != v->triangleRing.end(); ++it ) { Triangle *t = (*it); Edge *boundaryEdge = t->getOtherEdge( v ); boundaryRing[boundaryEdge->v1].registerEdge( boundaryEdge ); boundaryRing[boundaryEdge->v2].registerEdge( boundaryEdge ); boundaryEdges.push_back( boundaryEdge ); } // align the edges so that for each vertex e1 is the incomming and e2 is the outgoing edge Vertex *first = boundaryRing.begin()->first; Vertex *current = first; Vertex *next = 0; Vertex *prev = 0; do { // we have to be sure that each boundaryRing Vertex has an incomming and outgoing edge if( !boundaryRing[current].e1 || !boundaryRing[current].e2 ) { printf( "error : edge ring around vertex not closed boundary vertex has less than 2 edges (polygon hole?)\n" ); //++g_iterations; return false; } boundaryRing[current].setVertex( current ); next = boundaryRing[current].next; if( boundaryRing[next].e1 != boundaryRing[current].e2 ) boundaryRing[next].swap(); current = next; }while( current != first ); // we have to collect all edges going out from the vertex-ring vertices which are connected to // other vertices of the vertex ring - these will later be used for consistency check #2 (see chapter 4.4 of the paper) // for each vertex of the vertex Ring V for( std::map<Vertex *, EdgeInfoHelper>::iterator it = boundaryRing.begin(); it != boundaryRing.end(); ++it ) { Vertex *rv = it->first; // current vertex of the vertex ring // for each triangle referencing rv... for( std::vector<Triangle *>::iterator tit = rv->triangleRing.begin(); tit != rv->triangleRing.end(); ++tit ) { Triangle *rv_tri = *tit; // ... which doesnt belong to the triangleRing of v if( std::find( v->triangleRing.begin(), v->triangleRing.end(), rv_tri ) == v->triangleRing.end() ) { // collect the edges containing rv... for( size_t i=0; i<3; ++i ) if( rv_tri->e[i]->contains(rv) ) // ...and dont belong to the edgeRing list if( std::find( boundaryEdges.begin(), boundaryEdges.end(), rv_tri->e[i] ) == boundaryEdges.end() ) // store the edge if the node on the other side references another vertex of the vertex-ring if( boundaryRing.find( rv_tri->e[i]->getOtherVertex(rv) ) != boundaryRing.end() ) criticalEdges.push_back( rv_tri->e[i] ); } } } // remove duplicate entries std::sort( criticalEdges.begin(), criticalEdges.end() ); criticalEdges.erase( std::unique(criticalEdges.begin(), criticalEdges.end()), criticalEdges.end() ); // Now we will project the neighbourhood of v onto a plane so that we can employ the greedy // triangulation. For this we will have to find a projection of the neighbourhood of v so that // no edges intersect on that plane. If they would, then the greedy triangulation would introduce // folds which means that the topology would be destroyed. // Looking for a working projection may lead to a number of projection-trials. For the first try // we will take the plane to be the plane defined by the normal of v and (its distance to the origin). // This will do the job most of the time. math::Vec3f normal; // direction of the projection plane math::Vec3f base1; // base vector which builds the 2d-coordinate system math::Vec3f base2; // base vector which builds the 2d-coordinate system float distance; // distance of the plane to the origin CGAL::Orientation boundaryPolygonOrientation; // orientation (clockwise/counterclockwise of the boundary polyon) distance = -math::dotProduct( v->position, normal ); size_t trialCount = 13; // only one trial for now size_t currentTrial = 0; bool success = true; do { // we assume that we will be successfull success = true; switch(currentTrial) { case 0: // first trial: we take the plane defined by the normal of v normal = v->normal; break; // for all other trials we will try one of 12 different directions case 1:normal = math::normalize( math::Vec3f( .8507f, .4472f, .2764f ));break; case 2:normal = math::normalize( math::Vec3f( -.8507f, .4472f, .2764f ));break; case 3:normal = math::normalize( math::Vec3f( .8507f, -.4472f, -.2764f ));break; case 4:normal = math::normalize( math::Vec3f( -.8507f, -.4472f, -.2764f ));break; case 5:normal = math::normalize( math::Vec3f( .5257f, -.4472f, .7236f ));break; case 6:normal = math::normalize( math::Vec3f( .5257f, .4472f, -.7236f ));break; case 7:normal = math::normalize( math::Vec3f( -.5257f, -.4472f, .7236f ));break; case 8:normal = math::normalize( math::Vec3f( -.5257f, .4472f, -.7236f ));break; case 9:normal = math::normalize( math::Vec3f( .0f, .4472f, .8944f ));break; case 10:normal = math::normalize( math::Vec3f( .0f, -1.0f, .0f ));break; case 11:normal = math::normalize( math::Vec3f( .0f, 1.0f, .0f ));break; case 12:normal = math::normalize( math::Vec3f( .0f, -.4472f, -.8944f ));break; }; // compute the basis of the 2d-coordinate system of the plane defined by current normal base1 = math::normalize( math::projectPointOnPlane( normal, distance, boundaryRing.begin()->first->position ) - v->position ); base2 = math::normalize( math::crossProduct( normal, base1 ) ); // project neighbours into the given plane for( std::map<Vertex *, EdgeInfoHelper>::iterator it = boundaryRing.begin(); it != boundaryRing.end(); ++it ) it->second.projected = _get2d( base1, base2, math::projectPointOnPlane( normal, distance, it->first->position ) ); // topologic constistency check #1 (see chapter 4.4 of the paper) // now do the consistency check: test if all edges dont intersect and dont lie over each other // if any edge between the projected vertices intersect -> success = false // test each projected edge of the edge ring against each other edge for( std::vector<Edge *>::iterator it1 = boundaryEdges.begin(); it1 != boundaryEdges.end() - 1; ++it1 ) { for( std::vector<Edge *>::iterator it2 = it1+1; it2 != boundaryEdges.end(); ++it2 ) { Edge *e1 = *it1; Edge *e2 = *it2; math::Vec3f intersectionPoint; // skip if the 2 lines share a common vertex if( e2->contains(e1->v1) || e2->contains(e1->v2) ) continue; math::Vec2f e1_v1_projected = boundaryRing[e1->v1].projected; math::Vec2f e1_v2_projected = boundaryRing[e1->v2].projected; math::Vec2f e2_v1_projected = boundaryRing[e2->v1].projected; math::Vec2f e2_v2_projected = boundaryRing[e2->v2].projected; CGAL::Segment_2<K> line_1( Point( e1_v1_projected.x, e1_v1_projected.y ), Point(e1_v2_projected.x, e1_v2_projected.y) ); CGAL::Segment_2<K> line_2( Point( e2_v1_projected.x, e2_v1_projected.y ), Point(e2_v2_projected.x, e2_v2_projected.y) ); if( CGAL::do_intersect( line_1, line_2 ) ) { success = false; break; } } if( !success ) break; } if( success ) { // // now we do the topology consistency check #2 (see chapter 4.4 of the paper) // this is done by checking all critical edges whether they cross the interior of the // polygon boundary which is formed by the projected vertex ring vertices // to do this we create the 2 polygongs which can be made by using the edge as a divider // the line crosses the interior if both polgons have a counterclockwise orientation // for( std::vector<Edge *>::iterator it = criticalEdges.begin(); it != criticalEdges.end(); ++it ) { Edge *criticalEdge = *it; // setup left polygon // start from v1 and go to v2 Polygon leftPoly; prev = 0; current = criticalEdge->v1; do { leftPoly.push_back( current, boundaryRing[current].projected ); prev = current; current = boundaryRing[current].next; }while( current != criticalEdge->v2 ); leftPoly.push_back( current, boundaryRing[current].projected ); // setup right polygon // start from v2 and go to v1 Polygon rightPoly; prev = 0; current = criticalEdge->v2; do { rightPoly.push_back( current, boundaryRing[current].projected ); prev = current; current = boundaryRing[current].next; }while( current != criticalEdge->v1 ); rightPoly.push_back( current, boundaryRing[current].projected ); // if orientations of both polygons are the same then the critical edge crosses the bounding polygon interior if( leftPoly.orientation() == rightPoly.orientation() ) { printf( "info : unable to triangulate since critical edge(es) would cross the polygon interior - vertex is not removed\n" ); success = false; break; } } } }while( (++currentTrial < trialCount)&&(!success) ); if( !success ) { // we dont remove the vertex since we didnt managed to find a planar // projection of the neighbourhood which would not destroy the topology printf( "info : unable to find planar projection for vertex remove and retriangulation - vertex is not removed\n" ); //++g_iterations; return false; } boundaryPolygonOrientation = CGAL::orientation( Point_3( v->position ), Point_3( v->position + base1 ), Point_3( v->position + base2 ), Point_3( v->position + normal ) ); // execute the result ------------------------------------------------------------ // remove vertex v and the triangle ring around v removeVertex( v ); // compute squared distances // compute the squared distances of all point pairs std::vector<DistanceHelper> sqDistances; // sorted distances of each pair of points for( std::map<Vertex *, EdgeInfoHelper>::iterator it1 = boundaryRing.begin(); it1 != boundaryRing.end(); ++it1 ) for( std::map<Vertex *, EdgeInfoHelper>::iterator it2 = it1; it2 != boundaryRing.end(); ++it2 ) { Vertex *v1 = it1->first; Vertex *v2 = it2->first; if( v1 == v2 ) continue; // we dont want to add pairs, which would build a boundary edge, since those // already exist -> simply check for next or prev vertex in boundaryRing if( (boundaryRing[v1].next == v2)||(boundaryRing[v1].prev == v2) ) continue; sqDistances.push_back( DistanceHelper( it1->first, it2->first ) ); } // sort std::sort( sqDistances.begin(), sqDistances.end() ); // std::list<Polygon *> polygons; // polygons which have to be triangulated std::vector<Edge *> edges( boundaryEdges.begin(), boundaryEdges.end() ); // created edges // create polygon which is made by the boundary edges and put it on polygon list Polygon *boundaryPolygon = new Polygon(); first = boundaryRing.begin()->first; current = first; prev = 0; do { boundaryPolygon->push_back( current, boundaryRing[current].projected ); prev = current; current = boundaryRing[current].next; }while( current != first ); if( boundaryPolygon->orientation() != boundaryPolygonOrientation ) boundaryPolygon->flip(); polygons.push_back( boundaryPolygon ); // for each entry in the sqDistance list // find the polygon on the polygon list which contains h->v1 and h->v2 // check if edge is outside the polygon by checking the orientations of the left and right sides (build left and right polygons) // check if edge intersects with any other existing edge which dont have a point in h->v1 or h->v2 // if checks pass: // create edge -> assign it to the left and right polygons | add it to the list of edges // split the polygon by removing the polygon from polygon list and putting the left and right polygons on the list if it is not a triangle // // if the any polygon remains on the polygon list, throw an error that the triangulation has created a hole in the mesh //std::vector<Edge *> edges( edgeRing.begin(), edgeRing.end() ); // when the mother polygon is already a triangle, then we have sqDistances.size() == 0 // and we have to handle the polygon if( boundaryPolygon->isTriangle() ) { createTriangle( boundaryPolygon->vertices[0], boundaryPolygon->vertices[1], boundaryPolygon->vertices[2], edges ); polygons.clear(); delete boundaryPolygon; //++g_iterations; return true; } for( std::vector<DistanceHelper>::iterator it=sqDistances.begin(); it != sqDistances.end(); ++it ) { DistanceHelper *h = &(*it); Polygon *poly = 0; // polygon which contains both vertices of h std::list<Polygon *>::iterator pit; // find the polygon which contains both vertices of h for( pit = polygons.begin(); pit != polygons.end(); ++pit ) { Polygon *p = *pit; if( p->contains( h->v1 ) && p->contains( h->v2 ) ) { poly = p; break; } } // if no polygon could be found which contains both vertices of h, then // we can skip this one if( !poly ) continue; // test for intersection with all existing edges bool intersection = false; for( std::vector<Edge *>::iterator eit = edges.begin(); eit != edges.end(); ++eit) { Edge *e = (*eit); math::Vec3f intersectionPoint; // ---- test for intersection of the edges projected into 2d plane using cgal ---- // skip if the 2 lines share a common vertex if( e->contains(h->v1) || e->contains(h->v2) ) continue; CGAL::Segment_2<K> line_1( Point( boundaryRing[e->v1].projected.x, boundaryRing[e->v1].projected.y ), Point(boundaryRing[e->v2].projected.x, boundaryRing[e->v2].projected.y) ); CGAL::Segment_2<K> line_2( Point( boundaryRing[h->v1].projected.x, boundaryRing[h->v1].projected.y ), Point(boundaryRing[h->v2].projected.x, boundaryRing[h->v2].projected.y) ); if( CGAL::do_intersect( line_1, line_2 ) ) { intersection = true; break; } } // if there was an intersection, then we can skip this one // since a non-compatible edge would be introduced if( intersection ) continue; // no intersection, get the 2 polygons which would be created from dividing the mother polyon along the edge Polygon *left, *right; left = right = 0; poly->split( left, right, h->v1, h->v2 ); // if the 2 polygons have the same orientation, then we can be sure that // the edge goes through the interior of the polygon if( left->orientation() == right->orientation() ) { // remove the current polygon from the list of polygons polygons.erase( pit ); delete poly; // create the edge h->v1 -> h->v2 Edge *edge = createEdge( h->v1, h->v2 ); edges.push_back( edge ); // and add the left and righ polygon to the list if they are not triangles if( left->isTriangle() ) { // add triangle to the mesh createTriangle( left->vertices[0], left->vertices[1], left->vertices[2], edges ); // remove polygon helper structure delete left; }else polygons.push_back( left ); if( right->isTriangle() ) { // add triangle to the mesh createTriangle( right->vertices[0], right->vertices[1], right->vertices[2], edges ); // remove polygon helper structure delete right; }else polygons.push_back( right ); }else { delete left; delete right; } } if( !polygons.empty() ) printf( "error : hole created during retriangulation\n" ); for( std::list<Polygon *>::iterator pit = polygons.begin(); pit != polygons.end(); ++pit ) delete *pit; polygons.clear(); //++g_iterations; return true; }