UsmanGoraya's picture
Update app.py
ccd182c verified
import streamlit as st
import ezdxf
import tempfile
import pandas as pd
import os
# ---------- Function to extract data from DXF ----------
def extract_entities(uploaded_file):
with tempfile.NamedTemporaryFile(delete=False, suffix=".dxf") as tmp:
tmp.write(uploaded_file.read())
tmp_path = tmp.name
doc = ezdxf.readfile(tmp_path)
msp = doc.modelspace()
plan_data = {"rooms": [], "doors": [], "windows": []}
section_data = {"slabs": [], "beams": [], "columns": []}
for e in msp:
if e.dxftype() == "LWPOLYLINE" and "plan" in e.dxf.layer.lower():
points = e.get_points()
plan_data["rooms"].append({"points": points})
elif e.dxftype() == "LINE" and "door" in e.dxf.layer.lower():
plan_data["doors"].append({"start": e.dxf.start, "end": e.dxf.end})
elif e.dxftype() == "LINE" and "window" in e.dxf.layer.lower():
plan_data["windows"].append({"start": e.dxf.start, "end": e.dxf.end})
elif "section" in e.dxf.layer.lower():
if "slab" in e.dxf.layer.lower():
section_data["slabs"].append(e)
elif "beam" in e.dxf.layer.lower():
section_data["beams"].append(e)
elif "column" in e.dxf.layer.lower():
section_data["columns"].append(e)
return plan_data, section_data
# ---------- Function to estimate quantities ----------
def estimate_quantities(plan_data, section_data):
items = []
# Assumptions (typical values based on AU construction norms)
wall_height_ft = 10
wall_thickness_in = 9
brick_volume_in3 = 9 * 4.5 * 3
concrete_mix_ratio = {'cement': 1, 'sand': 1.5, 'crush': 3}
dry_volume_factor = 1.54
cement_bag_volume_cuft = 1.25 # 1 bag = 1.25 cuft of cement
# === 1. Brick masonry estimation ===
for room in plan_data["rooms"]:
points = room["points"]
if len(points) < 2:
continue
perimeter = 0
for i in range(len(points)):
x1, y1 = points[i][0:2]
x2, y2 = points[(i+1) % len(points)][0:2]
dist = ((x2 - x1)**2 + (y2 - y1)**2)**0.5
perimeter += dist
height_in = wall_height_ft * 12
wall_volume_in3 = perimeter * height_in * wall_thickness_in
wall_volume_cft = wall_volume_in3 / 1728
num_bricks = wall_volume_in3 / brick_volume_in3
items.append({
"Item": "Brick Masonry",
"Length": round(perimeter, 2),
"Width": wall_thickness_in,
"Height": height_in,
"Quantity": round(wall_volume_cft, 2),
"Unit": "CFT"
})
items.append({
"Item": "Bricks",
"Length": "-",
"Width": "-",
"Height": "-",
"Quantity": round(num_bricks),
"Unit": "No"
})
# === 2. Concrete works (slabs, beams, columns) ===
concrete_items = section_data["slabs"] + section_data["beams"] + section_data["columns"]
for component in concrete_items:
# Dummy default dimensions (can later be detected from DXF entities)
length = 12 # ft
width = 1 # ft
depth = 0.5 # ft
volume = length * width * depth
dry_volume = volume * dry_volume_factor
total_parts = sum(concrete_mix_ratio.values())
cement_cuft = dry_volume * (concrete_mix_ratio['cement'] / total_parts)
cement_bags = cement_cuft / cement_bag_volume_cuft
sand_cuft = dry_volume * (concrete_mix_ratio['sand'] / total_parts)
crush_cuft = dry_volume * (concrete_mix_ratio['crush'] / total_parts)
steel_kg = volume * 80 # approx 80 kg/m3 (AU rule of thumb)
items.append({
"Item": "Concrete",
"Length": length,
"Width": width,
"Height": depth,
"Quantity": round(volume, 2),
"Unit": "CFT"
})
items.append({
"Item": "Cement",
"Length": "-",
"Width": "-",
"Height": "-",
"Quantity": round(cement_bags, 1),
"Unit": "Bags"
})
items.append({
"Item": "Sand",
"Length": "-",
"Width": "-",
"Height": "-",
"Quantity": round(sand_cuft, 1),
"Unit": "CFT"
})
items.append({
"Item": "Crush",
"Length": "-",
"Width": "-",
"Height": "-",
"Quantity": round(crush_cuft, 1),
"Unit": "CFT"
})
items.append({
"Item": "Steel",
"Length": "-",
"Width": "-",
"Height": "-",
"Quantity": round(steel_kg, 1),
"Unit": "kg"
})
df = pd.DataFrame(items)
return df
# ---------- Streamlit App UI ----------
st.set_page_config(layout="centered")
st.title("🏗️ AutoCAD Drawing Estimator (AU Standards)")
uploaded_file = st.file_uploader("Upload AutoCAD DXF File", type=["dxf"])
if uploaded_file:
with st.spinner("Reading and analyzing the drawing..."):
try:
plan_data, section_data = extract_entities(uploaded_file)
df = estimate_quantities(plan_data, section_data)
st.success("✅ Drawing processed and estimate generated.")
st.dataframe(df)
output_path = "Construction_Estimate.xlsx"
df.to_excel(output_path, index=False)
with open(output_path, "rb") as f:
st.download_button("📥 Download Estimate (Excel)", f, file_name=output_path)
except Exception as e:
st.error(f"Error processing file: {e}")