Source code for TXLWizard.TXLWriter

'''
Controller class for generating TXL / SVG / HTML output.\n
Here we can add structures (definitions and content) which will be rendered in the output.
'''

from Patterns import Definitions
from Patterns import Structure
import TXLConverter
import os.path


[docs]class TXLWriter(object): ''' Controller class for generating TXL / SVG / HTML output.\n Here we can add structures (definitions and content) which will be rendered in the output.\n Optionally, a coordinate system grid is drawn. Parameters ---------- ShowGrid : bool, optional Show the coordinate system grid or not.\n Defaults to True GridWidth : int, optional Full width of the coordinate system grid in um.\n Defaults to 800 GridHeight : int, optional Full height of the coordinate system grid in um.\n Defaults to 800 GridSpacing : int, optional Coordinate Sytem Grid Spacing in um.\n Defaults to 100 SubGridSpacing : int, optional Coordinate System Sub-Grid Spacing in um.\n Defaults to 10 Precision : int, optional Number of digits for float to str conversion / Resolution of TXL file.\n Defaults to 4 Examples -------- IGNORE: >>> import sys >>> import os.path >>> sys.path.append(os.path.abspath(os.path.dirname(__file__)+'/../')) IGNORE Import required Modules >>> import TXLWizard.TXLWriter Initialize TXLWriter >>> TXLWriter = TXLWizard.TXLWriter.TXLWriter( ... ShowGrid=True, GridWidth=800, GridHeight=800 ... ) Add a definition structure and add a pattern of type `Circle` >>> MyDefinitionStructure = TXLWriter.AddDefinitionStructure('MyDefinition') >>> MyDefinitionStructure.AddPattern('Circle', Center=[0,0], Radius=20, Layer=3) #doctest: +ELLIPSIS <TXLWizard.Patterns.Circle.Circle object at 0x...> Add a content structure with a pattern `Reference` to reuse the definition structure. >>> MyContentStructure = TXLWriter.AddContentStructure('MySuperCircle') >>> MyContentStructure.AddPattern( ... 'Reference', ... ReferencedStructureID=MyDefinitionStructure.ID, ... OriginPoint=[20,50] ... ) #doctest: +ELLIPSIS <TXLWizard.Patterns.Reference.Reference object at 0x...> Generate the Output files with name `Example_TXLWriter.(txl|html|svg)` to the folder `Tests/Results` >>> TXLWriter.GenerateFiles('Tests/Results/TXLWriter/Example_TXLWriter') ''' def __init__(self, **kwargs): #: float: current software version self._Version = 1.7 #: :class:`TXLWizard.Patterns.Definitions.Definitions`: container for definition structures self._Definitions = Definitions.Definitions() #: bool: Show the coordinate system grid or not self._ShowGrid = True #: int: Full width of the coordinate system grid in um self._GridWidth = 800 #: int: Full height of the coordinate system grid in um self._GridHeight = 800 #: int: Coordinate Sytem Grid Spacing in um. self._GridSpacing = 100 #: int: Coordinate Sytem Sub Grid Spacing in um. self._SubGridSpacing = 10 #: int: Width of the SVG Image in pixels self._SVGWidth = 800 #: int: Height of the SVG Image in pixels self._SVGHeight = 800 #: int: number of digits for float to str conversion / Resolution of TXL file self._Precision = 4 #: int: incrementing number for automatically created indices self._AutoIndexIncrement = 0 #: dict: dictionary of all content structures self._ContentStructures = {} #: list of str: list of indices of content structures, needed for correct order self._ContentStructuresIndexList = [] #: dict: dictionary of all helper structures self._HelperStructures = {} #: list of str: list of indices of helper structures, needed for correct order self._HelperStructuresIndexList = [] for i in ['GridWidth', 'GridHeight', 'GridSpacing', 'SubGridSpacing', 'ShowGrid', 'Precision']: if i in kwargs: setattr(self, '_' + i, kwargs[i]) if self._ShowGrid: self._DrawGrid() def _DrawGrid(self): ''' Draws the coordinate system grids (grid and sub-grid) ''' LineWidth = 10 * 1. / 2. CoordinateXAxis = self._AddHelperStructure('CoordinateXAxis') CoordinateXAxis.AddPattern('Polyline', Points=[ [-self._GridWidth / 2, 0], [self._GridWidth / 2, 0] ], StrokeWidth=LineWidth) CoordinateYAxis = self._AddHelperStructure('CoordinateYAxis') CoordinateYAxis.AddPattern('Polyline', Points=[ [0, -self._GridHeight / 2], [0, self._GridHeight / 2] ], StrokeWidth=LineWidth) Grids = {} for GridName in ['Grid', 'SubGrid']: Grid = self._AddHelperStructure(GridName) Grids[GridName] = Grid GridSpacing = self.__getattribute__('_' + GridName + 'Spacing') if GridName == 'SubGrid': LineWidth = 1. / 2. for i in range(0, int(round(self._GridWidth / GridSpacing / 2))): for j in [-i * GridSpacing, i * GridSpacing]: Grid.AddPattern('Polyline', Points=[ [1. * j, -self._GridHeight / 2.], [1. * j, self._GridHeight / 2.] ], StrokeWidth=LineWidth) for i in range(0, int(round(self._GridHeight / GridSpacing / 2))): for j in [-i * GridSpacing, i * GridSpacing]: Grid.AddPattern('Polyline', Points=[ [-self._GridWidth / 2., 1. * j], [self._GridWidth / 2., 1. * j] ], StrokeWidth=LineWidth)
[docs] def AddDefinitionStructure(self, ID, **kwargs): ''' Add definition structure. A definition structure can be referenced by a content structure.\n A structure corresponds to the "STRUCT" command in the TXL file format. Parameters ---------- ID: str Unique identification of the structure. Must be used when referencing to this structure. kwargs: dict Keyword arguments passed to the structure constructor. See :class:`TXLWizard.Patterns.Structure.Structure` Returns ------- :class:`TXLWizard.Patterns.Structure.Structure` structure instance ''' if ID in self._Definitions.Structures: print('Warning! The structure "' + ID + '" already exists and will be overwritten!') kwargs['TXLWriter'] = self StructureObject = Structure.Structure(ID, **kwargs) self._Definitions.AddStructure(ID, StructureObject) return StructureObject
[docs] def AddContentStructure(self, ID, **kwargs): ''' Add content structure. A content structure can hold patterns that will render in the output.\n A structure corresponds to the "STRUCT" command in the TXL file format. Parameters ---------- ID: str Unique identification of the structure. Must be used when referencing to this structure. kwargs: dict Keyword arguments passed to the structure constructor. See :class:`TXLWizard.Patterns.Structure.Structure` Returns ------- :class:`TXLWizard.Patterns.Structure.Structure` structure instance ''' if ID in self._ContentStructures: print('Warning! The structure "' + ID + '" already exists and will be overwritten!') kwargs['TXLWriter'] = self StructureObject = Structure.Structure(ID, **kwargs) self._ContentStructures[ID] = StructureObject self._ContentStructuresIndexList.append(ID) return self._ContentStructures[ID]
def _AddHelperStructure(self, ID, **kwargs): ''' Add helper structure. Helper structures are only visible in the HTML / SVG Output.\n A structure corresponds to the "STRUCT" command in the TXL file format. Parameters ---------- ID: str Unique identification of the structure. Must be used when referencing to this structure. kwargs: dict keyword arguments passed to the structure constructor Returns ------- :class:`TXLWizard.Patterns.Structure.Structure` structure instance ''' if ID in self._HelperStructures: print('Warning! The structure "' + ID + '" already exists and will be overwritten!') kwargs['TXLWriter'] = self StructureObject = Structure.Structure(ID, **kwargs) self._HelperStructures[ID] = StructureObject self._HelperStructuresIndexList.append(ID) return self._HelperStructures[ID]
[docs] def ImportTXLFile(self, Filename, LayersToProcess=[]): ''' Import an existing TXL file for further processing.\n The content structures can be accessed with `self._ContentStructures` (read-only!).\n The order of the content structures is stored in `self._ContentStructuresIndexList` (read-only!).\n The definition structures are stored in `self._Definitions.Structures` Parameters ---------- Filename : str Path / Filename of the .txl file to be imported LayersToProcess : list of int, optional if given, only layers in this list are processed / shown.\n Defaults to [] Examples -------- Import required modules >>> import TXLWizard.TXLWriter >>> import TXLWizard.ShapeLibrary.Label Initialize TXLWriter >>> TXLWriter = TXLWizard.TXLWriter.TXLWriter() import TXL file `myPath/mask_orig.txl` >>> TXLWriter.ImportTXLFile('Tests/SampleFiles/Example_Simple_Original.txl', LayersToProcess=[1,3,4]) Get an existing structure and add a pattern to it >>> MyStructure = TXLWriter._ContentStructures['MyCircleArray'] >>> MyStructure.AddPattern( ... 'Circle', ... Center=[-100, 0], ... Radius=50, ... Layer=1 ... ) #doctest: +ELLIPSIS <TXLWizard.Patterns.Circle.Circle object at 0x...> Add a label >>> SampleLabelObject = TXLWizard.ShapeLibrary.Label.GetLabel( ... TXLWriter, ... Text='This is my text', ... OriginPoint=[ ... -200, 300 ... ], ... FontSize=150, ... StrokeWidth=20 ... ) Generate the Output files with name `ExampleSimple_Modified.(txl|html|svg)` to the folder `Tests/Results` >>> TXLWriter.GenerateFiles('Tests/Results/TXLWriter/Example_Simple_Modified') ''' TXLConverterObject = TXLConverter.TXLConverter(Filename, LayersToProcess=LayersToProcess, TXLWriter=self) TXLConverterObject.ParseTXLFile()
def _GetAutoStructureID(self, Prefix='AutoID'): ''' Generates a unique structure ID. Parameters ---------- Prefix: str, optional Prefix of the ID.\n Defaults to 'AutoID'. Returns ------- str generated ID ''' ID = Prefix + '_{:d}'.format(self._AutoIndexIncrement) self._AutoIndexIncrement += 1 return ID def _GetFloatFormatString(self, ID=''): ''' Returns a string for formatting a `float`, e.g. `{ID:1.3f}`. The number of digits is specified by `self._Precision` Parameters ---------- ID: str, optional Optional ID for the formatting option.\n Defaults to '' Returns ------- str: string for use with the `str.format()` function ''' if self._Precision > 0: FloatFormatString = '{' + str(ID) + ':1.' + str(self._Precision) + 'f}' else: FloatFormatString = '{' + str(ID) + ':1.0f}' return FloatFormatString
[docs] def GenerateFiles(self, Filename, TXL=True, SVG=True, HTML=True, TargetFolder=None): ''' Generate the output files (.txl, .svg, .html). Parameters ---------- Filename: str Path / Filename without extension. The corresponding path will be created if it does not exist TXL: bool, optional Enable TXL Output.\n Defaults to True SVG: bool, optional Enable SVG Output.\n Defaults to True HTML: bool, optional Enable HTML Output. If set to `True`, also `SVG` needs to be set to `True`\n Defaults to True TargetFolder: str, optional If given, the generated files are stored in the folder specified.\n If not given, the generated files are stored in the path specified in `Filename`\n Defaults to None. ''' Path = os.path.dirname(Filename) if TargetFolder != None: Path = TargetFolder Filename = Path.rstrip('/')+'/'+os.path.basename(Filename) if len(Path) and not os.path.exists(Path): os.makedirs(Path) if TXL: self._GenerateTXLFile(Filename) if SVG: self._GenerateSVGFile(Filename) if HTML: self._GenerateHTMLFile(Filename)
def _GenerateTXLFile(self, Filename): ''' Generate the TXL file. Parameters ---------- Filename: str Path / Filename without extension. ''' f = open(Filename + '.txl', 'w') f.write('LETXTLIB 1.0.0' + '\n') f.write('UNIT MICRON' + '\n') f.write(('RESOLVE ' + self._GetFloatFormatString()).format(10 ** (-1 * self._Precision)) + '\n') f.write('BEGLIB' + '\n') f.write('\n\n' + '! ### Definitions Start ###' + '\n') f.write(self._Definitions.GetTXLOutput()) f.write('\n\n' + '! ### Definitions End ###' + '\n\n') f.write('\n\n' + '! ### Content Structures Start ###' + '\n') for i in self._ContentStructuresIndexList: if self._ContentStructures[i].TXLOutput: f.write(self._ContentStructures[i].GetTXLOutput()) f.write('\n\n' + '! ### Content Structures End ###' + '\n') f.write('ENDLIB' + '\n') f.close() def _GenerateSVGFile(self, Filename): ''' Generate the TXL file. Parameters ---------- Filename: str Path / Filename without extension. ''' # See https://developer.mozilla.org/en-US/docs/Web/SVG f = open(Filename + '.svg', 'w') f.write('<svg version="1.1" baseProfile="full" width="800" height="800" ' + 'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' + 'id="SVGImage" viewBox="{:d} {:d} {:d} {:d}">'.format(int(-self._GridWidth / 2), int(-self._GridHeight / 2), int(self._GridWidth), int(self._GridHeight)) + '\n') f.write(''' <style type="text/css"> <![CDATA[ #HelperStructures{} #HelperStructures .Pattern{opacity:0.8} #CoordinateXAxis .Pattern{stroke:#000} #CoordinateYAxis .Pattern{stroke:#000} #HelperStructures #Grid .Pattern{opacity:0.1;stroke:#000} #HelperStructures #SubGrid .Pattern{opacity:0.1;stroke:#188487} .Pattern{stroke-width:0px;} .Layer0 .Pattern{fill:#467821;stroke:#467821;} .Layer1 .Pattern{fill:#348ABD;stroke:#348ABD;} .Layer2 .Pattern{fill:#E24A33;stroke:#E24A33;} .Layer3 .Pattern{fill:#A60628;stroke:#A60628;} .Layer4 .Pattern{fill:#CF4457;stroke:#CF4457;} .Pattern{opacity:0.6} /*.Pattern:hover, .Object:hover .Pattern{opacity:0.8}*/ ]]> </style> ''') f.write(self._Definitions.GetSVGOutput()) f.write('<g transform="translate({:1.2f},{:1.2f}),matrix(1,0,0,-1,0,0)">'.format(1. * self._SVGWidth / 2., 1. * self._SVGHeight / 2.) + '\n') f.write('<g id="HelperStructures">' + '\n') for i in self._HelperStructuresIndexList: f.write(self._HelperStructures[i].GetSVGOutput()) f.write('</g>') f.write('<g id="ContentStructures">' + '\n') for i in self._ContentStructuresIndexList: f.write(self._ContentStructures[i].GetSVGOutput()) f.write('</g>') f.write('</g>') f.write('</svg>') f.close() def _GenerateHTMLFile(self, Filename): ''' Generate the TXL file. Parameters ---------- Filename: str Path / Filename without extension. ''' f = open(Filename + '.svg', 'r') SVGData = f.read() f.close() f = open(Filename + '.html', 'w') f.write('<html>') f.write(''' <head> <style> body{margin:0px;padding:0px;} #SVGImage {box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;} </style> </head> ''') PanZoom = open(os.path.dirname(__file__) + '/Helpers/svg-pan-zoom.min.js', 'r') PanZoomJS = PanZoom.read() PanZoom.close() f.write(''' <body> <script type="text/javascript">''' + PanZoomJS + '''</script> <div class="Image">''' + SVGData + '''</div> <script type="text/javascript"> var SVGImage = document.getElementById('SVGImage'); SVGImage.setAttribute("height","100%"); SVGImage.setAttribute("width","100%"); SVGImage.removeAttribute("viewBox"); svgPanZoom('#SVGImage', { controlIconsEnabled: true, zoomScaleSensitivity: 0.4, minZoom: 0.5, maxZoom: 10000, }); </script> </body> ''') f.write('</html>')