A comprehensive Python package for creating, reading, modifying, and writing DXF (Drawing Exchange Format) documents with support for multiple DXF versions.
—
Specialized utility functions for text processing, pattern management, standards setup, date/time conversion, and various CAD-specific operations. The tools package provides essential utilities that support the core ezdxf functionality.
Conversion functions between Julian dates and standard datetime objects.
def juliandate(datetime) -> float:
"""
Convert datetime object to Julian date number.
Parameters:
- datetime: Python datetime object
Returns:
float: Julian date number
"""
def calendardate(julian: float):
"""
Convert Julian date number to datetime object.
Parameters:
- julian: Julian date number
Returns:
datetime: Python datetime object
"""Usage examples:
from ezdxf.tools import juliandate, calendardate
from datetime import datetime
# Convert to Julian date
now = datetime.now()
julian = juliandate(now)
print(f"Current Julian date: {julian}")
# Convert back to datetime
converted = calendardate(julian)
print(f"Converted back: {converted}")
# Use in DXF entities (some entities store dates as Julian dates)
creation_date = juliandate(datetime(2023, 1, 1, 12, 0, 0))Functions for handling binary data and hex string conversions.
def hex_strings_to_bytes(hex_strings) -> bytes:
"""
Convert list of hex strings to bytes.
Parameters:
- hex_strings: list of hexadecimal strings
Returns:
bytes: Combined binary data
"""
def bytes_to_hexstr(data: bytes, group_size: int = 1, upper: bool = True) -> str:
"""
Convert bytes to hex string representation.
Parameters:
- data: binary data
- group_size: bytes per group (for spacing)
- upper: use uppercase hex digits
Returns:
str: Hex string representation
"""Usage examples:
from ezdxf.tools import hex_strings_to_bytes, bytes_to_hexstr
# Convert hex strings to binary
hex_data = ['48656C6C6F', '20576F726C64'] # "Hello World" in hex
binary_data = hex_strings_to_bytes(hex_data)
print(binary_data.decode('utf-8')) # "Hello World"
# Convert binary to hex string
test_data = b"Test data"
hex_string = bytes_to_hexstr(test_data, group_size=2, upper=True)
print(f"Hex representation: {hex_string}")Text processing and formatting utilities for CAD-specific operations.
def escape(text: str) -> str:
"""
HTML escape text for safe display.
Parameters:
- text: input text
Returns:
str: HTML-escaped text
"""
def guid() -> str:
"""
Generate GUID string.
Returns:
str: GUID in standard format
"""
def suppress_zeros(s: str, leading: bool = True, trailing: bool = True) -> str:
"""
Remove leading and/or trailing zeros from number strings.
Parameters:
- s: number string
- leading: remove leading zeros
- trailing: remove trailing zeros
Returns:
str: Formatted number string
"""
def normalize_text_angle(angle: float, fix_upside_down: bool = True) -> float:
"""
Normalize text angle for readability.
Parameters:
- angle: text angle in radians
- fix_upside_down: flip upside-down text
Returns:
float: Normalized angle
"""Usage examples:
from ezdxf.tools import escape, guid, suppress_zeros, normalize_text_angle
import math
# HTML escape for safe display
unsafe_text = "<script>alert('test')</script>"
safe_text = escape(unsafe_text)
print(f"Escaped: {safe_text}")
# Generate unique identifier
unique_id = guid()
print(f"GUID: {unique_id}")
# Format numbers
number_str = "00012.3400"
clean_number = suppress_zeros(number_str, leading=True, trailing=True)
print(f"Cleaned: {clean_number}") # "12.34"
# Normalize text angles
upside_down_angle = math.radians(200) # 200 degrees
normalized = normalize_text_angle(upside_down_angle, fix_upside_down=True)
print(f"Normalized angle: {math.degrees(normalized)} degrees")Functions for manipulating binary flags in integer values.
def set_flag_state(flags: int, flag: int, state: bool = True) -> int:
"""
Set or clear binary flag in integer value.
Parameters:
- flags: current flag value
- flag: flag bit to modify
- state: True to set, False to clear
Returns:
int: Modified flag value
"""Usage examples:
from ezdxf.tools import set_flag_state
# Work with entity flags
current_flags = 0b00000000 # No flags set
# Set specific flags
current_flags = set_flag_state(current_flags, 0b00000001, True) # Set bit 0
current_flags = set_flag_state(current_flags, 0b00000100, True) # Set bit 2
current_flags = set_flag_state(current_flags, 0b00010000, True) # Set bit 4
print(f"Flags: {bin(current_flags)}") # 0b00010101
# Clear a flag
current_flags = set_flag_state(current_flags, 0b00000100, False) # Clear bit 2
print(f"Flags: {bin(current_flags)}") # 0b00010001Utility functions for processing sequences and iterables.
def take2(iterable):
"""
Iterate sequence as non-overlapping pairs.
Parameters:
- iterable: sequence to process
Yields:
tuple: consecutive pairs of elements
"""
def pairwise(iterable, close: bool = False):
"""
Iterate sequence as overlapping pairs.
Parameters:
- iterable: sequence to process
- close: include pair from last to first element
Yields:
tuple: overlapping pairs of elements
"""Usage examples:
from ezdxf.tools import take2, pairwise
# Process points as non-overlapping pairs
points = [(0, 0), (1, 1), (2, 0), (3, 1), (4, 0)]
# Non-overlapping pairs for line segments
for start, end in take2(points):
line = msp.add_line(start, end)
# Overlapping pairs for connected polyline
vertices = []
for p1, p2 in pairwise(points, close=True):
# Process each edge of the polygon
vertices.extend([p1, p2])
# Create closed polyline
poly = msp.add_lwpolyline(points)
poly.close()Comprehensive hatch pattern loading, analysis, and manipulation utilities.
def load(measurement: int = 1, factor: float = 1.0):
"""
Load hatch pattern definitions.
Parameters:
- measurement: measurement system (0=Imperial, 1=Metric)
- factor: scaling factor for patterns
Returns:
dict: Pattern definitions
"""
def scale_pattern(pattern, factor: float):
"""
Scale individual hatch pattern.
Parameters:
- pattern: pattern definition
- factor: scaling factor
Returns:
Pattern definition scaled by factor
"""
def scale_all(patterns, factor: float):
"""
Scale all patterns in collection.
Parameters:
- patterns: pattern collection
- factor: scaling factor
Returns:
Scaled pattern collection
"""
def parse(pattern_str: str):
"""
Parse hatch pattern definition string.
Parameters:
- pattern_str: pattern definition in AutoCAD format
Returns:
Parsed pattern data structure
"""
class PatternAnalyser:
"""Hatch pattern analysis and validation"""
def __init__(self, pattern): ...
def analyse(self):
"""Analyze pattern structure and properties"""
@property
def line_count(self) -> int:
"""Number of pattern lines"""
@property
def is_valid(self) -> bool:
"""True if pattern is valid"""
# Pattern constants and type definitions
ISO_PATTERN: dict
"""ISO standard hatch patterns"""
IMPERIAL_PATTERN: dict
"""Imperial measurement hatch patterns"""
HatchPatternLineType = List[float]
HatchPatternType = List[HatchPatternLineType]Usage examples:
from ezdxf.tools.pattern import load, scale_pattern, parse, PatternAnalyser
from ezdxf.tools.pattern import ISO_PATTERN
# Load standard patterns
metric_patterns = load(measurement=1, factor=1.0) # Metric
imperial_patterns = load(measurement=0, factor=25.4) # Imperial scaled to mm
# Scale specific pattern
if 'ANSI31' in metric_patterns:
scaled_ansi31 = scale_pattern(metric_patterns['ANSI31'], 2.0)
# Parse custom pattern
custom_pattern_str = """*CUSTOM,Custom diagonal lines
45, 0,0, 0,2.83, 2.83,-1.41
"""
custom_pattern = parse(custom_pattern_str)
# Analyze pattern
analyser = PatternAnalyser(custom_pattern)
analyser.analyse()
print(f"Pattern has {analyser.line_count} lines")
print(f"Pattern is valid: {analyser.is_valid}")
# Use pattern in hatch
hatch = msp.add_hatch()
hatch.set_pattern_fill('ANSI31', color=1, angle=0, scale=1.0)
# Add boundary paths to hatch...Functions for setting up standard drawing configurations, styles, and definitions.
def setup_drawing(doc, topics = None):
"""
Setup standard drawing configuration.
Parameters:
- doc: DXF document
- topics: list of setup topics ('linetypes', 'styles', 'dimstyles', etc.)
"""
def setup_linetypes(doc):
"""Setup standard AutoCAD linetypes in document"""
def setup_styles(doc):
"""Setup standard text styles in document"""
def setup_dimstyles(doc):
"""Setup standard dimension styles in document"""
def setup_dimstyle(doc, name: str):
"""
Setup specific dimension style by name.
Parameters:
- doc: DXF document
- name: dimension style name
"""Usage examples:
from ezdxf.tools.standards import setup_linetypes, setup_styles, setup_dimstyles
import ezdxf
# Create document with standard setup
doc = ezdxf.new('R2018')
# Setup standard configurations
setup_linetypes(doc) # CONTINUOUS, DASHED, DOTTED, etc.
setup_styles(doc) # Standard text styles
setup_dimstyles(doc) # Standard dimension styles
# Now you can use standard linetypes
line = doc.modelspace().add_line((0, 0), (10, 10), dxfattribs={
'linetype': 'DASHED',
'color': 1
})
# Check what was added
print("Available linetypes:")
for linetype in doc.linetypes:
print(f" {linetype.dxf.name}")
print("Available text styles:")
for style in doc.styles:
print(f" {style.dxf.name}")Transparency conversion functions (also available in colors module).
def float2transparency(value: float) -> int:
"""Convert float transparency (0-1) to DXF format"""
def transparency2float(value: int) -> float:
"""Convert DXF transparency to float (0-1)"""Various specialized utility functions for CAD operations.
# Text and string utilities
def text_size(text: str, font_size: float, font: str = None) -> tuple:
"""Estimate text size for layout calculations"""
def complex_ltype_definition(name: str, pattern, text_style: str = None):
"""Create complex linetype with text or shapes"""
# Debugging and analysis
def analyze_entity(entity):
"""Analyze entity structure and properties"""
def debug_entity(entity, stream = None):
"""Output detailed entity information for debugging"""
# Coordinate system utilities
def ocs_to_wcs(points, ocs_axis):
"""Convert Object Coordinate System points to World Coordinate System"""
def wcs_to_ocs(points, ocs_axis):
"""Convert World Coordinate System points to Object Coordinate System"""import ezdxf
from ezdxf.tools import juliandate, guid, suppress_zeros
from ezdxf.tools.pattern import load as load_patterns
from ezdxf.tools.standards import setup_drawing
from datetime import datetime
# Create document with full standard setup
doc = ezdxf.new('R2018')
setup_drawing(doc, topics=['linetypes', 'styles', 'dimstyles'])
# Load hatch patterns
patterns = load_patterns(measurement=1, factor=1.0) # Metric patterns
msp = doc.modelspace()
# Create drawing with various tools utilities
# Date stamp using Julian date
creation_date = juliandate(datetime.now())
title_text = f"Drawing created: {datetime.now().strftime('%Y-%m-%d')}"
title = msp.add_text(title_text, dxfattribs={
'height': 2.5,
'layer': 'TITLE'
})
# Unique identifier for drawing
drawing_id = guid()
id_text = msp.add_text(f"ID: {drawing_id}", dxfattribs={
'height': 1.5,
'insert': (0, -5),
'layer': 'TITLE'
})
# Dimension with suppressed zeros
dimension_value = "00012.5000"
clean_value = suppress_zeros(dimension_value)
dim_text = msp.add_text(f"Dimension: {clean_value}", dxfattribs={
'height': 2.0,
'insert': (0, -10),
'layer': 'DIMENSIONS'
})
# Hatch with pattern
if 'ANSI31' in patterns:
# Create boundary for hatch
boundary_points = [(10, 0), (20, 0), (20, 10), (10, 10)]
boundary = msp.add_lwpolyline(boundary_points, dxfattribs={'layer': 'HATCH_BOUNDARY'})
boundary.close()
# Create hatch with pattern
hatch = msp.add_hatch(dxfattribs={'layer': 'HATCHES'})
hatch.paths.add_polyline_path(boundary_points, is_closed=True)
hatch.set_pattern_fill('ANSI31', color=3, angle=45, scale=0.5)
# Save document
doc.saveas('tools_example.dxf')
print(f"Drawing saved with ID: {drawing_id}")Install with Tessl CLI
npx tessl i tessl/pypi-ezdxf