def CompositeProcess(imageWidth, imageHeight, tempDir, cmdList, region, opacities, bgcolor, fileQueue): """Performs the composition of image ppm files and writes the resulting ppm filename in the provided file queue :param imageWidth: image width :param imageHeight: image height :param tempDir: directory for rendering :param cmdList: list of d.rast/d.vect commands :param region: region as a dict or None :param opacites: list of opacities :param bgcolor: background color as a tuple of 3 values 0 to 255 :param fileQueue: the inter process communication queue storing the file name of the image """ maps = [] masks = [] for cmd in cmdList: maps.append(GetFileFromCmd(tempDir, cmd, region)) masks.append(GetFileFromCmd(tempDir, cmd, region, "pgm")) filename = GetFileFromCmds(tempDir, cmdList, region) # Set the environment variables for this process _setEnvironment(imageWidth, imageHeight, filename, transparent=False, bgcolor=bgcolor) opacities = [str(op) for op in opacities] bgcolor = ":".join([str(part) for part in bgcolor]) returncode, stdout, messages = read2_command( "g.pnmcomp", overwrite=True, input="%s" % ",".join(reversed(maps)), mask="%s" % ",".join(reversed(masks)), opacity="%s" % ",".join(reversed(opacities)), bgcolor=bgcolor, width=imageWidth, height=imageHeight, output=filename, ) if returncode != 0: gcore.warning("Rendering composite failed:\n" + messages) fileQueue.put(None) os.remove(filename) return fileQueue.put(filename)
def RenderProcess3D(imageWidth, imageHeight, tempDir, cmd, region, bgcolor, fileQueue): """Renders image with m.nviz.image and writes the resulting ppm filename in the provided file queue :param imageWidth: image width :param imageHeight: image height :param tempDir: directory for rendering :param cmd: m.nviz.image command as a list :param region: region as a dict :param bgcolor: background color as a tuple of 3 values 0 to 255 :param fileQueue: the inter process communication queue storing the file name of the image """ filename = GetFileFromCmd(tempDir, cmd, None) os.environ["GRASS_REGION"] = gcore.region_env(region3d=True, **region) Debug.msg(1, "Render image to file " + str(filename)) cmdTuple = cmdlist_to_tuple(cmd) cmdTuple[1]["output"] = os.path.splitext(filename)[0] # set size cmdTuple[1]["size"] = "%d,%d" % (imageWidth, imageHeight) # set format cmdTuple[1]["format"] = "ppm" cmdTuple[1]["bgcolor"] = bgcolor = ":".join([str(part) for part in bgcolor]) returncode, stdout, messages = read2_command(cmdTuple[0], **cmdTuple[1]) if returncode != 0: gcore.warning("Rendering failed:\n" + messages) fileQueue.put(None) os.environ.pop("GRASS_REGION") return os.environ.pop("GRASS_REGION") fileQueue.put(filename)
def RenderProcess2D(imageWidth, imageHeight, tempDir, cmd, region, bgcolor, fileQueue): """Render raster or vector files as ppm image and write the resulting ppm filename in the provided file queue :param imageWidth: image width :param imageHeight: image height :param tempDir: directory for rendering :param cmd: d.rast/d.vect command as a list :param region: region as a dict or None :param bgcolor: background color as a tuple of 3 values 0 to 255 :param fileQueue: the inter process communication queue storing the file name of the image """ filename = GetFileFromCmd(tempDir, cmd, region) transparency = True # Set the environment variables for this process _setEnvironment(imageWidth, imageHeight, filename, transparent=transparency, bgcolor=bgcolor) if region: os.environ['GRASS_REGION'] = gcore.region_env(**region) cmdTuple = CmdToTuple(cmd) returncode, stdout, messages = read2_command(cmdTuple[0], **cmdTuple[1]) if returncode != 0: gcore.warning("Rendering failed:\n" + messages) fileQueue.put(None) if region: os.environ.pop('GRASS_REGION') os.remove(filename) return if region: os.environ.pop('GRASS_REGION') fileQueue.put(filename)
def Load(self, force=False, bgcolor=(255, 255, 255), nprocs=4): """Loads data, both 2D and 3D. In case of 2D, it creates composites, even when there is only 1 layer to compose (to be changed for speedup) :param force: if True reload all data, otherwise only missing data :param bgcolor: background color as a tuple of 3 values 0 to 255 :param nprocs: number of procs to be used for rendering """ Debug.msg( 2, "BitmapProvider.Load: " "force={f}, bgcolor={b}, nprocs={n}".format(f=force, b=bgcolor, n=nprocs)) cmds = [] regions = [] if self._uniqueCmds: cmds.extend(self._uniqueCmds) regions.extend(self._regionsForUniqueCmds) if self._cmds3D: cmds.extend(self._cmds3D) regions.extend([None] * len(self._cmds3D)) count = self._dryRender(cmds, regions, force=force) self.renderingStarted.emit(count=count) # create no data bitmap if None not in self._bitmapPool or force: self._bitmapPool[None] = createNoDataBitmap( self.imageWidth, self.imageHeight) ok = self._renderer.Render(cmds, regions, regionFor3D=self._regionFor3D, bgcolor=bgcolor, force=force, nprocs=nprocs) self.renderingFinished.emit() if not ok: self.mapsLoaded.emit() # what to do here? return if self._cmdsForComposition: count = self._dryCompose(self._cmdsForComposition, self._regions, force=force) self.compositionStarted.emit(count=count) self._composer.Compose(self._cmdsForComposition, self._regions, self._opacities, bgcolor=bgcolor, force=force, nprocs=nprocs) self.compositionFinished.emit() if self._cmds3D: for cmd in self._cmds3D: self._bitmapPool[HashCmds([cmd], None)] = \ wx.Bitmap(GetFileFromCmd(self._tempDir, cmd, None)) self.mapsLoaded.emit()
def _dryRender(self, uniqueCmds, regions, force): """Determines how many files will be rendered. :param uniqueCmds: list of commands which are to be rendered :param force: if forced rerendering :param regions: list of regions assigned to the commands """ count = 0 for cmd, region in zip(uniqueCmds, regions): filename = GetFileFromCmd(self._tempDir, cmd, region) if not force and os.path.exists(filename) and \ self._mapFilesPool.GetSize(HashCmd(cmd, region)) == (self.imageWidth, self.imageHeight): continue count += 1 Debug.msg(3, "BitmapProvider._dryRender: {c} files to be rendered".format(c=count)) return count
def Render(self, cmdList, regions, regionFor3D, bgcolor, force, nprocs): """Renders all maps and stores files. :param cmdList: list of rendering commands to run :param regions: regions for 2D rendering assigned to commands :param regionFor3D: region for setting 3D view :param bgcolor: background color as a tuple of 3 values 0 to 255 :param force: if True reload all data, otherwise only missing data :param nprocs: number of procs to be used for rendering """ Debug.msg(3, "BitmapRenderer.Render") count = 0 # Variables for parallel rendering proc_count = 0 proc_list = [] queue_list = [] cmd_list = [] filteredCmdList = [] for cmd, region in zip(cmdList, regions): if cmd[0] == "m.nviz.image": region = None filename = GetFileFromCmd(self._tempDir, cmd, region) if (not force and os.path.exists(filename) and self._mapFilesPool.GetSize(HashCmd( cmd, region)) == (self.imageWidth, self.imageHeight)): # for reference counting self._mapFilesPool[HashCmd(cmd, region)] = filename continue filteredCmdList.append((cmd, region)) mapNum = len(filteredCmdList) stopped = False self._isRendering = True for cmd, region in filteredCmdList: count += 1 # Queue object for interprocess communication q = Queue() # The separate render process if cmd[0] == "m.nviz.image": p = Process( target=RenderProcess3D, args=( self.imageWidth, self.imageHeight, self._tempDir, cmd, regionFor3D, bgcolor, q, ), ) else: p = Process( target=RenderProcess2D, args=( self.imageWidth, self.imageHeight, self._tempDir, cmd, region, bgcolor, q, ), ) p.start() queue_list.append(q) proc_list.append(p) cmd_list.append((cmd, region)) proc_count += 1 # Wait for all running processes and read/store the created images if proc_count == nprocs or count == mapNum: for i in range(len(cmd_list)): proc_list[i].join() filename = queue_list[i].get() self._mapFilesPool[HashCmd(cmd_list[i][0], cmd_list[i][1])] = filename self._mapFilesPool.SetSize( HashCmd(cmd_list[i][0], cmd_list[i][1]), (self.imageWidth, self.imageHeight), ) proc_count = 0 proc_list = [] queue_list = [] cmd_list = [] self.renderingContinues.emit(current=count, text=_("Rendering map layers")) if self._stopRendering: self._stopRendering = False stopped = True break self._isRendering = False return not stopped