Example #1
0
 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
Example #2
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...")
Example #3
0
    def calculate_mls_values(self, subdivisions, degree, radius):
        if self.mls_subdivisions != subdivisions or self.mls_degree != degree:
            self._log.debug(u"Calculating mls grid values...")

            self.mls_subdivisions = subdivisions
            self.mls_degree = degree
            self.mls_radius = radius
            self.mls_distances = zeros(((subdivisions+2)**3,), dtype='f')
            self.mls_points = zeros(((subdivisions+2)**3,), dtype='3f')

            self.eps = self.box_diag / 100 #((subdivisions or 10) * 10.0)
            self._log.debug("Using radius %f, eps %f..." % (self.mls_radius, self.eps))
            self.square_solver = MinSquares(self)

            for index, point in enumerate(self.iter_regular_xyz_grid_points(subdivisions)):
                distance = self.square_solver.get_point(point, degree)
                self.mls_distances[index] = distance
                self.mls_points[index] = point
        else:
            self._log.debug(u"Using cached mls grid values...")
Example #4
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           = float(norm(max_point - min_point))
        self.distance_threshold = 1 # initialized when needed
        self.eps                = 1.0 # initialized when needed
        self.center             = min_point + 0.5 * (max_point - min_point)

        self.square_solver      = None # initialized when needed

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

        self.cube_node          = None

    @classmethod
    def from_file(cls, filename, invert_normals=False):
        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)
        vertices = array(vertices)
        normals = array(normals)
        # scale points
        scale_factor = 1.0/norm(max(vertices, 0) - min(vertices, 0))
        vertices *= scale_factor
        # invert normals?
        if invert_normals:
            normals *= -1
        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, radius):
        self.calculate_mls_values(subdivisions, degree, radius)
        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[:,3] = 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, radius):
        if self.mls_subdivisions != subdivisions or self.mls_degree != degree:
            self._log.debug(u"Calculating mls grid values...")

            self.mls_subdivisions = subdivisions
            self.mls_degree = degree
            self.mls_radius = radius
            self.mls_distances = zeros(((subdivisions+2)**3,), dtype='f')
            self.mls_points = zeros(((subdivisions+2)**3,), dtype='3f')

            self.eps = self.box_diag / 100 #((subdivisions or 10) * 10.0)
            self._log.debug("Using radius %f, eps %f..." % (self.mls_radius, self.eps))
            self.square_solver = MinSquares(self)

            for index, point in enumerate(self.iter_regular_xyz_grid_points(subdivisions)):
                distance = self.square_solver.get_point(point, degree)
                self.mls_distances[index] = distance
                self.mls_points[index] = point
        else:
            self._log.debug(u"Using cached mls grid values...")

    def query_distance(self, point):
        return self.square_solver.get_point(point, self.mls_degree)

    def query_normal(self, point):
        return self.square_solver.get_normal(point, self.mls_degree)

    def get_implicit_surface(self, subdivisions, degree, radius):
		if self.cube_node is None:
			self.calculate_mls_values(subdivisions, degree, radius)
			self.cube_node = MarchingCubeNode(
					name    = "implicit_surface",
					surface = self,
					color   = (1.0, 0.0, 0.0, 1.0),
					wireframe = False)
		return self.cube_node

    def get_halfedge_mesh(self, optimization_choice, value):
        if self.cube_node:
            halfedge_mesh = HalfEdgeMesh.from_triangles(self.cube_node)
            optimizer = HalfEdgeMeshOptimizer(halfedge_mesh, self)
            if optimization_choice == 0:
                optimizer.optimize_by_faces(value)
            elif optimization_choice == 1:
                optimizer.optimize_by_improvement(value)
            return halfedge_mesh.get_node("HalfEdge Mesh", color=array([1.0, 0.5, 0.0, 1.0]))
        else:
            return None

    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)
Example #5
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)
Example #6
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)