Exemple #1
0
// Merge this with other, taking the outlines from other.
// Other is not deleted, but left for the caller to handle.
void BLOBNBOX::really_merge(BLOBNBOX* other) {
  if (cblob_ptr != NULL && other->cblob_ptr != NULL) {
    C_OUTLINE_IT ol_it(cblob_ptr->out_list());
    ol_it.add_list_after(other->cblob_ptr->out_list());
  }
  compute_bounding_box();
}
Exemple #2
0
	void ksearch_common(Point q, unsigned int k, long unsigned int query_point_index, qknn &que, float Eps) {
		Point bound_box_lower_corner, bound_box_upper_corner;
		Point low, high;

		que.set_size(k);
		eps=(float) 1.0+Eps;
		if (query_point_index >= (k)) query_point_index -= (k);
		else query_point_index=0;

		long unsigned int initial_scan_upper_range=query_point_index+2*k+1;
		if (initial_scan_upper_range > (long unsigned int)points.size())
			initial_scan_upper_range = (long unsigned int)points.size();

		low = points[query_point_index];
		high = points[initial_scan_upper_range-1];
		for (long unsigned int i=query_point_index; i<initial_scan_upper_range; ++i) {
			que.update(points[i].sqr_dist(q), pointers[i]);
		}
		compute_bounding_box(q, bound_box_lower_corner, bound_box_upper_corner, sqrt(que.topdist()));

		if (lt(bound_box_upper_corner, high) && lt(low,bound_box_lower_corner)) {
			return;
		}

		//Recurse through the entire set
		recurse(0, points.size(), q, que, bound_box_lower_corner, bound_box_upper_corner, query_point_index, initial_scan_upper_range);
	}
Exemple #3
0
void Mesh::translateCenter(const Vec3& c)
{
	for(int i = 0; i < numVtx(); ++i)
	{
		Vertex_handle v = find_vertex(i);
		v->point() -= c;
	}
	compute_bounding_box();		
	centerOfMass();
}
Exemple #4
0
	inline void recurse(long unsigned int s,     // Starting index
	                    long unsigned int n,     // Number of points
	                    Point q,  // Query point
	                    qknn &ans, // Answer que
	                    Point &bound_box_lower_corner,
	                    Point &bound_box_upper_corner,
	                    long unsigned int initial_scan_lower_range,
	                    long unsigned int initial_scan_upper_range) {
		if (n < 4) {
			if (n == 0) return;

			bool update=false;
			for (long unsigned int i=0; i < n; ++i) {
				if ((s+i >= initial_scan_lower_range)
				        && (s+i < initial_scan_upper_range))
					continue;
				update = ans.update(points[s+i].sqr_dist(q), pointers[s+i]) || update;
			}
			if (update)
				compute_bounding_box(q, bound_box_lower_corner, bound_box_upper_corner, sqrt(ans.topdist()));
			return;
		}

		if ((s+n/2 >= initial_scan_lower_range) && (s+n/2 < initial_scan_upper_range)) {
		} else if (ans.update(points[s+n/2].sqr_dist(q), pointers[s+n/2]))
			compute_bounding_box(q, bound_box_lower_corner, bound_box_upper_corner, sqrt(ans.topdist()));

		double dsqb = lt.dist_sq_to_quad_box(q,points[s], points[s+n-1]);

		if (dsqb > ans.topdist()) return;
		if (lt(q,points[s+n/2])) {
			recurse(s, n/2, q, ans, bound_box_lower_corner, bound_box_upper_corner, initial_scan_lower_range, initial_scan_upper_range);
			if (lt(points[s+n/2],bound_box_upper_corner))
				recurse(s+n/2+1,n-n/2-1, q, ans, bound_box_lower_corner, bound_box_upper_corner, initial_scan_lower_range, initial_scan_upper_range);
		} else {
			recurse(s+n/2+1, n-n/2-1, q, ans, bound_box_lower_corner, bound_box_upper_corner, initial_scan_lower_range, initial_scan_upper_range);
			if (lt(bound_box_lower_corner,points[s+n/2]))
				recurse(s, n/2, q, ans, bound_box_lower_corner, bound_box_upper_corner, initial_scan_lower_range, initial_scan_upper_range);
		}
	}
Exemple #5
0
void Mesh::transformVertices(const TrMatrix& tr)
{
	for(Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it)
	{
		Vec3& p = it->m_p;
		p = tr.multVec(Vec4(p)).toVec();
	}

	// do some of the things done in finalize since all points were changed.
	compute_normals_per_facet();
	compute_normals_per_vertex();
	compute_bounding_box();	
	compute_triangle_surfaces();	
	centerOfMass();
}
Exemple #6
0
/* Bounds handler for the pixbuf canvas item */
static void
foo_canvas_pixbuf_bounds (FooCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
	FooCanvasPixbuf *gcp;
	PixbufPrivate *priv;

	gcp = FOO_CANVAS_PIXBUF (item);
	priv = gcp->priv;

	if (!priv->pixbuf) {
		*x1 = *y1 = *x2 = *y2 = 0.0;
		return;
	}

	compute_bounding_box (gcp, 0.0, 0.0,
			      x1, y1, x2, y2);
}
Exemple #7
0
/* Point handler for the pixbuf canvas item */
static double
foo_canvas_pixbuf_point (FooCanvasItem *item, double x, double y, int cx, int cy,
			   FooCanvasItem **actual_item)
{
	FooCanvasPixbuf *gcp;
	PixbufPrivate *priv;
	double x1, y1, x2, y2;
	int px, py;
	double no_hit;
	guchar *src;
	GdkPixbuf *pixbuf;

	gcp = FOO_CANVAS_PIXBUF (item);
	priv = gcp->priv;
	pixbuf = priv->pixbuf;

	*actual_item = item;

	no_hit = item->canvas->pixels_per_unit * 2 + 10;

	if (!priv->pixbuf)
		return no_hit;

	compute_bounding_box (gcp, 0.0, 0.0,
			      &x1, &y1, &x2, &y2);


	if (x < x1 || x >= x2 ||
	    y < y1 || y >= y2)
		return no_hit;

	if (!gdk_pixbuf_get_has_alpha (pixbuf) || priv->point_ignores_alpha)
		return 0.0;

	px = (x - x1) * gdk_pixbuf_get_width (pixbuf) / (x2 - x1);
	py = (y - y1) * gdk_pixbuf_get_height (pixbuf) / (y2 - y1);

	src = gdk_pixbuf_get_pixels (pixbuf) +
		py * gdk_pixbuf_get_rowstride (pixbuf) +
		px * gdk_pixbuf_get_n_channels (pixbuf);

	if (src[3] < 128)
		return no_hit;
	else
		return 0.0;
}
Exemple #8
0
void Mesh::rescaleAndCenter(float destdialen)
{
	Vec3 dia = m_max - m_min;
	Vec3 center = (m_max + m_min) / 2.0;

	float dialen = qMax(dia.x, dia.y);
	float scale = destdialen/dialen;

	for(int i = 0; i < numVtx(); ++i)
	{
		Vertex_handle v = find_vertex(i);
		Vec3 &p = v->point();
		p -= center;
		p *= scale;
	}

	compute_bounding_box();		
	centerOfMass();
}
Exemple #9
0
void Mesh::finalize(bool needEdges)
{
	buildVerticesInFaces();

	if (!m_externalVtxNormals && !m_externalFaceNormals)
	{
		compute_normals_per_facet();
		compute_normals_per_vertex();
	}
	else if (!m_externalFaceNormals)
	{
		average_normals_per_facet();
	}

	compute_bounding_box();		
	//mesh->estimateCurvature();
	compute_triangle_surfaces();	
	centerOfMass();
	//m_mesh->compute_volume();
	
	if (needEdges)
		buildEdges();
}
Exemple #10
0
// Rotates the box and the underlying blob.
void BLOBNBOX::rotate(FCOORD rotation) {
  cblob_ptr->rotate(rotation);
  rotate_box(rotation);
  compute_bounding_box();
}
int main()
{

    const uint n = 128; // 16384
    const uint k = 4;   // 128
    const double std_dev = 0.75; //0.20


    uint *idx = new uint[N];
    data_type *data_points = new data_type[N];
    uint *cntr_indices = new uint[K];
    kdTree_type *heap = new kdTree_type[HEAP_SIZE];
    data_type *initial_centre_positions= new data_type[K];

    // read data points from file
    if (read_data_points(n,k,std_dev,data_points,idx) == false)
        return 1;

    // read intial centre from file (random placement
    if (read_initial_centres(n,k,std_dev,initial_centre_positions,cntr_indices) == false)
        return 1;

    // print initial centres
    printf("Initial centres\n");
    for (uint i=0; i<k; i++) {
        printf("%d: ",i);
        for (uint d=0; d<D-1; d++) {
            printf("%d ",get_coord_type_vector_item(initial_centre_positions[i].value, d).to_int());
        }
        printf("%d\n",get_coord_type_vector_item(initial_centre_positions[i].value, D-1).to_int());
    }


    // compute axis-aligned hyper rectangle enclosing all data points
    data_type bnd_lo, bnd_hi;
    compute_bounding_box(data_points, idx, n, &bnd_lo, &bnd_hi);

    node_pointer root[P];
    kdTree_type *tree_image = new kdTree_type[HEAP_SIZE];
    node_pointer *tree_image_addr = new node_pointer[HEAP_SIZE];
    uint z=0;
    uint ofs=0;
    recursive_split(1, n, bnd_lo, bnd_hi, idx, data_points,&z,&ofs,root,heap,tree_image,tree_image_addr,n,k,std_dev);

    data_type clusters_out[K];
    coord_type_ext distortion_out[K];

    // FIXME: get automatic co-simulation working

    /*
    for (uint i=0; i<P; i++) {
    	root[i] = 0;
    }
    for (uint i=0; i<2*n-1; i++) {
    	tree_image[i].bnd_hi = bnd_hi;
    	tree_image[i].bnd_lo = bnd_lo;
    	tree_image[i].count.VAL = i;
    	tree_image[i].idx = NULL;
    	tree_image[i].left.VAL = 0;
    	tree_image[i].right.VAL = 0;
    	tree_image[i].midPoint = bnd_hi;
    	tree_image[i].sum_sq.VAL = 0;
    	tree_image[i].wgtCent = conv_short_to_long(bnd_hi);
    	tree_image_addr[i].VAL = i;
    }
	*/

    filtering_algorithm_top(tree_image,tree_image_addr,initial_centre_positions,2*n-1-1-(P-1),k-1,root,distortion_out,clusters_out);

    // print initial centres
    printf("New centres after clustering\n");
    for (uint i=0; i<k; i++) {
        printf("%d: ",i);
        for (uint d=0; d<D-1; d++) {
            printf("%d ",get_coord_type_vector_item(clusters_out[i].value, d).to_int());
        }
        printf("%d\n",get_coord_type_vector_item(clusters_out[i].value, D-1).to_int());
    }


    delete idx;
    delete data_points;
    delete initial_centre_positions;
    delete cntr_indices;

    // FIXME: find out why C simulation reports memory fault if I don't comment these lines out
    //delete heap;
    //delete tree_image;
    //delete tree_image_addr;


    return 0;
}
Exemple #12
0
/* Update handler for the pixbuf canvas item */
static void
foo_canvas_pixbuf_update (FooCanvasItem *item,
			    double i2w_dx, double i2w_dy,
			    int flags)
{
	FooCanvasPixbuf *gcp;
	PixbufPrivate *priv;
	double bbox_x0, bbox_y0, bbox_x1, bbox_y1;
	int w, h;

	gcp = FOO_CANVAS_PIXBUF (item);
	priv = gcp->priv;

	if (parent_class->update)
		(* parent_class->update) (item, i2w_dx, i2w_dy, flags);

	/* If we need a pixbuf update, or if the item changed visibility to
	 * shown, recompute the bounding box.
	 */
	if (priv->need_pixbuf_update || priv->need_xform_update ||
	    (flags & FOO_CANVAS_UPDATE_DEEP)) {

		foo_canvas_item_request_redraw (item);

		compute_bounding_box (gcp, i2w_dx, i2w_dy,
				      &bbox_x0, &bbox_y0,
				      &bbox_x1, &bbox_y1);

		foo_canvas_w2c_d (item->canvas,
				    bbox_x0, bbox_y0,
				    &item->x1, &item->y1);

		foo_canvas_w2c_d (item->canvas,
				    bbox_x1, bbox_y1,
				    &item->x2, &item->y2);

		item->x1 = floor (item->x1 + .5);
		item->y1 = floor (item->y1 + .5);
		item->x2 = floor (item->x2 + .5);
		item->y2 = floor (item->y2 + .5);

#ifdef FOO_CANVAS_PIXBUF_VERBOSE
		g_print ("BBox is %g %g %g %g\n", item->x1, item->y1, item->x2, item->y2);
#endif

		if (priv->pixbuf) {
			w = item->x2 - item->x1;
			h = item->y2 - item->y1;

			if (priv->pixbuf_scaled)
				g_object_unref (priv->pixbuf_scaled);
			if (gdk_pixbuf_get_width (priv->pixbuf) != w ||
			    gdk_pixbuf_get_height (priv->pixbuf) != h)
				priv->pixbuf_scaled = gdk_pixbuf_scale_simple (
					priv->pixbuf, w, h, priv->interp_type);
			else
				priv->pixbuf_scaled = g_object_ref (priv->pixbuf);
		}

		foo_canvas_item_request_redraw (item);

		priv->need_pixbuf_update = FALSE;
		priv->need_xform_update = FALSE;
	}
}
Exemple #13
0
void sfcnn_knng_work<Point, Ptype>::sfcnn_knng_work_init(long int N, unsigned int k, int num_threads)
{
  zorder_lt<Point> lt;
  Point bound_box_lower_corner,
	bound_box_upper_corner;
  double distance;
  long int range_b;
  long int range_e;

  if(N==0)
    {
      std::cerr << "Error:  Input Point List has size 0"<< std::endl;
      exit(1);
    }
  max = (std::numeric_limits<Ptype>::max)();
  min = (std::numeric_limits<Ptype>::min)();
  answer.resize(N);

  int SR = 2*k;


#ifdef _OPENMP
  long int chunk = N/num_threads;
  omp_set_num_threads(num_threads);
#endif

  pair_iter<typename std::vector<Point>::iterator,
    typename std::vector<long unsigned int>::iterator> a(points.begin(), pointers.begin()),
    b(points.end(), pointers.end());
  sort(a,b,lt);
  std::vector<qknn> que;
  que.resize(N);

#ifdef _OPENMP  
#pragma omp parallel private(distance, range_b, range_e) 
#endif
  {
#ifdef _OPENMP  
#pragma omp for schedule(static, chunk)
#endif
    for(long int i=0;i < N;++i)
      {
	range_b = i-SR;
	if(range_b < 0) range_b = 0;
	range_e = i+SR+1;
	if(range_e > N) range_e = N;
	que[i].set_size(k);
	for(long int j=range_b;j < i;++j)
	  {
	    distance = points[i].sqr_dist(points[j]);
	    que[i].update(distance, pointers[j]);
	  }
	for(long int j=i+1;j < range_e;++j)
	  {
	    distance = points[i].sqr_dist(points[j]);
	    que[i].update(distance, pointers[j]);
	  }
      }
  }

#ifdef _OPENMP  
#pragma omp parallel private(distance, range_b, range_e, bound_box_lower_corner, bound_box_upper_corner) 
#endif
  {
#ifdef _OPENMP  
#pragma omp for schedule(static, chunk)
#endif
      for(long int i=0;i < N;++i)
	{
	  range_b = i-SR;
	  if(range_b < 0) range_b = 0;
	  range_e = i+SR+1;
	  if(range_e > N) range_e = N;
	  compute_bounding_box(points[i], bound_box_lower_corner, bound_box_upper_corner, sqrt(que[i].topdist()));
	  if(!lt(bound_box_upper_corner, points[range_e-1]) || !lt(points[range_b], bound_box_lower_corner))
	    {
	      recurse(0, N, i, que[i],  
		      bound_box_lower_corner,
		      bound_box_upper_corner,
		      (long unsigned int) range_b,
		      (long unsigned int) range_e,
		      lt);
	      
	    }
	  que[i].answer(answer[pointers[i]]);
	  
	}
  }
      points.clear();
      pointers.clear();
}
Exemple #14
0
void sfcnn_knng_work<Point, Ptype>::recurse(long unsigned int s,   // Starting index
					    long unsigned int n,   // Number of points
					    long int q,
					    qknn &ans, // Answer que
					    Point &bound_box_lower_corner,
					    Point &bound_box_upper_corner,
					    long unsigned int initial_scan_lower_range,
					    long unsigned int initial_scan_upper_range,
					    zorder_lt<Point> &lt)
{	
  double distance;
  if(n < 4)
    {
      if(n == 0) return;
		
      bool update=false;
      for(long unsigned int i=0;i < n;++i)
	{
	  if((s+i >= initial_scan_lower_range) 
	     && (s+i < initial_scan_upper_range))
	    continue;
	  distance = points[q].sqr_dist(points[s+i]);
	  update = ans.update(distance, pointers[s+i]) || update;
	}
      if(update)
	compute_bounding_box(points[q], bound_box_lower_corner, bound_box_upper_corner, sqrt(ans.topdist()));
      return;
    }

  if((s+n/2 >= initial_scan_lower_range) && (s+n/2 < initial_scan_upper_range))
    {
    }
  else 
    {
      distance = points[q].sqr_dist(points[s+n/2]);
      if(ans.update(distance, pointers[s+n/2]))
	compute_bounding_box(points[q], bound_box_lower_corner, bound_box_upper_corner, sqrt(ans.topdist()));
    }
	
  if((lt.dist_sq_to_quad_box(points[q],points[s], points[s+n-1])) > ans.topdist())
    return;
	
	
  if(lt(points[q],points[s+n/2]))
    {
      recurse(s, n/2, q, ans, 
	      bound_box_lower_corner, 
	      bound_box_upper_corner, 
	      initial_scan_lower_range, 
	      initial_scan_upper_range,
	      lt);
      if(lt(points[s+n/2],bound_box_upper_corner))
	recurse(s+n/2+1,n-n/2-1, q, ans, 
		bound_box_lower_corner, 
		bound_box_upper_corner, 
		initial_scan_lower_range, 
		initial_scan_upper_range,
		lt);
    }
  else
    {
      recurse(s+n/2+1, n-n/2-1, q, ans, 
	      bound_box_lower_corner, 
	      bound_box_upper_corner, 
	      initial_scan_lower_range, 
	      initial_scan_upper_range,
	      lt);
      if(lt(bound_box_lower_corner,points[s+n/2]))
	recurse(s, n/2, q, ans, 
		bound_box_lower_corner, 
		bound_box_upper_corner, 
		initial_scan_lower_range, 
		initial_scan_upper_range,
		lt);
    }
}
 //determine bounding box from point cloud positions
 auto init_box(const ndarray<real_t, 2> position) const {
     return compute_bounding_box(position.view<vector_t>());
 }
Exemple #16
0
//In fact its function is same to compute_bounding_box?
void 
Instance::set_bounding_box(void)
{										
	compute_bounding_box();
}
Exemple #17
0
    std::list<VoronoiShard>
    voronoi_convex_hull_shatter(const gl::MeshPtr &the_mesh,
                                const std::vector<glm::vec3>& the_voronoi_points)
    {
        // points define voronoi cells in world space (avoid duplicates)
        // verts = source (convex hull) mesh vertices in local space
        
        std::list<VoronoiShard> ret;
        std::vector<glm::vec3> mesh_verts = the_mesh->geometry()->vertices();
        
        auto convexHC = std::make_shared<btConvexHullComputer>();
        btAlignedObjectArray<btVector3> vertices;
        
        btVector3 rbb, nrbb;
        btScalar nlength, maxDistance, distance;
        std::vector<glm::vec3> sortedVoronoiPoints = the_voronoi_points;
        
        btVector3 normal, plane;
        btAlignedObjectArray<btVector3> planes, convexPlanes;
        std::set<int> planeIndices;
        std::set<int>::iterator planeIndicesIter;
        int numplaneIndices;
        int i, j, k;
        
        // Normalize verts (numerical stability), convert to world space and get convexPlanes
        int numverts = mesh_verts.size();
//        auto aabb = the_mesh->boundingBox();
//        float scale_val = 1.f;//std::max(std::max(aabb.width(), aabb.height()), aabb.depth());
        
        auto mesh_transform = the_mesh->global_transform() ;//* scale(glm::mat4(), vec3(1.f / scale_val));
        std::vector<glm::vec3> world_space_verts;
        
        world_space_verts.resize(mesh_verts.size());
        for (i = 0; i < numverts ;i++)
        {
            world_space_verts[i] = (mesh_transform * vec4(mesh_verts[i], 1.f)).xyz();
        }
        
        //btGeometryUtil::getPlaneEquationsFromVertices(chverts, convexPlanes);
        // Using convexHullComputer faster than getPlaneEquationsFromVertices for large meshes...
        convexHC->compute(&world_space_verts[0].x, sizeof(world_space_verts[0]), numverts, 0.0, 0.0);
        
        int numFaces = convexHC->faces.size();
        int v0, v1, v2; // vertices
        
        // get plane equations for the convex-hull n-gons
        for (i = 0; i < numFaces; i++)
        {
            const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[i]];
            v0 = edge->getSourceVertex();
            v1 = edge->getTargetVertex();
            edge = edge->getNextEdgeOfFace();
            v2 = edge->getTargetVertex();
            plane = (convexHC->vertices[v1]-convexHC->vertices[v0]).cross(convexHC->vertices[v2]-convexHC->vertices[v0]).normalize();
            plane[3] = -plane.dot(convexHC->vertices[v0]);
            convexPlanes.push_back(plane);
        }
        const int numconvexPlanes = convexPlanes.size();
        
        int numpoints = the_voronoi_points.size();
        
        for (i = 0; i < numpoints ; i++)
        {
            auto curVoronoiPoint = the_voronoi_points[i];
            planes.copyFromArray(convexPlanes);
            
            for (j = 0; j < numconvexPlanes; j++)
            {
                planes[j][3] += planes[j].dot(type_cast(the_voronoi_points[i]));
            }
            maxDistance = SIMD_INFINITY;
            
            // sort voronoi points
            std::sort(sortedVoronoiPoints.begin(), sortedVoronoiPoints.end(), pointCmp(curVoronoiPoint));
            
            for (j=1; j < numpoints; j++)
            {
                normal = type_cast(sortedVoronoiPoints[j] - curVoronoiPoint);
                nlength = normal.length();
                if (nlength > maxDistance)
                    break;
                plane = normal.normalized();
                plane[3] = -nlength / btScalar(2.);
                planes.push_back(plane);
                getVerticesInsidePlanes(planes, vertices, planeIndices);
                
                if (vertices.size() == 0) break;
                
                numplaneIndices = planeIndices.size();
                if (numplaneIndices != planes.size())
                {
                    planeIndicesIter = planeIndices.begin();
                    for (k=0; k < numplaneIndices; k++)
                    {
                        if (k != *planeIndicesIter)
                            planes[k] = planes[*planeIndicesIter];
                        planeIndicesIter++;
                    }
                    planes.resize(numplaneIndices);
                }
                maxDistance = vertices[0].length();
                for (k=1; k < vertices.size(); k++)
                {
                    distance = vertices[k].length();
                    if (maxDistance < distance)
                        maxDistance = distance;
                }
                maxDistance *= btScalar(2.);
            }
            if (vertices.size() == 0)
                continue;
            
            // Clean-up voronoi convex shard vertices and generate edges & faces
            convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),0.0,0.0);
            
            // At this point we have a complete 3D voronoi shard mesh contained in convexHC
            
            // Calculate volume and center of mass (Stan Melax volume integration)
            numFaces = convexHC->faces.size();
            btScalar volume = btScalar(0.);
            btVector3 com(0., 0., 0.);
            
            for (j = 0; j < numFaces; j++)
            {
                const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]];
                v0 = edge->getSourceVertex();
                v1 = edge->getTargetVertex();
                edge = edge->getNextEdgeOfFace();
                v2 = edge->getTargetVertex();
                
                while (v2 != v0)
                {
                    // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here...
                    btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]);
                    volume += vol;
                    com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]);
                    edge = edge->getNextEdgeOfFace();
                    
                    v1 = v2;
                    v2 = edge->getTargetVertex();
                }
            }
            com /= volume * btScalar(4.);
            volume /= btScalar(6.);
            
            // Shift all vertices relative to center of mass
            int numVerts = convexHC->vertices.size();
            for (j = 0; j < numVerts; j++)
            {
                convexHC->vertices[j] -= com;
            }
            
            // now create our output geometry with indices
            std::vector<gl::Face3> outer_faces, inner_faces;
            std::vector<glm::vec3> outer_vertices, inner_vertices;
            int cur_outer_index = 0, cur_inner_index = 0;
            
            for (j = 0; j < numFaces; j++)
            {
                const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]];
                v0 = edge->getSourceVertex();
                v1 = edge->getTargetVertex();
                edge = edge->getNextEdgeOfFace();
                v2 = edge->getTargetVertex();
                
                // determine if it is an inner or outer face
                btVector3 cur_plane = (convexHC->vertices[v1] - convexHC->vertices[v0]).cross(convexHC->vertices[v2]-convexHC->vertices[v0]).normalize();
                cur_plane[3] = -cur_plane.dot(convexHC->vertices[v0]);
                bool is_outside = false;
                
                for(uint32_t q = 0; q < convexPlanes.size(); q++)
                {
                    if(is_equal(convexPlanes[q], cur_plane, 0.01f)){ is_outside = true; break;}
                }
                std::vector<gl::Face3> *shard_faces = &outer_faces;
                std::vector<glm::vec3> *shard_vertices = &outer_vertices;
                int *shard_index = &cur_outer_index;
                
                if(!is_outside)
                {
                    shard_faces = &inner_faces;
                    shard_vertices = &inner_vertices;
                    shard_index = &cur_inner_index;
                }
                
                int face_start_index = *shard_index;
                
                // advance index
                *shard_index += 3;
                
                // first 3 verts of n-gon
                glm::vec3 tmp[] = { type_cast(convexHC->vertices[v0]),
                                    type_cast(convexHC->vertices[v1]),
                                    type_cast(convexHC->vertices[v2])};
                
                shard_vertices->insert(shard_vertices->end(), tmp, tmp + 3);
                shard_faces->push_back(gl::Face3(face_start_index,
                                                 face_start_index + 1,
                                                 face_start_index + 2));
                
                // add remaining triangles of face (if any)
                while (true)
                {
                    edge = edge->getNextEdgeOfFace();
                    v1 = v2;
                    v2 = edge->getTargetVertex();
                    
                    // end of n-gon
                    if(v2 == v0) break;
                    
                    shard_vertices->push_back(type_cast(convexHC->vertices[v2]));
                    shard_faces->push_back(gl::Face3(face_start_index,
                                                     *shard_index - 1,
                                                     *shard_index));
                    (*shard_index)++;
                }
            }
            
            // entry construction
            gl::Mesh::Entry e0, e1;
            
            // outer entry
            e0.num_vertices = outer_vertices.size();
            e0.num_indices = outer_faces.size() * 3;
            e0.material_index = 0;
            
            // inner entry
            e1.base_index = e0.num_indices;
            e1.base_vertex = e0.num_vertices;
            e1.num_vertices = inner_vertices.size();
            e1.num_indices = inner_faces.size() * 3;
            e1.material_index = 1;
            
            // create gl::Mesh object for the shard
            auto inner_geom = gl::Geometry::create(), outer_geom = gl::Geometry::create();
            
            // append verts and indices
            outer_geom->append_faces(outer_faces);
            outer_geom->vertices() = outer_vertices;
            outer_geom->compute_face_normals();
            
            inner_geom->append_faces(inner_faces);
            inner_geom->append_vertices(inner_vertices);
            inner_geom->compute_face_normals();
            
            // merge geometries
            outer_geom->append_vertices(inner_geom->vertices());
            outer_geom->append_normals(inner_geom->normals());
            outer_geom->append_indices(inner_geom->indices());
            outer_geom->faces().insert(outer_geom->faces().end(),
                                       inner_geom->faces().begin(), inner_geom->faces().end());
            outer_geom->compute_bounding_box();
            
            auto inner_mat = gl::Material::create();
            
            auto m = gl::Mesh::create(outer_geom, gl::Material::create());
            m->entries() = {e0, e1};
            m->materials().push_back(inner_mat);
            m->set_position(curVoronoiPoint + type_cast(com));
//            m->transform() *= glm::scale(mat4(), vec3(scale_val));
            
            // compute projected texcoords (outside)
            gl::project_texcoords(the_mesh, m);
            
            // compute box mapped texcoords for inside vertices
            auto &indices = m->geometry()->indices();
            auto &vertices = m->geometry()->vertices();
            
            // aabb
            auto out_aabb = the_mesh->bounding_box();
            vec3 aabb_extents = out_aabb.halfExtents() * 2.f;
            
            uint32_t base_vertex = m->entries()[1].base_vertex;
            uint32_t k = m->entries()[1].base_index, kl = k + m->entries()[1].num_indices;
            
            for(;k < kl; k += 3)
            {
                gl::Face3 f(indices[k] + base_vertex,
                            indices[k] + base_vertex + 1,
                            indices[k] + base_vertex + 2);
                
                // normal
                const vec3 &v0 = vertices[f.a];
                const vec3 &v1 = vertices[f.b];
                const vec3 &v2 = vertices[f.c];
                
                vec3 n = glm::normalize(glm::cross(v1 - v0, v2 - v0));
                
                float abs_vals[3] = {fabsf(n[0]), fabsf(n[1]), fabsf(n[2])};
                
                // get principal direction
                int principle_axis = std::distance(abs_vals, std::max_element(abs_vals, abs_vals + 3));
                
//                switch (principle_axis)
//                {
//                    // X-axis
//                    case 0:
//                        //ZY plane
//                        m->geometry()->texCoords()[f.a] = vec2(v0.z - out_aabb.min.z / aabb_extents.z,
//                                                               v0.y - out_aabb.min.y / aabb_extents.y);
//                        m->geometry()->texCoords()[f.b] = vec2(v1.z - out_aabb.min.z / aabb_extents.z,
//                                                               v1.y - out_aabb.min.y / aabb_extents.y);
//                        m->geometry()->texCoords()[f.c] = vec2(v2.z - out_aabb.min.z / aabb_extents.z,
//                                                               v2.y - out_aabb.min.y / aabb_extents.y);
//                        break;
//                        
//                    // Y-axis
//                    case 1:
//                    // XZ plane
//                        m->geometry()->texCoords()[f.a] = vec2(v0.x - out_aabb.min.x / aabb_extents.x,
//                                                               v0.z - out_aabb.min.z / aabb_extents.z);
//                        m->geometry()->texCoords()[f.b] = vec2(v1.x - out_aabb.min.x / aabb_extents.x,
//                                                               v1.z - out_aabb.min.z / aabb_extents.z);
//                        m->geometry()->texCoords()[f.c] = vec2(v2.x - out_aabb.min.x / aabb_extents.x,
//                                                               v2.z - out_aabb.min.z / aabb_extents.z);
//                        break;
//                        
//                    // Z-axis
//                    case 2:
//                        //XY plane
//                        m->geometry()->texCoords()[f.a] = vec2(v0.x - out_aabb.min.x / aabb_extents.x,
//                                                               v0.y - out_aabb.min.y / aabb_extents.y);
//                        m->geometry()->texCoords()[f.b] = vec2(v1.x - out_aabb.min.x / aabb_extents.x,
//                                                               v1.y - out_aabb.min.y / aabb_extents.y);
//                        m->geometry()->texCoords()[f.c] = vec2(v2.x - out_aabb.min.x / aabb_extents.x,
//                                                               v2.y - out_aabb.min.y / aabb_extents.y);
//                        break;
//                        
//                    default:
//                        break;
//                }
            }
            // push to return structure
            ret.push_back({m, volume});
        }
        LOG_DEBUG << "Generated " << ret.size() <<" voronoi shards";
        return ret;
    }