Raw File
SpherePackSampling.h
#pragma once
#include "Sampler.h"
#include "NanoKdTree.h"

class SpherePackSampling{

public:
    static std::vector<Vector3d> sample(SurfaceMesh::Model * m, int randomSampleCount, double r)
    {
        std::vector<Vector3d> gridPoints = std::vector<Vector3d>();
        return sample(m,randomSampleCount,r,gridPoints);
    }

    static std::vector<Vector3d> sample(SurfaceMesh::Model * m, int randomSampleCount, double r, 
        std::vector<Vector3d> & gridPoints, int density = 1)
	{
        std::vector<Vector3d> samples, centers, rndSamples;

        // Centers of packed spheres
        centers = spheres(r, m->bbox().min(), m->bbox().max(), density);

		// Get a lot of random samples
		foreach(SamplePoint sp, Sampler(m).getSamples(randomSampleCount)){
			rndSamples.push_back(sp.pos);
		}

		// Initialize KD-tree
		NanoKdTree tree;
		foreach(Vector3d p, rndSamples) tree.addPoint(p);
		tree.build();

        foreach(Vector3d center, centers)
        {
			// Collect neighbors
			KDResults matches;
			int n = tree.ball_search( center, r, matches );

            if(n < 1) continue;

			// Record center
			Vector3d centerGroup (0,0,0);
			foreach(KDResultPair i, matches) 
				centerGroup += rndSamples[i.first];
			centerGroup /= matches.size();
			samples.push_back(centerGroup);

			gridPoints.push_back(center);
		}


		return samples;
	}

	/* Hexagonal close packing of spheres (HCP lattice) */
    static std::vector<Vector3d> spheres(double r, Vector3d bbmin, Vector3d bbmax, int density = 1)
	{
        std::vector<Vector3d> samples;

        std::vector< std::vector<Vector3d> > grid;

		double d = r * 2;

		double width = bbmax.x() - bbmin.x();
		double length = bbmax.y() - bbmin.y();
		double height = bbmax.z() - bbmin.z();

		Vector3d corner(bbmin.x()-r, bbmin.y()-r, bbmin.z());

		int dx = (width / r) + 1;
		int dy = (length / r) + 1;
		int dz = (height / r) + 1;

		Vector3d delta(r, sqrt(3.0) * r , 0);
		Vector3d center(0,0,0);

		grid.push_back(std::vector<Vector3d>());

		for(int x = 0; x < dx; x++)
			grid[0].push_back(corner + Vector3d(x * d, 0, 0));

		for(int y = 0; y < dy; y++){
			std::vector<Vector3d> row = grid.back();
			
			for(int x = 0; x < (int)row.size(); x++)	row[x] += delta;

			delta.x() = -delta.x();

			grid.push_back(row);
		}

		Vector3d omega(r, r, sqrt(6.0) * (2.0/3.0) * r);

		for(int z = 0; z < dz; z += density){
			for(int y = 0; y < dy; y += density)
				for(int x = 0; x < dx; x += density)
                    samples.push_back(grid[y][x] + center);
				
			omega.x() *= -1;
			omega.y() *= -1;

			center += omega;
		}

		return samples;
	}

	static std::vector<double> toKDPoint(const SurfaceMesh::Point & from){
		std::vector<double> p(3, 0.0);
		p[0] = from.x(); p[1] = from.y(); p[2] = from.z();
		return p;
	}
};
back to top