Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -26,15 +26,10 @@ uploaded_file = st.file_uploader("Upload your DXF file", type=["dxf"])
|
|
| 26 |
@st.cache_data
|
| 27 |
def extract_geometry(file_bytes):
|
| 28 |
try:
|
| 29 |
-
|
| 30 |
-
doc = ezdxf.read(io.TextIOWrapper(file_bytes, encoding='utf-8', errors='ignore'))
|
| 31 |
except Exception as e:
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
doc = ezdxf.read(file_bytes)
|
| 35 |
-
except Exception as ex:
|
| 36 |
-
st.error(f"Error reading DXF file: {ex}")
|
| 37 |
-
return [], 0.75, [], [], []
|
| 38 |
|
| 39 |
msp = doc.modelspace()
|
| 40 |
rooms = []
|
|
@@ -43,7 +38,22 @@ def extract_geometry(file_bytes):
|
|
| 43 |
windows = []
|
| 44 |
wall_thickness = DEFAULT_WALL_THICKNESS
|
| 45 |
|
| 46 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
for entity in msp:
|
| 48 |
if entity.dxftype() == "TEXT":
|
| 49 |
content = entity.dxf.text.lower()
|
|
@@ -54,7 +64,7 @@ def extract_geometry(file_bytes):
|
|
| 54 |
continue
|
| 55 |
|
| 56 |
elif entity.dxftype() == "LWPOLYLINE":
|
| 57 |
-
# Check if it's a closed polyline representing a
|
| 58 |
if entity.closed:
|
| 59 |
points = entity.get_points()
|
| 60 |
x_vals = [p[0] for p in points]
|
|
@@ -72,7 +82,25 @@ def extract_geometry(file_bytes):
|
|
| 72 |
elif entity.dxf.layer.lower() == "windows":
|
| 73 |
windows.append(("window", entity.dxf.start.x, entity.dxf.start.y))
|
| 74 |
|
| 75 |
-
return rooms, wall_thickness, doors, windows, room_shapes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
|
| 78 |
# Estimation Function
|
|
@@ -100,6 +128,7 @@ def estimate(rooms, wall_thickness, doors, windows):
|
|
| 100 |
"Brick Volume (cft)": BRICK_VOLUME_CFT
|
| 101 |
}
|
| 102 |
|
|
|
|
| 103 |
# Function to Generate PDF with Estimation
|
| 104 |
def generate_pdf(data_dict, calc_details, room_shapes):
|
| 105 |
image_path = draw_plan_image(room_shapes)
|
|
@@ -143,6 +172,7 @@ def generate_pdf(data_dict, calc_details, room_shapes):
|
|
| 143 |
pdf.output(tmp.name)
|
| 144 |
return tmp.name
|
| 145 |
|
|
|
|
| 146 |
# Function to Draw Plan Image
|
| 147 |
def draw_plan_image(room_shapes):
|
| 148 |
fig, ax = plt.subplots()
|
|
@@ -164,7 +194,7 @@ def draw_plan_image(room_shapes):
|
|
| 164 |
# Streamlit logic to display results
|
| 165 |
if uploaded_file:
|
| 166 |
file_bytes = io.BytesIO(uploaded_file.read())
|
| 167 |
-
rooms, wall_thickness, doors, windows, room_shapes = extract_geometry(file_bytes)
|
| 168 |
|
| 169 |
st.success(f"✔️ Parsed {len(rooms)} rooms, {len(doors)} doors, and {len(windows)} windows.")
|
| 170 |
st.write(f"📏 Wall Thickness: {wall_thickness} ft")
|
|
@@ -191,4 +221,5 @@ if uploaded_file:
|
|
| 191 |
room_shapes
|
| 192 |
)
|
| 193 |
with open(pdf_file, "rb") as f:
|
| 194 |
-
st.download_button("Download Estimation
|
|
|
|
|
|
| 26 |
@st.cache_data
|
| 27 |
def extract_geometry(file_bytes):
|
| 28 |
try:
|
| 29 |
+
doc = ezdxf.read(io.BytesIO(file_bytes))
|
|
|
|
| 30 |
except Exception as e:
|
| 31 |
+
st.error(f"Error reading DXF file: {e}")
|
| 32 |
+
return [], 0.75, [], [], []
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
msp = doc.modelspace()
|
| 35 |
rooms = []
|
|
|
|
| 38 |
windows = []
|
| 39 |
wall_thickness = DEFAULT_WALL_THICKNESS
|
| 40 |
|
| 41 |
+
# Detecting walls (parallel lines that represent wall edges)
|
| 42 |
+
wall_lines = []
|
| 43 |
+
for entity in msp:
|
| 44 |
+
if entity.dxftype() == "LINE":
|
| 45 |
+
wall_lines.append(entity)
|
| 46 |
+
|
| 47 |
+
# Check for parallel lines representing a wall (detect double lines)
|
| 48 |
+
wall_pairs = []
|
| 49 |
+
for i, line1 in enumerate(wall_lines):
|
| 50 |
+
for line2 in wall_lines[i + 1:]:
|
| 51 |
+
if are_lines_parallel(line1, line2):
|
| 52 |
+
# Calculate the distance between the two parallel lines
|
| 53 |
+
wall_thickness = calculate_wall_thickness(line1, line2)
|
| 54 |
+
wall_pairs.append((line1, line2, wall_thickness))
|
| 55 |
+
|
| 56 |
+
# Process rooms, doors, and windows from entities
|
| 57 |
for entity in msp:
|
| 58 |
if entity.dxftype() == "TEXT":
|
| 59 |
content = entity.dxf.text.lower()
|
|
|
|
| 64 |
continue
|
| 65 |
|
| 66 |
elif entity.dxftype() == "LWPOLYLINE":
|
| 67 |
+
# Check if it's a closed polyline representing a room
|
| 68 |
if entity.closed:
|
| 69 |
points = entity.get_points()
|
| 70 |
x_vals = [p[0] for p in points]
|
|
|
|
| 82 |
elif entity.dxf.layer.lower() == "windows":
|
| 83 |
windows.append(("window", entity.dxf.start.x, entity.dxf.start.y))
|
| 84 |
|
| 85 |
+
return rooms, wall_thickness, doors, windows, room_shapes, wall_pairs
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
# Function to Check if Lines are Parallel
|
| 89 |
+
def are_lines_parallel(line1, line2):
|
| 90 |
+
dx1, dy1 = line1.dxf.end.x - line1.dxf.start.x, line1.dxf.end.y - line1.dxf.start.y
|
| 91 |
+
dx2, dy2 = line2.dxf.end.x - line2.dxf.start.x, line2.dxf.end.y - line2.dxf.start.y
|
| 92 |
+
# Check if the direction vectors are nearly parallel (with some tolerance)
|
| 93 |
+
tolerance = 0.1
|
| 94 |
+
return abs(dx1 * dy2 - dy1 * dx2) < tolerance
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
# Function to Calculate the Thickness Between Two Parallel Lines
|
| 98 |
+
def calculate_wall_thickness(line1, line2):
|
| 99 |
+
x1, y1 = line1.dxf.start.x, line1.dxf.start.y
|
| 100 |
+
x2, y2 = line2.dxf.start.x, line2.dxf.start.y
|
| 101 |
+
# Calculate distance between the two lines using the distance formula
|
| 102 |
+
distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
|
| 103 |
+
return distance / 12 # Convert to feet
|
| 104 |
|
| 105 |
|
| 106 |
# Estimation Function
|
|
|
|
| 128 |
"Brick Volume (cft)": BRICK_VOLUME_CFT
|
| 129 |
}
|
| 130 |
|
| 131 |
+
|
| 132 |
# Function to Generate PDF with Estimation
|
| 133 |
def generate_pdf(data_dict, calc_details, room_shapes):
|
| 134 |
image_path = draw_plan_image(room_shapes)
|
|
|
|
| 172 |
pdf.output(tmp.name)
|
| 173 |
return tmp.name
|
| 174 |
|
| 175 |
+
|
| 176 |
# Function to Draw Plan Image
|
| 177 |
def draw_plan_image(room_shapes):
|
| 178 |
fig, ax = plt.subplots()
|
|
|
|
| 194 |
# Streamlit logic to display results
|
| 195 |
if uploaded_file:
|
| 196 |
file_bytes = io.BytesIO(uploaded_file.read())
|
| 197 |
+
rooms, wall_thickness, doors, windows, room_shapes, wall_pairs = extract_geometry(file_bytes)
|
| 198 |
|
| 199 |
st.success(f"✔️ Parsed {len(rooms)} rooms, {len(doors)} doors, and {len(windows)} windows.")
|
| 200 |
st.write(f"📏 Wall Thickness: {wall_thickness} ft")
|
|
|
|
| 221 |
room_shapes
|
| 222 |
)
|
| 223 |
with open(pdf_file, "rb") as f:
|
| 224 |
+
st.download_button("Download Estimation PDF", f, file_name="estimation_report.pdf")
|
| 225 |
+
|