Exemplo n.º 1
0
    def load_section_dict(self, sections: List[List[DXFTag]]) -> None:
        """ Merge sections of same type. """
        def add_section(name: str, tags) -> None:
            if name in section_dict:
                section_dict[name].extend(tags[2:])
            else:
                section_dict[name] = tags

        def _build_section_dict(d: dict) -> None:
            for name, section in d.items():
                if name in const.MANAGED_SECTIONS:
                    self.section_dict[name] = list(group_tags(section, 0))

        orphans = sections.pop()
        section_dict = dict()
        for section in sections:
            code, name = section[1]
            if code == 2:
                add_section(name, section)
            else:  # invalid section name tag e.g. (2, "HEADER")
                logger.warning(
                    'DXF structure error: missing section name tag, ignore '
                    'section.')

        header = section_dict.setdefault('HEADER', [
            DXFTag(0, 'SECTION'),
            DXFTag(2, 'HEADER'),
        ])
        self.rescue_orphaned_header_vars(header, orphans)
        _build_section_dict(section_dict)
Exemplo n.º 2
0
 def acad_mtext_defined_height_xdata(self) -> Tags:
     return Tags([
         DXFTag(1000, "ACAD_MTEXT_DEFINED_HEIGHT_BEGIN"),
         DXFTag(1070, 46),
         DXFTag(1040, self.defined_height),
         DXFTag(1000, "ACAD_MTEXT_DEFINED_HEIGHT_END"),
     ])
Exemplo n.º 3
0
 def dxftags(self) -> List[DXFTag]:
     # count = count of tags not faces!
     yield DXFTag(93, self.tag_count())
     for face in self.value:
         yield DXFTag(90, len(face))
         for index in face:
             yield DXFTag(90, index)
Exemplo n.º 4
0
    def rebuild_tables(self, tables: List[Tags]) -> List[Tags]:
        """ Rebuild TABLES section. """
        def append_table(name: str):
            if name not in content:
                return

            head = heads.get(name)
            if head:
                tables.append(head)
            else:
                # The new table head gets a valid handle from Auditor.
                tables.append(Tags([DXFTag(0, 'TABLE'), DXFTag(2, name)]))
            tables.extend(content[name])
            tables.append(Tags([DXFTag(0, 'ENDTAB')]))

        heads = dict()
        content = defaultdict(list)
        valid_tables = set(const.TABLE_NAMES_ACAD_ORDER)

        for entry in tables:
            name = entry[0].value.upper()
            if name == 'TABLE':
                try:
                    table_name = entry[1].value.upper()
                except (IndexError, AttributeError):
                    pass
                else:
                    heads[table_name] = entry
            elif name in valid_tables:
                content[name].append(entry)
        tables = [Tags([DXFTag(0, 'SECTION'), DXFTag(2, 'TABLES')])]
        for name in const.TABLE_NAMES_ACAD_ORDER:
            append_table(name)
        return tables
Exemplo n.º 5
0
def convert_text_lines_to_tags(text_lines):
    for line in text_lines:
        yield DXFTag(1, line[:255])
        if len(line) > 255:
            yield DXFTag(
                3, line[255:]
            )  # tail (max. 255 chars), what if line > 510 chars???
Exemplo n.º 6
0
 def test_tags_to_text_lines_short_lines(self):
     tags = [
         DXFTag(1, "123"),
         DXFTag(1, "456"),
         DXFTag(1, "789")
     ]
     expected = ["123", "456", "789"]
     self.assertEqual(expected, list(convert_tags_to_text_lines(tags)))
Exemplo n.º 7
0
 def acad_mtext_columns_xdata(self) -> Tags:
     tags = Tags([
         DXFTag(1000, "ACAD_MTEXT_COLUMNS_BEGIN"),
         DXFTag(1070, 47), DXFTag(1070, self.count),  # incl. main MTEXT
     ])
     tags.extend(  # writes only (count - 1) handles!
         DXFTag(1005, handle) for handle in self.mtext_handles())
     tags.append(DXFTag(1000, "ACAD_MTEXT_COLUMNS_END"))
     return tags
Exemplo n.º 8
0
 def dxftags(self):
     return [
         DXFTag(72, 2),  # edge type
         DXFVertex(10, self.center),
         DXFTag(40, self.radius),
         DXFTag(50, self.start_angle),
         DXFTag(51, self.end_angle),
         DXFTag(73, self.is_counter_clockwise),
     ]
Exemplo n.º 9
0
 def _seek_to_section(self, name: str) -> int:
     prev_tag = (0, None)
     self.file.seek(0)
     find = DXFTag(2, name)
     section = DXFTag(0, 'SECTION')
     for tag in low_level_tagger(self.file):
         if tag == find and prev_tag == section:
             break
         prev_tag = tag
     return self.file.tell()
Exemplo n.º 10
0
 def dxftags(self) -> Iterable[DXFTag]:
     for point in self:
         x, y, start_width, end_width, bulge = point
         yield DXFVertex(self.VERTEX_CODE, (x, y))
         if start_width:
             yield DXFTag(self.START_WIDTH_CODE, start_width)
         if end_width:
             yield DXFTag(self.END_WIDTH_CODE, end_width)
         if bulge:
             yield DXFTag(self.BULGE_CODE, bulge)
Exemplo n.º 11
0
 def dxftags(self):
     tags = [
         DXFTag(92, int(self.path_type_flags)),
         DXFTag(93, len(self.edges))
     ]
     for edge in self.edges:
         tags.extend(edge.dxftags())
     tags.extend(
         build_source_boundary_object_tags(self.source_boundary_objects))
     return tags
Exemplo n.º 12
0
 def dxftags(self):
     return [
         DXFTag(72, 3),  # edge type
         DXFVertex(10, self.center),
         DXFVertex(11, self.major_axis),
         DXFTag(40, self.ratio),
         DXFTag(50, self.start_angle),
         DXFTag(51, self.end_angle),
         DXFTag(73, self.is_counter_clockwise)
     ]
Exemplo n.º 13
0
 def test_tags_to_text_lines_long_lines(self):
     line = "0123456789" * 30
     tags = [
         DXFTag(1, line[:255]),
         DXFTag(3, line[255:]),
         DXFTag(1, line[:255]),
         DXFTag(3, line[255:]),
     ]
     expected = [line, line]
     self.assertEqual(expected, list(convert_tags_to_text_lines(tags)))
Exemplo n.º 14
0
    def dxftags(self) -> List[DXFTag]:
        tags = [
            DXFTag(72, 4),  # edge type
            DXFTag(94, int(self.degree)),
            DXFTag(73, int(self.rational)),
            DXFTag(74, int(self.periodic)),
            DXFTag(95, len(self.knot_values)),  # number of knots
            DXFTag(96, len(self.control_points)),  # number of control points
        ]
        # build knot values list
        # knot values have to be present and valid, otherwise AutoCAD crashes
        if len(self.knot_values):
            tags.extend([DXFTag(40, float(value)) for value in self.knot_values])
        else:
            raise DXFValueError("SplineEdge: missing required knot values")

        # build control points
        # control points have to be present and valid, otherwise AutoCAD crashes
        tags.extend([DXFVertex(10, (float(value[0]), float(value[1]))) for value in self.control_points])

        # build weights list, optional
        tags.extend([DXFTag(42, float(value)) for value in self.weights])

        # build fit points
        # fit points have to be present and valid, otherwise AutoCAD crashes
        # edit 2016-12-20: this is not true - there are cases with no fit points and without crashing AutoCAD
        tags.append(DXFTag(97, len(self.fit_points)))
        tags.extend([DXFVertex(11, (float(value[0]), float(value[1]))) for value in self.fit_points])

        tags.append(DXFVertex(12, (float(self.start_tangent[0]), float(self.start_tangent[1]))))
        tags.append(DXFVertex(13, (float(self.end_tangent[0]), float(self.end_tangent[1]))))
        return tags
Exemplo n.º 15
0
 def dxftags(self) -> Iterable[DXFTag]:
     for point in self:
         x, y, start_width, end_width, bulge = point
         yield DXFVertex(self.VERTEX_CODE, (x, y))
         if start_width or end_width:
             # Export always start- and end width together,
             # required for BricsCAD but not AutoCAD!
             yield DXFTag(self.START_WIDTH_CODE, start_width)
             yield DXFTag(self.END_WIDTH_CODE, end_width)
         if bulge:
             yield DXFTag(self.BULGE_CODE, bulge)
Exemplo n.º 16
0
 def bgcolor(self, rgb: 'RGB') -> None:
     color_value = rgb2int(rgb) | -0b111110000000000000000000000000  # it's magic
     try:
         xdata_bgcolor = self.tags.get_xdata('HATCHBACKGROUNDCOLOR')
     except DXFValueError:  # no xdata for background color found
         self.tags.xdata.append(Tags([
             DXFTag(1001, 'HATCHBACKGROUNDCOLOR'),
             DXFTag(1071, color_value),
         ]))
     else:
         xdata_bgcolor.set_first(DXFTag(1071, color_value))
Exemplo n.º 17
0
def tag_compiler(tags: Tags) -> Iterable[DXFTag]:
    """Special tag compiler for the DXF browser.

    This compiler should never fail and always return printable tags:

        - invalid point coordinates are returned as float("nan")
        - invalid ints are returned as string
        - invalid floats are returned as string

    """
    def to_float(v: str) -> float:
        try:
            return float(v)
        except ValueError:
            return float("NaN")

    count = len(tags)
    index = 0
    while index < count:
        code, value = tags[index]
        if code in POINT_CODES:
            try:
                y_code, y_value = tags[index + 1]
            except IndexError:  # x-coord as last tag
                yield DXFTag(code, to_float(value))
                return

            if y_code != code + 10:  # not an y-coord?
                yield DXFTag(code, to_float(value))  # x-coord as single tag
                index += 1
                continue

            try:
                z_code, z_value = tags[index + 2]
            except IndexError:  # no z-coord exist
                z_code = 0
                z_value = 0
            point: Sequence[float]
            if z_code == code + 20:  # is a z-coord?
                point = (to_float(value), to_float(y_value), to_float(z_value))
                index += 3
            else:  # a valid 2d point(x, y)
                point = (to_float(value), to_float(y_value))
                index += 2
            yield DXFVertex(code, point)
        else:  # a single tag
            try:
                if code == 0:
                    value = value.strip()
                yield DXFTag(code, TYPE_TABLE.get(code, str)(value))
            except ValueError:
                yield DXFTag(code, str(value))  # just as string
            index += 1
Exemplo n.º 18
0
        def append_table(name: str):
            if name not in content:
                return

            head = heads.get(name)
            if head:
                tables.append(head)
            else:
                # The new table head gets a valid handle from Auditor.
                tables.append(Tags([DXFTag(0, 'TABLE'), DXFTag(2, name)]))
            tables.extend(content[name])
            tables.append(Tags([DXFTag(0, 'ENDTAB')]))
Exemplo n.º 19
0
    def append(self, handle: str, sort_handle: str) -> None:
        """
        Append redraw association (handle, sort_handle).

        Args:
            handle: DXF entity handle (uppercase hex value without leading '0x')
            sort_handle: sort handle (uppercase hex value without leading '0x')

        """
        subclass = self.sortentstable_subclass
        subclass.append(DXFTag(331, handle))
        subclass.append(DXFTag(5, sort_handle))
Exemplo n.º 20
0
    def load_section_dict(self, sections: List[List[DXFTag]]) -> None:
        """Merge sections of same type."""
        def add_section(name: str, tags) -> None:
            if name in section_dict:
                section_dict[name].extend(tags[2:])
            else:
                section_dict[name] = tags

        def _build_section_dict(d: Dict) -> None:
            for name, section in d.items():
                if name in const.MANAGED_SECTIONS:
                    self.section_dict[name] = list(group_tags(section, 0))

        def _remove_unsupported_sections(d: Dict):
            for name in ("CLASSES", "OBJECTS", "ACDSDATA"):
                if name in d:
                    del d[name]
                    self.fixes.append((
                        AuditError.REMOVED_UNSUPPORTED_SECTION,
                        f"Removed unsupported {name} section for DXF R12.",
                    ))

        # Last section could be orphaned tags:
        orphans = sections.pop()
        if orphans and orphans[0] == (0, "SECTION"):
            # The last section contains not the orphaned tags:
            sections.append(orphans)
            orphans = []

        section_dict: "SectionDict" = dict()
        for section in sections:
            code, name = section[1]
            if code == 2:
                add_section(name, section)
            else:  # invalid section name tag e.g. (2, "HEADER")
                self.fixes.append((
                    AuditError.MISSING_SECTION_NAME_TAG,
                    "DXF structure error: missing section name tag, ignore section.",
                ))

        header = section_dict.setdefault(
            "HEADER",
            [
                DXFTag(0, "SECTION"),  # type: ignore
                DXFTag(2, "HEADER"),  # type: ignore
            ],
        )
        self.rescue_orphaned_header_vars(header, orphans)  # type: ignore
        self.dxfversion = _detect_dxf_version(header)
        if self.dxfversion <= const.DXF12:
            _remove_unsupported_sections(section_dict)
        _build_section_dict(section_dict)
Exemplo n.º 21
0
 def _setup_pattern(self, pattern, length):
     complex_line_type = True if isstring(pattern) else False
     if complex_line_type:  # a .lin like line type definition string
         self._setup_complex_pattern(pattern, length)
     else:
         # pattern: [2.0, 1.25, -0.25, 0.25, -0.25] - 1. element is total pattern length
         # pattern elements: >0 line, <0 gap, =0 point
         subclass = self.tags.get_subclass('AcDbLinetypeTableRecord')
         subclass.append(DXFTag(73, len(pattern) - 1))
         subclass.append(DXFTag(40, float(pattern[0])))
         for element in pattern[1:]:
             subclass.append(DXFTag(49, float(element)))
             subclass.append(DXFTag(74, 0))
Exemplo n.º 22
0
def test_equality():
    assert (1, "text") == DXFTag(1, "text"), "should be equal to tuple"
    # Python 2.7 Issue
    assert ((1, "text") != DXFTag(1, "text")) is False

    assert (1, "text") != DXFTag(1, "text2"), "should be not equal to tuple"
    assert DXFTag(1, "text") == (1, "text"), "should be equal to tuple"
    assert DXFTag(1, "text") != (1, "text2"), "should be not equal to tuple"
    assert DXFTag(1, "text") == DXFTag(1, "text")
    assert DXFTag(1, "text") != DXFTag(1, "text2")
Exemplo n.º 23
0
def test_equality():
    assert (1, 'text') == DXFTag(1, 'text'), 'should be equal to tuple'
    # Python 2.7 Issue
    assert ((1, 'text') != DXFTag(1, 'text')) is False

    assert (1, 'text') != DXFTag(1, 'text2'), 'should be not equal to tuple'
    assert DXFTag(1, 'text') == (1, 'text'), 'should be equal to tuple'
    assert DXFTag(1, 'text') != (1, 'text2'), 'should be not equal to tuple'
    assert DXFTag(1, 'text') == DXFTag(1, 'text')
    assert DXFTag(1, 'text') != DXFTag(1, 'text2')
Exemplo n.º 24
0
    def rebuild_tables(self, tables: List[Tags]) -> List[Tags]:
        """Rebuild TABLES section."""

        # Note: the recover module does not report invalid placed table entries,
        # it just recovers them. The "normal" loading process ignore these
        # misplaced table entries and logs a warning.

        def append_table(name: str):
            if name not in content:
                return

            head = heads.get(name)
            if head:
                tables.append(head)
            else:
                # The new table head gets a valid handle from Auditor.
                tables.append(Tags([DXFTag(0, "TABLE"), DXFTag(2, name)]))
            tables.extend(content[name])
            tables.append(Tags([DXFTag(0, "ENDTAB")]))

        heads = dict()
        content = defaultdict(list)
        valid_tables = set(const.TABLE_NAMES_ACAD_ORDER)

        for entry in tables:
            name = entry[0].value.upper()
            if name == "TABLE":
                try:
                    table_name = entry[1].value.upper()
                except (IndexError, AttributeError):
                    pass
                else:
                    heads[table_name] = entry
            elif name in valid_tables:
                content[name].append(entry)
        tables = [Tags([DXFTag(0, "SECTION"), DXFTag(2, "TABLES")])]

        names = list(const.TABLE_NAMES_ACAD_ORDER)
        if self.dxfversion <= const.DXF12:
            # Ignore BLOCK_RECORD table
            names.remove("BLOCK_RECORD")
            if "BLOCK_RECORD" in content:
                self.fixes.append((
                    AuditError.REMOVED_UNSUPPORTED_TABLE,
                    f"Removed unsupported BLOCK_RECORD table for DXF R12.",
                ))

        for name in names:
            append_table(name)
        return tables
Exemplo n.º 25
0
 def _setup_complex_pattern(self, pattern, length):
     tokens = lin_compiler(pattern)
     subclass = self.tags.get_subclass('AcDbLinetypeTableRecord')
     subclass.append(DXFTag(73, 0))  # temp length of 0
     subclass.append(DXFTag(40, length))
     count = 0
     for token in tokens:
         if isinstance(token, DXFTag):
             if subclass[-1].code == 49:  # useless 74 only after 49 :))
                 subclass.append(DXFTag(74, 0))
             subclass.append(token)
             count += 1
         else:  # TEXT or SHAPE
             subclass.extend(token.complex_ltype_tags(self.drawing))
     subclass.append(DXFTag(74, 0))  # useless 74 at the end :))
     subclass.update(DXFTag(73, count))
Exemplo n.º 26
0
def bytes_loader(stream: BinaryIO) -> Iterable[DXFTag]:
    """ Yields :class:``DXFTag`` objects from a bytes `stream`
    (untrusted external  source), skips all comment tags (group code == 999).

    ``DXFTag.code`` is always an ``int`` and ``DXFTag.value`` is always a
    raw bytes value without line endings. Works with file system streams and
    :class:`BytesIO` streams.

    Raises:
        DXFStructureError: Found invalid group code.

    """
    line = 1
    readline = stream.readline
    while True:
        code = readline()
        # ByteIO(): empty strings indicates EOF - does not raise an exception
        if code:
            try:
                code = int(code)
            except ValueError:
                code = code.decode(errors='ignore')
                raise const.DXFStructureError(
                    f'Invalid group code "{code}" at line {line}.')
        else:
            return

        value = readline()
        # ByteIO(): empty strings indicates EOF
        if value:
            if code != 999:
                yield DXFTag(code, value.rstrip(b'\r\n'))
            line += 2
        else:
            return
Exemplo n.º 27
0
 def _update_meta_data(self) -> None:
     count = len(self)
     if self._drawing.dxfversion > 'AC1009':
         subclass = self._table_header.get_subclass('AcDbSymbolTable')
     else:
         subclass = self._table_header.noclass
     subclass.set_first(DXFTag(70, count))
Exemplo n.º 28
0
 def _setup_pattern(self, pattern: Union[Iterable[float], str],
                    length: float) -> None:
     complex_line_type = True if isinstance(pattern, str) else False
     if complex_line_type:  # a .lin like line type definition string
         tags = self._setup_complex_pattern(pattern, length)
     else:
         # pattern: [2.0, 1.25, -0.25, 0.25, -0.25] - 1. element is total
         # pattern length pattern elements: >0 line, <0 gap, =0 point
         tags = Tags([
             DXFTag(72, 65),  # letter 'A'
             DXFTag(73, len(pattern) - 1),
             DXFTag(40, float(pattern[0])),
         ])
         for element in pattern[1:]:
             tags.append(DXFTag(49, float(element)))
             tags.append(DXFTag(74, 0))
     self.pattern_tags = LinetypePattern(tags)
Exemplo n.º 29
0
 def dxftags(self):
     if len(self.lines):
         tags = [DXFTag(78, len(self.lines))]
         for line in self.lines:
             tags.extend(line.dxftags())
     else:
         tags = []
     return tags
Exemplo n.º 30
0
    def new_extension_dict(self):
        """
        Creates and assigns a new extensions dictionary. Link to an existing extension dictionary will be lost.

        """
        xdict = self.drawing.objects.add_dictionary(owner=self.dxf.handle)
        self.set_app_data(ACAD_XDICTIONARY, [DXFTag(360, xdict.dxf.handle)])
        return xdict