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 SUBCLASS_MARKER, DXF2000
10from ezdxf.math import Vec3, Matrix44, NULLVEC, Z_AXIS
11from .dxfentity import base_class, SubclassProcessor
12from .dxfgfx import DXFGraphic, acdb_entity
13from .factory import register_entity
14
15if TYPE_CHECKING:
16    from ezdxf.eztypes import TagWriter, DXFNamespace
17
18__all__ = ['Ray', 'XLine']
19
20acdb_xline = DefSubclass('AcDbXline', {
21    'start': DXFAttr(10, xtype=XType.point3d, default=NULLVEC),
22    'unit_vector': DXFAttr(
23        11, xtype=XType.point3d, default=Z_AXIS,
24        validator=validator.is_not_null_vector,
25        fixer=RETURN_DEFAULT,
26    ),
27})
28acdb_xline_group_codes = group_code_mapping(acdb_xline)
29
30
31@register_entity
32class XLine(DXFGraphic):
33    """ DXF XLINE entity """
34    DXFTYPE = 'XLINE'
35    DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_xline)
36    MIN_DXF_VERSION_FOR_EXPORT = DXF2000
37    XLINE_SUBCLASS = 'AcDbXline'
38
39    def load_dxf_attribs(
40            self, processor: SubclassProcessor = None) -> 'DXFNamespace':
41        dxf = super().load_dxf_attribs(processor)
42        if processor:
43            processor.fast_load_dxfattribs(
44                dxf, acdb_xline_group_codes, subclass=2, recover=True)
45        return dxf
46
47    def export_entity(self, tagwriter: 'TagWriter') -> None:
48        """ Export entity specific data as DXF tags. """
49        super().export_entity(tagwriter)
50        tagwriter.write_tag2(SUBCLASS_MARKER, self.XLINE_SUBCLASS)
51        self.dxf.export_dxf_attribs(tagwriter, ['start', 'unit_vector'])
52
53    def transform(self, m: Matrix44) -> 'XLine':
54        """ Transform the XLINE/RAY entity by transformation matrix `m` inplace.
55        """
56        self.dxf.start = m.transform(self.dxf.start)
57        self.dxf.unit_vector = m.transform_direction(
58            self.dxf.unit_vector).normalize()
59        return self
60
61    def translate(self, dx: float, dy: float, dz: float) -> 'XLine':
62        """ Optimized XLINE/RAY translation about `dx` in x-axis, `dy` in
63        y-axis and `dz` in z-axis.
64
65        """
66        self.dxf.start = Vec3(dx, dy, dz) + self.dxf.start
67        return self
68
69
70@register_entity
71class Ray(XLine):
72    """ DXF Ray entity """
73    DXFTYPE = 'RAY'
74    DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_xline)
75    MIN_DXF_VERSION_FOR_EXPORT = DXF2000
76    XLINE_SUBCLASS = 'AcDbRay'
77