1# Copyright (c) 2019-2020 Manfred Moitzi 2# License: MIT License 3from typing import TYPE_CHECKING 4from ezdxf.lldxf import validator 5from ezdxf.lldxf.attributes import ( 6 DXFAttr, DXFAttributes, DefSubclass, XType, RETURN_DEFAULT, 7 group_code_mapping, 8) 9from ezdxf.lldxf.const import ( 10 SUBCLASS_MARKER, DXF12, MODEL_SPACE_R12, PAPER_SPACE_R12, MODEL_SPACE_R2000, 11 PAPER_SPACE_R2000, 12) 13from ezdxf.math import NULLVEC 14from .dxfentity import base_class, SubclassProcessor, DXFEntity 15from .factory import register_entity 16 17if TYPE_CHECKING: 18 from ezdxf.eztypes import TagWriter, DXFNamespace 19 20__all__ = ['Block', 'EndBlk'] 21 22acdb_entity = DefSubclass('AcDbEntity', { 23 # No auto fix for invalid layer names! 24 'layer': DXFAttr(8, default='0', validator=validator.is_valid_layer_name), 25 'paperspace': DXFAttr( 26 67, default=0, optional=True, 27 validator=validator.is_integer_bool, 28 fixer=RETURN_DEFAULT, 29 ), 30 31}) 32acdb_entity_group_codes = group_code_mapping(acdb_entity) 33 34acdb_block_begin = DefSubclass('AcDbBlockBegin', { 35 'name': DXFAttr(2, validator=validator.is_valid_block_name), 36 # The 2nd name with group code 3 is handles internally, and is not an 37 # explict DXF attribute. 38 'description': DXFAttr(4, default='', optional=True), 39 40 # Flags: 41 # 0 = Indicates none of the following flags apply 42 # 1 = This is an anonymous block generated by hatching, associative 43 # dimensioning, other internal operations, or an application 44 # 2 = This block has non-constant attribute definitions (this bit is not set 45 # if the block has any attribute definitions that are constant, or has 46 # no attribute definitions at all) 47 # 4 = This block is an external reference (xref) 48 # 8 = This block is an xref overlay 49 # 16 = This block is externally dependent 50 # 32 = This is a resolved external reference, or dependent of an external 51 # reference (ignored on input) 52 # 64 = This definition is a referenced external reference (ignored on input) 53 'flags': DXFAttr(70, default=0), 54 'base_point': DXFAttr(10, xtype=XType.any_point, default=NULLVEC), 55 'xref_path': DXFAttr(1, default=''), 56}) 57acdb_block_begin_group_codes = group_code_mapping(acdb_block_begin) 58 59MODEL_SPACE_R2000_LOWER = MODEL_SPACE_R2000.lower() 60MODEL_SPACE_R12_LOWER = MODEL_SPACE_R12.lower() 61PAPER_SPACE_R2000_LOWER = PAPER_SPACE_R2000.lower() 62PAPER_SPACE_R12_LOWER = PAPER_SPACE_R12.lower() 63 64 65@register_entity 66class Block(DXFEntity): 67 """ DXF BLOCK entity """ 68 DXFTYPE = 'BLOCK' 69 DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_block_begin) 70 71 # Block entity flags: 72 # This is an anonymous block generated by hatching, associative 73 # dimensioning, other internal operations, or an application: 74 ANONYMOUS = 1 75 76 # This block has non-constant attribute definitions (this bit is not set 77 # if the block has any attribute definitions that are constant, or has no 78 # attribute definitions at all): 79 NON_CONSTANT_ATTRIBUTES = 2 80 81 # This block is an external reference: 82 XREF = 4 83 84 # This block is an xref overlay: 85 XREF_OVERLAY = 8 86 87 # This block is externally dependent: 88 EXTERNAL = 16 89 90 # This is a resolved external reference, or dependent of an external reference: 91 RESOLVED = 32 92 93 # This definition is a referenced external reference: 94 REFERENCED = 64 95 96 def load_dxf_attribs( 97 self, processor: SubclassProcessor = None) -> 'DXFNamespace': 98 dxf = super().load_dxf_attribs(processor) 99 if processor is None: 100 return dxf 101 processor.fast_load_dxfattribs(dxf, acdb_entity_group_codes, 1) 102 processor.fast_load_dxfattribs(dxf, acdb_block_begin_group_codes, 2) 103 if processor.r12: 104 name = dxf.name.lower() 105 if name == MODEL_SPACE_R12_LOWER: 106 dxf.name = MODEL_SPACE_R2000 107 elif name == PAPER_SPACE_R12_LOWER: 108 dxf.name = PAPER_SPACE_R2000 109 return dxf 110 111 def export_entity(self, tagwriter: 'TagWriter') -> None: 112 """ Export entity specific data as DXF tags. """ 113 super().export_entity(tagwriter) 114 115 if tagwriter.dxfversion > DXF12: 116 tagwriter.write_tag2(SUBCLASS_MARKER, acdb_entity.name) 117 if self.dxf.hasattr('paperspace'): 118 tagwriter.write_tag2(67, 1) 119 self.dxf.export_dxf_attribs(tagwriter, 'layer') 120 if tagwriter.dxfversion > DXF12: 121 tagwriter.write_tag2(SUBCLASS_MARKER, acdb_block_begin.name) 122 123 name = self.dxf.name 124 if tagwriter.dxfversion == DXF12: 125 # export modelspace and paperspace with leading '$' instead of '*' 126 if name.lower() == MODEL_SPACE_R2000_LOWER: 127 name = MODEL_SPACE_R12 128 elif name.lower() == PAPER_SPACE_R2000_LOWER: 129 name = PAPER_SPACE_R12 130 131 tagwriter.write_tag2(2, name) 132 self.dxf.export_dxf_attribs(tagwriter, ['flags', 'base_point']) 133 tagwriter.write_tag2(3, name) 134 self.dxf.export_dxf_attribs(tagwriter, ['xref_path', 'description']) 135 136 @property 137 def is_layout_block(self) -> bool: 138 """ Returns ``True`` if this is a :class:`~ezdxf.layouts.Modelspace` or 139 :class:`~ezdxf.layouts.Paperspace` block definition. 140 """ 141 name = self.dxf.name.lower() 142 return name.startswith('*model_space') or name.startswith( 143 '*paper_space') 144 145 @property 146 def is_anonymous(self) -> bool: 147 """ Returns ``True`` if this is an anonymous block generated by 148 hatching, associative dimensioning, other internal operations, or an 149 application. 150 151 """ 152 return self.get_flag_state(Block.ANONYMOUS) 153 154 @property 155 def is_xref(self) -> bool: 156 """ Returns ``True`` if bock is an external referenced file.""" 157 return self.get_flag_state(Block.XREF) 158 159 @property 160 def is_xref_overlay(self) -> bool: 161 """ Returns ``True`` if bock is an external referenced overlay file. """ 162 return self.get_flag_state(Block.XREF_OVERLAY) 163 164 165acdb_block_end = DefSubclass('AcDbBlockEnd', {}) 166 167 168@register_entity 169class EndBlk(DXFEntity): 170 """ DXF ENDBLK entity """ 171 DXFTYPE = 'ENDBLK' 172 DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_block_end) 173 174 def load_dxf_attribs(self, 175 processor: SubclassProcessor = None) -> 'DXFNamespace': 176 dxf = super().load_dxf_attribs(processor) 177 if processor: 178 processor.fast_load_dxfattribs(dxf, acdb_entity_group_codes, 1) 179 return dxf 180 181 def export_entity(self, tagwriter: 'TagWriter') -> None: 182 """ Export entity specific data as DXF tags. """ 183 super().export_entity(tagwriter) 184 185 if tagwriter.dxfversion > DXF12: 186 tagwriter.write_tag2(SUBCLASS_MARKER, acdb_entity.name) 187 if self.dxf.hasattr('paperspace'): 188 tagwriter.write_tag2(67, 1) 189 self.dxf.export_dxf_attribs(tagwriter, 'layer') 190 if tagwriter.dxfversion > DXF12: 191 tagwriter.write_tag2(SUBCLASS_MARKER, acdb_block_end.name) 192