def test_flat_DXFList(self): atoms = DXFList() atoms.append(DXFAtom('HEADER')) atoms.append(DXFAtom('SECTION', 1)) self.assertEqual(dxfstr(atoms), ' 0\nHEADER\n 1\nSECTION\n') result = tags2str(atoms) self.assertEqual(dxfstr(atoms), result)
def test_Sublists(self): atoms = DXFList([ DXFList([ DXFAtom('TAG1'), DXFAtom('TAG2'), DXFList([ DXFAtom('TAG14'), DXFAtom('TAG15'), DXFAtom('TAG16'), ]), DXFAtom('TAG3'), ]), DXFList([ DXFAtom('TAG4'), DXFAtom('TAG5'), DXFAtom('TAG6'), DXFList([ DXFAtom('TAG11'), DXFAtom('TAG12'), DXFAtom('TAG13'), ]), ]), DXFAtom('TAG7'), ]) self.assertEqual(dxfstr(atoms), tags2str(atoms))
def _build_rect(self): data = DXFList() self._calc_corners() if self.color is not None: data.append(self._build_polyline()) if self.bgcolor is not None: data.append(self._build_solid()) return data
def _get_body(self): """ Return header section content as DXFList. """ varlist = [ DXFList((DXFAtom(key, 9), value)) for key, value in self.variables.items() ] return DXFList((DXFName('HEADER'), DXFList(varlist)))
class Entities(_Section): def __init__(self): self.entities = DXFList() def _get_body(self): return DXFList( (DXFName('ENTITIES'), self.entities)) def add(self, entity): self.entities.append(entity)
class Entities(_Section): def __init__(self): self.entities = DXFList() def _get_body(self): return DXFList((DXFName('ENTITIES'), self.entities)) def add(self, entity): """ Add a DXF entity to the entities section. """ self.entities.append(entity)
def _build(self): data = DXFList() self.transformed_points = self._transform_points(self.points) if self.color is not None: data.append(self._build_polyline()) if self.bgcolor is not None: if len(self.points) <= 4: data.append(self._build_solid()) elif self.solidFillQuads: for i in range(len(self.points) // 2 - 1): data.append(self._build_solid_quad(i)) else: for i in range(len(self.points) - 2): data.append(self._build_solid_triangle(i)) return data
def get_dxf_entity(self, coords, layer): """ Create the cell content as MText-object. :param coords: tuple of border-coordinates : left, right, top, bottom :param layer: layer, which should be used for dxf entities """ if not len(self.text): return DXFList() left, right, top, bottom = self.get_workspace_coords(coords) style = self.style halign = style['halign'] valign = style['valign'] rotated = self.style['rotation'] text = self.text if style['stacked']: rotated = 0. text = '\n'.join((char for char in self.text.replace('\n', ' '))) xpos = (left, float(left + right) / 2., right)[halign] ypos = (bottom, float(bottom + top) / 2., top)[valign - 1] return MText(text, (xpos, ypos), linespacing=self.style['linespacing'], style=self.style['textstyle'], height=self.style['textheight'], rotation=rotated, xscale=self.style['xscale'], halign=halign, valign=valign, color=self.style['textcolor'], layer=layer)
def __init__(self, insert, nrows, ncols, default_grid=True): """ :param insert: insert point as 2D or 3D point :param int nrows: row count :param int ncols: column count :param bool default_grid: if **True** always a solid line grid will be drawn, if **False**, only explicit defined borders will be drawn, default grid has a priority of 50. """ self.insert = insert self.nrows = nrows self.ncols = ncols self.row_heights = [DEFAULT_TABLE_HEIGHT] * nrows self.col_widths = [DEFAULT_TABLE_WIDTH] * ncols self.bglayer = DEFAULT_TABLE_BGLAYER self.fglayer = DEFAULT_TABLE_FGLAYER self.gridlayer = DEFAULT_TABLE_GRIDLAYER self.styles = {'default': Style.get_default_cell_style()} if not default_grid: default_style = self.get_cell_style('default') default_style.set_border_status(False, False, False, False) self._cells = {} # data cells self.frames = [] # border frame objects # visibility_map stores the visibilty of the cells, created in _setup self.visibility_map = None # grid manages the border lines, created in _setup self.grid = None # data contains the resulting dxf entities self.data = DXFList() self.empty_cell = Cell(self) # represents all empty cells
def _build_dxf_entities(self): """ Create the DXF-TEXT entities. """ dxf_entities = DXFList() textlines = self.textlines if len(textlines) > 1: if self.mirror & dxfwrite.MIRROR_Y: textlines.reverse() for linenum, text in enumerate(textlines): alignpoint = self._get_align_point(linenum) params = self._build_text_params(alignpoint) dxf_entities.append(Text(text=text, **params)) elif len(textlines) == 1: params = self._build_text_params(self.insert) dxf_entities = Text(text=textlines[0], **params).__dxftags__() return dxf_entities
def _get_body(self): return DXFList( (DXFName('TABLES'), self.linetypes, self.layers, self.styles, self.views, self.appids, self.viewports, self.ucs, ) )
def __init__(self, insert, width, height, rotation=0., halign=const.LEFT, valign=const.TOP, color=const.BYLAYER, bgcolor=None, layer='0', linetype=None): self.insert = insert self.width = float(width) self.height = float(height) self.rotation = math.radians(rotation) self.halign = halign self.valign = valign self.color = color self.bgcolor = bgcolor self.layer = layer self.linetype = linetype self.points = None self.data = DXFList()
def _build(self): data = DXFList() ralign = self._get_radius_align() self.points = self._calc_points(ralign) align_vector = self._get_align_vector() self._transform_points(align_vector) if self.color is not None: data.append(self._build_polyline()) if self.bgcolor is not None: #if _calc_points has been run, rmin is already set if self.rmin <= 0: #if self.angle%(2*math.pi) == math.radians(90): #rounded corner case for i in range(self.segments + 1): data.append(self._build_solid_triangle(i)) else: #rmin>0, normal operation for i in range(self.segments + 1): data.append(self._build_solid_quad(i)) return data
def _build(self): data = DXFList() self.points = self._calc_points() self._transform_points() if self.color is not None: data.append(self._build_polyline()) if self.bgcolor is not None: #if _calc_points has been run, rmin is already set for i in range(self.segments): data.append(self._build_solid_triangle(i)) return data
def __init__(self, text, insert, linespacing=1.5, **kwargs): self.textlines = text.split('\n') self.insert = insert self.linespacing = linespacing self.valign = kwargs.get('valign', dxfwrite.TOP) # only top, middle, bottom if self.valign == dxfwrite.BASELINE: # baseline for MText not usefull self.valign = dxfwrite.BOTTOM self.halign = kwargs.get('halign', dxfwrite.LEFT) # only left, center, right self.height = kwargs.get('height', 1.0) self.style = kwargs.get('style', 'STANDARD') self.oblique = kwargs.get('oblique', 0.0) # in degree self.rotation = kwargs.get('rotation', 0.0) # in degree self.xscale = kwargs.get('xscale', 1.0) self.mirror = kwargs.get('mirror', 0) self.layer = kwargs.get('layer', '0') self.color = kwargs.get('color', dxfwrite.BYLAYER) self.data = DXFList() if len(self.textlines)>1: # more than one line self._build_dxf_text_entities() elif len(self.textlines) == 1: # just a normal text with one line kwargs['alignpoint'] = insert # text() needs the align point self.data.append(Text(text=text, insert=insert, **kwargs))
def __init__(self): self.entities = DXFList()
class MText(object): """ MultiLine-Text buildup with simple Text-Entities. Mostly the same kwargs like DXFEngine.text(). Caution: align point is always the insert point, I don't need a second alignpoint because horizontal alignment FIT, ALIGN, BASELINE_MIDDLE is not supported. linespacing -- linespacing in percent of height, 1.5 = 150% = 1+1/2 lines """ name = 'MTEXT' def __init__(self, text, insert, linespacing=1.5, **kwargs): self.textlines = text.split('\n') self.insert = insert self.linespacing = linespacing self.valign = kwargs.get('valign', dxfwrite.TOP) # only top, middle, bottom if self.valign == dxfwrite.BASELINE: # baseline for MText not usefull self.valign = dxfwrite.BOTTOM self.halign = kwargs.get('halign', dxfwrite.LEFT) # only left, center, right self.height = kwargs.get('height', 1.0) self.style = kwargs.get('style', 'STANDARD') self.oblique = kwargs.get('oblique', 0.0) # in degree self.rotation = kwargs.get('rotation', 0.0) # in degree self.xscale = kwargs.get('xscale', 1.0) self.mirror = kwargs.get('mirror', 0) self.layer = kwargs.get('layer', '0') self.color = kwargs.get('color', dxfwrite.BYLAYER) self.data = DXFList() if len(self.textlines)>1: # more than one line self._build_dxf_text_entities() elif len(self.textlines) == 1: # just a normal text with one line kwargs['alignpoint'] = insert # text() needs the align point self.data.append(Text(text=text, insert=insert, **kwargs)) @property def lineheight(self): """ absolute linespacing in drawing units """ return self.height * self.linespacing def _build_dxf_text_entities(self): """ create the dxf TEXT entities """ if self.mirror & dxfwrite.MIRROR_Y: self.textlines.reverse() for linenum, text in enumerate(self.textlines): alignpoint = self._get_align_point(linenum) params = self._build_text_params(alignpoint) self.data.append(Text(text=text, **params)) def _get_align_point(self, linenum): """Calculate the align point depending on the line number. """ x = self.insert[0] y = self.insert[1] try: z = self.insert[2] except IndexError: z = 0. # rotation not respected if self.valign == dxfwrite.TOP: y -= linenum * self.lineheight elif self.valign == dxfwrite.MIDDLE: y0 = linenum * self.lineheight fullheight = (len(self.textlines) - 1) * self.lineheight y += (fullheight/2) - y0 else: # dxfwrite.BOTTOM y += (len(self.textlines) - 1 - linenum) * self.lineheight return self._rotate( (x, y, z) ) # consider rotation def _rotate(self, alignpoint): """Rotate alignpoint around insert point about rotation degrees.""" dx = alignpoint[0] - self.insert[0] dy = alignpoint[1] - self.insert[1] beta = math.radians(self.rotation) x = self.insert[0] + dx * math.cos(beta) - dy * math.sin(beta) y = self.insert[1] + dy * math.cos(beta) + dx * math.sin(beta) return (round(x, 6), round(y, 6), alignpoint[2]) def _build_text_params(self, alignpoint): """Build the calling dict for Text().""" return { 'insert': alignpoint, 'alignpoint': alignpoint, 'layer': self.layer, 'color': self.color, 'style': self.style, 'height': self.height, 'xscale': self.xscale, 'mirror': self.mirror, 'rotation': self.rotation, 'oblique': self.oblique, 'halign': self.halign, 'valign': self.valign, } def __dxf__(self): """ get the dxf string """ return self.data.__dxf__()
def _get_body(self): return DXFList((DXFName('ENTITIES'), self.entities))
def __dxftags__(self): return DXFList( (DXFAtom('SECTION'), DXFList(self._get_body()), DXFAtom('ENDSEC')))
def test_empty_DXFList(self): atoms = DXFList() self.assertEqual(dxfstr(atoms), '') self.assertEqual(dxfstr(atoms), tags2str(atoms))
def _get_body(self): body = DXFList() body.append(DXFName('BLOCKS')) body.extend(self.blocks.values()) return body
def _setup(self): """ Table generation setup. """ self.data = DXFList() self.visibility_map = VisibilityMap(self) self.grid = Grid(self)
def get_dxf_entity(self, coords, layer): return DXFList()
def __dxf__(self): self._build_table() result = self.data.__dxf__() self.data = DXFList() # don't need to keep this data in memory return result
class Table(object): """A HTML-table like object. The table object contains the table data cells. """ name = 'TABLE' def __init__(self, insert, nrows, ncols, default_grid=True): """ :param insert: insert point as 2D or 3D point :param int nrows: row count :param int ncols: column count :param bool default_grid: if **True** always a solid line grid will be drawn, if **False**, only explicit defined borders will be drawn, default grid has a priority of 50. """ self.insert = insert self.nrows = nrows self.ncols = ncols self.row_heights = [DEFAULT_TABLE_HEIGHT] * nrows self.col_widths = [DEFAULT_TABLE_WIDTH] * ncols self.bglayer = DEFAULT_TABLE_BGLAYER self.fglayer = DEFAULT_TABLE_FGLAYER self.gridlayer = DEFAULT_TABLE_GRIDLAYER self.styles = {'default': Style.get_default_cell_style()} if not default_grid: default_style = self.get_cell_style('default') default_style.set_border_status(False, False, False, False) self._cells = {} # data cells self.frames = [] # border frame objects # visibility_map stores the visibilty of the cells, created in _setup self.visibility_map = None # grid manages the border lines, created in _setup self.grid = None # data contains the resulting dxf entities self.data = DXFList() self.empty_cell = Cell(self) # represents all empty cells def set_col_width(self, column, value): """Set column width of **column** to **value** (in drawing units). """ self.col_widths[column] = float(value) def set_row_height(self, row, value): """Set row heigth of **row** to **value** (in drawing units). """ self.row_heights[row] = float(value) def text_cell(self, row, col, text, span=(1, 1), style='default'): """Create a new text cell at pos (**row**, **col**), with **text** as content, text can be a multi line text, use ``'\\n'`` as line seperator. The cell spans over **span** cells and has the cell style with the name **style**. """ cell = TextCell(self, text, style=style, span=span) return self.set_cell(row, col, cell) # pylint: disable-msg=W0102 def block_cell(self, row, col, blockdef, span=(1, 1), attribs={}, style='default'): """Create a new block cell at position (**row**, **col**), content is a block reference inserted by a :ref:`INSERT` entity, attributes will be added if the block definition contains :ref:`ATTDEF`. Assignments are defined by attribs-key to attdef-tag association. Example: attribs = {'num': 1} if an :ref:`ATTDEF` with tag=='num' in the block definition exists, an attrib with text=str(1) will be created and added to the insert entity. The cell spans over **span** cells and has the cell style with the name **style**. """ cell = BlockCell(self, blockdef, style=style, attribs=attribs, span=span) return self.set_cell(row, col, cell) def set_cell(self, row, col, cell): """Insert a **cell** at position (**row**, **col**).""" row, col = self.validate_index(row, col) self._cells[row, col] = cell return cell def get_cell(self, row, col): """Get cell at position (**row**, **col**).""" row, col = self.validate_index(row, col) try: return self._cells[row, col] except KeyError: return self.empty_cell # emtpy cell with default style def validate_index(self, row, col): row = int(row) col = int(col) if row < 0 or row >= self.nrows or \ col < 0 or col >= self.ncols: raise IndexError('cell index out of range') return row, col def frame(self, row, col, width=1, height=1, style='default'): """Create a Frame object which frames the cell area starting at **row**, **col** covering **widths** columns and **heigth** rows. """ frame = Frame(self, pos=(row, col), span=(height, width), style=style) self.frames.append(frame) return frame def new_cell_style(self, name, **kwargs): """Create a new Style object with the name **name**. :param kwargs: see Style.get_default_cell_style() """ style = deepcopy(self.get_cell_style('default')) style.update(kwargs) self.styles[name] = style return style def new_border_style(self, color=const.BYLAYER, status=True, priority=100, linetype=None): """Create a new border style. :param bool status: if **True** border is visible, **False** border is hidden :param int color: dxf color index :param string linetype: linetype name, BYLAYER if None :param int priority: drawing priority - higher values covers lower values """ border_style = Style.get_default_border_style() border_style['color'] = color border_style['linetype'] = linetype border_style['status'] = status border_style['priority'] = priority return border_style def get_cell_style(self, name): """Get cell style by **name**. """ return self.styles[name] def iter_visible_cells(self): """Iterate over all visible cells. returns a generator which yields all visible cells as tuples: **row**, **col**, **cell** """ if self.visibility_map is None: raise Exception("Can only be called at dxf creation.") return ((row, col, self.get_cell(row, col)) for row, col in self.visibility_map) def __dxf__(self): self._build_table() result = self.data.__dxf__() self.data = DXFList() # don't need to keep this data in memory return result def _setup(self): """Table generation setup.""" self.visibility_map = VisibilityMap(self, status=VISIBLE) self.grid = Grid(self) def _build_table(self): """Table is generated on calling the __dxf__() method.""" self._setup() self.grid.draw_lines() for row, col, cell in self.iter_visible_cells(): self.grid.draw_cell_background(row, col, cell) self.grid.draw_cell_content(row, col, cell) self._cleanup() def _cleanup(self): """Table generation cleanup. """ self.visibility_map = None self.grid = None
class Rectangle(object): """ 2D Rectangle, consisting of a polyline and a solid as background filling. """ name = 'RECTANGLE' def __init__(self, insert, width, height, rotation=0., halign=const.LEFT, valign=const.TOP, color=const.BYLAYER, bgcolor=None, layer='0', linetype=None): self.insert = insert self.width = float(width) self.height = float(height) self.rotation = math.radians(rotation) self.halign = halign self.valign = valign self.color = color self.bgcolor = bgcolor self.layer = layer self.linetype = linetype self.points = None self.data = DXFList() def _build_rect(self): self._calc_corners() if self.color is not None: self._build_polyline() if self.bgcolor is not None: self._build_solid() def _calc_corners(self): points = [(0., 0.), (self.width, 0.), (self.width, self.height), (0., self.height)] align_vector = self._get_align_vector() self.points = [vadd(self.insert, # move to insert point rotate_2d( # rotate at origin vadd(point, align_vector), self.rotation)) for point in points] def _get_align_vector(self): if self.halign == const.CENTER: dx = -self.width/2. elif self.halign == const.RIGHT: dx = -self.width else: # const.LEFT dx = 0. if self.valign == const.MIDDLE: dy = -self.height/2. elif self.valign == const.BOTTOM: dy = -self.height else: #const.TOP dy = 0. return (dx, dy) def _build_polyline(self): """ build the rectangle with a polyline """ polyline = Polyline(self.points, color=self.color, layer=self.layer) polyline.close() if self.linetype is not None: polyline['linetype'] = self.linetype self.data.append(polyline) def _build_solid(self): """ build the background solid """ self.data.append(Solid( self.points, color=self.bgcolor, layer=self.layer)) def __dxf__(self): """ get the dxf string """ self._build_rect() return self.data.__dxf__()