Esempio n. 1
0
    def dxftags(self) -> Tags:
        def flag(flag):
            return 1 if self.dxf.flags & flag else 0

        dxf = self.dxf
        tags = [
            DXFTag(1001, 'ACAD'),
            DXFTag(1000, 'MVIEW'),
            DXFTag(1002, '{'),
            DXFTag(1070, 16),  # extended data version, always 16 for R11/12
            DXFVertex(1010, dxf.view_target_point),
            DXFVertex(1010, dxf.view_direction_vector),
            DXFTag(1040, dxf.view_twist_angle),
            DXFTag(1040, dxf.view_height),
            DXFTag(1040, dxf.view_center_point[0]),
            DXFTag(
                1040,
                dxf.view_center_point[1],
            ),
            DXFTag(1040, dxf.perspective_lens_length),
            DXFTag(1040, dxf.front_clip_plane_z_value),
            DXFTag(1040, dxf.back_clip_plane_z_value),
            DXFTag(1070, dxf.render_mode),
            DXFTag(1070, dxf.circle_zoom),
            DXFTag(1070, flag(const.VSF_FAST_ZOOM)),
            DXFTag(1070, dxf.ucs_icon),
            DXFTag(1070, flag(const.VSF_SNAP_MODE)),
            DXFTag(1070, flag(const.VSF_GRID_MODE)),
            DXFTag(1070, flag(const.VSF_ISOMETRIC_SNAP_STYLE)),
            DXFTag(1070, 0),  # snap isopair ???
            DXFTag(1040, dxf.snap_angle),
            DXFTag(1040, dxf.snap_base_point[0]),
            DXFTag(1040, dxf.snap_base_point[1]),
            DXFTag(1040, dxf.snap_spacing[0]),
            DXFTag(1040, dxf.snap_spacing[1]),
            DXFTag(1040, dxf.grid_spacing[0]),
            DXFTag(1040, dxf.grid_spacing[1]),
            DXFTag(1070, flag(const.VSF_HIDE_PLOT_MODE)),
            DXFTag(1002, '{'),  # start frozen layer list
        ]
        tags.extend(
            DXFTag(1003, layer_name) for layer_name in self.frozen_layers)
        tags.extend([
            DXFTag(1002, '}'),  # end of frozen layer list
            DXFTag(1002, '}'),  # MVIEW
        ])
        return Tags(tags)
Esempio n. 2
0
def round_tags(tags: Tags, ndigits: int) -> Iterator[DXFTag]:
    for tag in tags:
        if isinstance(tag, DXFVertex):
            yield DXFVertex(tag.code, (round(d, ndigits) for d in tag.value))
        elif isinstance(tag.value, float):
            yield DXFTag(tag.code, round(tag.value, ndigits))  # type: ignore
        else:
            yield tag
Esempio n. 3
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),
     ]
Esempio n. 4
0
    def dxftags(self):
        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
Esempio n. 5
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)
Esempio n. 6
0
 def set_mesh_data(self, vertices=None, faces=None):
     if vertices is None:
         vertices = []
     else:
         vertices = list(vertices)
     if faces is None:
         faces = []
     else:
         faces = list(faces)
     self._remove_mesh_data()
     geodata = self.AcDbGeoData
     geodata.append(DXFTag(93, len(vertices)))
     for source, target in vertices:
         geodata.append(DXFVertex(13, (source[0], source[1])))
         geodata.append(DXFVertex(14, (target[0], target[1])))
     geodata.append(DXFTag(96, len(faces)))
     for face in faces:
         geodata.extend(
             DXFTag(code, index) for code, index in zip((97, 98, 99), face))
Esempio n. 7
0
 def set_seed_points(self, points: Sequence[Tuple[float, float]]) -> None:
     if len(points) < 1:
         raise DXFValueError("Param points should be a collection of 2D points and requires at least one point.")
     hatch_tags = self.AcDbHatch
     first_seed_point_index = self._get_seed_point_index(hatch_tags)
     existing_seed_points = hatch_tags.collect_consecutive_tags([10],
                                                                start=first_seed_point_index)  # don't rely on 'Number of seed points'
     new_seed_points = [DXFVertex(10, (point[0], point[1])) for point in points]  # only use x and y coordinate,
     self.dxf.n_seed_points = len(new_seed_points)  # set new count of seed points
     # replace existing seed points
     hatch_tags[first_seed_point_index: first_seed_point_index + len(existing_seed_points)] = new_seed_points
Esempio n. 8
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)
Esempio n. 9
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
Esempio n. 10
0
    def dxftags(self) -> List[DXFTag]:
        has_bulge = self.has_bulge()

        vtags = []
        for x, y, bulge in self.vertices:
            vtags.append(DXFVertex(10, (float(x), float(y))))
            if has_bulge:
                vtags.append(DXFTag(42, float(bulge)))

        tags = [
            DXFTag(92, int(self.path_type_flags)),
            DXFTag(72, int(has_bulge)),
            DXFTag(73, int(self.is_closed)),
            DXFTag(93, len(self.vertices)),
        ]
        tags.extend(vtags)
        tags.extend(build_source_boundary_object_tags(self.source_boundary_objects))
        return tags
Esempio n. 11
0
def test_init():
    v = DXFVertex(10, (1, 2, 3))
    assert v.value == (1., 2., 3.)
Esempio n. 12
0
def test_dxf_string():
    v = DXFVertex(10, (1, 2, 3))
    assert v.dxfstr() == " 10\n1.0\n 20\n2.0\n 30\n3.0\n"
Esempio n. 13
0
def test_dxf_tags():
    v = DXFVertex(10, (1, 2, 3))
    tags = tuple(v.dxftags())
    assert tags[0] == (10, 1.)
    assert tags[1] == (20, 2.)
    assert tags[2] == (30, 3.)
Esempio n. 14
0
def test_clone():
    v = DXFVertex(10, (1, 2, 3))
    v2 = v.clone()
    assert v2.code == v.code
    assert v2.value == v.value
Esempio n. 15
0
def test_xdata_string():
    v = DXFVertex(1011, (1, 2, 3))
    assert v.dxfstr() == "1011\n1.0\n1021\n2.0\n1031\n3.0\n"
Esempio n. 16
0
def byte_tag_compiler(tags: Iterable[DXFTag],
                      encoding=const.DEFAULT_ENCODING) -> Iterable[DXFTag]:
    """ Compiles DXF tag values imported by bytes_loader() into Python types.

    Raises DXFStructureError() for invalid float values and invalid coordinate
    values.

    Expects DXF coordinates written in x, y[, z] order, see function
    :func:`safe_tag_loader` for usage with applied repair filters.

    Args:
        tags: DXF tag generator, yielding tag values as bytes like bytes_loader()
        encoding: text encoding

    Raises:
        DXFStructureError: Found invalid DXF tag or unexpected coordinate order.

    """
    def error_msg(tag):
        code = tag.code
        value = tag.value.decode(encoding)
        return f'Invalid tag ({code}, "{value}") near line: {line}.'

    tags = iter(tags)
    undo_tag = None
    line = 0
    while True:
        try:
            if undo_tag is not None:
                x = undo_tag
                undo_tag = None
            else:
                x = next(tags)
                line += 2
            code = x.code
            if code in POINT_CODES:
                y = next(tags)  # y coordinate is mandatory
                line += 2
                # e.g. y-code for x-code=10 is 20
                if y.code != code + 10:
                    raise const.DXFStructureError(
                        f"Missing required y-coordinate near line: {line}.")
                # optional z coordinate
                z = next(tags)
                line += 2
                try:
                    # is it a z-coordinate like (30, 0.0) for base x-code=10
                    if z.code == code + 20:
                        point = (float(x.value), float(y.value),
                                 float(z.value))
                    else:
                        point = (float(x.value), float(y.value))
                        undo_tag = z
                except ValueError:
                    raise const.DXFStructureError(
                        f'Invalid floating point values near line: {line}.')
                yield DXFVertex(code, point)
            elif code in BINARY_DATA:
                # maybe pre compiled in low level tagger (binary DXF)
                if isinstance(x, DXFBinaryTag):
                    tag = x
                else:
                    try:
                        tag = DXFBinaryTag.from_string(code, x.value)
                    except ValueError:
                        raise const.DXFStructureError(
                            f'Invalid binary data near line: {line}.')
                yield tag
            else:  # just a single tag
                type_ = TYPE_TABLE.get(code, str)
                value: bytes = x.value
                if type_ is str:
                    if code == 0:
                        # remove white space from structure tags
                        value = x.value.strip()
                    yield DXFTag(code, value.decode(encoding))
                else:
                    try:
                        # fast path for int and float
                        yield DXFTag(code, type_(value))
                    except ValueError:
                        # slow path - ProE stores int values as floats :((
                        if type_ is int:
                            try:
                                yield DXFTag(code, int(float(x.value)))
                            except ValueError:
                                raise const.DXFStructureError(error_msg(x))
                        else:
                            raise const.DXFStructureError(error_msg(x))
        except StopIteration:
            return
Esempio n. 17
0
 def dxftags(self):
     return [
         DXFTag(72, 1),  # edge type
         DXFVertex(10, self.start),
         DXFVertex(11, self.end),
     ]
Esempio n. 18
0
def test_write_point_tag():
    s, t = setup_stream()
    t.write_tag(DXFVertex(10, (7., 8., 9.)))
    result = s.getvalue()
    assert result == ' 10\n7.0\n 20\n8.0\n 30\n9.0\n'
Esempio n. 19
0
 def _set_path_tags(self, vertices):
     boundary = [DXFVertex(11, value) for value in vertices]
     subclasstags = Tags(tag for tag in self.tags.subclasses[2] if tag.code != 11)  # filter out existing path tags
     subclasstags.extend(boundary)
     self.tags.subclasses[2] = subclasstags
Esempio n. 20
0
def test_strtag2_vector():
    assert ' 10\n1.0\n 20\n2.0\n 30\n3.0\n' == DXFVertex(10, Vec3(1, 2, 3)).dxfstr()
    assert ' 10\n1.0\n 20\n2.0\n 30\n3.0\n' == DXFVertex(10, Vec3((1, 2, 3))).dxfstr()
    assert ' 10\n1.0\n 20\n2.0\n 30\n0.0\n' == DXFVertex(10, Vec3(1, 2)).dxfstr()
    assert ' 10\n1.0\n 20\n2.0\n 30\n0.0\n' == DXFVertex(10, Vec3((1, 2))).dxfstr()
Esempio n. 21
0
def byte_tag_compiler(
    tags: Iterable[DXFTag],
    encoding=const.DEFAULT_ENCODING,
    messages: List = None,
    errors: str = 'surrogateescape',
) -> Iterable[DXFTag]:
    """ Compiles DXF tag values imported by bytes_loader() into Python types.

    Raises DXFStructureError() for invalid float values and invalid coordinate
    values.

    Expects DXF coordinates written in x, y[, z] order, see function
    :func:`safe_tag_loader` for usage with applied repair filters.

    Args:
        tags: DXF tag generator, yielding tag values as bytes like bytes_loader()
        encoding: text encoding
        messages: list to store error messages
        errors: specify decoding error handler

            - "surrogateescape" to preserve possible binary data (default)
            - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data
            - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data

    Raises:
        DXFStructureError: Found invalid DXF tag or unexpected coordinate order.

    """
    def error_msg(tag):
        code = tag.code
        value = tag.value.decode(encoding)
        return f'Invalid tag ({code}, "{value}") near line: {line}.'

    if messages is None:
        messages = []
    tags = iter(tags)
    undo_tag = None
    line = 0
    while True:
        try:
            if undo_tag is not None:
                x = undo_tag
                undo_tag = None
            else:
                x = next(tags)
                line += 2
            code = x.code
            if code in POINT_CODES:
                y = next(tags)  # y coordinate is mandatory
                line += 2
                # e.g. y-code for x-code=10 is 20
                if y.code != code + 10:
                    raise const.DXFStructureError(
                        f"Missing required y-coordinate near line: {line}.")
                # optional z coordinate
                z = next(tags)
                line += 2
                try:
                    # is it a z-coordinate like (30, 0.0) for base x-code=10
                    if z.code == code + 20:
                        try:
                            point = (float(x.value), float(y.value),
                                     float(z.value))
                        except ValueError:  # search for any float values
                            point = (_search_float(x.value),
                                     _search_float(y.value),
                                     _search_float(z.value))
                    else:
                        try:
                            point = (float(x.value), float(y.value))
                        except ValueError:  # seach for any float values
                            point = (
                                _search_float(x.value),
                                _search_float(y.value),
                            )
                        undo_tag = z
                except ValueError:
                    raise const.DXFStructureError(
                        f'Invalid floating point values near line: {line}.')
                yield DXFVertex(code, point)
            elif code in BINARY_DATA:
                # maybe pre compiled in low level tagger (binary DXF)
                if isinstance(x, DXFBinaryTag):
                    tag = x
                else:
                    try:
                        tag = DXFBinaryTag.from_string(code, x.value)
                    except ValueError:
                        raise const.DXFStructureError(
                            f'Invalid binary data near line: {line}.')
                yield tag
            else:  # just a single tag
                type_ = TYPE_TABLE.get(code, str)
                value: bytes = x.value
                if type_ is str:
                    if code == 0:
                        # remove white space from structure tags
                        value = x.value.strip().upper()
                    try:  # 2 stages to document decoding errors
                        str_ = value.decode(encoding, errors='strict')
                    except UnicodeDecodeError:
                        str_ = value.decode(encoding, errors=errors)
                        messages.append(
                            (AuditError.DECODING_ERROR,
                             f'Fixed unicode decoding error near line {line}'))

                    # Convert DXF unicode notation "\U+xxxx" to unicode,
                    # but exclude structure tags (code>0):
                    if code and has_dxf_unicode(str_):
                        str_ = decode_dxf_unicode(str_)

                    yield DXFTag(code, str_)
                else:
                    try:
                        # fast path for int and float
                        yield DXFTag(code, type_(value))
                    except ValueError:
                        # slow path - e.g. ProE stores int values as floats :((
                        if type_ is int:
                            try:
                                yield DXFTag(code, _search_int(x.value))
                            except ValueError:
                                raise const.DXFStructureError(error_msg(x))
                        elif type_ is float:
                            try:
                                yield DXFTag(code, _search_float(x.value))
                            except ValueError:
                                raise const.DXFStructureError(error_msg(x))
                        else:
                            raise const.DXFStructureError(error_msg(x))
        except StopIteration:
            return
Esempio n. 22
0
 def test_write_point_tag(self, t):
     t.write_tag(DXFVertex(10, (7., 8., 9.)))
     assert t.tags[0] == (10, 7.)
     assert t.tags[1] == (20, 8.)
     assert t.tags[2] == (30, 9.)
Esempio n. 23
0
 def _set_path_tags(self, vertices: Sequence[Tuple[float, float]]):
     boundary = [DXFVertex(14, value) for value in vertices]
     subclasstags = Tags(tag for tag in self.tags.subclasses[2] if tag.code != 14)
     subclasstags.extend(boundary)
     self.tags.subclasses[2] = subclasstags
     self.dxf.count_boundary_points = len(vertices)