Пример #1
0
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);


}
Пример #2
0
//
// 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;
}