예제 #1
0
class ImplicitSurface(object):
    def __init__(self, points, normals):
        self._log = logging.getLogger('ImplicitSurface')
        self.points = points
        self.normals = normals
        self.tree = cKDTree(self.points)

        # choose distance threshold and eps depending on bbox diameter
        min_point, max_point = self.get_bounding_box()
        self.box_diag = norm(max_point - min_point)
        self.eps = self.box_diag * 0.1
        self.center = min_point + 0.5 * (max_point - min_point)


        # cache mls results
        self.mls_subdivisions = None
        self.mls_distances = []
        self.mls_normals = []
        self.mls_points = []

    @classmethod
    def from_file(cls, filename):
        logging.getLogger('SurfaceFactory').info(u"Reading surface from '%s'..." % filename)
        vertices = []
        normals = []
        for vertex, normal in openOff(filename).iter_vertices_and_normals():
            vertices.append(vertex)
            normals.append(normal)
        return cls(points=vertices, normals=normals)

    def get_bounding_box(self, expansion_factor=0.2):
        """Returns the minumum and maximum corners of the bounding box.

        :Parameters:
            expansion_factor : float
                The factor by which to enlarge the bounding box.

        :return: (min_point, max_point)
        """
        min_point = min(self.points, 0)
        max_point = max(self.points, 0)
        diff = max_point - min_point
        min_point -= diff*expansion_factor
        max_point += diff*expansion_factor
        return (min_point, max_point)

    def get_parameter_grid(self, subdivisions, degree=None):
        if degree:
            self.calculate_mls_values(subdivisions, degree)
        if self.mls_subdivisions:
            self._log.debug(u"Calculating colors...")
            colors = zeros(((subdivisions+2)**3,), dtype='4f')
            max_abs_distance = max([abs(min(self.mls_distances)), abs(max(self.mls_distances))])
            for index, distance in enumerate(self.mls_distances):
                if distance < 0:
                    colors[index] = (0.0, 0.0, 1.0, 0.0)
                else:
                    colors[index] = (0.0, 1.0, 0.0, 0.0)
                colors[index] *= (1.0 - abs(float(distance)/max_abs_distance))**4
                colors[index] += (0.0, 0.0, 0.0, 1.0)
        else:
            self._log.debug(u"Using plain colors...")
            colors = None
        return PointCloudNode(
                name   = 'parameter grid',
                points = [(x,y,z) for x,y,z in self.iter_regular_xyz_grid_points(subdivisions)],
                color  = (0.0,1.0,0.0,0.6),
                colors = colors)

    def get_original_point_cloud(self):
        return PointCloudNode(
                name   = 'point cloud',
                points = self.points,
                color  = (1.0, 1.0, 1.0, 1.0))

    def calculate_mls_values(self, subdivisions, degree):
        if self.mls_subdivisions != subdivisions:
            self.distance_threshold = self.box_diag / float(subdivisions + 1)
            self.square_solver = MinSquares(self)
            self._log.debug(u"Calculating mls grid values...")
            self.mls_subdivisions = subdivisions
            self.mls_distances = zeros(((subdivisions+2)**3,), dtype='f')
            self.mls_normals = zeros(((subdivisions+2)**3,), dtype='3f')
            self.mls_points = zeros(((subdivisions+2)**3,), dtype='3f')
            for index, point in enumerate(self.iter_regular_xyz_grid_points(subdivisions)):
                distance, normal = self.square_solver.solveEquations(point, degree)
                self.mls_distances[index] = distance
                self.mls_normals[index] = normal
                self.mls_points[index] = point
        else:
            self._log.debug(u"Using cached mls grid values...")

    def get_implicit_surface(self, subdivisions, degree):
        self.calculate_mls_values(subdivisions, degree)
        return MarchingCubeNode(
                name    = "implicit_surface",
                surface = self,
                color   = (1.0, 0.0, 0.0, 1.0),
                wireframe = False)
        # TODO: perform marching cubes algorithm
#        return SurfaceNode(
#                name   = 'mls surface',
#                width  = subdivisions+2,
#                height = subdivisions+2,
#                points = self.mls_points,
#                normals= self.mls_normals,
#                color  = (1.0,0.0,0.0,0.9))

    def iter_regular_xyz_grid_points(self, subdivisions):
        min_point, max_point = self.get_bounding_box()
        for x in linspace(min_point[0], max_point[0], subdivisions+2):
            for y in linspace(min_point[1], max_point[1], subdivisions+2):
                for z in linspace(min_point[2], max_point[2], subdivisions+2):
                #self._log.debug(u"Yielding (%f, %f)..." % (x, y))
                    yield (x, y, z)
예제 #2
0
class Surface(object):
    def __init__(self, points):
        self._log = logging.getLogger('Surface')
        self.mapping = {}
        for point in points:
            self.mapping[point[0:2]] = point[2]
        self.points = self.mapping.keys()
        self.tree = KDTree(self.points)
        self.square_solver = MinSquares(self)
        # cache mls results
        self.mls_subdivisions = None
        self.mls_points = None

    @classmethod
    def from_file(cls, filename):
        logging.getLogger('SurfaceFactory').info(u"Reading surface from '%s'..." % filename)
        return cls(openOff(filename).iter_vertices())

    def get_parameter_plane(self, subdivisions):
        return SurfaceNode(
                name   = 'parameter plane',
                width  = subdivisions+2,
                height = subdivisions+2,
                points = [(x,y,0) for x,y in self.iter_regular_xy_grid_points(subdivisions)],
                color  = (1.0,1.0,1.0,0.9),
                wireframe = True)

    def get_original_point_cloud(self):
        return PointCloudNode(
                name   = 'point cloud',
                points = self.mapping,
                color  = (1.0, 1.0, 1.0, 0.9))

    def get_mls_interpolated_surface(self, subdivisions):
        if self.mls_subdivisions != subdivisions:
            points_normals = [(x,y) + self.square_solver.solveEquations((x,y)) for x,y in self.iter_regular_xy_grid_points(subdivisions)]
            self.mls_points = [(x,y,z) for x,y,z,n in points_normals]
            self.mls_normals = [n for x,y,z,n in points_normals]
            self.mls_subdivisions = subdivisions
        return SurfaceNode(
                name   = 'mls surface',
                width  = subdivisions+2,
                height = subdivisions+2,
                points = self.mls_points,
                normals= self.mls_normals,
                color  = (1.0,0.0,0.0,0.9))

    def get_bezier_interpolated_surface(self, mls_subdivisions, bezier_factor):
        self._log.debug(u"Creating surface using grid %d and bezier factor %d" % (mls_subdivisions, bezier_factor))
        if self.mls_subdivisions != mls_subdivisions:
            self.get_mls_interpolated_surface(mls_subdivisions)

        value_matrix = transpose(reshape(array(self.mls_points)[:,2], (mls_subdivisions+2, mls_subdivisions+2)), (1,0))
        casteljau = Casteljau(value_matrix)
        points_normals = [(x,y) + casteljau.evaluate_point((x,y)) for x,y in self.iter_regular_xy_grid_points(mls_subdivisions*bezier_factor)]
        return SurfaceNode(
                name   = 'bezier surface',
                width  = mls_subdivisions*bezier_factor+2,
                height = mls_subdivisions*bezier_factor+2,
                points = [(x,y,z) for x,y,z,n in points_normals],
                normals= [n for x,y,z,n in points_normals],
                color  = (0.0,1.0,0.0,0.5))

    def iter_regular_xy_grid_points(self, subdivisions):
        min_point = min(self.points, 0)
        max_point = max(self.points, 0)

        for x in linspace(min_point[0], max_point[0], subdivisions+2):
            for y in linspace(min_point[1], max_point[1], subdivisions+2):
                #self._log.debug(u"Yielding (%f, %f)..." % (x, y))
                yield (x, y)