dxfedit/03_Python_OpenSource_DXF/insert_tables_from_data.py
2025-09-09 18:42:30 +08:00

174 lines
7.2 KiB
Python

import ezdxf
from ezdxf.math import Vec3
import os
# ==============================================================================
# 1. STYLE & GEOMETRY DEFINITIONS
# Based on the analysis of the existing DXF file.
# ==============================================================================
# --- Column widths for the two types of tables ---
TABLE_1_COL_WIDTHS = [15.0, 30.0, 55.0, 10.0, 30.0, 10.0, 10.0, 20.0] # Simplified for main part
TABLE_2_COL_WIDTHS = [15.0, 30.0, 55.0, 10.0, 30.0, 10.0, 10.0, 20.0, 47.5, 15.0, 5.0, 25.0, 20.0, 30.0, 5.0, 10.0, 5.0, 15.0, 10.0, 10.0, 5.0, 5.0, 20.0]
# --- Row Heights ---
DEFAULT_ROW_HEIGHT = 8.0
HEADER_ROW_1_HEIGHT = 5.5
HEADER_ROW_2_HEIGHT = 6.5
# --- Text Style Templates (Height, dX, dY) ---
# These represent common text placements within a cell.
STYLES = {
# Generic styles from content analysis
"id_number": (3.50, 5.00, 5.50),
"part_code": (3.00, 1.50, 5.50),
"name_zh": (3.50, 2.00, 4.00),
"name_en": (2.00, 2.00, 7.00),
"spec": (3.00, 18.50, 4.00),
"quantity": (3.00, 4.00, 5.50),
"material": (3.00, 8.50, 5.50),
"single_weight": (3.00, 2.00, 6.00),
"total_weight": (3.00, 2.00, 6.00),
"remark": (3.00, 3.50, 3.50),
# Specific Header Styles (from Header Analysis)
"header_zh": (3.50, 4.50, 5.50),
"header_en": (2.00, 2.00, 4.75),
"header_mass_zh": (3.50, 2.50, 5.60),
"header_mass_en": (2.00, 8.30, 4.80),
}
# ==============================================================================
# 2. DATA TO BE INSERTED
# This would typically come from an Excel file or database.
# ==============================================================================
TABLE_1_DATA = [
# Each item in the list is a row.
# Each item in the row is a cell, containing a list of (style, text) tuples.
[ [("id_number", "21")], [("part_code", "N-123-A")], [("name_zh", "新盖板"), ("name_en", "NEW COVER")], [("quantity", "2")], [("material", "S30408")], [("single_weight", "5.1")], [("total_weight", "10.2")], [("remark", "自定义")] ],
[ [("id_number", "22")], [("part_code", "N-456-B")], [("name_zh", "新支架"), ("name_en", "NEW BRACKET"), ("spec", "M20x150")], [("quantity", "4")], [("material", "Q235B")], [("single_weight", "2.0")], [("total_weight", "8.0")], [("remark", "")] ],
]
TABLE_2_HEADER_DATA = [
# Simplified header based on analysis
[ [("header_zh", "件 号")], [("header_zh", "图号或标准号")], [("header_zh", "名 称")], [("header_zh", "数量")], [("header_zh", "材 料")], [("header_mass_zh", "质量"), ("header_mass_en", "MASS(kg)")], [], [("header_zh", "备 注")] ],
[ [("header_en", "PARTS .NO.")], [("header_en", "DWG NO. OR STD. NO.")], [("header_en", "PARTS. NAME.")], [("header_en", "QTY.")], [("header_en", "MAT'L'")], [], [], [("header_en", "REMARKS")] ],
]
# ==============================================================================
# 3. DRAWING LOGIC
# ==============================================================================
def draw_table(msp, start_pos, col_widths, data_rows):
"""
Draws a complete table with grid lines and text.
Args:
msp: Modelspace object from ezdxf.
start_pos: Vec3 top-left starting position for the table.
col_widths: List of column widths.
data_rows: List of rows, where each row is a list of cells.
"""
current_pos = start_pos.copy()
col_x_coords = [current_pos.x]
for width in col_widths:
col_x_coords.append(col_x_coords[-1] + width)
# --- Draw Rows and Text ---
for row_data in data_rows:
row_y_top = current_pos.y
row_y_bottom = row_y_top - DEFAULT_ROW_HEIGHT
# Draw horizontal line for the row top
msp.add_line((current_pos.x, row_y_top), (col_x_coords[-1], row_y_top))
# Draw vertical lines and add text for each cell
for i, cell_data in enumerate(row_data):
cell_x_left = col_x_coords[i]
cell_x_right = col_x_coords[i+1]
# Draw left vertical line for the cell
msp.add_line((cell_x_left, row_y_top), (cell_x_left, row_y_bottom))
# Add text entities for the cell
for style_key, text_content in cell_data:
if not text_content: continue
style = STYLES.get(style_key)
if not style:
print(f"Warning: Style '{style_key}' not found. Skipping text.")
continue
text_height, dX, dY = style
# Calculate absolute position for the text
insert_pos = (cell_x_left + dX, row_y_top - dY)
msp.add_text(
text_content,
height=text_height,
dxfattribs={
"style": "Standard",
"insert": insert_pos,
}
)
# Draw the rightmost vertical line for the row
msp.add_line((col_x_coords[-1], row_y_top), (col_x_coords[-1], row_y_bottom))
# Move to the next row position by creating a new Vec3 object
current_pos = Vec3(current_pos.x, row_y_bottom)
# Draw the final bottom line of the table
msp.add_line((start_pos.x, current_pos.y), (col_x_coords[-1], current_pos.y))
# ==============================================================================
# 4. MAIN EXECUTION
# ==============================================================================
def main():
source_dxf_path = r"C:\Users\83500\久翌\CAD编辑同步excel\测试文件区\04_Test_Files\料表.dxf"
output_dxf_path = os.path.join(os.path.dirname(source_dxf_path), "料表_with_inserted_tables.dxf")
try:
doc = ezdxf.readfile(source_dxf_path)
msp = doc.modelspace()
except IOError:
print(f"Could not read DXF file: {source_dxf_path}")
return
except ezdxf.DXFStructureError:
print(f"Invalid or corrupted DXF file: {source_dxf_path}")
return
# --- Define where to start drawing the new tables ---
# We will use a fixed starting position below the existing content.
start_y = 150.0
start_x_1 = 266.0 # Aligns with the first table
start_x_2 = 700.0 # Place second table to the right
# --- Draw the first table ---
print("Drawing Table 1...")
table1_start_pos = Vec3(start_x_1, start_y)
# Combine header and data for drawing
# For this demo, we will create a small table with 2 data rows and a header
full_table_1_data = TABLE_1_DATA + TABLE_2_HEADER_DATA
draw_table(msp, table1_start_pos, TABLE_1_COL_WIDTHS, full_table_1_data)
# --- Draw the second table ---
print("Drawing Table 2...")
table2_start_pos = Vec3(start_x_2, start_y)
# Draw the same table again for demonstration
draw_table(msp, table2_start_pos, TABLE_1_COL_WIDTHS, full_table_1_data)
# --- Save the modified DXF ---
try:
doc.saveas(output_dxf_path)
print(f"Successfully saved modified DXF to: {output_dxf_path}")
except IOError:
print(f"Could not save DXF file to: {output_dxf_path}")
if __name__ == "__main__":
main()