예제 #1
0
파일: state.cpp 프로젝트: oakfr/omni3d
void SM_UpdateHistory2( ExtrinsicParameters &pose )
{
    Vec3d center = pose.getTranslation();

    // update each correspondence
    for (int i=0; i<cq.size(); i++) {

        if ( cq[i].age > 0 )
            cq[i].age--;

        if ( !cq[i].valid() ) {
            cq[i].notseen++;
            cq[i].line->status = UNKNOWN;
        }

        if ( cq[i].valid() ) {

            Edge *line = cq[i].line;
            Vec3d a = line->getA()-center;
            Vec3d b = line->getB()-center;
            EdgePlane selected_edgeplane = cq[i].eps[cq[i].eid];
            EdgePlane edgeplane = EdgePlane( a, b, center, selected_edgeplane._cameraId, 0, 0 );
            edgeplane.fromWorldFrameToCameraFrame( pose );
            double angle = edgeplane.angle( selected_edgeplane );
            if ( angle > toRadians( 5.0 ) ) {
                SM_Clear(i);
                cq[i].notseen++;
                LOG(LEVEL_INFO, "[%d][%d] valid but too far (angle = %.3f deg.) [%d,%d]", i, cq[i].line->_id, toDegrees(angle), cq[i].age, cq[i].notseen);
                cq[i].line->status = UNKNOWN;
            } else {
                cq[i].notseen = 0;
                cq[i].age++;
                LOG(LEVEL_INFO, "[%d][%d] valid and continues (angle = %.3f deg.) [%d,%d]", i, cq[i].line->_id, toDegrees(angle), cq[i].age, cq[i].notseen);
                if ( cq[i].age > 4 )
                    cq[i].line->status = ACCEPTED;
            }
        }
        if ( cq[i].notseen > 0 && cq[i].notseen < 4 ) {
            int p = history[cq[i]._id].size();
            if ( p-cq[i].notseen-1 >= 0 ) {
                cq[i] = history[cq[i]._id][p-cq[i].notseen-1];
                cq[i].notseen++;
                LOG(LEVEL_INFO, "[%d][%d] not seen but recovered in history [%d,%d]", i, cq[i].line->_id, cq[i].age, cq[i].notseen);
                cq[i].line->status = PENDING;
            } else {
                LOG(LEVEL_INFO, "[%d][%d] not seen and not recovered in history [%d,%d]", i, cq[i].line->_id, cq[i].age, cq[i].notseen);
                cq[i].line->status = UNKNOWN;
            }
        }
        if ( !cq[i].valid() && cq[i].notseen >= 4 ) {
            SM_Clear(i);
            cq[i].notseen++;
            LOG(LEVEL_INFO, "[%d][%d] invalid and not seen for too long [%d,%d]", i, cq[i].line->_id, cq[i].age, cq[i].notseen);
            cq[i].line->status = UNKNOWN;
        }
    }
}
예제 #2
0
파일: state.cpp 프로젝트: oakfr/omni3d
// insert a correspondence in the queue
// avoid duplicates (each model line has at most one correspondence)
void SM_InsertItem( corresStatus status, Edge *line )
{
    assert( line != NULL );

    for (int i=0; i<cq.size(); i++) {
        if ( cq[i].line->_id == line->_id ) {
            LOG(LEVEL_INFO, "trying to insert line that already exists %d", line->_id);
            assert(false);
        }
    }

    cq.push_back( corres( line, EdgePlane(), status ) );
}
예제 #3
0
파일: frame.cpp 프로젝트: oakfr/omni3d
/* convert a list of 3D edges into edge planes
 */
void Frame::convert3DEdgesToEdgePlanes (int sensorId, edgePlaneVector edges, edgePlaneVector &edgeplanes, Vec3d center)
{
	return;

	// read the 3D edges and convert them into edge planes
	int counter = 0;
		for (int edgeId=0;edgeId<edges.size();edgeId++) {
			EdgePlane edge = edges[edgeId];
			EdgePlane edgeplane = EdgePlane(edge._a - center,edge._b - center,center,sensorId,edgeId,counter);
			if (edgeplane.length() > 0) {
				edgeplanes.push_back(edgeplane);
				counter++;
			}
		}
}
예제 #4
0
파일: frame.cpp 프로젝트: oakfr/omni3d
/* return the i-th edge plane
 */
EdgePlane Frame::getEdgePlane (int id)
{
	assert (id < n_edgeplanes_chained);

	for (int i=0;i<_edgeplanes_chained.size();i++) {
		for (int j=0;j<_edgeplanes_chained[i].size();j++) {
			if (_edgeplanes_chained[i][j]._uid == id)
				return _edgeplanes_chained[i][j];
		}
	}

	printf("edgeplane not found for ID %d. Max ID = %d\n",id,n_edgeplanes_chained);
	assert (false);
	return EdgePlane();
}
예제 #5
0
bool MyGlWindow::update_correspondences()
{
	ExtrinsicParameters original_pose = _camera->getPose();

	Vec3d eps = get_expected_position(8);
	Quaternion epr = get_expected_rotation();

	//_camera->setTranslation( eps );

	// update correspondences
	SM_UpdateCorrespondences( );

	printf("correspondences updated [%d]\n", SM_Size());

	// enforce geometric constraints
	SM_VerifyCorrespondences( _camera->getPose() );

	int i,j,run;

	// quick hack for video -- remove asap
	/*for (i=0;i<pose_history.size();i++) {
		if ( pose_history[i].id == frameId ) {
			_camera->setPose( pose_history[i] );
			break;
		}
	}

	return true;*/
	// end quick hack

	//detect_edges();

	//std::vector< intVector > edges_buckets;
	//distribute_edgeplanes_into_buckets( edges_buckets );

	//ExtrinsicParameters pose = original_pose;
	write_correspondences( frameId );
	
	ExtrinsicParameters best_pose = original_pose;

	// keep only valid correspondences
	CorrespondenceVector ds;
	for (i=0;i<SM_Size();i++) {
		if ( SM_Get(i).valid() && SM_Get(i).age >= 4 &&  SM_Get(i).eid != -1) {
			Correspondence d;
			d.first = SM_Get(i).line;
			d.second = SM_Get(i).eps[SM_Get(i).eid];
			ds.push_back( d );
		}
	}

	int n = ds.size();

	if ( n < 5 ) {
		LOG(LEVEL_INFO, "too few correspondences to localize (%d).", n );

		return false;
	}

	_n_correspondences = n;

	LOG(LEVEL_INFO, "using %d correspondences for localization", ds.size());
	
	double max_distance = 2 * _LUT.inchToModelUnit( mmToInch(_camera->_max_translation_speed) );

	// RANSAC
	_point_cloud.clear();

	double best_penalty = 1E10;

	int size = INIT_MIN_CORRESPONDENCES;

	std::vector< ExtrinsicParameters > poses;
	double wweight = 0.0;
	//double nweight = 0.0;
	Vec3d average_position = Vec3d(0,0,0);

	for (run=0;run<6000;run++) {

		_camera->setPose( original_pose );

		CorrespondenceVector set;

		intVector indices;

		selectNRandomInt( size, ds.size(), indices );

		for (i=0;i<indices.size();i++) {
			Correspondence d = ds[indices[i]];

			set.push_back( d );
		}

		refineCameraPoseFromNCorrespondences( set );

		if ( len(_camera->getTranslation() - original_pose.getTranslation()) > max_distance ) 
			continue;

		_point_cloud.push_back( _camera->getTranslation() );
		
		poses.push_back( _camera->getPose() );

		// keep pose that scores the best
		double penalty = 0.0;
		int counter = 0;

		Vec3d center = _camera->getTranslation();

		for (i=0;i<n;i++) {

			bool used = false;
			for (j=0;j<indices.size();j++) {
				if ( indices[j] == i ) {
					used = true;
					break;
				}
			}

			if ( used )
				continue;

			counter++;

			Edge *line = ds[i].first;
			Vec3d a = line->getA()-center;
			Vec3d b = line->getB()-center;
			EdgePlane edgeplane = EdgePlane( a, b, center, 0, 0, 0 );
			edgeplane.fromWorldFrameToCameraFrame( _camera->getPose() );
		
			penalty += fabs( edgeplane.angle( ds[i].second ) );
		}

		if ( counter > 0 ) {
			penalty /= counter;
		} else {
			continue;
		}

		if ( penalty > EPS ) {
			// update the average
			average_position += 1.0 / penalty * _camera->getTranslation();
			wweight += 1.0 / penalty;
			//printf("weight = %f\n", wweight);
		}

		if ( penalty < best_penalty ) {

			best_penalty = penalty;

			best_pose = _camera->getPose();
		}

		//_camera->getPose().print();
	}

	_camera->setPose( best_pose );
	
	//if ( wweight > EPS ) {
	//	printf("weight = %f\n", wweight);
	//	_camera->setTranslation( average_position / wweight );
	//}

	double dd = len(_camera->getTranslation() - original_pose.getTranslation());

	if ( dd > max_distance ) {
		_camera->setPose( original_pose );
		return true;
	}
			
	return true;
}
예제 #6
0
// relock
void MyGlWindow::relock ( double max_dihedral_angle, int nruns )
{
	// lookup LUT
	_LUT.lookup( _camera->came.getTranslation(), MIN_SUBTENDED_ANGLE, 0.0, 100, 0);

	int i;

	printf("detecting edges\n");

	// detect edges
	detect_edges();

	// distribute visible edges into buckets
	std::vector< intVector > edges_buckets;
	distribute_edgeplanes_into_buckets( edges_buckets );

	// compute the region size on the tessellatio
	printf("computing region\n");

	int level = 1 + max_dihedral_angle / SPHERE_TESSELLATION_RESOLUTION;
	LOG(LEVEL_INFO, "region size: %d", level);

	int N = _LUT._lines.size();

	printf("converting lines\n");
	// convert the model lines into edgeplanes in the camera coordinate frame
	edgePlaneVector lines_edgeplanes;
	intVector line_ids;
	for (i=0;i<N;i++) {
		Vec3d a = _camera->fromWorldFrameToCameraFrame( _LUT._lines[i]->getA() );
		Vec3d b = _camera->fromWorldFrameToCameraFrame( _LUT._lines[i]->getB() );
		Vec3d s = Vec3d(0,0,0);
		lines_edgeplanes.push_back( EdgePlane( a, b, s, -1, _LUT._lines[i]->_id, i ) );
		line_ids.push_back( _LUT._lines[i]->_id );
	}

	corresVector correspondences;

	// clear the state machine
	SM_Clear();

	// for each model line, search the possible matches
	for (i=0;i<N;i++) {

		EdgePlane line = lines_edgeplanes[i];

		intVector cells;
		get_edgeplane_buckets( line, cells );

		// create a correspondence
		corres c ( _LUT._lines[i] );

		for (int m=0;m<cells.size();m++) {

			int bucket_id = cells[m];

			for (int j=0;j<edges_buckets[bucket_id].size();j++) {

				int edge_id = edges_buckets[bucket_id][j];

				EdgePlane edge;
				if (!_camera->_frame.get_edgeplane_chained( edge_id, edge ) ) {
					LOG(LEVEL_ERROR, "error accessing edgeplane %d out of %d edgeplanes.", edge_id, _camera->_frame.n_edgeplanes_chained );
					continue;
				}

				double angle = line.angle( edge );

				if ( angle > max_dihedral_angle ) 
					continue;

				c.eps.push_back( edge );
			}

			if ( c.valid() ) {
				correspondences.push_back( c );
				SM_InsertItem( c );
			}
		}
	}

	ExtrinsicParameters original_pose = _camera->getPose();
	ExtrinsicParameters best_pose = original_pose;
	double best_score = score_camera_pose( original_pose, edges_buckets );
	
	LOG(LEVEL_INFO, "start score: %f", best_score );
	
	// find the best camera pose possible
	for (int run=0; run < nruns; run++) {

		// reset camera pose
		_camera->setPose( original_pose );

		// draw random correspondences
		CorrespondenceVector cs;

		intVector indices;
		selectNRandomInt( 5/*INIT_MIN_CORRESPONDENCES*/, SM_Size(), indices);

		// for each correspondence, pick a choice randomly
		for (i=0;i<indices.size();i++) {
			Correspondence d;
			d.first = SM_Get(indices[i]).line;
			int p = MIN( SM_Get(indices[i]).eps.size()-1, (double)rand() / (RAND_MAX+1) * (SM_Get(indices[i]).eps.size()-1));
			d.second = SM_Get(indices[i]).eps[p];
			cs.push_back( d );
		}

		refineCameraPoseFromNCorrespondences( cs );

		double score = score_camera_pose( _camera->getPose(), edges_buckets );

		if ( score > best_score ) {

			best_score = score;
			best_pose = _camera->getPose();
		}	
	}

	// keep the best camera pose found so far
	_camera->setPose( best_pose );

	LOG(LEVEL_INFO, "new score: %f", best_score );

	// clear the state machine
	SM_Clear();

	// populate correspondences again
	correspondences.clear();
	init_correspondences( correspondences, edges_buckets, MAINTENANCE_DIHEDRAL_ANGLE, MAINTENANCE_MIN_OVERLAP, true );
}
예제 #7
0
// populate a set of correspondences
// correspondences are saved in the state machine if <store> is set to true
//
void MyGlWindow::init_correspondences( corresVector &correspondences, std::vector< intVector > &edges_buckets, double max_dihedral_angle, double min_overlap, bool store )
{
	int i,k, counter=0;

	// lookup LUT
	_LUT.lookup( _camera->came.getTranslation(), MIN_SUBTENDED_ANGLE, 0.0, 100, 0);

	int N = MIN(MAINTENANCE_MAX_CORRESPONDENCES ,_LUT._lines.size());
	int M = _camera->_frame.nedgeplanes_chained();

	LOG(LEVEL_INFO, "init correspondences: %d model lines and %d images edges", N, M);

	if ( store ) {
		SM_Clear();
		SM_ClearHistory();
	}

	correspondences.clear();

	// convert the model lines into edgeplanes in the camera coordinate frame
	edgePlaneVector lines_edgeplanes;
	intVector line_ids;
	for (i=0;i<N;i++) {
		Vec3d a = _camera->fromWorldFrameToCameraFrame( _LUT._lines[i]->getA() );
		Vec3d b = _camera->fromWorldFrameToCameraFrame( _LUT._lines[i]->getB() );
		Vec3d s = Vec3d(0,0,0);
		lines_edgeplanes.push_back( EdgePlane( a, b, s, -1, _LUT._lines[i]->_id, i ) );
		line_ids.push_back( _LUT._lines[i]->_id );
	}

	std::vector< intVector > matches; // each element is a list of edge IDs matching the corresponding line
	for (i=0;i<N;i++) {					// the first element is the local line ID
		intVector v;
		v.push_back( i );
		matches.push_back( v );
	}

	// for each model line, search the possible matches
	for (i=0;i<N;i++) {
		
		EdgePlane line = lines_edgeplanes[i];
		
		
		intVector bucket_ids;
		get_edgeplane_buckets( line, bucket_ids );
				
		// create a correspondence
		corres c ( _LUT._lines[i] );
		c.age = 11;
		c.line->status = UNKNOWN; // status of line is unknown
		
		double best_angle = M_PI;
		bool found = false;
		EdgePlane best_edge;
		
		for (k=0;k<bucket_ids.size();k++) {
			
			int bucket_id = bucket_ids[k];
			
			//LOG(LEVEL_INFO, "processing line %d (bucket: %d, has %d elements)", _LUT._lines[i]->_id, bucket_id, edges_buckets[bucket_id].size() );

			for (int j=0;j<edges_buckets[bucket_id].size();j++) {
				
				int edge_id = edges_buckets[bucket_id][j];
				
				EdgePlane edge;
				if (!_camera->_frame.get_edgeplane_chained( edge_id, edge ) ) {
					LOG(LEVEL_ERROR, "error accessing edgeplane %d out of %d edgeplanes.", edge_id, _camera->_frame.n_edgeplanes_chained );
					continue;
				}
				
				double angle = line.angle( edge );
				
				if ( edge.overlap( line ) < EPS && line.overlap( edge ) < EPS )
					continue;
				
				if ( edge.length() < toRadians(15.0) )
					continue;
				
				if ( angle < best_angle && angle < toRadians( 5.0 ) ) {
					
					best_angle = angle;
					
					best_edge = edge;
					
					found = true;
				}
				
				//c.eps.push_back( edge );
			}
		}

		if ( found ) {
			//LOG(LEVEL_INFO, "found a match");
			_camera->updateColor( best_edge, false );
			c.eps.push_back( best_edge );
			c.eid = 0;
			c.length = best_edge.length();
			c.line->status = ACCEPTED;
			counter++;
		} else {
			//LOG(LEVEL_INFO, "found no match");
		}

		correspondences.push_back( c );

		if ( store )
			SM_InsertItem( c );
	}

	// contraint geometry on correspondences
	//SM_VerifyCorrespondences( _camera->getPose() );

	ExtrinsicParameters pose = _camera->getPose();
	pose.id = frameId;

	LOG(LEVEL_INFO, "%d valid correspondences.", counter);

	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );
	pose_history.push_back( pose );

}
예제 #8
0
파일: Polygon.cpp 프로젝트: mark711/Cafu
template<class T> bool Polygon3T<T>::IsValid(const double RoundEpsilon, const double MinVertexDist) const
{
    // Punkt 4: Es muß mindestens 3 Vertices geben.
    if (Vertices.Size()<3) return false;


    // Punkt 4: Die Plane muß halbwegs wohldefiniert sein.
    if (!Plane.IsValid()) return false;


    // Ohne expliziten Punkt: Alle Vertices müssen *in* der Ebene liegen.
    for (unsigned long VertexNr=0; VertexNr<Vertices.Size(); VertexNr++)
    {
        const double Dist=Plane.GetDistance(Vertices[VertexNr]);

        if (Dist> RoundEpsilon) return false;
        if (Dist<-RoundEpsilon) return false;
    }


    // Punkt 5: No two vertices must be coincident.
    // Normally I'd only run the check for all (V[i], V[i+1]) pairs, but even with the additional check for
    // convexity below, that would not catch rhombuses (Rauten) whose top and bottom vertices are near identical,
    // that is, closer than MinVertexDist.
    for (unsigned long VertexNr=0; VertexNr+1<Vertices.Size(); VertexNr++)
        for (unsigned long VNr=VertexNr+1; VNr<Vertices.Size(); VNr++)
            if (length(Vertices[VertexNr]-Vertices[VNr])<MinVertexDist) return false;


    // Punkt 1 und Punkt 3: Stelle Konvexität und Orientierung sicher.
    for (unsigned long VertexNr=0; VertexNr<Vertices.Size(); VertexNr++)
    {
        // Intentionally don't cache any DivisionByZero exceptions here.
        // If one occurs, the situation is much worse than a "return false;" would express
        // (the EdgePlane ctor *must* succeed after all the assertions above).
        unsigned long NextVertexNr=VertexNr+1<Vertices.Size() ? VertexNr+1 : 0;
        Plane3T<T> EdgePlane(Vertices[VertexNr],
                             Vertices[NextVertexNr],
                             Vertices[VertexNr]-Plane.Normal, T(0.00001));   // (Assume that MinVertexDist is well larger than 1.)

        // Alle Vertices des Polys außer VertexNr und NextVertexNr müssen mindestens RoundEpsilon über der EdgePlane liegen!
        for (unsigned long VNr=0; VNr<Vertices.Size(); VNr++)
            if (VNr!=VertexNr && VNr!=NextVertexNr)
                if (EdgePlane.GetDistance(Vertices[VNr])<RoundEpsilon) return false;
    }


    // Punkt 2: Das Polygon befindet sich (bzgl. Orientierung) auf der *Vorderseite* der Ebene
    // Konstruiere dazu einen Vektor, der auf den Vektoren der Edges 0-1 und 1-2 senkrecht steht,
    // und projeziere diesen Vektor auf den Einheitsnormalenvektor der Poly.Plane.
    const Vector3T<T> N_=cross(Vertices[1]-Vertices[0], Vertices[2]-Vertices[1]);
    const T           l_=length(N_);

    // Wenn l_==0.0 tatsächlich vorkäme, wäre das ein schwerer Fehler!
    // l_ darf nämlich sehr klein sein, aber nach obigen Tests keinesfalls 0.
    if (l_==0.0) return false;

    const T Proj=-dot(scale(N_, T(1.0)/l_), Plane.Normal);

    if (Proj>1.0+RoundEpsilon) return false;
    if (Proj<1.0-RoundEpsilon) return false;


    // Alle Tests bestanden!
    return true;
}
예제 #9
0
파일: state.cpp 프로젝트: oakfr/omni3d
// report statistics
//
void SM_Statistics( int frameid, ExtrinsicParameters &pose )
{
    int i;

    // open the file
    FILE *f = fopen( "loca_stats.dat", "a" );

    if ( f == NULL ) {
        LOG(LEVEL_ERROR, "could not open file loca_stats.dat!");
        return;
    }

    // compute the distribution of correspondences
    double accepted=0.0, pending=0.0, unknown=0.0;

    int n = cq.size();

    for (i=0; i<n; i++) {
        if (cq[i].line == NULL)
            continue;
        if (cq[i].line->status == ACCEPTED)
            accepted += 1.0 / n;
        if (cq[i].line->status == PENDING)
            pending += 1.0 / n;
        if (cq[i].line->status == UNKNOWN)
            unknown += 1.0 / n;
    }

    // compute the average and standard deviation of angular error for accepted correspondences
    doubleVector angles;
    Vec3d center = pose.getTranslation();

    for (i=0; i<n; i++) {
        if ( cq[i].line == NULL )
            continue;
        if ( cq[i].line->status != ACCEPTED )
            continue;

        Edge *line = cq[i].line;
        Vec3d a = line->getA()-center;
        Vec3d b = line->getB()-center;
        EdgePlane selected_edgeplane = cq[i].eps[cq[i].eid];
        EdgePlane edgeplane = EdgePlane( a, b, center, selected_edgeplane._cameraId, 0, 0 );
        edgeplane.fromWorldFrameToCameraFrame( pose );
        double angle = toDegrees( edgeplane.angle( selected_edgeplane ) );

        angles.push_back( angle );
    }

    int n_accepted = angles.size();

    double average = 0.0;
    double stdev = 0.0;

    if ( n_accepted > 0 ) {

        for (i=0; i<angles.size(); i++)
            average += angles[i] / n_accepted;

        for (i=0; i<angles.size(); i++)
            stdev += ( angles[i] - average ) * ( angles[i] - average );

        stdev = sqrt( stdev ) / n_accepted;
    }

    // write the stats into the file
    fprintf(f, "%d %d %.1f %.1f %.1f %.2f %.2f\n", frameid, n, 100.0 * accepted, 100.0 * pending, 100.0 * unknown, average, stdev);

    fclose(f);
}
예제 #10
0
파일: state.cpp 프로젝트: oakfr/omni3d
void SM_VerifyCorrespondences( ExtrinsicParameters &pose )
{
    // 1. if two model lines get assigned to the same image edge, one correspondence must go
    int i,j;
    Vec3d center = pose.getTranslation();

    // for each pair of valid correspondences
    bool done = false;

    while (!done) {

        done = true;

        for (i=0; i<cq.size(); i++) {

            if ( !cq[i].valid() )
                continue;

            for (j=i+1; j<cq.size(); j++) {

                if ( !cq[j].valid() )
                    continue;

                // if the two correspondences have the same image edge...
                if ( cq[i].eps[cq[i].eid]._uid == cq[j].eps[cq[j].eid]._uid ) {

                    done = false;

                    EdgePlane edge = cq[i].eps[cq[i].eid];

                    EdgePlane line_i, line_j;
                    Vec3d a = cq[i].line->getA()-center;
                    Vec3d b = cq[i].line->getB()-center;

                    // make a synthetic edge plane for model line 1
                    line_i = EdgePlane( a, b, center, 0, 0, 0 );
                    line_i.fromWorldFrameToCameraFrame( pose );

                    a = cq[j].line->getA()-center;
                    b = cq[j].line->getB()-center;

                    // make a synthetic edge plane for model line 2
                    line_j = EdgePlane( a, b, center, 0, 0, 0 );
                    line_j.fromWorldFrameToCameraFrame( pose );

                    // cancel one of the two correspondences
                    if ( edge.angle( line_i ) < edge.angle( line_j ) ) {
                        cq[j].eps.clear();
                        cq[j].eid = -1;
                        cq[j].length = 0.0;
                    } else {
                        cq[i].eps.clear();
                        cq[i].eid = -1;
                        cq[i].length = 0.0;
                    }

                    break;
                }
            }

            if ( !done )
                break;
        }
    }

    return;

    // 2. if two close lines are assigned to two close edges, enforce ordering
    done = false;

    while (!done) {

        done = true;

        for (i=0; i<cq.size(); i++) {

            if ( !cq[i].valid() )
                continue;

            for (j=i+1; j<cq.size(); j++) {

                if ( !cq[j].valid() )
                    continue;

                EdgePlane ei = cq[i].eps[cq[i].eid];
                EdgePlane ej = cq[j].eps[cq[j].eid];

                if ( ei.angle( ej ) > toRadians( 10.0 ) )
                    continue;

                if ( ei.overlap( ej ) < EPS || ej.overlap( ei ) < EPS )
                    continue;

                // flip normals if needed
                if ( dot(ei._normal, ej._normal) < 0 )
                    ej._normal = -ej._normal;

                EdgePlane line_i, line_j;
                Vec3d a = cq[i].line->getA()-center;
                Vec3d b = cq[i].line->getB()-center;

                // make a synthetic edge plane for model line 1
                line_i = EdgePlane( a, b, center, 0, 0, 0 );
                line_i.fromWorldFrameToCameraFrame( pose );

                a = cq[j].line->getA()-center;
                b = cq[j].line->getB()-center;

                // make a synthetic edge plane for model line 2
                line_j = EdgePlane( a, b, center, 0, 0, 0 );
                line_j.fromWorldFrameToCameraFrame( pose );

                // check that the swap is possible
                if ( ej.overlap( line_i ) < 0.5 || ei.overlap( line_j ) < 0.5 )
                    continue;

                // flip normals if needed
                if ( dot(line_i._normal, ei._normal) < 0 )
                    line_i._normal = -line_i._normal;

                if ( dot(line_j._normal, ei._normal) < 0 )
                    line_j._normal = -line_j._normal;

                // swap correspondences
                if ( dot(cross(ei._normal,ej._normal), cross(line_i._normal, line_j._normal)) < 0.0 ) {
                    LOG(LEVEL_INFO, "flipping correspondences %d and %d", i, j);
                    cq[i].eps[cq[i].eid] = ej;
                    cq[j].eps[cq[j].eid] = ei;
                }
            }
        }
    }

}