), # Oblique angle in degrees: "oblique": DXFAttr(51, default=0, optional=True), "extrusion": DXFAttr( 210, xtype=XType.point3d, default=Z_AXIS, optional=True, validator=validator.is_not_null_vector, fixer=RETURN_DEFAULT, ), }, ) acdb_shape_group_codes = group_code_mapping(acdb_shape) merged_shape_group_codes = merge_group_code_mappings( acdb_entity_group_codes, acdb_shape_group_codes # type: ignore ) @register_entity class Shape(DXFGraphic): """DXF SHAPE entity""" DXFTYPE = "SHAPE" DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_shape) def load_dxf_attribs(self, processor: SubclassProcessor = None
def test_duplicate_group_codes(): m = group_code_mapping(acdb_dublicates) assert m[1] == ['n1', 'n2', 'n3'] assert m[2] == ['n4', 'n5'] assert m[3] == 'n6'
def test_if_callbacks_are_marked(): m = group_code_mapping(acdb_unique) assert m[5] == '*n5', 'callbacks have to marked with a leading "*"'
def test_unique_group_codes(): m = group_code_mapping(acdb_unique) assert len(m) == 5 assert set(type(v) for v in m.values()) == {str}
def test_ignored_group_codes(): # These group codes are ignored from logging as unprocessed tags, which # would happen if they are just left out: m = group_code_mapping(acdb_unique, ignore=(1, 2)) assert m[1] == '*IGNORE' assert m[2] == '*IGNORE'
validator=validator.is_one_of({0, 5, 6, 8}), fixer=RETURN_DEFAULT, ), 'thickness': DXFAttr(39, default=0, optional=True), 'extrusion': DXFAttr( 210, xtype=XType.point3d, default=Z_AXIS, optional=True, validator=validator.is_not_null_vector, fixer=RETURN_DEFAULT, ), }) acdb_polyline_group_codes = group_code_mapping(acdb_polyline, ignore=(66, )) # Notes to SEQEND: # todo: A loaded entity should have a valid SEQEND, a POLYLINE without vertices # makes no sense - has to be tested # # A virtual POLYLINE does not need a SEQEND, because it can not be exported, # therefore the SEQEND entity should not be created in the # DXFEntity.post_new_hook() method. # # A bounded POLYLINE needs a SEQEND to valid at export, therefore the # LinkedEntities.post_bind_hook() method creates a new SEQEND after binding # the entity to a document if needed. @factory.register_entity
'ambient_light_color_2': DXFAttr(421, dxfversion='AC1021'), # as True Color: 'ambient_light_color_3': DXFAttr(431, dxfversion='AC1021'), 'sun_handle': DXFAttr(361, dxfversion='AC1021'), 'ref_vp_object_1': DXFAttr(335, dxfversion='AC1021'), # unknown meaning, don't ask mozman 'ref_vp_object_2': DXFAttr(343, dxfversion='AC1021'), # unknown meaning, don't ask mozman 'ref_vp_object_3': DXFAttr(344, dxfversion='AC1021'), # unknown meaning, don't ask mozman 'ref_vp_object_4': DXFAttr(91, dxfversion='AC1021'), # unknown meaning, don't ask mozman }) acdb_viewport_group_codes = group_code_mapping(acdb_viewport) # Note: # The ZOOM XP factor is calculated with the following formula: # group_41 / group_45 (or pspace_height / mspace_height). FROZEN_LAYER_GROUP_CODE = 331 @register_entity class Viewport(DXFGraphic): """ DXF VIEWPORT entity """ DXFTYPE = 'VIEWPORT' DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_viewport) viewport_id = 2 # Notes to vieport_id:
281, default=0, dxfversion=DXF2007, validator=validator.is_integer_bool, fixer=RETURN_DEFAULT, ), # see ezdxf/units.py 'units': DXFAttr(70, default=0, dxfversion=DXF2007, validator=validator.is_in_integer_range(0, 25), fixer=RETURN_DEFAULT), # 310: Binary data for bitmap preview (optional) - removed (ignored) by ezdxf }) acdb_blockrec_group_codes = group_code_mapping(acdb_blockrec) # optional XDATA for all DXF versions # 1000: "ACAD" # 1001: "DesignCenter Data" (optional) # 1002: "{" # 1070: Autodesk Design Center version number # 1070: Insert units: like 'units' # 1002: "}" @register_entity class BlockRecord(DXFEntity): """ DXF BLOCK_RECORD table entity BLOCK_RECORD is the hard owner of all entities in BLOCK definitions, this
DXFAttr( 98, default=0, validator=validator.is_greater_or_equal_zero, fixer=RETURN_DEFAULT, ), # MPolygon: offset vector in OCS ??? "offset_vector": DXFAttr(11, xtype=XType.point2d, default=(0, 0)), # MPolygon: number of degenerate boundary paths (loops), where a # degenerate boundary path is a border that is ignored by the hatch: "degenerated_loops": DXFAttr(99, default=0), }, ) acdb_mpolygon_group_code = group_code_mapping(acdb_mpolygon) @register_entity class MPolygon(DXFPolygon): """DXF MPOLYGON entity The MPOLYGON is not a core DXF entity, and requires a CLASS definition. """ DXFTYPE = "MPOLYGON" DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_mpolygon) MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 LOAD_GROUP_CODES = acdb_mpolygon_group_code
73, default=0, dxfversion=DXF2007, validator=validator.is_integer_bool, fixer=RETURN_DEFAULT, ), 'background_handle': DXFAttr(332, optional=True, dxfversion=DXF2007), 'live_selection_handle': DXFAttr(334, optional=True, dxfversion=DXF2007), 'visual_style_handle': DXFAttr(348, optional=True, dxfversion=DXF2007), 'sun_handle': DXFAttr(361, optional=True, dxfversion=DXF2010), }) acdb_view_group_codes = group_code_mapping(acdb_view) @register_entity class View(DXFEntity): """ DXF VIEW entity """ DXFTYPE = 'VIEW' DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_view) def load_dxf_attribs(self, processor: SubclassProcessor = None ) -> 'DXFNamespace': dxf = super().load_dxf_attribs(processor) if processor: processor.fast_load_dxfattribs(dxf, acdb_view_group_codes,
# PlotStyleName type enum (AcDb::PlotStyleNameType). Stored and moved around # as a 16-bit integer. Custom non-entity 'plotstyle_enum': DXFAttr(380, dxfversion=DXF2007, default=1, optional=True), # Handle value of the PlotStyleName object, basically a hard pointer, but # has a different range to make backward compatibility easier to deal with. 'plotstyle_handle': DXFAttr(390, dxfversion=DXF2007, optional=True), # 92 or 160?: Number of bytes in the proxy entity graphics represented in # the subsequent 310 groups, which are binary chunk records (optional) # 310: Proxy entity graphics data (multiple lines; 256 characters max. per # line) (optional), compiled by TagCompiler() to a DXFBinaryTag() objects }) acdb_entity_group_codes = group_code_mapping(acdb_entity) def elevation_to_z_axis(dxf: 'DXFNamespace', names: Iterable[str]): # The elevation group code (38) is only used for DXF R11 and prior and # ignored for DXF R2000 and later. # DXF R12 and later store the entity elevation in the z-axis of the # vertices, but AutoCAD supports elevation for R12 if no z-axis is present. # DXF types with legacy elevation support: # SOLID, TRACE, TEXT, CIRCLE, ARC, TEXT, ATTRIB, ATTDEF, INSERT, SHAPE # The elevation is only used for DXF R12 if no z-axis is stored in the DXF # file. This is a problem because ezdxf loads the vertices always as 3D # vertex including a z-axis even if no z-axis is present in DXF file. if dxf.hasattr('elevation'): elevation = dxf.elevation
"generation_flags": DXFAttr(71, default=0), # Last height used: "last_height": DXFAttr(42, default=2.5), # Primary font file name: # ATTENTION: The font file name can be an empty string and the font family # may be stored in XDATA! See also posts at the (unrelated) issue #380. "font": DXFAttr(3, default="txt"), # Big font name, blank if none "bigfont": DXFAttr(4, default=""), }, ) acdb_style_group_codes = group_code_mapping(acdb_style) # XDATA: This is not a reliable source for font data! # 1001 <ctrl> ACAD # 1000 <str> Arial ; font-family sometimes an empty string! # 1071 <int> 34 ; flags # ---- # "Arial" "normal" flags = 34 = 0b00:00000000:00000000:00100010 # "Arial" "italic" flags = 16777250 = 0b01:00000000:00000000:00100010 # "Arial" "bold" flags = 33554466 = 0b10:00000000:00000000:00100010 # "Arial" "bold+italic" flags = 50331682 = 0b11:00000000:00000000:00100010 @register_entity class Textstyle(DXFEntity): """DXF STYLE entity"""
validator=validator.is_not_null_vector, fixer=RETURN_DEFAULT, ), # Ratio has to be in the range from 1e-6 to 1, but could be negative: 'ratio': DXFAttr( 40, default=MAX_RATIO, validator=is_valid_ratio, fixer=fix_ratio), # Start of ellipse, this value is 0.0 for a full ellipse: 'start_param': DXFAttr(41, default=0), # End of ellipse, this value is 2*pi for a full ellipse: 'end_param': DXFAttr(42, default=math.tau), }) acdb_ellipse_group_code = group_code_mapping(acdb_ellipse) HALF_PI = math.pi / 2.0 @register_entity class Ellipse(DXFGraphic): """ DXF ELLIPSE entity """ DXFTYPE = 'ELLIPSE' DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_ellipse) MIN_DXF_VERSION_FOR_EXPORT = DXF2000 def load_dxf_attribs(self, processor: SubclassProcessor = None ) -> 'DXFNamespace': dxf = super().load_dxf_attribs(processor) if processor:
'gen_proc_val_bool': DXFAttr(291), 'gen_proc_val_int': DXFAttr(271), 'gen_proc_val_real': DXFAttr(469), 'gen_proc_val_text': DXFAttr(301), 'gen_proc_table_end': DXFAttr(292), 'gen_proc_val_color_index': DXFAttr(62), 'gen_proc_val_color_rgb': DXFAttr(420), 'gen_proc_val_color_name': DXFAttr(430), 'map_utile': DXFAttr(270), # multiple usage of group code 270 'translucence': DXFAttr(148), 'self_illumination': DXFAttr(90), 'reflectivity': DXFAttr(468), 'illumination_model': DXFAttr(93), 'channel_flags': DXFAttr(94, default=63), }) acdb_material_group_codes = group_code_mapping(acdb_material) @register_entity class Material(DXFObject): DXFTYPE = 'MATERIAL' DEFAULT_ATTRIBS = { 'diffuse_color_method': 1, 'diffuse_color_value': -1023410177, } DXFATTRIBS = DXFAttributes(base_class, acdb_material) def __init__(self): super().__init__() self.diffuse_mapper_matrix: Optional[Matrix44] = None # code 43 self.specular_mapper_matrix: Optional[Matrix44] = None # code 47