Beispiel #1
0
    def run(self, cad):
        """ @brief Generates ASDF from cad structure
            @param cad Input cad data structure
            @returns Dictionary with 'asdf' defined
        """
        koko.FRAME.status = 'Generating ASDF'

        values = self.get_values()
        if not values: return False

        # Render the expression into an image
        expr = cad.shape

        zmin = expr.zmin if expr.zmin else 0
        zmax = expr.zmax if expr.zmax else 0
        dz = zmax - zmin

        border = cad.border
        region = Region((expr.xmin - border * expr.dx,
                         expr.ymin - border * expr.dy, zmin - border * dz),
                        (expr.xmax + border * expr.dx,
                         expr.ymax + border * expr.dy, zmax + border * dz),
                        values['res'] * cad.mm_per_unit)

        self.asdf = expr.asdf(region=region, mm_per_unit=cad.mm_per_unit)

        koko.FRAME.status = ''

        return {'asdf': self.asdf}
Beispiel #2
0
    def make_flat_image(self, expr, scale):
        """ @brief Renders a flat single image
            @param expr MathTree expression
            @returns An Image object
        """
        region = Region(
            (expr.xmin-self.cad.border*expr.dx,
             expr.ymin-self.cad.border*expr.dy,
             0),
            (expr.xmax+self.cad.border*expr.dx,
             expr.ymax+self.cad.border*expr.dy,
             0),
            scale
        )

        koko.FRAME.status = 'Rendering with libfab'
        self.output += ">>  Rendering image with libfab\n"

        start = datetime.now()
        img = expr.render(region, interrupt=self.c_event,
                          mm_per_unit=self.cad.mm_per_unit)
        img.color = expr.color

        dT = datetime.now() - start
        self.output += "#   libfab render time: %s\n" % dT
        return img
Beispiel #3
0
    def preview(self, event):
        """ @brief Load a downsampled version of the full ASDF
        """
        params = self.get_params(get_bounds=False)
        if params is None:  return
        for p in params:    exec('{0} = params["{0}"]'.format(p))

        voxels = ni * nj * nk

        shift = int(ceil(log(voxels / 128.**3, 8)))
        full = Region(
            (0, 0, 0), (ni-1, nj-1, nk-1), 1, dummy=True
        )
        libfab.build_arrays(
            full, 0, 0, 0, ni*mm, nj*mm, nk*mm
        )
        full.free_arrays = True

        asdf = ASDF(
            libfab.import_vol_region(
                self.filename, ni, nj, nk, full, shift, density,
                True, close_boundary
            )
        )
        mesh = asdf.triangulate()

        koko.FRAME.get_menu('View', '3D').Check(True)
        koko.APP.render_mode('3D')
        koko.GLCANVAS.load_mesh(mesh)
        koko.GLCANVAS.snap = True
Beispiel #4
0
    def refine_math(self):
        """ @brief Refines a mesh based on a math tree
            @details Splits the mesh's bounding box then renders both subregions
            at a higher detail level, saving them in self.children
        """
        region = Region(
            (self.X.lower / self.source.scale,
             self.Y.lower / self.source.scale,
             self.Z.lower / self.source.scale),
            (self.X.upper / self.source.scale,
             self.Y.upper / self.source.scale,
             self.Z.upper / self.source.scale),
             depth=self.source.depth+1
        )

        subregions = region.split()
        meshes = []
        for s in subregions:
            asdf = self.source.expr.asdf(
                region=s, mm_per_unit=self.source.scale
            )
            mesh = asdf.triangulate()

            mesh.source = Struct(
                type=MathTree,
                expr=self.source.expr.clone(),
                depth=self.source.depth+1,
                scale=self.source.scale
            )
            meshes.append(mesh)

        self.children = meshes
        libfab.free_mesh(self.ptr)
        self.ptr = None
Beispiel #5
0
    def render(self,
               region=None,
               resolution=None,
               mm_per_unit=None,
               threads=8,
               interrupt=None):
        """ @brief Renders a math tree into an Image
            @param region Evaluation region (if None, taken from expression bounds)
            @param resolution Render resolution in voxels/unit
            @param mm_per_unit Real-world scale
            @param threads Number of threads to use
            @param interrupt threading.Event that aborts rendering if set
            @returns Image data structure
        """

        if region is None:
            if self.dx is None or self.dy is None:
                raise Exception('Unknown render region!')
            elif resolution is None:
                raise Exception('Region or resolution must be provided!')
            region = Region(
                (self.xmin, self.ymin, self.zmin if self.zmin else 0),
                (self.xmax, self.ymax, self.zmax if self.zmax else 0),
                resolution)

        try:
            float(mm_per_unit)
        except ValueError, TypeError:
            raise ValueError('mm_per_unit must be a number')
Beispiel #6
0
 def bounding_region(self, resolution, alpha=0, beta=0):
     """ @brief Finds a bounding region with the given rotation
         @param resolution Region resolution (voxels/unit)
         @param alpha Rotation about Z axis
         @param beta Rotation about X axis
     """
     b = self.bounds(alpha, beta)
     return Region((b.xmin, b.ymin, b.zmin), (b.xmax, b.ymax, b.zmax),
                   resolution)
Beispiel #7
0
 def make_asdf(self, expr, flat=False):
     ''' Renders an expression to an ASDF '''
     if flat:
         region = Region((expr.xmin - self.cad.border * expr.dx,
                          expr.ymin - self.cad.border * expr.dy, 0),
                         (expr.xmax + self.cad.border * expr.dx,
                          expr.ymax + self.cad.border * expr.dy, 0),
                         self.resolution * self.cad.mm_per_unit)
     else:
         region = Region((expr.xmin - self.cad.border * expr.dx,
                          expr.ymin - self.cad.border * expr.dy,
                          expr.zmin - self.cad.border * expr.dz),
                         (expr.xmax + self.cad.border * expr.dx,
                          expr.ymax + self.cad.border * expr.dy,
                          expr.zmax + self.cad.border * expr.dz),
                         self.resolution * self.cad.mm_per_unit)
     asdf = expr.asdf(region=region,
                      mm_per_unit=self.cad.mm_per_unit,
                      interrupt=self.c_event)
     return asdf
Beispiel #8
0
    def make_mesh(self, expr):
        """ @brief Converts an expression into a mesh.
            @returns The mesh, or False if failure.
        """

        self.output += '>>  Generating triangulated mesh\n'

        DEPTH = 0
        while DEPTH <= 4:

            region = Region(
                (expr.xmin - self.cad.border*expr.dx,
                 expr.ymin - self.cad.border*expr.dy,
                 expr.zmin - self.cad.border*expr.dz),
                (expr.xmax + self.cad.border*expr.dx,
                 expr.ymax + self.cad.border*expr.dy,
                 expr.zmax + self.cad.border*expr.dz),
                 depth=DEPTH
            )

            koko.FRAME.status = 'Rendering to ASDF'

            start = datetime.now()
            asdf = expr.asdf(region=region, mm_per_unit=self.cad.mm_per_unit,
                             interrupt=self.c_event)

            self.output += '#   ASDF render time: %s\n' % (datetime.now() - start)
            if self.event.is_set(): return
            koko.FRAME.output = self.output

            koko.FRAME.status = 'Triangulating'
            start = datetime.now()
            mesh = asdf.triangulate(interrupt=self.c_event)

            if mesh.vcount: break
            else:           DEPTH += 1

        mesh.source = Struct(
            type=MathTree, expr=expr.clone(),
            depth=DEPTH, scale=self.cad.mm_per_unit
        )

        if self.event.is_set(): return

        self.output += '#   Meshing time: %s\n' % (datetime.now() - start)
        self.output += "Generated {:,} vertices and {:,} triangles\n".format(
            mesh.vcount if mesh else 0, mesh.tcount if mesh else 0)

        koko.FRAME.output = self.output
        return mesh
Beispiel #9
0
    def make_image(self, expr):
        ''' Renders a single expression, returning the image
        '''
        zmin = self.cad.zmin if self.cad.zmin else 0
        zmax = self.cad.zmax if self.cad.zmax else 0

        region = Region((self.cad.xmin, self.cad.ymin, zmin),
                        (self.cad.xmax, self.cad.ymax, zmax),
                        self.resolution * self.cad.mm_per_unit)

        img = expr.render(region,
                          mm_per_unit=self.cad.mm_per_unit,
                          interrupt=self.c_event)

        img.color = expr.color
        return img
Beispiel #10
0
    def collapse_tree(self):
        """ @brief Re-renders from the source math tree
        """
        region = Region(
            (self.X.lower / self.source.scale,
             self.Y.lower / self.source.scale,
             self.Z.lower / self.source.scale),
            (self.X.upper / self.source.scale,
             self.Y.upper / self.source.scale,
             self.Z.upper / self.source.scale),
             depth=self.source.depth
        )

        asdf = self.source.expr.asdf(
            region=region, mm_per_unit=self.source.scale
        )
        return asdf.triangulate()
Beispiel #11
0
    def make_image(self, expr, zmin, zmax):
        """ @brief Renders an expression
            @param expr MathTree expression
            @param zmin Minimum Z value (arbitrary units)
            @param zmax Maximum Z value (arbitrary units)
            @returns None for a null image, False for a failure, the Image if success.
        """

        # Adjust view bounds based on cad file scale
        # (since view bounds are in mm, we have to convert to the cad
        #  expression's unitless measure)
        xmin = self.view.xmin
        xmax = self.view.xmax
        ymin = self.view.ymin
        ymax = self.view.ymax

        if expr.xmin is None:   xmin = xmin
        else:   xmin = max(xmin, expr.xmin - self.cad.border*expr.dx)

        if expr.xmax is None:   xmax = xmax
        else:   xmax = min(xmax, expr.xmax + self.cad.border*expr.dx)

        if expr.ymin is None:   ymin = ymin
        else:   ymin = max(ymin, expr.ymin - self.cad.border*expr.dy)

        if expr.ymax is None:   ymax = ymax
        else:   ymax = min(ymax, expr.ymax + self.cad.border*expr.dy)

        region = Region( (xmin, ymin, zmin), (xmax, ymax, zmax),
                         self.view.pixels_per_unit )

        koko.FRAME.status = 'Rendering with libfab'
        self.output += ">>  Rendering image with libfab\n"

        start = datetime.now()
        img = expr.render(region, interrupt=self.c_event,
                          mm_per_unit=self.cad.mm_per_unit)

        img.color = expr.color
        dT = datetime.now() - start
        self.output += "#   libfab render time: %s\n" % dT
        return img
Beispiel #12
0
    def run(self, event):
        params = self.get_params()
        for p in params:    exec('{0} = params["{0}"]'.format(p))

        full = Region(
            (imin, jmin, kmin),
            (imax, jmax, kmax),
            1, dummy=True
        )
        libfab.build_arrays(
            full, imin*mm, jmin*mm, kmin*mm, (imax+1)*mm, (jmax+1)*mm, (kmax+1)*mm
        )
        # Position the lower corner based on imin, jmin, kmin
        full.imin = imin
        full.jmin = jmin
        full.kmin = kmin
        full.free_arrays = True

        koko.FRAME.status = 'Importing ASDF'
        wx.Yield()

        asdf = ASDF(
            libfab.import_vol_region(
                self.filename, ni, nj, nk, full, 0, density,
                True, close_boundary
            )
        )

        koko.FRAME.status = 'Triangulating'
        wx.Yield()

        mesh = asdf.triangulate()
        koko.FRAME.get_menu('View', '3D').Check(True)
        koko.APP.render_mode('3D')
        koko.GLCANVAS.load_mesh(mesh)
        koko.GLCANVAS.snap = True
        koko.FAB.set_input(asdf)

        koko.FRAME.status = ''
        koko.APP.mode = 'asdf'
        koko.APP.filename = None
        koko.APP.savepoint(False)
Beispiel #13
0
    def asdf(self,
             region=None,
             resolution=None,
             mm_per_unit=None,
             merge_leafs=True,
             interrupt=None):
        """ @brief Constructs an ASDF from a math tree.
            @details Runs in up to eight threads.
            @param region Evaluation region (if None, taken from expression bounds)
            @param resolution Render resolution in voxels/unit
            @param mm_per_unit Real-world scale
            @param merge_leafs Boolean determining whether leaf cells are combined
            @param interrupt threading.Event that aborts rendering if set
            @returns ASDF data structure
        """

        if region is None:
            if not self.bounded:
                raise Exception('Unknown render region!')
            elif resolution is None:
                raise Exception('Region or resolution must be provided!')
            region = Region(
                (self.xmin, self.ymin, self.zmin if self.zmin else 0),
                (self.xmax, self.ymax, self.zmax if self.zmax else 0),
                resolution)

        if interrupt is None: interrupt = threading.Event()

        # Shared flag to interrupt rendering
        halt = ctypes.c_int(0)

        # Split the region into up to 8 sections
        split = region.octsect(all=True)
        subregions = [split[i] for i in range(8) if split[i] is not None]
        ids = [i for i in range(8) if split[i] is not None]

        threads = len(subregions)
        clones = [self.clone() for i in range(threads)]
        packed = [libfab.make_packed(c.ptr) for c in clones]

        # Generate a root for the tree
        asdf = ASDF(libfab.asdf_root(packed[0], region), color=self.color)
        asdf.lock.acquire()

        # Multithread the solver process
        q = Queue.Queue()
        args = zip(packed, ids, subregions, [q] * threads)

        # Helper function to construct a single branch
        def construct_branch(ptree, id, region, queue):
            asdf = libfab.build_asdf(ptree, region, merge_leafs, halt)
            queue.put((id, asdf))

        # Run the constructor in parallel to make the branches
        multithread(construct_branch, args, interrupt, halt)
        for p in packed:
            libfab.free_packed(p)

        # Attach the branches to the root
        for s in subregions:
            try:
                id, branch = q.get_nowait()
            except Queue.Empty:
                break
            else:
                # Make sure we didn't get a NULL pointer back
                # (which could occur if the halt flag was raised)
                try:
                    branch.contents
                except ValueError:
                    asdf.lock.release()
                    return None
                asdf.ptr.contents.branches[id] = branch
        libfab.get_d_from_children(asdf.ptr)
        libfab.simplify(asdf.ptr, merge_leafs)
        asdf.lock.release()

        # Set a scale on the ASDF if one was provided
        if mm_per_unit is not None: asdf.rescale(mm_per_unit)

        return asdf