基于python的CAD等高线绘制
这是我本科在做《路基工程课程设计》挡土墙设计的时候,老师只给了原始地面数据点,因为疫情在家时间充裕,我就摸索了python画CAD,最终实现了绘制不同等高距的等高线绘制。 python面向对象编程。
基础知识
我这个代码只适合地面趋势简单的,通过差值得到固定整数高程点,然后将相同高程点依次连接。
note:
- 当时是在windows先写的代码,因为要用到win32com.client这个库,所以我估计 Mac下应该用不了,但可以修改代码绘制dxf文件,不调用CAD。
- 后续我再补充 Excel文件、输出CAD的文件及效果图
源代码
# _*_ coding:utf-8- _*_
from pyautocad import APoint, Autocad, aDouble
import win32com.client
import numpy as np
dgj = 0.5 # 等高距
ctfs = 10 # 放大倍数,本身采取m为单位绘制,可能放大10倍后输出效果好些
"""
等高线计算
"""
#连接excel读取数据,这个地方可以做一个前处理,直接把excel数据作为数组或者numpy数组进行处理
xlapp = win32com.client.Dispatch("Excel.Application")
wb = xlapp.ActiveWorkbook
ws = xlapp.ActiveWorkbook.ActiveSheet
"""
K58+70向右走为前进方向,绘制在
"""
"""
First
定义一个类,输入 list,其元素为APoint
内部函数得到插值的数据点,打印点数据
"""
class nei_cha:
def __init__(self, pnts = [APoint(0,1)], dgj = 0.5, gu_ding_cha_zhi = "X" ):
# gu_ding_cz = "X" 意思是不进行固定插值操作
self.pnts = pnts
self.dgj = dgj
self.gu_ding_cha_zhi = gu_ding_cha_zhi
# 输入两个三维坐标,x/y是相等的,内插得到所需高程
# 返回的是,该区间内得到的点组成的list
def do_two_points(self, p1 = APoint(0), p2 = APoint(0)):
if self.gu_ding_cha_zhi == "X":
nmax = int(max(p1.z, p2.z) // self.dgj)
nmin = int(min(p1.z, p2.z) // self.dgj)
if nmax == nmin: # 这两个点之间内插不出来
return 0
else:
nmax = self.gu_ding_cha_zhi
nmin = self.gu_ding_cha_zhi - 1
if (p1.z - nmax) * (p2.z - nmin) > 0: # 固定插值不在区间内
return 0
if p1.x == p2.x: # x坐标一样,需要内插Z到y
"""
求直线方程,y
"""
k = (p1.y - p2.y)/(p1.z - p2.z)
b = p1.y - k * p1.z
if self.gu_ding_cha_zhi == "X":
ni = np.array(range(nmin, nmax)).reshape(int(nmax - nmin), 1)
zi = (ni + 1) * self.dgj
else:
ni = np.array([self.gu_ding_cha_zhi]).reshape(int(nmax - nmin), 1)
zi = ni
yi = np.around(k * zi + b, 3)
#yi = np.interp(zi, [p1.z, p2.z], [p1.y, p2.y])
xi = np.full((len(yi), 1), p1.x)
pts_np = np.hstack((xi, yi, zi))
return pts_np
else: # y坐标一样,需要内插Z得到x
return 0
def do_it(self):
pnts_np = np.array([])
for i in range(len(self.pnts) - 1):
p_np_i = self.do_two_points(self.pnts[i], self.pnts[i+1])
if type(p_np_i) != type(0):
try:
pnts_np = np.vstack((pnts_np, p_np_i))
except:
pnts_np = p_np_i
if len(pnts_np) != len(np.array([])):
return pnts_np
else:
return 0
# points是原始地面点高程
ground_points = []
row = 2
while row <= 20:
i = 6 # 左侧数据
j = 8 # 右侧数据
# 桩号点绘图坐标
x0 = ((row - 2) / 3) * 10 + 70
y0 = 0
z0 = ws.cells(row, 7).value
p0 = APoint(x0, y0, z0)
pts = []
pts.append(p0)
# 拾取左侧点数据
while i >= 1:
try:
z_ = ws.cells(row, i).value
y_ = ws.cells(row + 1, i).value
pti = pts[-1] + (0, y_, z_)
pts.append(pti)
except:
pass
i -= 1
# 拾取右侧点数据
while ws.cells(row, j).value:
try:
z_ = ws.cells(row, j).value
y_ = - ws.cells(row + 1, j).value
ptj = pts[0] + (0, y_, z_)
pts.insert(0, ptj)
except:
print("右侧点拾取失败了:cells(%d,%d)"% (row, j))
pass
j += 1
ground_points.append(pts)
for i in pts:
print(i)
print("")
row = row + 3
# 利用上方点开始使用类进行,插值
all_np = []
for i in ground_points:
cha_zhi_la = nei_cha(i, dgj)
a = cha_zhi_la.do_it()
try:
all_np = np.vstack((all_np, a))
except:
all_np = a
pts_all = [APoint(list(i)) for i in all_np]
pts_all.sort(key = lambda x:x.z)
del all_np
h_min = pts_all[0].z
h_max = pts_all[-1].z
zzzi = h_min
sorted_pts = []
while zzzi <= h_max:
_ = [i for i in pts_all if i.z == zzzi]
_.sort(key = lambda x:x[0])
sorted_pts.append(_)
zzzi += dgj
del pts_all
for i in sorted_pts:
elevation = i[0].z
print("高程为 %s 的数据点"% elevation)
for l_ in i:
print(l_)
# 连接cad,并输出结果
del sorted_pts[0:11]
del sorted_pts[-10:-1]
acad = Autocad(create_if_not_exists=True)
acad.prompt("connect with the Autocad successfully.")
print("connect with the Autocad successfully.")
dwg = acad.ActiveDocument
# 定义等高线图层
dgx = acad.doc.layers.add("等高线")
dgx.LineWeight = 25
dwg.ActiveLayer = dgx
dgxbz = acad.doc.layers.add("等高线标注")
for m in range(len(sorted_pts)):
i = sorted_pts[m]
elevation = i[0].z
print("高程为 %s 的数据点"% elevation)
for l_ in i:
print(l_)
try:
for j in i:
j.z = 0
pt = aDouble([j for _ in i for j in _ * ctfs])
hl = acad.model.AddPolyLine(pt)
hl.LineWeight = 25
hl.Elevation = elevation
hl.Thickness = 900
if m % 5 == 0:
hl.LineWeight = 100
hl.color = 1
text_string = elevation
insertpt = i[0] * ctfs
textobj = acad.model.addMtext(insertpt, 26, text_string)
textobj.Height = 8
textobj.BackgroundFill = True
textobj.color = 1
textobj.layer = "等高线标注"
except:
print('*' * 10, "高程为 %s 的数据点不足,跳过绘制此等高线"% elevation)
pass