def delete_layout(self, name: str) -> None: """ Delete paper space layout `name` and all entities owned by this layout. Available only for DXF R2000 or later, DXF R12 supports only one paperspace and it can't be deleted. """ if name not in self.layouts: raise DXFValueError("Layout '{}' does not exist.".format(name)) else: self.layouts.delete(name)
def _parse_list(self, tags: Iterable[Tuple]) -> List: data = list(tags) content = [] for code, value in data[2:-1]: factory = self.converter.get(code) if factory: content.append(factory(value)) else: raise DXFValueError(f"unsupported group code: {code}") return content
def new_line( angle: float = 0., base_point: Tuple[float, float] = (0., 0.), offset: Tuple[float, float] = (0., 0.), dash_length_items: List[float] = None) -> 'PatternDefinitionLine': if dash_length_items is None: raise DXFValueError( "Parameter 'dash_length_items' must not be None.") return PatternDefinitionLine(angle, base_point, offset, dash_length_items)
def grid(self, size: Tuple[int, int] = (1, 1), spacing: Tuple[float, float] = (1, 1)) -> 'Insert': """ Place block reference in a grid layout, grid `size` defines the row- and column count, `spacing` defines the distance between two block references. Args: size: grid size as ``(row_count, column_count)`` tuple spacing: distance between placing as ``(row_spacing, column_spacing)`` tuple """ if len(size) != 2: raise DXFValueError("Parameter size has to be a (row_count, column_count)-tuple.") if len(spacing) != 2: raise DXFValueError("Parameter spacing has to be a (row_spacing, column_spacing)-tuple.") self.dxf.row_count = size[0] self.dxf.column_count = size[1] self.dxf.row_spacing = spacing[0] self.dxf.column_spacing = spacing[1] return self
def _add(self, tags: Tags) -> None: tags = Tags(tags) if len(tags): appid = tags[0].value if appid in self.data: logger.info(f"Duplicate XDATA appid {appid} in one entity") if has_valid_xdata_group_codes(tags): self.data[appid] = tags else: raise DXFValueError( f"found invalid XDATA group code in {tags}")
def _set_gradient(self, gradient_data: 'GradientData') -> None: gradient_data.name = gradient_data.name.upper() if gradient_data.name not in const.GRADIENT_TYPES: raise DXFValueError('Invalid gradient type name: %s' % gradient_data.name) self._remove_pattern_data() self._remove_gradient_data() self.dxf.solid_fill = 1 self.dxf.pattern_name = 'SOLID' self.dxf.pattern_type = const.HATCH_TYPE_PREDEFINED self.AcDbHatch.extend(gradient_data.dxftags())
def set_open_rational(self, control_points: Sequence['Vertex'], weights: Sequence[float], degree: int = 3) -> None: """ Open rational B-spline with uniform knot vector, start and end at your first and last control points, and has additional control possibilities by weighting each control point. """ self.set_open_uniform(control_points, degree=degree) self.dxf.flags = self.dxf.flags | self.RATIONAL if len(weights) != len(control_points): raise DXFValueError('Control point count must be equal to weights count.') self.weights = weights
def replace(self, tag: str, value: str) -> None: """ Replaces the value of the first custom property `tag` by a new `value`. """ properties = self.properties for index in range(len(properties)): name = properties[index][0] if name == tag: properties[index] = (name, value) return raise DXFValueError("Tag '%s' does not exist" % tag)
def acquire_arrow(self, name: str): """ For standard AutoCAD and ezdxf arrows create block definitions if required, otherwise check if block `name` exist. (internal API) """ from ezdxf.render.arrows import ARROWS if ARROWS.is_acad_arrow(name) or ARROWS.is_ezdxf_arrow(name): ARROWS.create_block(self.blocks, name) elif name not in self.blocks: raise DXFValueError(f'Arrow block "{name}" does not exist.')
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
def new(self, name: str, dxfattribs: dict = None) -> 'Layout': """ Create a new Layout. Args: name (str): layout name as shown in tab dxfattribs (dict): DXF attributes for the ``LAYOUT`` entity """ if not is_valid_name(name): raise DXFValueError('name contains invalid characters') if dxfattribs is None: dxfattribs = {} if name in self._layouts: raise DXFValueError('Layout "{}" already exists'.format(name)) def create_dxf_layout_entity() -> str: dxfattribs['name'] = name dxfattribs['owner'] = self._dxf_layout_management_table.dxf.handle dxfattribs.setdefault('taborder', len(self._layouts) + 1) dxfattribs['block_record'] = block_record_handle entity = self.drawing.objects.create_new_dxf_entity( 'LAYOUT', dxfattribs) return entity.dxf.handle block_layout = self.drawing.blocks.new_layout_block() block_record_handle = block_layout.block_record_handle block_record = block_layout.block_record layout_handle = create_dxf_layout_entity() block_record.dxf.layout = layout_handle # create valid layout entity layout = Layout(self.drawing, layout_handle) # add layout to management tables self._dxf_layout_management_table[name] = layout_handle self._layouts[name] = layout return layout
def get(self, appid: str) -> Tags: """Returns the DXF tags as :class:`~ezdxf.lldxf.tags.Tags` list stored by `appid`. Raises: DXFValueError: no data for `appid` exist """ if appid in self.data: return self.data[appid] else: raise DXFValueError(appid)
def get_extension_dict(self, create=True): block_record = self.block_record try: xdict = block_record.get_extension_dict() except (DXFValueError, DXFKeyError): # DXFValueError: block_record has no extension dict # DXFKeyError: block_record has an extension dict handle, but extension dict does not exist if create: xdict = block_record.new_extension_dict() else: raise DXFValueError('Extension dictionary do not exist.') return xdict
def set_matrix(subclass, code, data): values = list(data) if len(values) != 16: raise DXFValueError("Transformation matrix requires 16 values.") try: insert_pos = subclass.tag_index(code) except DXFValueError: insert_pos = len(subclass) subclass.remove_tags((code, )) tags = [DXFTag(code, value) for value in values] subclass[insert_pos:insert_pos] = tags
def set_data(self, entities: Iterable['DXFGraphic']) -> None: """ Set `entities` as new group content, entities should be an iterable :class:`GraphicEntity` or inherited (LINE, CIRCLE, ...). Raises :class:`DXFValueError` if not all entities be on the same layout (modelspace or any paperspace layout but not block) """ entities = list(entities) # for generators if not all_entities_on_same_layout(entities): raise DXFValueError( "All entities have to be on the same layout (modelspace or any paperspace layout but not block).") self.clear() self._data = entities
def delete_vertices(self, pos, count=1): db = self.entitydb prev_vertex = self.__getitem__(pos - 1).tags if pos > 0 else self.tags vertex = db[prev_vertex.link] while vertex.dxftype() == 'VERTEX': db.delete_handle(prev_vertex.link) # remove from database prev_vertex.link = vertex.link # remove vertex from list count -= 1 if count == 0: return vertex = db[prev_vertex.link] raise DXFValueError("invalid count")
def remove(self, tag: str, all: bool = False) -> None: """ Remove first occurrence of 'tag', removes all occurrences if param all is True. """ found_tag = False for item in self.properties: if item[0] == tag: self.properties.remove(item) found_tag = True if not all: return if not found_tag: raise DXFValueError("Tag '%s' does not exist" % tag)
def check(value): value = cast_value(attrib_def.code, value) if not attrib_def.is_valid_value(value): if attrib_def.fixer: value = attrib_def.fixer(value) logger.debug(f'Fixed invalid attribute "{key}" in entity' f' {str(self._entity)} to "{str(value)}".') else: raise DXFValueError( f'Invalid value {str(value)} for attribute "{key}" in ' f'entity {str(self._entity)}.') return value
def remove(self, tag: str, all: bool = False) -> None: """ Removes the first occurrence of custom property `tag`, removes all occurrences if `all` is ``True``. Raises `:class:`DXFValueError` if `tag` does not exist. """ found_tag = False for item in self.properties: if item[0] == tag: self.properties.remove(item) found_tag = True if not all: return if not found_tag: raise DXFValueError("Tag '%s' does not exist" % tag)
def rename(self, old_name: str, new_name: str) -> None: """ Rename a layout from `old_name` to `new_name`. Can not rename layout ``'Model'`` and the new name of a layout must not exist. Args: old_name: actual layout name new_name: new layout name Raises: DXFValueError: try to rename ``'Model'`` DXFValueError: Layout `new_name` already exist. """ if old_name == 'Model': raise DXFValueError('Can not rename model space.') if new_name in self._layouts: raise DXFValueError('Layout "{}" already exist.'.format(new_name)) layout = self._layouts[old_name] layout.rename(new_name) del self._layouts[old_name] self._layouts[new_name] = layout
def set_vertices(self, vertices: Sequence[Sequence[float]], is_closed: bool = 1) -> None: new_vertices = [] for vertex in vertices: if len(vertex) == 2: x, y = vertex bulge = 0 elif len(vertex) == 3: x, y, bulge = vertex else: raise DXFValueError("Invalid vertex format, expected (x, y) or (x, y, bulge)") new_vertices.append((x, y, bulge)) self.vertices = new_vertices self.is_closed = is_closed
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.")
def set_pos(self, p1, p2=None, align=None): if align is None: align = self.get_align() align = align.upper() self.set_align(align) self.set_dxf_attrib('insert', p1) if align in ('ALIGNED', 'FIT'): if p2 is None: raise DXFValueError("Alignment '{}' requires a second alignment point.".format(align)) else: p2 = p1 self.set_dxf_attrib('align_point', p2) return self
def bspline_control_frame(fit_points: Iterable['Vertex'], degree: int = 3, method: str = 'distance', power: float = .5): """ Generates the control points for the `B-spline`_ control frame by `Curve Global Interpolation`_. Given are the fit points and the degree of the B-spline. The function provides 3 methods for generating the parameter vector t: =================== ============================================================ Method Description =================== ============================================================ ``'uniform'`` creates a uniform t vector, from ``0`` to ``1`` evenly spaced; see `uniform`_ method ``'distance'`` creates a t vector with values proportional to the fit point distances, see `chord length`_ method ``'centripetal'`` creates a t vector with values proportional to the fit point distances ^ ``power``; see `centripetal`_ method =================== ============================================================ Args: fit_points: fit points of B-spline, as list of :class:`Vector` compatible objects degree: degree of B-spline method: calculation method for parameter vector t power: power for centripetal method Returns: :class:`BSpline` """ def create_t_vector(): if method == 'uniform': return uniform_t_vector(fit_points) # equally spaced 0 .. 1 elif method == 'distance': return distance_t_vector(fit_points) elif method == 'centripetal': return centripetal_t_vector(fit_points, power=power) else: raise DXFValueError('Unknown method: {}'.format(method)) fit_points = Vector.list(fit_points) count = len(fit_points) order = degree + 1 if order > count: raise DXFValueError( 'Need more fit points for degree {}'.format(degree)) t_vector = list(create_t_vector()) knots = list(control_frame_knots(count - 1, degree, t_vector)) control_points = global_curve_interpolation(fit_points, degree, t_vector, knots) bspline = BSpline(control_points, order=order, knots=knots) bspline.t_array = t_vector return bspline
def required_knot_values(count: int, order: int) -> int: # just to show the connections # count = count of control points = n + 1 # k = order of spline = degree + 1 # 2 <= k <= n + 1 # p = degree # order = p + 1 k = order n = count - 1 p = k - 1 if not (2 <= k <= (n + 1)): raise DXFValueError('Invalid count/order combination') # n + p + 2 = count + order return n + p + 2
def get_xdata(self, appid: str) -> Tags: """ Returns extended data for `appid`. Args: appid: application name as defined in the APPID table. Raises: DXFValueError: no extended data for `appid` found """ if self.xdata: return Tags(self.xdata.get(appid)[1:]) else: raise DXFValueError(appid)
def get_app_data(self, appid: str) -> Tags: """ Returns application defined data for `appid`. Args: appid: application name as defined in the APPID table. Raises: DXFValueError: no data for `appid` found """ if self.appdata: return self.appdata.get(appid)[1:-1] else: raise DXFValueError(appid)
def move_to_layout(self, entity, layout): """ Move entity from block layout to another layout. Args: entity: DXF entity to move layout: any layout (model space, paper space, block) """ if entity.dxf.handle in self._entity_space: self.unlink_entity(entity) layout.add_entity(entity) else: raise DXFValueError('Layout does not contain entity.')
def delete(self, group: DXFGroup) -> None: """ Delete GROUP by name or Group() object. """ if isinstance(group, str): # delete group by name super(GroupManager, self).delete(group) else: # group should be a DXFEntity group_handle = group.dxf.handle for name, _group in self: if group_handle == _group.dxf.handle: super(GroupManager, self).delete(name) return raise DXFValueError("GROUP not in group table registered.")
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)