civil-tools-v 0.0.5__py3-none-any.whl → 0.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CivilTools/Const/Steel.py +3 -3
- CivilTools/FigureGenerator/BasicPNGPlotter.py +93 -5
- CivilTools/FigureGenerator/StairCalculationSheetPNGPlotter.py +595 -5
- CivilTools/FigureGenerator/__init__.py +1 -0
- CivilTools/ReportGenerator/DocPicture.py +5 -2
- CivilTools/ReportGenerator/StairCalculationReport.py +346 -52
- CivilTools/ReportGenerator/UtilFunctions.py +91 -0
- CivilTools/YDBLoader/BuildingDefine/StairPart/LoadDefine.py +15 -7
- CivilTools/YDBLoader/BuildingDefine/StairPart/StairComponent.py +8 -0
- CivilTools/YDBLoader/BuildingDefine/StairPart/StairPart.py +66 -6
- CivilTools/__init__.py +3 -1
- {civil_tools_v-0.0.5.dist-info → civil_tools_v-0.0.6.dist-info}/METADATA +1 -1
- {civil_tools_v-0.0.5.dist-info → civil_tools_v-0.0.6.dist-info}/RECORD +16 -16
- {civil_tools_v-0.0.5.dist-info → civil_tools_v-0.0.6.dist-info}/LICENSE +0 -0
- {civil_tools_v-0.0.5.dist-info → civil_tools_v-0.0.6.dist-info}/WHEEL +0 -0
- {civil_tools_v-0.0.5.dist-info → civil_tools_v-0.0.6.dist-info}/top_level.txt +0 -0
CivilTools/Const/Steel.py
CHANGED
@@ -11,10 +11,10 @@ class SteelLevel:
|
|
11
11
|
|
12
12
|
|
13
13
|
class Steel:
|
14
|
-
HRB300 = SteelLevel("HRB300",
|
14
|
+
HRB300 = SteelLevel("HRB300", 270, 2100000)
|
15
15
|
HRB355 = SteelLevel("HRB355", 300, 2000000)
|
16
|
-
HRB400 = SteelLevel("HRB400",
|
17
|
-
HRB500 = SteelLevel("HRB500",
|
16
|
+
HRB400 = SteelLevel("HRB400", 360, 2000000)
|
17
|
+
HRB500 = SteelLevel("HRB500", 435, 2000000)
|
18
18
|
Q235 = SteelLevel("Q235", 111, 2000000)
|
19
19
|
Q345 = SteelLevel("Q345", 111, 2000000)
|
20
20
|
Q355 = SteelLevel("Q355", 111, 2000000)
|
@@ -1,5 +1,42 @@
|
|
1
|
-
from PIL import Image, ImageDraw
|
1
|
+
from PIL import Image, ImageDraw, ImageFont
|
2
2
|
import warnings
|
3
|
+
import math
|
4
|
+
import io
|
5
|
+
|
6
|
+
|
7
|
+
def draw_rotated_text(
|
8
|
+
image, text, position, rotate, font, fill, x_offset=0, y_offset=0
|
9
|
+
):
|
10
|
+
# 创建临时透明图层
|
11
|
+
text_layer = Image.new("RGBA", image.size, (0, 0, 0, 0))
|
12
|
+
text_draw = ImageDraw.Draw(text_layer)
|
13
|
+
|
14
|
+
# 计算文字包围盒
|
15
|
+
bbox = text_draw.textbbox((0, 0), text, font=font)
|
16
|
+
text_width, text_height = bbox[2] - bbox[0], bbox[3] - bbox[1]
|
17
|
+
|
18
|
+
# 在临时图层中央绘制文字
|
19
|
+
text_draw.text(
|
20
|
+
(
|
21
|
+
(text_layer.width - text_width + x_offset) / 2,
|
22
|
+
(text_layer.height - text_height + y_offset) / 2,
|
23
|
+
),
|
24
|
+
text,
|
25
|
+
font=font,
|
26
|
+
fill=fill,
|
27
|
+
)
|
28
|
+
|
29
|
+
# 绕中心点旋转
|
30
|
+
rotated = text_layer.rotate(
|
31
|
+
rotate, center=(text_layer.width // 2, text_layer.height // 2), expand=True
|
32
|
+
)
|
33
|
+
|
34
|
+
# 计算最终粘贴位置
|
35
|
+
paste_x = position[0] - rotated.width // 2
|
36
|
+
paste_y = position[1] - rotated.height // 2
|
37
|
+
|
38
|
+
# 合并到原图
|
39
|
+
image.paste(rotated, (paste_x, paste_y), rotated)
|
3
40
|
|
4
41
|
|
5
42
|
class BasicPNGPlotter:
|
@@ -9,14 +46,33 @@ class BasicPNGPlotter:
|
|
9
46
|
self.image = Image.new("RGBA", (width, height), bg)
|
10
47
|
self.draw = ImageDraw.Draw(self.image)
|
11
48
|
|
12
|
-
def draw_horizental_line(self, s_x, s_y, length, color="black", line_width=
|
49
|
+
def draw_horizental_line(self, s_x, s_y, length, color="black", line_width=5):
|
13
50
|
"""画一段水平线,length为长度,正代表向右"""
|
14
51
|
self.draw_line(s_x, s_y, s_x + length, s_y, color, line_width)
|
15
52
|
|
16
|
-
def draw_vertical_line(self, s_x, s_y, length, color="black", line_width=
|
53
|
+
def draw_vertical_line(self, s_x, s_y, length, color="black", line_width=5):
|
17
54
|
"""画一段竖直线,length为长度,正代表向下"""
|
18
55
|
self.draw_line(s_x, s_y, s_x + length, s_y, color, line_width)
|
19
56
|
|
57
|
+
def draw_arc(self, start_x, start_y, width, height, start_degree, sweep_degree):
|
58
|
+
bbox = (
|
59
|
+
start_x,
|
60
|
+
start_y,
|
61
|
+
start_x + width,
|
62
|
+
start_y + height,
|
63
|
+
)
|
64
|
+
self.draw.arc(bbox, start_degree, sweep_degree, fill="black", width=5)
|
65
|
+
|
66
|
+
def draw_circle(self, start_x, start_y, diameter, line_width=5):
|
67
|
+
bbox = (
|
68
|
+
start_x,
|
69
|
+
start_y,
|
70
|
+
start_x + diameter,
|
71
|
+
start_y + diameter,
|
72
|
+
)
|
73
|
+
# 绘制圆(轮廓线)
|
74
|
+
self.draw.ellipse(bbox, outline="black", width=line_width)
|
75
|
+
|
20
76
|
def draw_rectangle(
|
21
77
|
self, s_x, s_y, rec_width, rec_height, color="black", line_width=2
|
22
78
|
):
|
@@ -26,19 +82,51 @@ class BasicPNGPlotter:
|
|
26
82
|
self.draw_vertical_line(s_x, s_y, rec_height, color, line_width)
|
27
83
|
self.draw_vertical_line(s_x + rec_width, s_y, rec_height, color, line_width)
|
28
84
|
|
29
|
-
def draw_line(self, s_x, s_y, e_x, e_y, color="black", width=
|
85
|
+
def draw_line(self, s_x, s_y, e_x, e_y, color="black", width=5):
|
30
86
|
if s_x < 0 or s_x > self.width or s_y < 0 or s_y > self.height:
|
31
87
|
warnings.warn("Start point is out of figure.")
|
32
88
|
if e_x < 0 or e_x > self.width or e_y < 0 or e_y > self.height:
|
33
89
|
warnings.warn("End point is out of figure.")
|
34
90
|
self.draw.line((s_x, s_y, e_x, e_y), fill=color, width=width)
|
35
91
|
|
92
|
+
def draw_text(
|
93
|
+
self,
|
94
|
+
x: int,
|
95
|
+
y: int,
|
96
|
+
text: str,
|
97
|
+
font_size: int,
|
98
|
+
degree: float,
|
99
|
+
x_offset: float = 0,
|
100
|
+
y_offset: float = 0,
|
101
|
+
):
|
102
|
+
font = ImageFont.truetype("simhei.ttf", font_size)
|
103
|
+
draw_rotated_text(
|
104
|
+
self.image,
|
105
|
+
text,
|
106
|
+
(x, y),
|
107
|
+
degree / math.pi * 180,
|
108
|
+
font,
|
109
|
+
"black",
|
110
|
+
x_offset,
|
111
|
+
y_offset,
|
112
|
+
)
|
113
|
+
|
36
114
|
def draw_png(self):
|
37
|
-
self.draw.line((0, 0, 500, 500), fill="black", width=
|
115
|
+
self.draw.line((0, 0, 500, 500), fill="black", width=5)
|
38
116
|
|
39
117
|
def save(self, path):
|
40
118
|
self.image.save(path, "PNG")
|
41
119
|
|
120
|
+
def to_stream(self):
|
121
|
+
# 将图片保存到内存中的 BytesIO 对象
|
122
|
+
img_buffer = io.BytesIO()
|
123
|
+
self.image.save(img_buffer, "PNG") # 保存为 PNG 格式
|
124
|
+
del self.image
|
125
|
+
del self.draw # 关闭图形,释放内存
|
126
|
+
# 将指针重置到流的开头,以便后续读取
|
127
|
+
img_buffer.seek(0)
|
128
|
+
return img_buffer
|
129
|
+
|
42
130
|
|
43
131
|
if __name__ == "__main__":
|
44
132
|
p = BasicPNGPlotter(1500, 800)
|