Ejemplo n.º 1
0
    def add(self, key: str, entity: DXFObject) -> None:
        """Add entry ``(key, value)``.

        Raises:
            DXFValueError: invalid entity handle
            DXFTypeError: invalid DXF type

        """
        if isinstance(entity, str):
            if not is_valid_handle(entity):
                raise DXFValueError(
                    f"Invalid entity handle #{entity} for key {key}")
        elif isinstance(entity, DXFGraphic):
            if self.doc is not None and self.doc.is_loading:
                # AutoCAD add-ons can store graphical entities in DICTIONARIES
                # in the OBJECTS section and AutoCAD does not complain - so just
                # preserve them!
                # Example "ZJMC-288.dxf" in issue #585, add-on: "acdgnlsdraw.crx"?
                logger.warning(f"Invalid entity {str(entity)} in {str(self)}")
            else:
                # Do not allow ezdxf users to add graphical entities to a
                # DICTIONARY object!
                raise DXFTypeError(
                    f"Graphic entities not allowed: {entity.dxftype()}")
        self._data[key] = entity
Ejemplo n.º 2
0
 def render(self) -> None:
     """ Render graphical representation as anonymous block. """
     if self.is_virtual:
         raise DXFTypeError('can not render virtual entity')
     # Do not delete existing anonymous block, it is maybe referenced
     # by a dimension entity in another block reference! Dimensions in block
     # references share the same geometry block!
     self.override().render()
Ejemplo n.º 3
0
    def export_mesh_data(self, tagwriter: 'TagWriter'):
        if len(self.source_vertices) != len(self.target_vertices):
            raise DXFTypeError("GEODATA mesh definition error: source and target point count does not match.")

        tagwriter.write_tag2(93, len(self.source_vertices))
        for s, t in zip(self.source_vertices, self.target_vertices):
            tagwriter.write_vertex(13, s)
            tagwriter.write_vertex(14, t)

        tagwriter.write_tag2(96, len(self.faces))
        for face in self.faces:
            if len(face) != 3:
                raise DXFTypeError("GEODATA face definition error: invalid index count {}.".format(len(face)))
            f1, f2, f3 = face
            tagwriter.write_tag2(97, f1)
            tagwriter.write_tag2(98, f2)
            tagwriter.write_tag2(99, f3)
Ejemplo n.º 4
0
 def acis_data(self, lines: Iterable[str]):
     """ Set ACIS data as list of strings for DXF R2000 to DXF R2010. In case of DXF R2013 and later, setting ACIS
     data as binary data is not supported.
     """
     if self.has_binary_data:
         raise DXFTypeError(
             'Setting ACIS data not supported for DXF R2013 and later.')
     else:
         self._acis_data = list(lines)
Ejemplo n.º 5
0
 def add_entry(self, entry: 'DXFEntity') -> None:
     """ Add a table `entry`, created by other object than this table. (internal API) """
     if entry.dxftype() != self._head.dxf.name:
         raise DXFTypeError('Invalid table entry type {} for table {}'.format(entry.dxftype(), self.name))
     name = entry.dxf.name
     if self.has_entry(name):
         raise DXFTableEntryError('{} {} already exists!'.format(self._head.dxf.name, name))
     entry.doc = self.doc
     entry.owner = self._head.dxf.handle
     self._append(entry)
Ejemplo n.º 6
0
    def __setitem__(self, key, item):
        """Set self[key] to value, key has to be a string.

        Raises:
            DXFTypeError: key is not a string

        """
        if not isinstance(key, str):
            raise DXFTypeError("key is not a string")
        self._user_dict[key] = item
Ejemplo n.º 7
0
    def delete(self, group: Union[DXFGroup, str]) -> None:
        """ Delete `group`, `group` can be an object of type :class:`DXFGroup` or a group name as string. """
        if isinstance(group, str):  # delete group by name
            name = group
        elif group.dxftype() == 'GROUP':
            name = group.get_name()
        else:
            raise DXFTypeError(group.dxftype())

        if name in self:
            super().delete(name)
        else:
            raise DXFValueError("GROUP not in group table registered.")
Ejemplo n.º 8
0
def explode_entity(entity: 'DXFGraphic',
                   target_layout: 'BaseLayout' = None) -> 'EntityQuery':
    """
    Explode parts of an entity as primitives into target layout, if target layout is ``None``,
    the target layout is the layout of the source entity.

    Returns an :class:`~ezdxf.query.EntityQuery` container with all DXF parts.

    Args:
        entity: DXF entity to explode, has to have a :meth:`virtual_entities()` method
        target_layout: target layout for DXF parts, ``None`` for same layout as source entity

    .. versionadded:: 0.12

    (internal API)

    """
    dxftype = entity.dxftype()

    if not hasattr(entity, 'virtual_entities'):
        raise DXFTypeError(f'Can not explode entity {dxftype}.')

    if entity.doc is None:
        raise DXFStructureError(
            f'{dxftype} has to be assigned to a DXF document.')

    entitydb = entity.doc.entitydb
    if entitydb is None:
        raise DXFStructureError(
            f'Exploding {dxftype} requires an entity database.')

    if target_layout is None:
        target_layout = entity.get_layout()
        if target_layout is None:
            raise DXFStructureError(
                f'{dxftype} without layout assigment, specify target layout.')

    entities = []

    for e in entity.virtual_entities():
        entitydb.add(e)
        target_layout.add_entity(e)
        entities.append(e)

    source_layout = entity.get_layout()
    if source_layout is not None:
        source_layout.delete_entity(entity)
    else:
        entitydb.delete_entity(entity)
    return EntityQuery(entities)
Ejemplo n.º 9
0
    def link_dxf_object(self, name: str, obj: DXFObject) -> None:
        """Add `obj` and set owner of `obj` to this dictionary.

        Graphical DXF entities have to reside in a layout and therefore can not
        be owned by a :class:`Dictionary`.

        Raises:
            DXFTypeError: `obj` has invalid DXF type

        """
        if not isinstance(obj, DXFObject):
            raise DXFTypeError(f"invalid DXF type: {obj.dxftype()}")
        self.add(name, obj)
        obj.dxf.owner = self.dxf.handle
Ejemplo n.º 10
0
def explode_entity(entity: "DXFGraphic",
                   target_layout: "BaseLayout" = None) -> "EntityQuery":
    """Explode parts of an entity as primitives into target layout, if target
    layout is ``None``, the target layout is the layout of the source entity.

    Returns an :class:`~ezdxf.query.EntityQuery` container with all DXF parts.

    Args:
        entity: DXF entity to explode, has to have a :meth:`virtual_entities()`
            method
        target_layout: target layout for DXF parts, ``None`` for same layout as
            source entity

    (internal API)

    """
    dxftype = entity.dxftype()
    virtual_entities = getattr(entity, "virtual_entities")
    if virtual_entities is None or dxftype in EXCLUDE_FROM_EXPLODE:
        raise DXFTypeError(f"Can not explode entity {dxftype}.")

    if entity.doc is None:
        raise DXFStructureError(
            f"{dxftype} has to be assigned to a DXF document.")

    entitydb = entity.doc.entitydb
    if entitydb is None:
        raise DXFStructureError(
            f"Exploding {dxftype} requires an entity database.")

    if target_layout is None:
        target_layout = entity.get_layout()
        if target_layout is None:
            raise DXFStructureError(
                f"{dxftype} without layout assignment, specify target layout.")

    entities = []
    for e in virtual_entities():
        target_layout.add_entity(e)
        entities.append(e)

    source_layout = entity.get_layout()
    if source_layout is not None:
        source_layout.delete_entity(entity)
    else:
        entitydb.delete_entity(entity)
    return EntityQuery(entities)
Ejemplo n.º 11
0
    def add_entity(self, entity: "DXFGraphic") -> None:
        """Add an existing :class:`DXFGraphic` entity to a layout, but be sure
        to unlink (:meth:`~BaseLayout.unlink_entity`) entity from the previous
        owner layout. Adding entities from a different DXF drawing is not
        supported.
        """
        # bind virtual entities to the DXF document:
        doc = self.doc
        if entity.dxf.handle is None and doc:
            factory.bind(entity, doc)
        handle = entity.dxf.handle
        if handle is None or handle not in self.doc.entitydb:
            raise DXFStructureError(
                "Adding entities from a different DXF drawing is not supported."
            )

        if not is_graphic_entity(entity):
            raise DXFTypeError(f"invalid entity {str(entity)}")
        self.block_record.add_entity(entity)
Ejemplo n.º 12
0
    def import_paperspace_layout(self, name: str) -> 'Layout':
        """
        Import paperspace layout `name` into target drawing. Recreates the source paperspace layout in the target
        drawing, renames the target paperspace if already a paperspace with same `name` exist and imports all
        entities from source paperspace into target paperspace.

        Args:
            name: source paper space name as string

        Returns: new created target paperspace :class:`Layout`

        Raises:
            KeyError: source paperspace does not exist
            DXFTypeError: invalid modelspace import

        """
        if name.lower() == 'model':
            raise DXFTypeError('Can not import modelspace, use method import_modelspace().')
        source_layout = self.source.layouts.get(name)
        target_layout = self.recreate_source_layout(name)
        self.import_entities(source_layout, target_layout)
        return target_layout
Ejemplo n.º 13
0
    def commit(self) -> None:
        """Store all changes to the underlying :class:`XData` instance.
        This call is not required if using the :meth:`entity` context manager.

        Raises:
            DXFValueError: invalid chars ``"\\n"`` or ``"\\r"`` in a string
            DXFTypeError: invalid data type

        """
        data = []
        for value in self._data:
            if isinstance(value, str):
                if len(value) > 255:  # XDATA limit for group code 1000
                    raise DXFValueError("string too long, max. 255 characters")
                if "\n" in value or "\r" in value:
                    raise DXFValueError(
                        "found invalid line break '\\n' or '\\r'")
            code = self.group_codes.get(type(value))
            if code:
                data.append(dxftag(code, value))
            else:
                raise DXFTypeError(f"invalid type: {type(value)}")
        self.xdata.set_xlist(self._appid, self._name, data)
Ejemplo n.º 14
0
 def copy(self):
     raise DXFTypeError('Copying of underlay not supported.')
Ejemplo n.º 15
0
    def add_foreign_entity(self, entity: "DXFGraphic", copy=True) -> None:
        """Add a foreign DXF entity to a layout, this foreign entity could be
        from another DXF document or an entity without an assigned DXF document.
        The intention of this method is to add **simple** entities from another
        DXF document or from a DXF iterator, for more complex operations use the
        :mod:`~ezdxf.addons.importer` add-on. Especially objects with BLOCK
        section (INSERT, DIMENSION, MLEADER) or OBJECTS section dependencies
        (IMAGE, UNDERLAY) can not be supported by this simple method.

        Not all DXF types are supported and every dependency or resource
        reference from another DXF document will be removed except attribute
        layer will be preserved but only with default attributes like
        color ``7`` and linetype ``CONTINUOUS`` because the layer attribute
        doesn't need a layer table entry.

        If the entity is part of another DXF document, it will be unlinked from
        this document and its entity database if argument `copy` is ``False``,
        else the entity will be copied. Unassigned entities like from DXF
        iterators will just be added.

        Supported DXF types:

            - POINT
            - LINE
            - CIRCLE
            - ARC
            - ELLIPSE
            - LWPOLYLINE
            - SPLINE
            - POLYLINE
            - 3DFACE
            - SOLID
            - TRACE
            - SHAPE
            - MESH
            - ATTRIB
            - ATTDEF
            - TEXT
            - MTEXT
            - HATCH

        Args:
            entity: DXF entity to copy or move
            copy: if ``True`` copy entity from other document else unlink from
                other document

        """
        foreign_doc = entity.doc
        dxftype = entity.dxftype()
        if dxftype not in SUPPORTED_FOREIGN_ENTITY_TYPES:
            raise DXFTypeError(f"unsupported DXF type: {dxftype}")
        if foreign_doc is self.doc:
            raise DXFValueError("entity from same DXF document")

        if foreign_doc is not None:
            if copy:
                entity = entity.copy()
            else:
                # Unbind entity from other document without destruction.
                factory.unbind(entity)

        entity.remove_dependencies(self.doc)
        # add to this layout & bind to document
        self.add_entity(entity)
Ejemplo n.º 16
0
 def copy(self) -> 'DXFEntity':
     raise DXFTypeError('Cloning of tag storage {} not supported.'.format(
         self.DXFTYPE))
Ejemplo n.º 17
0
 def copy(self):
     """ Prevent copying. (internal interface)"""
     raise DXFTypeError('Copying of ACIS data not supported.')
Ejemplo n.º 18
0
 def copy(self):
     raise DXFTypeError('Cloning of {} not supported.'.format(self.DXFTYPE))
Ejemplo n.º 19
0
 def copy(self):
     raise DXFTypeError('Copying of MLINESTYLE not supported.')
Ejemplo n.º 20
0
 def copy(self):
     raise DXFTypeError('Copying of GROUP not supported.')
Ejemplo n.º 21
0
    def page_setup(self, size: Tuple[float, float] = (297, 210),
                   margins: Tuple[float, float, float, float] = (10, 15, 10, 15),
                   units: str = 'mm',
                   offset: Tuple[float, float] = (0, 0),
                   rotation: int = 0,
                   scale: int = 16,
                   name: str = 'ezdxf',
                   device: str = 'DWG to PDF.pc3') -> None:
        """
        Setup plot settings and paper size and reset viewports. All parameters in given `units` (mm or inch).

        Reset paper limits, extends and viewports.

        Args:
            size: paper size as (width, height) tuple
            margins: (top, right, bottom, left) hint: clockwise
            units: ``'mm'`` or ``'inch'``
            offset: plot origin offset is 2D point
            rotation: see table Rotation
            scale: int 0-32 = standard scale type or tuple(numerator, denominator) e.g. ``(1, 50)`` for 1:50
            name: paper name prefix ``'{name}_({width}_x_{height}_{unit})'``
            device: device .pc3 configuration file or system printer name

        === ============
        int Rotation
        === ============
        0   no rotation
        1   90 degrees counter-clockwise
        2   upside-down
        3   90 degrees clockwise
        === ============

        """
        if int(rotation) not in (0, 1, 2, 3):
            raise DXFValueError("valid rotation values: 0-3")

        if isinstance(scale, tuple):
            standard_scale = 16
        elif isinstance(scale, int):
            standard_scale = scale
            scale = STD_SCALES.get(standard_scale, (1, 1))
        else:
            raise DXFTypeError("scale has to be an int or a tuple(numerator, denominator)")
        if scale[0] == 0:
            raise DXFValueError("scale numerator can't be 0.")
        if scale[1] == 0:
            raise DXFValueError("scale denominator can't be 0.")

        self.use_standard_scale(False)  # works best, don't know why
        paper_width, paper_height = size
        margin_top, margin_right, margin_bottom, margin_left = margins
        units = units.lower()
        if units.startswith('inch'):
            units = 'Inches'
            plot_paper_units = 0
            unit_factor = 25.4  # inch to mm
        elif units == 'mm':
            units = 'MM'
            plot_paper_units = 1
            unit_factor = 1.0
        else:
            raise DXFValueError('Supported units: "mm" and "inch"')

        # Setup PLOTSETTINGS
        # all paper sizes in mm
        dxf = self.dxf_layout.dxf
        dxf.page_setup_name = ''
        dxf.plot_configuration_file = device
        dxf.paper_size = '{0}_({1:.2f}_x_{2:.2f}_{3})'.format(name, paper_width, paper_height, units)
        dxf.left_margin = margin_left * unit_factor
        dxf.bottom_margin = margin_bottom * unit_factor
        dxf.right_margin = margin_right * unit_factor
        dxf.top_margin = margin_top * unit_factor
        dxf.paper_width = paper_width * unit_factor
        dxf.paper_height = paper_height * unit_factor
        dxf.scale_numerator = scale[0]
        dxf.scale_denominator = scale[1]
        dxf.plot_paper_units = plot_paper_units
        dxf.plot_rotation = rotation

        x_offset, y_offset = offset
        dxf.plot_origin_x_offset = x_offset * unit_factor  # conversion to mm
        dxf.plot_origin_y_offset = y_offset * unit_factor  # conversion to mm
        dxf.standard_scale_type = standard_scale
        dxf.unit_factor = 1. / unit_factor  # 1/1 for mm; 1/25.4 ... for inch

        # Setup Layout
        self.reset_paper_limits()
        self.reset_extends()
        self.reset_viewports()
Ejemplo n.º 22
0
 def copy(self):
     raise DXFTypeError(f'Cloning of {self.DXFTYPE} not supported.')
Ejemplo n.º 23
0
 def copy(self) -> 'DXFEntity':
     raise DXFTypeError(
         f'Cloning of tag storage {self.dxftype()} not supported.')
Ejemplo n.º 24
0
 def copy(self):
     raise DXFTypeError('Copying of IMAGE not supported.')