Пример #1
0
 def __delitem__(self, handle: str) -> None:
     """ Delete entity by `handle`. Removes entity only from database, does
     not destroy the entity.
     """
     if self.locked:
         raise DXFInternalEzdxfError('Locked entity database.')
     del self._database[handle]
Пример #2
0
def register_entity(cls):
    name = cls.DXFTYPE
    if name in ENTITY_CLASSES:
        raise DXFInternalEzdxfError(
            f'Double registration for DXF type {name}.')
    ENTITY_CLASSES[name] = cls
    return cls
Пример #3
0
 def dim_style(self):
     if self.drawing is not None:
         dim_style_name = self.dxf.dimstyle
         # raises ValueError if not exists, but all used dim styles should exists!
         return self.drawing.dimstyles.get(dim_style_name)
     else:
         raise DXFInternalEzdxfError('Dimension.drawing attribute not initialized.')
Пример #4
0
    def get_dim_style(self) -> 'DimStyle':
        """ Returns the associated :class:`DimStyle` entity. """
        if self.doc is None:
            raise DXFInternalEzdxfError('Dimension.drawing attribute not initialized.')

        dim_style_name = self.dxf.dimstyle
        # raises ValueError if not exists, but all used dim styles should exists!
        return self.doc.dimstyles.get(dim_style_name)
Пример #5
0
    def active_layout(self) -> Paperspace:
        """
        Returns the active paperspace layout.

        """
        for layout in self:
            if layout.is_active_paperspace:
                return cast(Paperspace, layout)
        raise DXFInternalEzdxfError('No active paperspace layout found.')
Пример #6
0
    def export_entity(self, tagwriter: 'TagWriter') -> None:
        super().export_entity(tagwriter)
        # AcDbEntity export is done by parent class
        if tagwriter.dxfversion == DXF12:
            raise DXFInternalEzdxfError('Exporting BLOCK_RECORDS for DXF R12.')
        tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name)
        tagwriter.write_tag2(SUBCLASS_MARKER, acdb_blockrec.name)

        self.dxf.export_dxf_attribs(tagwriter, ['name', 'layout', 'units', 'explode', 'scale'])
Пример #7
0
    def active_layout(self) -> 'Layout':
        """
        Returns active paper space layout.

        """
        for layout in self:
            if layout.block_record_name.upper() == '*PAPER_SPACE':
                return layout
        raise DXFInternalEzdxfError('No active paper space found.')
Пример #8
0
    def __setitem__(self, handle: str, entity: DXFEntity) -> None:
        """ Set `entity` for `handle`. """
        assert isinstance(handle, str), type(handle)
        assert isinstance(entity, DXFEntity), type(entity)
        if self.locked:
            raise DXFInternalEzdxfError('Locked entity database.')

        if handle == '0' or not is_valid_handle(handle):
            raise ValueError(f'Invalid handle {handle}.')
        self._database[handle] = entity
Пример #9
0
 def set_acad_dstyle(self, data: dict) -> None:
     if self.drawing is None:
         raise DXFInternalEzdxfError(
             'Dimension.drawing attribute not initialized.')
     # replace virtual 'dimtxsty' attribute by 'dimtxsty_handle'
     if _DIMTXSTY in data:
         dimtxsty = data.pop(_DIMTXSTY)
         txtstyle = self.drawing.styles.get(dimtxsty)
         data['dimtxsty_handle'] = txtstyle.dxf.handle
     super().set_acad_dstyle(data)
Пример #10
0
    def __setitem__(self, handle: str, entity: DXFEntity) -> None:
        """Set `entity` for `handle`."""
        assert isinstance(handle, str), type(handle)
        assert isinstance(entity, DXFEntity), type(entity)
        assert entity.is_alive, "Can not store destroyed entity."
        if self.locked:
            raise DXFInternalEzdxfError("Locked entity database.")

        if handle == "0" or not is_valid_handle(handle):
            raise ValueError(f"Invalid handle {handle}.")
        self._database[handle] = entity
Пример #11
0
    def export_entity(self, tagwriter: "TagWriter") -> None:
        super().export_entity(tagwriter)
        if tagwriter.dxfversion == DXF12:
            raise DXFInternalEzdxfError("Exporting BLOCK_RECORDS for DXF R12.")
        tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name)
        tagwriter.write_tag2(SUBCLASS_MARKER, acdb_blockrec.name)

        self.dxf.export_dxf_attribs(
            tagwriter,
            [
                "name",
                "layout",
                "units",
                "explode",
                "scale",
            ],
        )
Пример #12
0
    def set_acad_dstyle(self, data: dict) -> None:
        """ Set XDATA section ACAD:DSTYLE, to override DIMSTYLE attributes for
        this DIMENSION entity.

        Args:
            data: ``dict`` with DIMSTYLE attribute names as keys.

        (internal API)

        """
        if self.doc is None:
            raise DXFInternalEzdxfError(
                'Dimension.doc attribute not initialized.')

        # ezdxf uses internally only resource names for arrows, line types and
        # text styles, but DXF 2000 and later requires handles for these
        # resources:
        actual_dxfversion = self.doc.dxfversion
        data = self.dim_style_attr_names_to_handles(data, actual_dxfversion)
        tags = []
        dim_style_attributes = self.dim_style_attributes()
        for key, value in data.items():
            if key not in dim_style_attributes:
                # Ignore unknown attributes
                logging.debug(f'Ignore unknown DIMSTYLE attribute: "{key}"')
                continue
            dxf_attr = dim_style_attributes.get(key)
            if dxf_attr and dxf_attr.code > 0:  # skip internal and virtual tags
                if dxf_attr.dxfversion > actual_dxfversion:
                    logging.debug(
                        f'Unsupported DIMSTYLE attribute "{key}" for '
                        f'DXF version {self.doc.acad_release}')
                    continue
                code = dxf_attr.code
                tags.append((1070, code))
                if code == 5:
                    # DimStyle 'dimblk' has group code 5 but is not a handle
                    tags.append((1000, value))
                else:
                    tags.append((get_xcode_for(code), value))

        if len(tags):
            self.set_xdata_list('ACAD', 'DSTYLE', tags)
Пример #13
0
 def export_dxf(self, tagwriter: 'TagWriter') -> None:
     if self.dxf.handle is None:
         raise DXFInternalEzdxfError(
             'TABLE needs a handle, maybe loaded from DXF R12 without handle!'
         )
     # 1. tag: (0, DXFTYPE)
     tagwriter.write_tag2(STRUCTURE_MARKER, self.DXFTYPE)
     tagwriter.write_tag2(2, self.dxf.name)
     if tagwriter.dxfversion >= DXF2000:
         tagwriter.write_tag2(5, self.dxf.handle)
         if self.extension_dict:
             self.extension_dict.export_dxf(tagwriter)
         tagwriter.write_tag2(OWNER_CODE, self.dxf.owner)
         tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table.name)
         tagwriter.write_tag2(70, self.dxf.count)
         if self.dxf.name == 'DIMSTYLE':  # the one exception - typical Autodesk
             tagwriter.write_tag2(SUBCLASS_MARKER, 'AcDbDimStyleTable')
     else:  # DXF R12
         #  TABLE does not need a handle at all
         tagwriter.write_tag2(70, self.dxf.count)
Пример #14
0
    def frozen_layers(self) -> List[str]:
        """ Set/get frozen layers as list of layer names. """
        type_ = self._frozen_layers_content_type
        if type_ == 'names':
            return self._frozen_layers

        bag: List[str] = []
        entitydb = self.doc.entitydb
        if type_ == 'handles':
            for handle in self._frozen_layers:
                try:
                    bag.append(entitydb[handle].dxf.name)
                except KeyError:  # ignore non-existing layers
                    pass
        else:
            raise DXFInternalEzdxfError(
                f'invalid frozen_layer_content_type: "{type_}"')
        self._frozen_layers = bag
        self._frozen_layers_content_type = 'names'
        return bag
Пример #15
0
    def __init__(
        self,
        dimension: "Dimension",
        ucs: "UCS" = None,
        override: "DimStyleOverride" = None,
    ):
        super().__init__(dimension, ucs, override)
        dimtype = self.dimension.dimtype
        measurement = self.measurement
        if dimtype == 3:
            self.is_diameter_dim = True
        elif dimtype == 4:
            self.is_radius_dim = True
        else:
            raise DXFInternalEzdxfError(f"Invalid dimension type {dimtype}")

        self.center: Vec2 = self._center()  # override in diameter dimension
        self.point_on_circle: Vec2 = Vec2(self.dimension.dxf.defpoint4)
        # modify parameters for special scenarios
        if measurement.user_location is None:
            if (
                measurement.text_is_inside
                and measurement.text_inside_horizontal
                and measurement.text_movement_rule == 1
            ):  # move text, add leader
                # use algorithm for user define dimension line location
                measurement.user_location = self.center.lerp(
                    self.point_on_circle
                )
                measurement.text_valign = 0  # text vertical centered

        direction = self.point_on_circle - self.center
        self.dim_line_vec = direction.normalize()
        self.dim_line_angle = self.dim_line_vec.angle_deg
        self.radius = direction.magnitude
        # get_measurement() works for radius and diameter dimension
        measurement.update(self.dimension.get_measurement())
        self.outside_default_distance = self.radius + 2 * self.arrows.arrow_size
        self.outside_default_defpoint = self.center + (
            self.dim_line_vec * self.outside_default_distance
        )
        self.outside_text_force_dimline = bool(self.dim_style.get("dimtofl", 1))
        # final dimension text (without limits or tolerance)

        # default location is outside, if not forced to be inside
        measurement.text_is_outside = not measurement.force_text_inside
        # text_outside: user defined location, overrides default location
        if measurement.user_location is not None:
            measurement.text_is_outside = self.is_location_outside(
                measurement.user_location
            )

        self._total_text_width: float = 0.0
        if measurement.text:
            # text width and required space
            self._total_text_width = self.total_text_width()
            if self.tol.has_limits:
                # limits show the upper and lower limit of the measurement as
                # stacked values and with the size of tolerances
                self.tol.update_limits(measurement.value)

        # default rotation is angle of dimension line, from center to point on circle.
        rotation = self.dim_line_angle
        if measurement.text_is_outside and measurement.text_outside_horizontal:
            rotation = 0.0
        elif measurement.text_is_inside and measurement.text_inside_horizontal:
            rotation = 0.0

        # final absolute text rotation (x-axis=0)
        measurement.text_rotation = normalize_text_angle(
            rotation, fix_upside_down=True
        )

        # final text location
        measurement.text_location = self.get_text_location()
        self.geometry.set_text_box(self.init_text_box())
        # write final text location into DIMENSION entity
        if measurement.user_location:
            self.dimension.dxf.text_midpoint = measurement.user_location
        # default locations
        elif (
            measurement.text_is_outside and measurement.text_outside_horizontal
        ):
            self.dimension.dxf.text_midpoint = self.outside_default_defpoint
        else:
            self.dimension.dxf.text_midpoint = measurement.text_location
Пример #16
0
    def __init__(self,
                 dimension: 'Dimension',
                 ucs: 'UCS' = None,
                 override: 'DimStyleOverride' = None):
        super().__init__(dimension, ucs, override)
        dimtype = self.dimension.dimtype
        if dimtype == 3:
            self.is_diameter_dim = True
            self.text_prefix = 'Ø'
        elif dimtype == 4:
            self.is_radius_dim = True
            self.text_prefix = 'R'
        else:
            raise DXFInternalEzdxfError(f'Invalid dimension type {dimtype}')

        self.center = self._center()  # override in diameter dimension
        self.point_on_circle = Vec2(self.dimension.dxf.defpoint4)
        # modify parameters for special scenarios
        if self.user_location is None:  # default location
            if self.text_inside and self.text_inside_horizontal and self.text_movement_rule == 1:  # move text, add leader
                # use algorithm for user define dimension line location
                self.user_location = self.center.lerp(self.point_on_circle)
                self.text_valign = 0  # text vertical centered

        direction = self.point_on_circle - self.center
        self.dim_line_vec = direction.normalize()
        self.dim_line_angle = self.dim_line_vec.angle_deg
        self.radius = direction.magnitude
        # get_measurement() works for radius and diameter dimension
        self.measurement = self.dimension.get_measurement()
        self.outside_default_distance = self.radius + 2 * self.arrow_size
        self.outside_default_defpoint = self.center + (
            self.dim_line_vec * self.outside_default_distance)
        self.outside_text_force_dimline = self.dim_style.get('dimtofl', 1)
        # final dimension text (without limits or tolerance)
        self.text = self.text_override(
            self.measurement * self.dim_measurement_factor)  # type: str

        # default location is outside, if not forced to be inside
        self.text_outside = not self.force_text_inside
        # text_outside: user defined location, overrides default location
        if self.user_location is not None:
            self.text_outside = self.is_location_outside(self.user_location)

        if self.text:
            # text width and required space
            self.dim_text_width = self.text_width(self.text)  # type: float
            if self.dim_tolerance:
                self.dim_text_width += self.tol_text_width

            elif self.dim_limits:
                # limits show the upper and lower limit of the measurement as stacked values
                # and with the size of tolerances
                measurement = self.measurement * self.dim_measurement_factor
                self.measurement_upper_limit = measurement + self.tol_maximum
                self.measurement_lower_limit = measurement - self.tol_minimum
                self.tol_text_upper = self.format_tolerance_text(
                    self.measurement_upper_limit)
                # Only the lower limit has a text prefix
                self.tol_text_lower = self.text_prefix + self.format_tolerance_text(
                    self.measurement_lower_limit)
                self.tol_text_width = self.tolerance_text_width(
                    max(len(self.tol_text_upper), len(self.tol_text_lower)))

                # only limits are displayed so:
                self.dim_text_width = self.tol_text_width

        # default rotation is angle of dimension line, from center to point on circle.
        rotation = self.dim_line_angle
        if self.text_outside and self.text_outside_horizontal:
            rotation = 0
        elif self.text_inside and self.text_inside_horizontal:
            rotation = 0

        # final absolute text rotation (x-axis=0)
        self.text_rotation = normalize_text_angle(rotation,
                                                  fix_upside_down=True)

        # final text location
        self.text_location = self.get_text_location()  # type: Vec2

        self.text_box = TextBox(center=self.text_location,
                                width=self.dim_text_width,
                                height=self.text_height,
                                angle=self.text_rotation,
                                gap=self.text_gap * .75)
        # write final text location into DIMENSION entity
        if self.user_location:
            self.dimension.dxf.text_midpoint = self.user_location
        # default locations
        elif self.text_outside and self.text_outside_horizontal:
            self.dimension.dxf.text_midpoint = self.outside_default_defpoint
        else:
            self.dimension.dxf.text_midpoint = self.text_location