UsmanGoraya commited on
Commit
dccfa19
ยท
verified ยท
1 Parent(s): a35ff0e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -60
app.py CHANGED
@@ -1,18 +1,15 @@
1
  import streamlit as st
2
  import ezdxf
 
3
  import pandas as pd
4
  import os
5
 
 
6
  def extract_entities(uploaded_file):
7
- import ezdxf
8
- import tempfile
9
-
10
- # Save the uploaded file to a temporary file
11
  with tempfile.NamedTemporaryFile(delete=False, suffix=".dxf") as tmp:
12
  tmp.write(uploaded_file.read())
13
  tmp_path = tmp.name
14
 
15
- # Read using ezdxf.readfile (expects a path, and handles binary too)
16
  doc = ezdxf.readfile(tmp_path)
17
  msp = doc.modelspace()
18
 
@@ -20,7 +17,7 @@ def extract_entities(uploaded_file):
20
  section_data = {"slabs": [], "beams": [], "columns": []}
21
 
22
  for e in msp:
23
- if e.dxftype() == "LWPOLYLINE" and e.dxf.layer.lower() == "plan":
24
  points = e.get_points()
25
  plan_data["rooms"].append({"points": points})
26
  elif e.dxftype() == "LINE" and "door" in e.dxf.layer.lower():
@@ -37,72 +34,111 @@ def extract_entities(uploaded_file):
37
 
38
  return plan_data, section_data
39
 
 
 
 
40
 
41
- def calculate_quantities(plan_data, section_data):
42
- results = []
43
-
44
- # Sample calculation โ€” replace with real parsing logic
45
  for room in plan_data["rooms"]:
46
- length = 15
47
- width = 12
48
- height = 10
49
- volume = length * width * height
50
-
51
- opening_volume = len(plan_data["doors"]) * 21 + len(plan_data["windows"]) * 15
52
- net_volume = volume - opening_volume
53
- brick_volume = 9 * 4.5 * 3 / 1728 # in ftยณ
54
- num_bricks = int(net_volume / brick_volume)
55
-
56
- results.append({
57
- "Component": "Wall",
58
- "Length (ft)": length,
59
- "Width (ft)": 0.75,
60
- "Height (ft)": height,
61
- "Total Bricks": num_bricks,
62
- "Unit": "Bricks"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  })
64
 
 
65
  for slab in section_data["slabs"]:
66
- slab_volume = 20 * 10 * 0.5
67
- results.append({
68
- "Component": "Slab",
69
- "Length (ft)": 20,
70
- "Width (ft)": 10,
71
- "Depth (ft)": 0.5,
72
- "Volume (cu ft)": slab_volume,
73
- "Unit": "cu ft"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  })
75
 
76
- return pd.DataFrame(results)
77
-
78
- def save_to_excel(df):
79
- os.makedirs("output", exist_ok=True)
80
- output_path = os.path.join("output", "quantities.xlsx")
81
- df.to_excel(output_path, index=False)
82
- return output_path
83
 
84
- # Streamlit UI
85
- st.set_page_config(page_title="Construction Estimator", layout="wide")
86
- st.title("๐Ÿ—๏ธ Construction Material Estimator (Australian Standards)")
87
 
88
- uploaded_file = st.file_uploader("๐Ÿ“‚ Upload AutoCAD DXF File", type=["dxf"])
89
 
90
  if uploaded_file:
91
- st.info("โณ Processing DXF file...")
92
- plan_data, section_data = extract_entities(uploaded_file)
93
-
94
- st.success("โœ… DXF parsed successfully.")
95
-
96
- st.write("### ๐Ÿ“ Plan View Summary")
97
- st.json(plan_data)
98
 
99
- st.write("### ๐Ÿงฎ Estimating Materials...")
100
- result_df = calculate_quantities(plan_data, section_data)
101
 
102
- st.write("### ๐Ÿ“Š Final Quantities")
103
- st.dataframe(result_df)
104
 
105
- excel_path = save_to_excel(result_df)
 
106
 
107
- with open(excel_path, "rb") as f:
108
- st.download_button("๐Ÿ“ฅ Download Excel Report", f, "quantities.xlsx")
 
1
  import streamlit as st
2
  import ezdxf
3
+ import tempfile
4
  import pandas as pd
5
  import os
6
 
7
+ # ---------- Function to extract data from DXF ----------
8
  def extract_entities(uploaded_file):
 
 
 
 
9
  with tempfile.NamedTemporaryFile(delete=False, suffix=".dxf") as tmp:
10
  tmp.write(uploaded_file.read())
11
  tmp_path = tmp.name
12
 
 
13
  doc = ezdxf.readfile(tmp_path)
14
  msp = doc.modelspace()
15
 
 
17
  section_data = {"slabs": [], "beams": [], "columns": []}
18
 
19
  for e in msp:
20
+ if e.dxftype() == "LWPOLYLINE" and "plan" in e.dxf.layer.lower():
21
  points = e.get_points()
22
  plan_data["rooms"].append({"points": points})
23
  elif e.dxftype() == "LINE" and "door" in e.dxf.layer.lower():
 
34
 
35
  return plan_data, section_data
36
 
37
+ # ---------- Function to estimate quantities ----------
38
+ def estimate_quantities(plan_data, section_data):
39
+ items = []
40
 
41
+ # Room brickwork (assuming wall height 10 ft, thickness 9 in)
 
 
 
42
  for room in plan_data["rooms"]:
43
+ points = room["points"]
44
+ if len(points) < 2:
45
+ continue
46
+ perimeter = 0
47
+ for i in range(len(points)):
48
+ x1, y1 = points[i][0:2]
49
+ x2, y2 = points[(i+1) % len(points)][0:2]
50
+ dist = ((x2 - x1)**2 + (y2 - y1)**2)**0.5
51
+ perimeter += dist
52
+
53
+ # Convert from inches (assuming drawing in inches)
54
+ height = 10 * 12
55
+ thickness = 9
56
+ volume = perimeter * height * thickness # cubic inches
57
+ volume_cft = volume / 1728 # to cubic feet
58
+ bricks = volume / (9 * 4.5 * 3) # number of bricks
59
+
60
+ items.append({
61
+ "Item": "Brick Masonry (Room)",
62
+ "Length": round(perimeter, 2),
63
+ "Width": 9,
64
+ "Height": height,
65
+ "Quantity": round(volume_cft, 2),
66
+ "Unit": "CFT"
67
+ })
68
+ items.append({
69
+ "Item": "Bricks (Room)",
70
+ "Length": "-",
71
+ "Width": "-",
72
+ "Height": "-",
73
+ "Quantity": round(bricks, 0),
74
+ "Unit": "No"
75
  })
76
 
77
+ # Basic concrete estimation (dummy logic, assuming 1 slab = 12'x12'x6")
78
  for slab in section_data["slabs"]:
79
+ length = 12
80
+ width = 12
81
+ depth = 0.5
82
+ volume = length * width * depth
83
+ cement_bags = volume * 1.54 / 5.5 # assuming M20 mix
84
+ sand = volume * 1.54 * (1.5 / 5.5)
85
+ crush = volume * 1.54 * (3 / 5.5)
86
+
87
+ items.append({
88
+ "Item": "Concrete Slab",
89
+ "Length": length,
90
+ "Width": width,
91
+ "Height": depth,
92
+ "Quantity": round(volume, 2),
93
+ "Unit": "CFT"
94
+ })
95
+ items.append({
96
+ "Item": "Cement Bags (Slab)",
97
+ "Length": "-",
98
+ "Width": "-",
99
+ "Height": "-",
100
+ "Quantity": round(cement_bags, 1),
101
+ "Unit": "Bags"
102
+ })
103
+ items.append({
104
+ "Item": "Sand (Slab)",
105
+ "Length": "-",
106
+ "Width": "-",
107
+ "Height": "-",
108
+ "Quantity": round(sand, 1),
109
+ "Unit": "CFT"
110
+ })
111
+ items.append({
112
+ "Item": "Crush (Slab)",
113
+ "Length": "-",
114
+ "Width": "-",
115
+ "Height": "-",
116
+ "Quantity": round(crush, 1),
117
+ "Unit": "CFT"
118
  })
119
 
120
+ return pd.DataFrame(items)
 
 
 
 
 
 
121
 
122
+ # ---------- Streamlit App UI ----------
123
+ st.set_page_config(layout="centered")
124
+ st.title("๐Ÿ—๏ธ AutoCAD Drawing Estimator (AU Standards)")
125
 
126
+ uploaded_file = st.file_uploader("Upload AutoCAD DXF File", type=["dxf"])
127
 
128
  if uploaded_file:
129
+ with st.spinner("Reading and analyzing the drawing..."):
130
+ try:
131
+ plan_data, section_data = extract_entities(uploaded_file)
132
+ df = estimate_quantities(plan_data, section_data)
 
 
 
133
 
134
+ st.success("โœ… Drawing processed and estimate generated.")
135
+ st.dataframe(df)
136
 
137
+ output_path = "Construction_Estimate.xlsx"
138
+ df.to_excel(output_path, index=False)
139
 
140
+ with open(output_path, "rb") as f:
141
+ st.download_button("๐Ÿ“ฅ Download Estimate (Excel)", f, file_name=output_path)
142
 
143
+ except Exception as e:
144
+ st.error(f"Error processing file: {e}")