示例#1
0
int main()
{
  CGAL::Random_points_in_sphere_3<Point_3> gen(100.0);
  std::list<Point_3>   points;

  // generate 250 points randomly in a sphere of radius 100.0
  // and insert them into the triangulation
  CGAL::cpp11::copy_n(gen, 250, std::back_inserter(points) );
  Delaunay T;
  T.insert(points.begin(), points.end());

  std::list<Vertex_handle>  vertices;
  T.incident_vertices(T.infinite_vertex(), std::back_inserter(vertices));
  std::cout << "This convex hull of the 250 points has "
            << vertices.size() << " points on it." << std::endl;

  // remove 25 of the input points
  std::list<Vertex_handle>::iterator v_set_it = vertices.begin();
  for (int i = 0; i < 25; i++)
  {
     T.remove(*v_set_it);
     v_set_it++;
  }

  //copy the convex hull of points into a polyhedron and use it
  //to get the number of points on the convex hull
  Surface_mesh chull;
  CGAL::convex_hull_3_to_face_graph(T, chull);
  
  std::cout << "After removal of 25 points, there are "
            << num_vertices(chull) << " points on the convex hull." << std::endl;

  return 0;
}
int main()
{
  std::vector<Point> points;
  points.push_back(Point(0,0));
  points.push_back(Point(1,0));
  points.push_back(Point(0,1));
  points.push_back(Point(4,10));
  points.push_back(Point(2,2));
  points.push_back(Point(-1,0));

  
  Delaunay T;
  T.insert( boost::make_transform_iterator(points.begin(),Auto_count()),
            boost::make_transform_iterator(points.end(),  Auto_count() )  );

  CGAL_assertion( T.number_of_vertices() == 6 );
  
  // check that the info was correctly set.
  Delaunay::Finite_vertices_iterator vit;
  for (vit = T.finite_vertices_begin(); vit != T.finite_vertices_end(); ++vit)
    if( points[ vit->info() ] != vit->point() ){
      std::cerr << "Error different info" << std::endl;
      exit(EXIT_FAILURE);
    }
  std::cout << "OK" << std::endl;
  
  return 0;
}
示例#3
0
文件: B2.cpp 项目: piotrmwojcik/AA
void addNearest(Delaunay &T)
{
      Delaunay::Finite_vertices_iterator vit;

    for (vit = T.finite_vertices_begin(); vit != T.finite_vertices_end();++vit)
    {
    
        Delaunay::Vertex_circulator vit2, done;
        std::vector <Vertex_handle> L;
        vit2 = vit->incident_vertices();
        done = vit2;
        do {
            if (T.is_infinite(vit2)) continue;
            std::stringstream ss1, ss2;
            int a, b;

            ss1 << vit->info();
            ss2 << vit2->info();


            ss1 >> a; ss2 >> b;

            if (b == a) continue;

           G[a].push_back(b);

        } while (++vit2 != done);


    }

}
示例#4
0
int main()
{
  CGAL::Geomview_stream gv(CGAL::Bbox_3(-100, -100, -100, 600, 600, 600));
  gv.set_line_width(4);
  // gv.set_trace(true);
  gv.set_bg_color(CGAL::Color(0, 200, 200));
  // gv.clear();
  Delaunay D;
  Delaunay3d D3d;
  Terrain T;
  std::ifstream iFile("data/points3", std::ios::in);
  Point3 p;
  while ( iFile >> p )
  {
      D.insert( Point2(p.x(), p.y()) );
      D3d.insert( p );
      T.insert( p );
  }
  // use different colors, and put a few sleeps/clear.
  gv << CGAL::BLUE;
  std::cout << "Drawing 2D Delaunay triangulation in wired mode.\n";
  gv.set_wired(true);
  gv << D;
#if 1 // It's too slow !  Needs to use OFF for that.
  gv << CGAL::RED;
  std::cout << "Drawing its Voronoi diagram.\n";
  gv.set_wired(true);
  D.draw_dual(gv);
#endif
  sleep(5);
  gv.clear();
  std::cout << "Drawing 2D Delaunay triangulation in non-wired mode.\n";
  gv.set_wired(false);
  gv << D;
  sleep(5);
  gv.clear();
  std::cout << "Drawing 3D Delaunay triangulation in wired mode.\n";
  gv.set_wired(true);
  gv << D3d;
  sleep(5);
  gv.clear();
  std::cout << "Drawing 3D Delaunay triangulation in non-wired mode.\n";
  gv.set_wired(false);
  gv << D3d;
  sleep(5);
  gv.clear();
  std::cout << "Drawing Terrain in wired mode.\n";
  gv.set_wired(true);
  gv << T;
  sleep(5);
  gv.clear();
  std::cout << "Drawing Terrain in non-wired mode.\n";
  gv.set_wired(false);
  gv << T;
  std::cout << "Enter a key to finish" << std::endl;
  char ch;
  //std::cin >> ch;
  std::cin.get();
  return 0;
}
void asign_index_to_cells(std::map<Delaunay::Cell_handle,int> &index,Delaunay &T)
{
	int N=0;
	for(Delaunay::Finite_cells_iterator itr=T.finite_cells_begin();itr!=T.finite_cells_end();itr++)
	{
		index.insert(pair<const Delaunay::Finite_cells_iterator,int>(itr,N));
		N++;
	}
}
bool isEdgeElementary( const Delaunay & t,
		       const Vertex_handle & v1, 
		       const Vertex_handle & v2 )
{
  if ( t.is_infinite( v1 ) || t.is_infinite( v2 ) ) return false;
  Z2i::Point a( toDGtal( v1->point())),
    b(toDGtal( v2->point()));
  return (b-a).norm( Z2i::Point::L_1 ) == 1;
}
示例#7
0
int main()
{
  Delaunay dt;
  Delaunay::Vertex_handle vh;

  vh  = dt.insert(Point(0,0,0));
  vh->info() = "Paris";
  vh = dt.insert(Point(1,0,0.1));
  vh->info() = "London";
  vh = dt.insert(Point(0,1,0.2));
  vh->info() = "New York";
  
  return 0;
}
示例#8
0
int main()
{
  std::ifstream in("data/terrain.cin");
  std::istream_iterator<Point> begin(in);
  std::istream_iterator<Point> end;

  Delaunay dt;
  dt.insert(begin, end);
  std::cout << dt.number_of_vertices() << std::endl;
  std::ofstream fout_T;
  fout_T.open("Tri.txt");
  fout_T << dt;
  fout_T.close();
  return 0;
}
示例#9
0
void draw_facets(Delaunay &Tr,std::vector<Facet> &facets,PointColor pcolors,CGAL::Geomview_stream &gv) {
  if(! gv_on) return;
  CGAL::Color colors[] = {CGAL::BLUE,CGAL::GREEN,CGAL::YELLOW,CGAL::DEEPBLUE,
			  CGAL::PURPLE,CGAL::VIOLET,CGAL::ORANGE,CGAL::RED};
  if(pcolors.size() == 0) 
    return draw_facets(Tr,facets,gv);
  // draw with color interpolation
  for (std::vector<Facet>::iterator it = facets.begin();it != facets.end();it++) {
    Facet f = *it;
    Cell_handle c = f.first;
    int j = f.second;
    CGAL::Color vcolors[3];
    int k = 0;
    for(int i = 0;i < 4;i++) 
      if(i != j)
	vcolors[k++] = pcolors[c->vertex(i)->info()];
    int r = (vcolors[0].red() + vcolors[1].red() + vcolors[2].red()) / 3;
    int g = (vcolors[0].green() + vcolors[1].green() + vcolors[2].green()) / 3;
    int b = (vcolors[0].blue() + vcolors[1].blue() + vcolors[2].blue()) / 3;
    gv << CGAL::Color(r,g,b);
    //    std::cout << "RGB " << r << " " << g << " " << b <<std::endl;
    Triangle t = Tr.triangle(f);
    gv << t;
  }
}
bool
emptyLatticeTriangle( const Delaunay & t,
                      const Vertex_handle & v1,
                      const Vertex_handle & v2,
                      const Vertex_handle & v3 )
{
  if ( t.is_infinite( v1 ) 
       || t.is_infinite( v2 ) 
       || t.is_infinite( v3 ) ) return false;
  Z2i::Point a( toDGtal( v1->point())),
    b(toDGtal( v2->point())),
    c(toDGtal( v3->point()));
  
  Z2i::Vector ab( b - a ), ac( c - a );
  int d = ab[ 0 ] * ac[ 1 ] - ab[ 1 ] * ac[ 0 ];
  return ( d == 1 ) || (d == -1 );
}
int
twiceNbLatticePointsInTriangle( const Delaunay & t,
				const Vertex_handle & v1,
				const Vertex_handle & v2,
				const Vertex_handle & v3 )
{
  if ( t.is_infinite( v1 ) 
       || t.is_infinite( v2 ) 
       || t.is_infinite( v3 ) ) return 10000000;
  Z2i::Point a( toDGtal( v1->point())),
    b(toDGtal( v2->point())),
    c(toDGtal( v3->point()));
  
  Z2i::Vector ab( b - a ), ac( c - a );
  int d = ab[ 0 ] * ac[ 1 ] - ab[ 1 ] * ac[ 0 ];
  d = (d >= 0) ? (d - 1) : (-d - 1);
  return d;
}
void init_cells(Delaunay &T,int* cells)
{
	int S=T.number_of_finite_cells();
	int* ptr1=cells;
	for(int i=0;i<S;i++)
	{
		*ptr1=0;
		ptr1++;
	}
}
void triangulate(Delaunay &T,std::vector<Point> &exterior)
{
	for(int i=0;i<20;i++)
	{
		std::vector<Point>::iterator be=exterior.begin()+exterior.size()*i/20;
		std::vector<Point>::iterator en=exterior.begin()+exterior.size()*(i+1)/20;
		T.insert(be,en);
		std::cout<<"*";
	}

}
示例#14
0
void draw_facets(Delaunay &Tr,std::vector<Facet> &facets,CGAL::Geomview_stream &gv) {
  if(! gv_on) return;
  CGAL::Color colors[] = {CGAL::BLUE,CGAL::GREEN,CGAL::YELLOW,CGAL::DEEPBLUE,
			  CGAL::PURPLE,CGAL::VIOLET,CGAL::ORANGE,CGAL::RED};
  int k = 0;
  for (std::vector<Facet>::iterator it = facets.begin();it != facets.end();it++,k++) {
    gv << colors[k % 8];
    Triangle t = Tr.triangle(*it);
    gv << t;
  }
}
bool
emptyLatticeTriangle( const Delaunay & t, const Face_handle & f )
{
  if ( t.is_infinite( f ) ) return false;
  Z2i::Point a( toDGtal(f->vertex(0)->point())),
    b(toDGtal(f->vertex(1)->point())),
    c(toDGtal(f->vertex(2)->point()));
  
  Z2i::Vector ab( b - a ), ac( c - a );
  int d = ab[ 0 ] * ac[ 1 ] - ab[ 1 ] * ac[ 0 ];
  return ( d == 1 ) || (d == -1 );
}
int main () {
	cin.sync_with_stdio(false);
	cout.sync_with_stdio(false);
	Delaunay d;
	int n;
	cin>>n;
	for (int i=0;i<n;++i) {
		double x,y;
		cin>>x>>y;
		d.add_point(x, y);
	}
	d.build();
	auto t=d.get_triangles();
	size_t cnt=t.size()*3;
	cout<<cnt<<endl;
	/*for (auto x : t) {
		cout<<x.a->x<<' '<<x.a->y<<' '<<x.b->x<<' '<<x.b->y<<endl;
		cout<<x.a->x<<' '<<x.a->y<<' '<<x.c->x<<' '<<x.c->y<<endl;
		cout<<x.b->x<<' '<<x.b->y<<' '<<x.c->x<<' '<<x.c->y<<endl;
	}*/
	/*Delaunay d;
	for (;;) {
		double x,y;
		if (!cin.good()) break;
		cin>>x;
		if (!cin.good()) break;
		cin>>y;
		d.add_point(x, y);
	}
	d.build();
	double answer=0;
	size_t ans=0;
	vector< vector<const Delaunay::point *> > cells;
	d.build_voronoi_cells(cells);
	for (size_t i = 0; i < cells.size(); ++i)
		if (cells[i].size())
			answer += cells[i].size(), ++ans;
	cout<<(ans==0 ? 0 : (answer/ans))<<endl;*/
	return 0;
}
示例#17
0
void SparseVectorField::triangulate()
{
  Delaunay dt;
  Delaunay::Finite_edges_iterator eIter;
  Delaunay::Finite_faces_iterator fIter;
  vector< Point >::const_iterator fpIter;
  int i;
  map< Delaunay::Vertex_handle, int > V;
  map< Point, int > Vi;
  Delaunay::Finite_vertices_iterator vIter;
  
  dt.insert(startPoints_.begin(), startPoints_.end());
  
  // Map each vertex to its index.
  for(int i = 0; i < startPoints_.size(); i++)
    Vi[startPoints_[i]] = i;
  
  // Map vertices in the Delaunay triangulation to the original vertices.
  for(vIter = dt.finite_vertices_begin(); vIter != dt.finite_vertices_end(); vIter++)
    V[vIter] = Vi[Point(vIter->point().x(), vIter->point().y())];
  
  // Retrieve vertex indices from the vertex map.
  for(fIter = dt.finite_faces_begin(); fIter != dt.finite_faces_end(); fIter++)
  {
    Delaunay::Face f = *fIter;
    
    triIndices_.push_back(V[f.vertex(0)]);
    triIndices_.push_back(V[f.vertex(1)]);
    triIndices_.push_back(V[f.vertex(2)]);
  }
  
  triangulationValid_ = true;
}
示例#18
0
int main(int argc, char **argv)
{
  int n=1000000;
  int rep=100;
  if (argc>=2)
    n=atoi(argv[1]);
  if (argc>=3)
    rep=atoi(argv[2]);
  std::vector<Point> points;
  points.reserve(n);  
  CGAL::Random_points_in_disc_2<Point,Creator> g(1);
  CGAL::copy_n( g, n, std::back_inserter(points));
  Delaunay original;
  original.insert(points.begin(),points.end());
  
  double res=0;
  for (int r=0;r<rep;++r){
    Delaunay delaunay=original;
    std::vector<Vertex_handle> vertices;
    for(FVI fvi = delaunay.finite_vertices_begin(); fvi != delaunay.finite_vertices_end();++fvi){
      vertices.push_back(fvi);
    }
    CGAL::Timer t;
    t.start();
    for (int k=0; k<vertices.size(); ++k)
      delaunay.remove(vertices[k]);
    t.stop();
    res+=t.time();
    if (delaunay.number_of_vertices()!=0){
      std::cerr << "ERROR"<< std::endl;
      return 1;
    }
  }

  std::cout << res/rep << std::endl;
            
  return 0;
}
示例#19
0
void draw_cells_edges(Delaunay &Tr,std::vector<Cell_handle> &cells,CGAL::Geomview_stream &gv) {
  if(! gv_on) return;
  CGAL::Color colors[] = {CGAL::BLUE,CGAL::GREEN,CGAL::YELLOW};
  int k = 0;
  for (std::vector<Cell_handle>::iterator it = cells.begin();it != cells.end();it++,k++) {
    Cell_handle c = *it;
    gv << colors[k % 3];
    for(int i = 0;i<4;i++)
      for(int j = i+1;j < 4;j++) {
	Segment e = Tr.segment(c,i,j);
	gv << e;
      }
  }
}
示例#20
0
void draw_tetra(Delaunay &Tr,std::vector<Cell_handle> &cells,CGAL::Geomview_stream &gv) {
  if(! gv_on) return;
  CGAL::Color colors[] = {CGAL::BLUE,CGAL::GREEN,CGAL::YELLOW,CGAL::DEEPBLUE,
			  CGAL::PURPLE,CGAL::VIOLET,CGAL::ORANGE,CGAL::RED};
  int k = 0;
  for (std::vector<Cell_handle>::iterator it = cells.begin();it != cells.end();it++,k++) {
    Cell_handle c = *it;
    gv << colors[k % 8];
    Tetrahedron t = Tr.tetrahedron(c);
    //    Tetrahedron t(c->vertex(0)->point(),c->vertex(1)->point(),
    //		  c->vertex(2)->point(),c->vertex(3)->point());
    gv << t;
  }
}
示例#21
0
int main()
{
  std::ifstream fin("terrain.pts"); // elevation ranges from 0 to 100
  Delaunay dt;

  dt.insert(std::istream_iterator<Point_3>(fin),
	    std::istream_iterator<Point_3>());

  Interval_skip_list isl;
  for(Finite_faces_iterator fh = dt.finite_faces_begin();
      fh != dt.finite_faces_end();
      ++fh){
    isl.insert(Interval(fh));
  }
  std::list<Interval> level;
  isl.find_intervals(50, std::back_inserter(level));
  for(std::list<Interval>::iterator it = level.begin();
      it != level.end();
      ++it){
    std::cout << dt.triangle(it->face_handle()) << std::endl;
  }
  return 0;
}
示例#22
0
int main()
{
  Delaunay T;
  CGAL::Random_points_in_sphere_3<Point> rnd;

  // First, make sure the triangulation is 3D.
  T.insert(Point(0,0,0));
  T.insert(Point(1,0,0));
  T.insert(Point(0,1,0));
  T.insert(Point(0,0,1));

  assert(T.dimension() == 3);

  // Inserts 100 random points if and only if their insertion
  // in the Delaunay tetrahedralization conflicts with
  // an even number of cells.
  for (int i = 0; i != 100; ++i) {
    Point p = *rnd++;

    // Locate the point
    Delaunay::Locate_type lt;
    int li, lj;
    Cell_handle c = T.locate(p, lt, li, lj);
    if (lt == Delaunay::VERTEX)
      continue; // Point already exists

    // Get the cells that conflict with p in a vector V,
    // and a facet on the boundary of this hole in f.
    std::vector<Cell_handle> V;
    Facet f;

    T.find_conflicts(p, c,
                     CGAL::Oneset_iterator<Facet>(f), // Get one boundary facet
                     std::back_inserter(V));          // Conflict cells in V

    if ((V.size() & 1) == 0)  // Even number of conflict cells ?
      T.insert_in_hole(p, V.begin(), V.end(), f.first, f.second);
  }

  std::cout << "Final triangulation has " << T.number_of_vertices()
            << " vertices." << std::endl;

  return 0;
}
string DelaunayMesh::InsertSites(Delaunay & mesh, vector<Point2D *> & input)
{
    string answer = "";

    for(unsigned int i = 0; i < input.size(); i++)
    {
        // cerr << "insert " << i << "/" << input.size() << " : (" <<  input[i]->id << ", " << input[i]->x << ", " << input[i]->y << ")" << endl; // debug

        switch(mesh.InsertSite(*input[i]))
        {
        case Delaunay::INSERT_OK:
            // nothing else to do
            break;

        case Delaunay::INSERT_DUPLICATE:
            input[i]->category = Point2D::ORPHAN;
            break;

        case Delaunay::INSERT_FAIL:
            // answer = "cannot insert site";
            input[i]->category = Point2D::ORPHAN;
            break;

        default:
            throw Exception("LloydRelaxation::InsertSites(): unhandled insert site case");
        }
    }

#if 0
    vector<Point2D *> output;
    for(unsigned int i = 0; i < input.size(); i++)
    {
        if(input[i])
        {
            output.push_back(input[i]);
        }
    }
    input = output;
#endif

    return answer;
}
void VoronoiCgal_Patch::mark_domains(Delaunay& ct, Delaunay::Face_handle start,
									 int index, std::list<Delaunay::Edge>& border)
{
	if (start->info().nesting_level != TRIANGLE_NOT_INIT)
	{
		return;
	}

	std::list<Delaunay::Face_handle> queue;
	queue.push_back(start);

	while (! queue.empty())
	{
		Delaunay::Face_handle fh = queue.front();
		queue.pop_front();

		if (fh->info().nesting_level == TRIANGLE_NOT_INIT)
		{
			fh->info().nesting_level = index;

			for (int i = 0; i < 3; i++)
			{
				Delaunay::Edge e(fh, i);
				Delaunay::Face_handle n = fh->neighbor(i);

				if (n->info().nesting_level == TRIANGLE_NOT_INIT)
				{
					if (ct.is_constrained(e))
					{
						border.push_back(e);
					}
					else
					{
						queue.push_back(n);
					}
				}
			}
		}
	}
}
示例#25
0
int main()
{
  Delaunay T;
  CGAL::Random_points_in_cube_3<Point> rnd(0.5);
  GT::Vector_3 v(0.5,0.5,0.5);

  // First, make sure the triangulation is 3D.
  T.insert(Point(0,0,0));
  T.insert(Point(.1,0,0));
  T.insert(Point(0,.1,0));
  T.insert(Point(0,0,.1));

  // Gets the conflict region of 100 random points
  // in the Delaunay tetrahedralization
  for (int i = 0; i != 100; ++i) {
    Point p = (*rnd++)+v;

    // Locate the point
    Delaunay::Locate_type lt;
    int li, lj;
    Cell_handle c = T.locate(p, lt, li, lj);
    if (lt == Delaunay::VERTEX)
      continue; // Point already exists

    // Get the cells that conflict with p in a vector V,
    // and a facet on the boundary of this hole in f.
    std::vector<Cell_handle> V;
    Facet f;

    T.find_conflicts(p, c,
		     CGAL::Oneset_iterator<Facet>(f), // Get one boundary facet
		     std::back_inserter(V));          // Conflict cells in V
    }

  std::cout << "Final triangulation has " << T.number_of_vertices()
            << " vertices." << std::endl;

  return 0;
}
void TrPlaneStress2dXFEM :: XfemElementInterface_partitionElement(AList< Triangle > *answer, std :: vector< FloatArray > &together)
{
    Delaunay dl;
    dl.triangulate(together, answer);
    return;
/*
	// Two cases may occur when partitioning: we will get a subdomain
	// with either 3 or 4 nodes.
	if( together->giveSize() == 3 )
	{
		// 3 nodes

        FloatArray *p1 = new FloatArray();
        * p1 = * ( together->at(1) );
        FloatArray *p2 = new FloatArray();
        * p2 = * ( together->at(2) );
        FloatArray *p3 = new FloatArray();
        * p3 = * ( together->at(3) );

        Triangle *triangle = new Triangle(p1, p2, p3);
        if ( !triangle->isOrientedAnticlockwise() ) {
            triangle->changeToAnticlockwise();
        }

        answer->put(1, triangle);

	}
	else
	{
		if( together->giveSize() == 4 )
		{
			// 4 nodes

			// The array *together contains the four vertices of the area to be subdivided.
			// The intersection points are located in the first two entries in the array and
			// the vertex points are located in the last two entries in the array. We do not know
			// if the last two entries are numbered such that the four vertices form a proper quad.
			// We have to check if this is the case and if not, we swap the last two points.
			int nodeMap[4] = {1, 2, 3, 4};



			//////////////////////////////////////////////////////////////////////
			// We have two options for the subdivision.
			//
			// Which option we choose will probably not matter in the end.
			// However, trying to get triangles of good quality can't do
			// any harm. Start by checking the mesh quality we
			// will get for the two choices.


	        FloatArray *p1 = new FloatArray();
	        * p1 = * ( together->at(nodeMap[0]) );
	        FloatArray *p2 = new FloatArray();
	        * p2 = * ( together->at(nodeMap[1]) );
	        FloatArray *p3 = new FloatArray();
	        * p3 = * ( together->at(nodeMap[2]) );
	        FloatArray *p4 = new FloatArray();
	        * p4 = * ( together->at(nodeMap[3]) );


//	        bPoint2 b1_tmp( p1->at(1), p1->at(2) );
//	        bPoint2 b2_tmp( p2->at(1), p2->at(2) );
//	        bPoint2 b3_tmp( p3->at(1), p3->at(2) );
//	        bPoint2 b4_tmp( p4->at(1), p4->at(2) );

//	        bPoint2 cutLine( b2_tmp.x() - b1_tmp.x(), b2_tmp.y() - b1_tmp.y() );
	        FloatArray cutLine;
	        cutLine.beDifferenceOf(*p2, *p1);

//	        bPoint2  elLine( b4_tmp.x() - b3_tmp.x(), b4_tmp.y() - b3_tmp.y() );
	        FloatArray elLine;
	        elLine.beDifferenceOf(*p2, *p3);

//	        if( bDot(cutLine, elLine) > 0 )
	        if( cutLine.dotProduct(elLine) > 0.0 )
	        {
//	        	printf("Permuting node map.\n");
	        	nodeMap[2] = 4;
	        	nodeMap[3] = 3;
	        }

	        * p1 = * ( together->at(nodeMap[0]) );
	        * p2 = * ( together->at(nodeMap[1]) );
	        * p3 = * ( together->at(nodeMap[2]) );
	        * p4 = * ( together->at(nodeMap[3]) );

//	        bPoint2 b1( p1->at(1), p1->at(2) );
//	        bPoint2 b2( p2->at(1), p2->at(2) );
//	        bPoint2 b3( p3->at(1), p3->at(2) );
//	        bPoint2 b4( p4->at(1), p4->at(2) );


	        // Subdivision alternative 1
	        // 1 - 2 - 4
	        // and
	        // 2 - 3 - 4

	        // Triangle 1
//	        double a1_1 = bDist( b1, b2 );
	        double a1_1 = p1->distance(*p2);
//	        double b1_1 = bDist( b2, b4 );
	        double b1_1 = p2->distance(*p4);
//	        double c1_1 = bDist( b4, b1 );
	        double c1_1 = p4->distance(*p1);

//	        bSeg2 AB1_1(b1, b2);
//	        double h1_1 = bDist(b4, AB1_1);
	        double h1_1 = p4->distance(*p1,*p2);

	        double A1_1 = 0.5*a1_1*h1_1;
	        double R1_1 = 0.25*a1_1*b1_1*c1_1/A1_1;

	        double sin_a1_1 = 0.5*a1_1/R1_1;
	        double sin_b1_1 = 0.5*b1_1/R1_1;
	        double sin_c1_1 = 0.5*c1_1/R1_1;

	        double rho1_1 = ( sin_a1_1 + sin_b1_1 +  sin_c1_1 )/( 2.0*sin_a1_1*sin_b1_1*sin_c1_1 );
//	        printf("rho1_1: %e ", rho1_1);

	        // Triangle 2
//	        double a2_1 = bDist( b2, b3 );
	        double a2_1 = p2->distance(*p3);
//	        double b2_1 = bDist( b3, b4 );
	        double b2_1 = p3->distance(*p4);
//	        double c2_1 = bDist( b4, b2 );
	        double c2_1 = p4->distance(*p2);

//	        bSeg2 AB2_1(b2, b3);
//	        double h2_1 = bDist(b4, AB2_1);
	        double h2_1 = p4->distance(*p2,*p3);

	        double A2_1 = 0.5*a2_1*h2_1;
	        double R2_1 = 0.25*a2_1*b2_1*c2_1/A2_1;

	        double sin_a2_1 = 0.5*a2_1/R2_1;
	        double sin_b2_1 = 0.5*b2_1/R2_1;
	        double sin_c2_1 = 0.5*c2_1/R2_1;

	        double rho2_1 = ( sin_a2_1 + sin_b2_1 +  sin_c2_1 )/( 2.0*sin_a2_1*sin_b2_1*sin_c2_1 );
//	        printf("rho2_1: %e\n", rho2_1);

	        double worst1 = max( fabs(rho1_1-2.0), fabs(rho2_1-2.0) );
//	        printf("worst1: %e\n", worst1 );

	        // Subdivision alternative 2
	        // 1 - 2 - 3
	        // and
	        // 1 - 3 - 4

	        // Triangle 1
//	        double a1_2 = bDist( b1, b2 );
	        double a1_2 = p1->distance(p2);
//	        double b1_2 = bDist( b2, b3 );
	        double b1_2 = p2->distance(*p3);
//	        double c1_2 = bDist( b3, b1 );
	        double c1_2 = p3->distance(*p1);

//	        bSeg2 AB1_2(b1, b2);
//	        double h1_2 = bDist(b3, AB1_2);
	        double h1_2 = p3->distance(*p1,*p2);

	        double A1_2 = 0.5*a1_2*h1_2;
	        double R1_2 = 0.25*a1_2*b1_2*c1_2/A1_2;

	        double sin_a1_2 = 0.5*a1_2/R1_2;
	        double sin_b1_2 = 0.5*b1_2/R1_2;
	        double sin_c1_2 = 0.5*c1_2/R1_2;

	        double rho1_2 = ( sin_a1_2 + sin_b1_2 +  sin_c1_2 )/( 2.0*sin_a1_2*sin_b1_2*sin_c1_2 );
//	        printf("rho1_2: %e ", rho1_2);

	        // Triangle 2
//	        double a2_2 = bDist( b1, b3 );
	        double a2_2 = p1->distance(*p3);
//	        double b2_2 = bDist( b3, b4 );
	        double b2_2 = p3->distance(*p4);
//	        double c2_2 = bDist( b4, b1 );
	        double c2_2 = p4->distance(*p1);

//	        bSeg2 AB2_2(b1, b3);
//	        double h2_2 = bDist(b4, AB2_2);
	        double h2_2 = p4->distance(*p1,*p3);

	        double A2_2 = 0.5*a2_2*h2_2;
	        double R2_2 = 0.25*a2_2*b2_2*c2_2/A2_2;

	        double sin_a2_2 = 0.5*a2_2/R2_2;
	        double sin_b2_2 = 0.5*b2_2/R2_2;
	        double sin_c2_2 = 0.5*c2_2/R2_2;

	        double rho2_2 = ( sin_a2_2 + sin_b2_2 +  sin_c2_2 )/( 2.0*sin_a2_2*sin_b2_2*sin_c2_2 );
//	        printf("rho2_2: %e\n", rho2_2);

	        double worst2 = max( fabs(rho1_2-2.0), fabs(rho2_2-2.0) );
//	        printf("worst2: %e\n", worst2 );


			//////////////////////////////////////////////////////////////////////

	        if( worst1 < worst2 )
	        {
	        	// Choose subdivision 1
		        // 1 - 2 - 4
		        // and
		        // 2 - 3 - 4

//	        	printf("Choosing subdivision 1.\n");

		        FloatArray *p1A = new FloatArray();
		        * p1A = * ( together->at(nodeMap[0]) );
		        FloatArray *p2A = new FloatArray();
		        * p2A = * ( together->at(nodeMap[1]) );
		        FloatArray *p3A = new FloatArray();
		        * p3A = * ( together->at(nodeMap[3]) );

		        Triangle *triangle1 = new Triangle(p1A, p2A, p3A);

		        if ( !triangle1->isOrientedAnticlockwise() ) {
		            triangle1->changeToAnticlockwise();
		        }
		        answer->put(1, triangle1);

		        FloatArray *p1B = new FloatArray();
		        * p1B = * ( together->at(nodeMap[1]) );
		        FloatArray *p2B = new FloatArray();
		        * p2B = * ( together->at(nodeMap[2]) );
		        FloatArray *p3B = new FloatArray();
		        * p3B = * ( together->at(nodeMap[3]) );

		        Triangle *triangle2 = new Triangle(p1B, p2B, p3B);

		        if ( !triangle2->isOrientedAnticlockwise() ) {
		            triangle2->changeToAnticlockwise();
		        }
		        answer->put(2, triangle2);

	        }
	        else
	        {
	        	// Choose subdivision 2
		        // 1 - 2 - 3
		        // and
		        // 1 - 3 - 4

//	        	printf("Choosing subdivision 2.\n");

		        FloatArray *p1A = new FloatArray();
		        * p1A = * ( together->at(nodeMap[0]) );
		        FloatArray *p2A = new FloatArray();
		        * p2A = * ( together->at(nodeMap[1]) );
		        FloatArray *p3A = new FloatArray();
		        * p3A = * ( together->at(nodeMap[2]) );

		        Triangle *triangle1 = new Triangle(p1A, p2A, p3A);

		        if ( !triangle1->isOrientedAnticlockwise() ) {
		            triangle1->changeToAnticlockwise();
		        }
		        answer->put(1, triangle1);

		        FloatArray *p1B = new FloatArray();
		        * p1B = * ( together->at(nodeMap[0]) );
		        FloatArray *p2B = new FloatArray();
		        * p2B = * ( together->at(nodeMap[2]) );
		        FloatArray *p3B = new FloatArray();
		        * p3B = * ( together->at(nodeMap[3]) );

		        Triangle *triangle2 = new Triangle(p1B, p2B, p3B);

		        if ( !triangle2->isOrientedAnticlockwise() ) {
		            triangle2->changeToAnticlockwise();
		        }
		        answer->put(2, triangle2);

	        }

		}
	}
*/
}
示例#27
0
文件: B2.cpp 项目: piotrmwojcik/AA
void computeD(Delaunay &T)
{
      T.insert(points.begin(), points.end());
      G.resize(n);
}
示例#28
0
文件: ekfoa.cpp 项目: Yvaine/ekfoa
void EKFOA::process(const double delta_t, cv::Mat & frame, Eigen::Vector3d & rW, Eigen::Vector4d & qWR, Eigen::Matrix3d & axes_orientation_and_confidence, std::vector<Point3d> (& XYZs)[3], Delaunay & triangulation, Point3d & closest_point){
	double time_total;
	std::vector<cv::Point2f> features_to_add;
	std::vector<Features_extra> features_extra;

	/*
	 * EKF prediction (state and measurement prediction)
	 */
	time_total = (double)cv::getTickCount();
	double time_prediction = (double)cv::getTickCount();
	filter.predict_state_and_covariance(delta_t);
	filter.compute_features_h(cam, features_extra);
	time_prediction = (double)cv::getTickCount() - time_prediction;
//	std::cout << "predict = " << time_prediction/((double)cvGetTickFrequency()*1000.) << "ms" << std::endl;

	/*
	 * Sense and map management (delete features from EKF)
	 */
	double time_tracker = (double)cv::getTickCount();
	motion_tracker.process(frame, features_extra, features_to_add);
	//TODO: Why is optical flow returning points outside the image???
	time_tracker = (double)cv::getTickCount() - time_tracker;

	time_total = time_total + time_tracker; //do not count the time spent by the tracker

	//Delete no longer seen features from the state, covariance matrix and the features_extra:
	double time_del = (double)cv::getTickCount();
	filter.delete_features(features_extra);
	time_del = (double)cv::getTickCount() - time_del;
//	std::cout << "delete  = " << time_del/((double)cvGetTickFrequency()*1000.) << "ms" << std::endl;

	/*
	 * EKF Update step and map management (add new features to EKF)
	 */
	double time_update = (double)cv::getTickCount();
	filter.update(cam, features_extra);
	time_update = (double)cv::getTickCount() - time_update;
//	std::cout << "update  = " << time_update/((double)cvGetTickFrequency()*1000.) << "ms" << std::endl;


	//Add new features
	double time_add = (double)cv::getTickCount();
	filter.add_features_inverse_depth(cam, features_to_add);
	time_add = (double)cv::getTickCount() - time_add;
//	std::cout << "add_fea = " << time_add/((double)cvGetTickFrequency()*1000.) << "ms" << std::endl;


	/*
	 * Triangulation, surface and GUI data setting:
	 */
	double time_triangulation = (double)cv::getTickCount();

	std::vector< std::pair<Point2d, size_t> > triangle_list;
	std::list<Triangle> triangles_list_3d;

	const Eigen::VectorXd & x_k_k = filter.x_k_k();
	const Eigen::MatrixXd & p_k_k = filter.p_k_k();

	//Set the position, so the GUI can draw it:
	rW = x_k_k.segment<3>(0);//current position

	//Set the axes orientation and confidence:
	axes_orientation_and_confidence.setIdentity();//axes_orientation_and_confidence stores in each column one axis (X, Y, Z)
	axes_orientation_and_confidence *= 5; //make the lines larger, so they are actually informative
	//Apply rotation matrix:
	Eigen::Matrix3d qWR_R;//Rotation matrix of current orientation quaternion
	qWR = x_k_k.segment<4>(3);
	MotionModel::quaternion_matrix(qWR, qWR_R);
	axes_orientation_and_confidence.applyOnTheLeft(qWR_R); // == R * axes_orientation_and_confidence
	for (int axis=0 ; axis<axes_orientation_and_confidence.cols() ; axis++){
		//Set the length to be 3*sigma:
		axes_orientation_and_confidence.col(axis) *= 3*std::sqrt(p_k_k(axis, axis)); //the first 3 positions of the cov matrix define the confidence for the position
		//Translate origin:
		axes_orientation_and_confidence.col(axis) += rW;
	}

	int num_features = (x_k_k.rows()-13)/6;
	XYZs[0].resize(num_features);
	XYZs[1].resize(num_features);
	XYZs[2].resize(num_features);


	//Compute the 3d positions and inverse depth variances of all the points in the state
	int i=0; //Feature counter
	for (int start_feature=13 ; start_feature<x_k_k.rows() ; start_feature+=6){
		const int feature_inv_depth_index = start_feature + 5;

		//As with any normal distribution, nearly all (99.73%) of the possible depths lie within three standard deviations of the mean!
		const double sigma_3 = std::sqrt(p_k_k(feature_inv_depth_index, feature_inv_depth_index)); //sqrt(depth_variance)

		const Eigen::VectorXd & yi = x_k_k.segment(start_feature, 6);
		Eigen::VectorXd point_close(x_k_k.segment(start_feature, 6));
		Eigen::VectorXd point_far(x_k_k.segment(start_feature, 6));

		//Change the depth of the feature copy, so that it is possible to represent the range between -3*sigma and 3*sigma:
		point_close(5) += sigma_3;
		point_far(5) -= sigma_3;

		Eigen::Vector3d XYZ_mu = (Feature::compute_cartesian(yi)); //mu (mean)
		Eigen::Vector3d XYZ_close = (Feature::compute_cartesian(point_close)); //mean + 3*sigma. (since inverted signs are also inverted)
		Eigen::Vector3d XYZ_far = (Feature::compute_cartesian(point_far)); //mean - 3*sigma

		//The center of the model is ALWAYS the current position of the camera/robot, so have to 'cancel' the current orientation (R_inv) and translation (rWC = x_k_k.head(3)):
		//Note: It is nicer to do this in the GUI class, as it is only a presention/perspective change. But due to the structure, it was easier to do it here.
		XYZs[0][i] = Point3d(XYZ_mu(0), XYZ_mu(1), XYZ_mu(2)); //mu (mean)
		XYZs[1][i] = Point3d(XYZ_close(0), XYZ_close(1), XYZ_close(2)); //mean + 3*sigma. (since inverted signs are also inverted)
		XYZs[2][i] = Point3d(XYZ_far(0), XYZ_far(1), XYZ_far(2)); //mean - 3*sigma

		//If the size that contains the 99.73% of the inverse depth distribution is smaller than the current inverse depth, add it to the surface:
		const double size_sigma_3 = std::abs(1.0/(x_k_k(feature_inv_depth_index)-sigma_3) - 1.0/(x_k_k(feature_inv_depth_index)+sigma_3));
		if (size_sigma_3 < 1/x_k_k(feature_inv_depth_index)){
			triangle_list.push_back(std::make_pair(Point2d(features_extra[i].z(0), features_extra[i].z(1)), i));
		}

		if (x_k_k(feature_inv_depth_index) < 0 ){
			std::cout << "feature behind the camera!!! : idx=" << i << ", value=" << x_k_k(feature_inv_depth_index) << std::endl;
		}
		i++;
	}

	triangulation.insert(triangle_list.begin(), triangle_list.end());

	cv::Scalar delaunay_color = cv::Scalar(255, 0, 0); //blue
	for(Delaunay::Finite_faces_iterator fit = triangulation.finite_faces_begin(); fit != triangulation.finite_faces_end(); ++fit) {
		const Delaunay::Face_handle & face = fit;
		//face->vertex(i)->info() = index of the point in the observation list.
		line(frame, features_extra[face->vertex(0)->info()].z_cv, features_extra[face->vertex(1)->info()].z_cv, delaunay_color, 1);
		line(frame, features_extra[face->vertex(1)->info()].z_cv, features_extra[face->vertex(2)->info()].z_cv, delaunay_color, 1);
		line(frame, features_extra[face->vertex(2)->info()].z_cv, features_extra[face->vertex(0)->info()].z_cv, delaunay_color, 1);

		//Add the face of the linked 3d points of this 2d triangle:
		triangles_list_3d.push_back(Triangle(XYZs[1][face->vertex(0)->info()], XYZs[1][face->vertex(1)->info()], XYZs[1][face->vertex(2)->info()])); //XYZs[1] == close
	}

	// constructs AABB tree
	Tree tree(triangles_list_3d.begin(), triangles_list_3d.end());

	if (tree.size()>0){
		// compute closest point and squared distance
		Point3d point_query(rW[0], rW[1], rW[2]);
		closest_point = tree.closest_point(point_query);
//		FT sqd = tree.squared_distance(point_query);

		Eigen::Vector3d last_displacement_vector = last_position - rW;

//		double repealing_force = 0;
//		if (std::sqrt(sqd) < 0.2){
//			std::cout << "can crash! " << std::endl;
//			repealing_force = 1/std::sqrt(sqd);
//		}
//		std::cout << "distance = [distance, " << std::sqrt(sqd) << "];" << std::endl;
//		std::cout << "repealing_force = [repealing_force, " << repealing_force << "];" << std::endl;
	}


	//remember this position
	last_position = rW;
//	std::cout << "certaint= " << p_k_k.diagonal().sum() << std::endl;

	time_triangulation = (double)cv::getTickCount() - time_triangulation;
//	std::cout << "Triang  = " << time_triangulation/((double)cvGetTickFrequency()*1000.) << "ms" << std::endl;

	time_total = (double)cv::getTickCount() - time_total;
//	std::cout << "EKF     = " << time_total/((double)cvGetTickFrequency()*1000.) << "ms" << std::endl;

//	std::cout << "tracker = " << time_tracker/((double)cvGetTickFrequency()*1000.) << "ms" << std::endl;
}
/**
 * Performs the testing of dynamic convex hull of CGAL.
 */
int main(int argc, char** argv)
{
	DEBUG_START;
	if (argc != 2)
	{
		print_usage(argc, argv);
		DEBUG_END;
		return EXIT_FAILURE;
	}

	int num_points = 0;
	if (sscanf(argv[1], "%d", &num_points) != 1)
	{
		print_usage(argc, argv);
		DEBUG_END;
		return EXIT_FAILURE;
	}

	CGAL::Random_points_on_sphere_3<Point_3> gen(100.0);
	std::list<Point_3> points;
	
	/*
	 * generate <num_points> points randomly on a sphere of radius 100.0
	 * and copy them to a std::vector
	 */
	CGAL::cpp11::copy_n(gen, num_points, std::back_inserter(points) );
	
	/* begin time measurement */
	TimeMeasurer timer;
	timer.pushTimer();
	Delaunay T;

	T.insert(points.begin(), points.end());
	std::list<Vertex_handle> vertices;
	T.incident_vertices(T.infinite_vertex(), std::back_inserter(vertices));
	
	/*
	 * copy the convex hull of points into a polyhedron and use it
	 * to get the number of points on the convex hull
	 */
	Polyhedron_3 chull0;
	CGAL::convex_hull_3_to_polyhedron_3(T,chull0);
	
	std::cout << "The convex hull contains " << chull0.size_of_vertices()
		<< " vertices" << std::endl;
	
	/* end time measurement */
	double timeFirst = timer.popTimer();
	printf("Time for initial construction of convex hull: %lf\n", timeFirst);
	
	/* begin time measurement */
	timer.pushTimer();
	
	/* Remove 90% of points. */
	float nReduced = (1. - 1. / (float) FACTOR_OF_VERTICES_REDUCTION) *
		chull0.size_of_vertices();
		
	std::list<Vertex_handle>::iterator v_set_it = vertices.begin();
	for (int i = 0; i < nReduced; i++)
	{
		T.remove(*v_set_it);
		v_set_it++;
	}

	/*
	 * copy the convex hull of points into a polyhedron and use it
	 * to get the number of points on the convex hull
	 */
	Polyhedron_3 chull;
	CGAL::convex_hull_3_to_polyhedron_3(T,chull);
	
	/* end time measurement */
	double timeSecond = timer.popTimer();
	printf("Time for recalculating of convex hull: %lf\n", timeSecond);
	
	std::cout << "The convex hull contains " << chull.size_of_vertices()
		<< " vertices" << std::endl;

	DEBUG_END;
	return 0;
}
示例#30
0
    void LFS::compute(const std::vector<vec3>& vertices, 
		double sliver_quality_degree /*= 0.01*/,
		const bool* feature_label /*= 0*/) {
        Delaunay* del = Delaunay::create("CGAL_spatial_sort") ;
        del->set_vertices(vertices) ;
        std::vector<int> tets ;
        del->get_tetras(tets, false) ;
        unsigned int nb_tets = (unsigned int)tets.size() / 4 ;

        //compute tets' circumcenter and radius
        std::vector<vec3> tet_circumcenter(nb_tets);
        std::vector<double> tet_radius(nb_tets);
        std::vector<bool> used_tet(nb_tets, false); // to avoid multiple insertion

        int nv = (int)vertices.size();
        poles.clear();
        poles.reserve(nv*2);
        std::vector<double> dis(nv, 0);
        std::vector<int> tetid(nv, -1);
        std::vector<bool> infinite_flag(nv, false);
        std::vector<bool> infinite_tet(nb_tets, false);
        N.clear();
        N.resize(nv);
        std::fill(N.begin(),N.end(), vec3(0,0,0)); // N x + d = 0 is a plane equation
        std::vector<double> d(nv, 0);
        std::vector<bool> good_tetra(nb_tets, true); 

        int start = 0;
        int vertex_id[4];
        vec3 normal;
        double quality[6];
        int bad_tetra = 0;
        const double mPI = 3.1415926535897932384626433832795;
        const double sliver_quality = sliver_quality_degree / 180. * mPI;
        for(unsigned int i = 0; i < nb_tets; i++) 
            {
                //set id
                int inf_id = -1;
                for (int j = 0; j < 4; j++)
                    {
                        vertex_id[j] = tets[start+j];
                        if (vertex_id[j] == -1)
                            {
                                infinite_tet[i] = true;
                                inf_id = j;
                            }
                    }

                if (!infinite_tet[i])
                    {
                        bool suc = tetra_circumcenter_squaredradius(
                            vertices[tets[start]], 
                            vertices[tets[start+1]], 
                            vertices[tets[start+2]],
                            vertices[tets[start+3]], 
                            tet_circumcenter[i], tet_radius[i], quality);
						if ( suc == false ||
							(
								(quality[0] <= sliver_quality ||  quality[0] >= mPI - sliver_quality) &&
								(quality[1] <= sliver_quality ||  quality[1] >= mPI - sliver_quality) &&
								(quality[2] <= sliver_quality ||  quality[2] >= mPI - sliver_quality) &&
								(quality[3] <= sliver_quality ||  quality[3] >= mPI - sliver_quality) &&
								(quality[4] <= sliver_quality ||  quality[4] >= mPI - sliver_quality) &&
								(quality[5] <= sliver_quality ||  quality[5] >= mPI - sliver_quality) 
							)
						   )
                        {
                            good_tetra[i] = false;
                            bad_tetra++;
                        }
                        

                        //set dis
                        if (good_tetra[i])
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                if ( tet_radius[i] > dis[ vertex_id[j] ] )
                                {
                                    dis[ vertex_id[j] ] = tet_radius[i];
                                    tetid[ vertex_id[j] ] = i;
                                }
                            }
                        }
                        


                    }
                else
                    {
                        const int &id1 = vertex_id[(inf_id+1)%4];
                        const int &id2 = vertex_id[(inf_id+2)%4];
                        const int &id3 = vertex_id[(inf_id+3)%4];

                        infinite_flag[ id1  ] = true;
                        infinite_flag[ id2  ] = true;
                        infinite_flag[ id3  ] = true;
                        normal = inf_id%2==0? 
                            normalize(cross(vertices[id3]-vertices[id1], vertices[id2]-vertices[id1])):
                            normalize(cross(vertices[id2]-vertices[id1], vertices[id3]-vertices[id1]));
                        N[id1] += normal;
                        N[id2] += normal;
                        N[id3] += normal;
                    }

                start += 4;
            }

        std::cerr <<"Total tetrahedrons (including infinite tetras): " << nb_tets << std::endl;
        std::cerr <<"detected " << bad_tetra << " sliver tetrahedrons (min dihedral angle = " << sliver_quality_degree <<" degree" << std::endl;
        //set poles, first round
        for (int i = 0; i < nv; i++)
            {
                if (!infinite_flag[i])
                    {
                        if ( used_tet[tetid[i]] == false && 
							(feature_label == 0 || feature_label[i] == false))
                            {
                                poles.push_back( tet_circumcenter[ tetid[i] ] );
                                used_tet[tetid[i]] = true;
                            }

                        N[i] = tet_circumcenter[ tetid[i] ] - vertices[i];
                    }
                d[i] = -Geex::dot(N[i], vertices[i]);

            }

        //set poles, second round
        std::fill(dis.begin(),dis.end(), 0);
        std::fill(tetid.begin(),tetid.end(), -1);
        start = 0;
        for (unsigned int i = 0; i < nb_tets; i++)
            {
                if (!infinite_tet[i]  && good_tetra[i])
                    {
                        for (int j = 0; j < 4; j++)
                            {
                                const int& vid = tets[start+j];
                                if ( tet_radius[i] > dis[ vid ] &&  Geex::dot(N[vid], tet_circumcenter[i])+ d[vid] < 0 )
                                    {
                                        dis[vid] = tet_radius[i];
                                        tetid[vid] = i;
                                    }
                            }
                    }
                start += 4;
            }
        for (int i = 0; i < nv; i++)
            {
                if ( tetid[i] >= 0  && used_tet[tetid[i]] == false &&
					(feature_label == 0 || feature_label[i] == false))
                    {
                        poles.push_back( tet_circumcenter[ tetid[i] ] );
                        used_tet[tetid[i]] = true;
                    }
            }
        delete del ;
        create_kdtree();
    }