Python的ezdxf包操作dxf文件 获取属性 计算 长度,角度,面积,中心点

文章展示了如何使用Python的ezdxf库来读取和处理DXF文件中的各种图形实体,如线段(LINE)、轻型多边形线(LWPOLYLINE)、弧(ARC)和圆(CIRCLE)。通过计算线段长度、角度、弧长、面积等属性,以及对多边形进行炸开和重组,提供了详细的代码示例来解释这些操作。

Python的ezdxf包操作dxf文件 获取属性 计算 长度,角度,面积,中心点
pip install ezdxf==1.0.2 -i https://pypi.mirrors.ustc.edu.cn/simple/
代码如下:

import math
#from shapely.geometry import Polygon
import ezdxf

def get_line_length_angle(e):
    #return math.atan2(start[1]-end[1], start[0]-end[0])*180/math.pi
    start=e.dxf.start
    end=e.dxf.end
    l=ezdxf.math.distance(start,end)
    a= math.degrees(math.atan2(end[1]-start[1], end[0]-start[0]))
    x=(start[0]+end[0])/2
    y=(start[1]+end[1])/2
    line_mid=x,y
    return l,a if a>=0 else a+360,line_mid

# helper function
def print_entity_line(e):
    print(e.dxf.dxftype)
    print(e.dxf.all_existing_dxf_attribs())
    print("LINE on layer: %s\n" % e.dxf.layer)
    print("LINE on color: %s\n" % e.dxf.color)
    print("start point: %s\n" % e.dxf.start)
    print("end point: %s\n" % e.dxf.end)
    print("LINE on linetype: %s\n" % e.dxf.linetype)
    print("LINE on color: %s\n" % e.dxf.lineweight)
    print("LINE on lineweight: %s\n" % e.dxf.handle)
    #print("长度: %s\n" % math.dist(e.dxf.start, e.dxf.end))
    l,a,line_mid=get_line_length_angle(e)
    print("长度: %s\n" % l)
    print("角度: %s\n" % a)
    print(line_mid)
    
def print_entity_lwpolyline(e):
    print(e.dxf.dxftype)
    print(e.dxf.all_existing_dxf_attribs())
    print("LWPOLYLINE on layer: %s\n" % e.dxf.layer)
    print("LWPOLYLINE on color: %s\n" % e.dxf.color)
    print("LWPOLYLINE on linetype: %s\n" % e.dxf.linetype)
    print("LWPOLYLINE on lineweight: %s\n" % e.dxf.lineweight)
    mlength=[]
    #分解,炸开
    for i in e.explode():
        mlength.append(ezdxf.math.distance(i.dxf.start, i.dxf.end))
    with e.points('xy') as points:
        print(points)
    print("长度: %s\n" % sum(mlength))
    #print("面积: %s\n" % Polygon(points).area)
    print("面积: %s\n" % ezdxf.math.area(points))

def get_arc_length_area(e):
    end_a = e.dxf.end_angle
    start_a=e.dxf.start_angle
    r=e.dxf.radius
    #弧长l = A * np.pi * R / 180
    a=end_a+(360 if start_a>end_a else 0)-start_a
    l=a*r*math.pi/180
    #圆弧面积
    area=l*r/2
    #CAD圆弧面积=圆弧面积 加或减 三角面积
    arc_delta=ezdxf.math.area([e.start_point,e.end_point,e.dxf.center])
    cad_area=area - (arc_delta if end_a-start_a<180 else -1*arc_delta)
    #圆弧中点坐标
    x= e.dxf.center[0]+r*math.cos(math.radians(a/2+start_a));
    y= e.dxf.center[1]+r*math.sin(math.radians(a/2+start_a));
    arc_mid=x,y
    return l,area,cad_area,arc_mid

def print_entity_arc(e):
    print(e.dxf.dxftype)
    print(e.dxf.all_existing_dxf_attribs())
    print("ARC on layer: %s\n" % e.dxf.layer)
    print("ARC on color: %s\n" % e.dxf.color)
    print("ARC on color: %s\n" % e.dxf.linetype)
    print("ARC on color: %s\n" % e.dxf.lineweight)
    print("center point: %s\n" % e.dxf.center)
    print("ARC on radius: %s\n" % e.dxf.radius)
    print("ARC on start_angle: %s\n" % e.dxf.start_angle)
    print("ARC on end_angle: %s\n" % e.dxf.end_angle)
    l,area,cad_area,arc_mid=get_arc_length_area(e)
    print("弧长: %s\n" % l)
    print("圆弧面积: %s\n" % area)
    print("CAD计算圆弧面积: %s\n" % cad_area)
    print(arc_mid)

def print_entity_circle(e):
    print(e.dxf.dxftype)
    print(e.dxf.all_existing_dxf_attribs())
    print("CIRCLE on layer: %s\n" % e.dxf.layer)
    print("CIRCLE on color: %s\n" % e.dxf.color)
    print("CIRCLE on linetype: %s\n" % e.dxf.linetype)
    print("CIRCLE on lineweight: %s\n" % e.dxf.lineweight)
    print("center point: %s\n" % e.dxf.center)
    print("CIRCLE on radius: %s\n" % e.dxf.radius)
    print("圆的周长: %s\n" % str(math.pi*e.dxf.radius*2))
    print("圆的面积: %s\n" % str(math.pi*e.dxf.radius**2))
    #print(e.dxf.get('layer'))
    
def print_entity_polyline(e):
    print(e.dxf.dxftype)
    print(e.dxf.all_existing_dxf_attribs())
    print("POLYLINE on layer: %s\n" % e.dxf.layer)
    print("POLYLINE on color: %s\n" % e.dxf.color)
    print("POLYLINE on linetype: %s\n" % e.dxf.linetype)
    print("POLYLINE on lineweight: %s\n" % e.dxf.lineweight)
    points=[]
    for i in e.vertices:
        print(i.dxf.all_existing_dxf_attribs())
        points.append(i.dxf.location)
    mlength=[]
    arc_areas=[]
    #分解,炸开
    for i in e.explode():
        #print_entity_line(i)
        #points.append(i.dxf.start)
        #points.append(i.dxf.end)
        #print(i.dxftype)
        if i.dxftype()=="ARC":
            l,area,cad_area,m_mid=get_arc_length_area(i)
            mlength.append(l)
            arc_areas.append(cad_area)
        if i.dxftype()=="LINE":
            mlength.append(ezdxf.math.distance(i.dxf.start, i.dxf.end))
    
    print(points)
    print(mlength)
    print("长度: %s\n" % sum(mlength))
    #print("面积: %s\n" % Polygon(points).area)
    print("面积: %s\n" % str(ezdxf.math.area(points)+sum(arc_areas)))
    '''
    if e.is_poly_face_mesh:
        mesh = MeshBuilder.from_polyface(e)
        print(mesh.vertices)
        print(mesh.faces)

    '''
#读取 dxf 格式 r12
doc = ezdxf.readfile("sample.dxf")
# iterate over all entities in modelspace
msp = doc.modelspace()
'''
for e in msp:
    if e.dxftype() == "LINE":
        print_entity(e)
'''

# entity query for all LINE entities in modelspace
for e in msp.query("LINE"):
    print_entity_line(e)
    
for e in msp.query("LWPOLYLINE"):
    print_entity_lwpolyline(e)
    
for e in msp.query("ARC"):
    print_entity_arc(e)
    
for e in msp.query("CIRCLE"):
    print_entity_circle(e)
    
for e in msp.query("POLYLINE"):
    print_entity_polyline(e)

import cv2 import numpy as np import ezdxf from ezdxf.math import Vec2 import math import os def gray_to_dxf_fixed_line(input_image, output_dxf, line_length_um=70, line_width_um=5, grid_factor=0.2, max_angle_deg=180): """ 将灰度图像转换为带定向线段的DXF文件 固定线段长度和宽度,方向基于灰度值 参数: input_image: 输入图像路径 output_dxf: 输出DXF文件路径 line_length_um: 线段长度(微米) line_width_um: 线段宽度(微米) grid_factor: 网格尺寸相对于线段长度的比例(0-1) max_angle_deg: 最大旋转角度(度) """ # 读取灰度图像 if not os.path.exists(input_image): raise FileNotFoundError(f"输入图像不存在: {input_image}") gray_img = cv2.imread(input_image, cv2.IMREAD_GRAYSCALE) if gray_img is None: raise ValueError(f"无法读取图像: {input_image}") height, width = gray_img.shape print(f"图像尺寸: {width}×{height}像素") # 创建DXF文档 doc = ezdxf.new(dxfversion="R2010") msp = doc.modelspace() # 添加自定义图层和属性 lines_layer = doc.layers.add("FILL_LINES") lines_layer.color = 7 # 白色 lines_layer.lineweight = int(line_width_um * 100) # 1单位=0.01mm # 计算网格尺寸 grid_size = int(line_length_um * grid_factor) if grid_size < 1: grid_size = 1 print(f"网格尺寸: {grid_size}像素, 线段长度: {line_length_um}微米") # 角度转换 max_angle_rad = math.radians(max_angle_deg) # 遍历网格单元 line_count = 0 for y in range(0, height, grid_size): for x in range(0, width, grid_size): # 获取网格区域 y_end = min(y + grid_size, height) x_end = min(x + grid_size, width) if y_end - y <= 0 or x_end - x <= 0: continue # 计算网格平均灰度值 grid = gray_img[y:y_end, x:x_end] avg_gray = np.mean(grid) # 计算旋转角度 angle = (avg_gray / 255.0) * 2 * max_angle_rad - max_angle_rad # 计算线段中心点 (DXF坐标系y轴朝上) center_x = x + (x_end - x) / 2 center_y = height - (y + (y_end - y) / 2) # 翻转y轴 # 计算线段端点 half_length = line_length_um / 2 cos_angle = math.cos(angle) sin_angle = math.sin(angle) start_x = center_x - half_length * cos_angle start_y = center_y - half_length * sin_angle end_x = center_x + half_length * cos_angle end_y = center_y + half_length * sin_angle # 创建DXF线段并添加到图层 line = msp.add_line( start=(start_x, start_y), end=(end_x, end_y), dxfattribs={'layer': 'FILL_LINES'} ) line_count += 1 # 保存DXF文件 doc.saveas(output_dxf) print(f"生成成功: 创建{line_count}条线段, 输出文件: {output_dxf}") return True # 示例用法 if __name__ == "__main__": # 输入输出设置 input_image = "input.jpg" # 输入灰度图像路径 output_dxf = "line_fill.dxf" # 输出DXF文件路径 # 线段参数 (单位: 微米) line_length_um = 0.007 # 线段长度 line_width_um = 0.005 # 线段宽度 # 调用转换函数 gray_to_dxf_fixed_line( input_image=input_image, output_dxf=output_dxf, line_length_um=line_length_um, line_width_um=line_width_um, grid_factor=0.0001, # 网格尺寸比例 max_angle_deg=160 # 最大旋转角度 )这段代码生成的CAD图纸线条过于稀疏
06-10
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值