import win32com.client
import pythoncom
import tkinter as tk
from tkinter import messagebox
import numpy
import math
'''打开选择文件夹对话框'''
window = tk.Tk()
window.title("权属面积批量修改0.1")
window.geometry('380x30+800+200') # 290 160为窗口大小,+1000 +10 定义窗口弹出时的默认展示位置
window.resizable(0, 0)
window['background'] = 'DimGray'
def vtpnt(x, y, z=0):
"""坐标点转化为浮点数"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, (x, y, z))
def vtobj(obj):
"""转化为对象数组"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_DISPATCH, obj)
def vtFloat(list):
"""列表转化为浮点数"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, list)
def vtInt(list):
"""列表转化为整数"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_I2, list)
def vtVariant(list):
"""列表转化为变体"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_VARIANT, list)
def list_format_conversion(old_list, leixing=False, step=2, deduction=None):
if leixing is False:
leixing = list
else:
leixing = tuple
new_list = []
for counte in range(0, len(old_list), step):
new_list.append(leixing(old_list[counte:counte + step])[:deduction])
return new_list
'''
进位,返回str
'''
def rrd(point, f):
if f == 0:
point = str(int(point))
elif f > 0:
SP = str(numpy.around(point, f))
sy = SP.split(".")
n = len(sy[1])
if n < f:
sj = f - n
point = sy[0] + "." + sy[1] + "0" * sj
else:
point = SP
elif f < 0:
tk.messagebox.showinfo('提示', "取位不可为负")
return point
'''
计算顺时针或逆时针
green方法判断面积正负
'''
def polyline_order(P):
n = len(P)
P.append(P[0])
S = 0
for i in range(0, n):
S = S + (P[i][0] + P[i + 1][0]) * (P[i + 1][1] - P[i][1])
if S > 0:
return False # 逆时针
else:
return True # 顺时针
def compute_polygon_area(points):
point_num = len(points)
if (point_num < 3): return 0.0
s = points[0][1] * (points[point_num - 1][0] - points[1][0])
# for i in range(point_num): # (int i = 1 i < point_num ++i):
for i in range(1, point_num): # 有小伙伴发现一个bug,这里做了修改,但是没有测试,需要使用的亲请测试下,以免结果不正确。
s += points[i][1] * (points[i - 1][0] - points[(i + 1) % point_num][0])
return numpy.around(abs(s / 2.0), 4)
'''
计算方位角
'''
def cross_point(line1, line2): # 计算交点函数
x1 = line1[0] # 取四点坐标
y1 = line1[1]
x2 = line1[2]
y2 = line1[3]
x3 = line2[0]
y3 = line2[1]
x4 = line2[2]
y4 = line2[3]
k1 = (y2 - y1) * 1.0 / (x2 - x1) # 计算k1,由于点均为整数,需要进行浮点数转化
b1 = y1 * 1.0 - x1 * k1 * 1.0 # 整型转浮点型是关键
if (x4 - x3) == 0: # L2直线斜率不存在操作
k2 = None
b2 = 0
else:
k2 = (y4 - y3) * 1.0 / (x4 - x3) # 斜率存在操作
b2 = y3 * 1.0 - x3 * k2 * 1.0
if k2 == None:
x = x3
else:
x = (b2 - b1) * 1.0 / (k1 - k2)
y = k1 * x * 1.0 + b1 * 1.0
return [x, y]
def azimuth(x1, y1, x2, y2):
angle = 0
dx = x2 - x1
dy = y2 - y1
if dx == 0 and dy > 0: # 判断象限
angle = 0
if dx == 0 and dy < 0:
angle = 180
if dy == 0 and dx > 0:
angle = 90
if dy == 0 and dx < 0:
angle = 270
if dx > 0 and dy > 0:
angle = math.atan(dx / dy) * 180 / math.pi
elif dx < 0 and dy > 0:
angle = 360 + math.atan(dx / dy) * 180 / math.pi
elif dx < 0 and dy < 0:
angle = 180 + math.atan(dx / dy) * 180 / math.pi
elif dx > 0 and dy < 0:
angle = 180 + math.atan(dx / dy) * 180 / math.pi
angle = 90 - angle
angle = math.radians(angle)
return angle # j
'''
计算西北角
'''
def distance(point, poly):
d = {}
min_d = []
azimuth_2 = {}
for Endpoint in poly:
distance_list = math.sqrt((Endpoint[0] - point[0]) ** 2 + (Endpoint[1] - point[1]) ** 2)
d.update({tuple(Endpoint): distance_list})
for key, val in d.items():
if val == min(d.values()):
min_d.append(key)
if len(min_d) > 1:
for x, y in min_d:
angle = azimuth(x, y, point[0], point[1])
azimuth_2.update({(x, y): angle})
min_point = max(azimuth_2, key=azimuth_2.get)
return min_point
elif len(min_d) == 1:
min_point = min_d[0]
return min_point
'''
重画西北角
'''
def Select_element():
global acad, doc, mp, original_area
acad = win32com.client.Dispatch("AutoCAD.Application")
doc = acad.ActiveDocument
doc.Utility.Prompt("\n醉后不知天在水\n满船清梦压星河\n")
mp = doc.ModelSpace # 模型空间
tk.messagebox.showinfo('提示', "请在屏幕拾取图元,以Enter键结束")
try:
doc.SelectionSets.Item("SS1").Delete()
except:
tk.messagebox.showinfo('警告', "Delete selection failed")
slt = doc.SelectionSets.Add("SS1")
slt.SelectOnScreen()
mmm = float(text1_var.get())
for x in slt:
if x.ObjectName == "AcDbPolyline":
original_area = x.Area # 面积
old_coord = list_format_conversion(x.Coordinates, leixing=True)
new_coord = tuple({}.fromkeys(old_coord).keys()) # 剔除重复点
list4 = []
for ier in old_coord:
if ier not in list4:
list4.append(ier)
else:
center, radius = vtpnt(ier[0], ier[1], 0), 2
cenobj = acad.ActiveDocument.Layers.Add("01重复点")
acad.ActiveDocument.ActiveLayer = cenobj
ClrNum = 2
cenobj.color = ClrNum
mp.AddCircle(center, radius)
Polyline_coordinates = [list(x) for x in new_coord] # 改变坐标格式【【1,2】,【4,3】,【6,7】】
if not polyline_order(Polyline_coordinates): # 若逆时针,反转列表
Polyline_coordinates.reverse()
poly_x = [x[0] for x in Polyline_coordinates]
poly_y = [y[1] for y in Polyline_coordinates]
max_y = max(poly_y)
min_x = min(poly_x)
northwest_point = [min_x, max_y] # 矩形框西北角
northwest_point_end_point_distance = distance(northwest_point, Polyline_coordinates) # 图斑最靠近图框西北角的坐标
count = Polyline_coordinates.index(list(northwest_point_end_point_distance)) # 查找在列表中的位置
Polyline_coordinates = Polyline_coordinates[:-1]
for _ in range(0, count):
delete = Polyline_coordinates.pop(0)
Polyline_coordinates.append(delete)
XY1 = Polyline_coordinates[0]
XY2 = Polyline_coordinates[1]
XY3 = Polyline_coordinates[2]
XY4 = Polyline_coordinates[3]
angle = azimuth(XY4[0], XY4[1], XY1[0], XY1[1]) # 角度
angle2 = azimuth(XY3[0], XY3[1], XY2[0], XY2[1]) # 角度
angle3 = azimuth(XY4[0], XY4[1], XY3[0], XY3[1]) # 角度
angle4 = math.radians(180) + (angle3 - angle) - math.radians(90)
area = mmm - original_area # 面积差值
d1 = math.sqrt((XY3[0] - XY4[0]) ** 2 + (XY3[1] - XY4[1]) ** 2) # 1,2 点距离
d5 = math.sqrt((XY2[0] - XY1[0]) ** 2 + (XY2[1] - XY1[1]) ** 2) # 1,2 点距离
d2 = (area * 2) / (d1 + d5) # 延长距离
d3 = d2 / math.cos(angle4)
xMargin1 = XY4[0] - math.cos(angle) * d3
yMargin1 = XY4[1] - math.sin(angle) * d3
xMargin2 = xMargin1 + math.cos(angle3) * d1
yMargin2 = yMargin1 + math.sin(angle3) * d1
line1 = [xMargin1, yMargin1, xMargin2, yMargin2]
line2 = XY2 + XY3
dSanDian = cross_point(line1, line2)
Polyline_coordinates[3] = [xMargin1, yMargin1]
Polyline_coordinates[2] = [dSanDian[0], dSanDian[1]]
ff = compute_polygon_area(Polyline_coordinates) - mmm
if ff > 0.0:
while True:
d3 = d3 - 0.000001
xMargin3 = XY4[0] - math.cos(angle) * (d3)
yMargin3 = XY4[1] - math.sin(angle) * (d3)
xMargin4 = xMargin3 + math.cos(angle3) * d1
yMargin4 = yMargin3 + math.sin(angle3) * d1
line1 = [xMargin3, yMargin3, xMargin4, yMargin4]
line2 = XY2 + XY3
dSanDian = cross_point(line1, line2)
Polyline_coordinates[3] = [xMargin3, yMargin3]
Polyline_coordinates[2] = [dSanDian[0], dSanDian[1]]
sd = compute_polygon_area(Polyline_coordinates)
if (mmm - 0.00004) <= sd <= (mmm + 0.00004):
break
elif ff < 0.0:
while True:
d3 = d3 + 0.000001
xMargin3 = XY4[0] - math.cos(angle) * d3
yMargin3 = XY4[1] - math.sin(angle) * d3
xMargin4 = xMargin3 + math.cos(angle3) * d1
yMargin4 = yMargin3 + math.sin(angle3) * d1
line1 = [xMargin3, yMargin3, xMargin4, yMargin4]
line2 = XY2 + XY3
dSanDian = cross_point(line1, line2)
Polyline_coordinates[3] = [xMargin3, yMargin3]
Polyline_coordinates[2] = [dSanDian[0], dSanDian[1]]
v = compute_polygon_area(Polyline_coordinates)
if (mmm - 0.00004) <= v <= (mmm + 0.00004):
break
else:
pass
Polyline_coordinates = numpy.array([m for n in Polyline_coordinates for m in n], dtype=numpy.float)
points = vtFloat(Polyline_coordinates)
# 设定图层
layerobj = acad.ActiveDocument.Layers.Add("02调整后面积图层")
acad.ActiveDocument.ActiveLayer = layerobj
# 多段线颜色
ClrNum = 1
layerobj.color = ClrNum
polylineobj = mp.AddLightweightPolyline(points)
polylineobj.Closed = True
messagebox.showinfo("tip","完成。")
lable1 = tk.Label(window, text="[面积替换:平方米]", width=15).grid(row=0, column=0)
text1_var = tk.StringVar() # 获取text_1输入的值
text1_var.set(r'400')
text1 = tk.Entry(window, textvariable=text1_var, bd=5).grid(row=0, column=1)
tk.Button(window, text="开始", width=15, height=1, command=Select_element, bg="Silver").grid(row=0, column=2)
window.mainloop()