ifc-qto-extraction
Extract quantities from IFC/Revit models for quantity takeoff. Uses DDC converters to get element counts, areas, volumes, lengths with grouping and reporting.
Install / Use
npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill ifc-qto-extractionInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
Development & EngineeringSupported Platforms
Our assessment of ifc-qto-extraction
ifc-qto-extraction scores 91/100 on our quality scale, 1202nd of 4,644 Development & Engineering skills we index (top 26%).
Its SKILL.md is 19 KB long, well organised into 22 sections with 7 code examples: a thorough specification that gives an agent plenty to work with.
It has 333 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 44 days ago, so ifc-qto-extraction is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
ifc-qto-extraction compared with similar skills
All 4 of these similar skills score higher than ifc-qto-extraction; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| ifc-qto-extraction (this skill)by datadrivenconstruction | 91 | 333 | 44d ago | SKILL.md |
| Agent-Reachby Panniantong | 100 | 91.2k | 19d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.4k | today | CLAUDE.md |
| ai-job-searchby MadsLorentzen | 100 | 45.0k | 1d ago | CLAUDE.md |
| claude-howtoby luongnv89 | 100 | 41.7k | 5d ago | CLAUDE.md |
Frequently asked questions
- How do I install ifc-qto-extraction?
- Run
npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill ifc-qto-extraction. The install tabs above show the steps for each supported agent. - Which AI agents does ifc-qto-extraction work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is ifc-qto-extraction safe to use?
- It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is ifc-qto-extraction still maintained?
- The repository was last updated 44 days ago, so ifc-qto-extraction is actively maintained.
Skill content
View source on GitHubname: "ifc-qto-extraction" description: "Extract quantities from IFC/Revit models for quantity takeoff. Uses DDC converters to get element counts, areas, volumes, lengths with grouping and reporting." homepage: "https://datadrivenconstruction.io" metadata: {"openclaw":{"emoji":"📐","os":["darwin","linux","win32"],"homepage":"https://datadrivenconstruction.io","requires":{"bins":["python3"],"anyBins":["IfcConvert","ifcopenshell"]}}}
IFC Quantity Takeoff Extraction
Extract structured quantity data from BIM models (IFC, Revit) for cost estimation, material ordering, and progress tracking.
Business Case
Problem: Manual quantity takeoff is:
- Time-consuming (40-80 hours for medium project)
- Error-prone (human counting mistakes)
- Not repeatable (changes require full rework)
- Disconnected from design (no live updates)
Solution: Automated QTO from BIM that:
- Extracts all quantities in minutes
- Groups by type, level, zone
- Updates instantly with model changes
- Exports to Excel for pricing
ROI: 90% reduction in QTO time, near-zero counting errors
DDC Tools Used
┌──────────────────────────────────────────────────────────────────────┐
│ QTO EXTRACTION PIPELINE │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ INPUT CONVERT ANALYZE │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ .rvt │ │ DDC │ │ Python │ │
│ │ .ifc │─────────►│Converter│───────────►│ pandas │ │
│ │ .dwg │ │ │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ │
│ │ .xlsx │ │ Grouped │ │
│ │ raw data│ │ QTO │ │
│ └─────────┘ └─────────┘ │
│ │ │
│ OUTPUT ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ QTO Report │ │
│ │ • Element counts by type │ │
│ │ • Areas (m², ft²) │ │
│ │ • Volumes (m³, ft³) │ │
│ │ • Lengths (m, ft) │ │
│ │ • Weights (kg, tons) │ │
│ │ • Grouped by level/zone/system │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
CLI Commands
Revit to Excel (with BBox for volumes)
# Basic extraction
RvtExporter.exe "C:\Models\Building.rvt"
# Full extraction with bounding boxes (for volume calculations)
RvtExporter.exe "C:\Models\Building.rvt" complete bbox
# Include schedules (Revit's built-in QTO)
RvtExporter.exe "C:\Models\Building.rvt" complete bbox schedule
IFC to Excel
# Extract IFC data
IfcExporter.exe "C:\Models\Building.ifc"
# Output: Building.xlsx with all IFC entities
DWG to Excel (2D areas)
# Extract DWG blocks and areas
DwgExporter.exe "C:\Drawings\FloorPlan.dwg"
Python Implementation
import pandas as pd
import numpy as np
from pathlib import Path
import subprocess
from typing import List, Dict, Optional
from dataclasses import dataclass
@dataclass
class QuantityItem:
"""Single quantity line item"""
category: str
type_name: str
count: int
area: float = 0.0
volume: float = 0.0
length: float = 0.0
weight: float = 0.0
unit_area: str = "m²"
unit_volume: str = "m³"
unit_length: str = "m"
level: str = ""
zone: str = ""
class BIMQuantityExtractor:
"""Extract quantities from BIM models using DDC converters"""
def __init__(self, converter_path: str):
self.converter_path = Path(converter_path)
def convert_model(self, model_path: str, options: List[str] = None) -> Path:
"""Convert BIM model to Excel"""
model = Path(model_path)
options = options or ["complete", "bbox"]
# Determine converter
ext = model.suffix.lower()
converters = {
'.rvt': 'RvtExporter.exe',
'.rfa': 'RvtExporter.exe',
'.ifc': 'IfcExporter.exe',
'.dwg': 'DwgExporter.exe',
'.dgn': 'DgnExporter.exe'
}
converter = self.converter_path / converters.get(ext, 'RvtExporter.exe')
# Build command
cmd = [str(converter), str(model)] + options
# Execute
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"Conversion failed: {result.stderr}")
# Return path to generated Excel
xlsx_path = model.with_suffix('.xlsx')
return xlsx_path
def load_bim_data(self, xlsx_path: str) -> pd.DataFrame:
"""Load converted BIM data from Excel"""
xlsx = Path(xlsx_path)
if not xlsx.exists():
raise FileNotFoundError(f"Excel file not found: {xlsx}")
# Read main data sheet
df = pd.read_excel(xlsx, sheet_name=0)
# Clean column names
df.columns = df.columns.str.strip()
return df
def extract_quantities(
self,
df: pd.DataFrame,
group_by: str = "Type Name",
include_categories: List[str] = None
) -> List[QuantityItem]:
"""Extract quantities grouped by type"""
# Filter categories if specified
if include_categories and 'Category' in df.columns:
df = df[df['Category'].isin(include_categories)]
# Group and aggregate
quantities = []
for (category, type_name), group in df.groupby(['Category', group_by]):
item = QuantityItem(
category=str(category),
type_name=str(type_name),
count=len(group)
)
# Extract area
area_cols = ['Area', 'Surface Area', 'Gross Area', 'Net Area']
for col in area_cols:
if col in group.columns:
item.area = group[col].sum()
break
# Extract volume
vol_cols = ['Volume', 'Gross Volume', 'Net Volume']
for col in vol_cols:
if col in group.columns:
item.volume = group[col].sum()
break
# Extract length
len_cols = ['Length', 'Curve Length', 'Unconnected Height']
for col in len_cols:
if col in group.columns:
item.length = group[col].sum()
break
# Extract level if available
if 'Level' in group.columns:
levels = group['Level'].dropna().unique()
item.level = ', '.join(str(l) for l in levels)
quantities.append(item)
return quantities
def extract_by_level(
self,
df: pd.DataFrame,
group_by: str = "Type Name"
) -> Dict[str, List[QuantityItem]]:
"""Extract quantities grouped by level"""
result = {}
if 'Level' not in df.columns:
result['All Levels'] = self.extract_quantities(df, group_by)
return result
for level, level_df in df.groupby('Level'):
level_name = str(level) if pd.notna(level) else 'Unassigned'
result[level_name] = self.extract_quantities(level_df, group_by)
return result
def calculate_concrete_quantities(self, df: pd.DataFrame) -> dict:
"""Calculate concrete quantities for typical elements"""
concrete_categories = [
'Floors', 'Structural Floors',
'Walls', 'Structural Walls',
'Structural Foundations', 'Foundation',
'Structural Columns', 'Columns',
'Structural Framing', 'Beams'
]
concrete_df = df[df['Category'].isin(concrete_categories)]
return {
'total_volume_m3': concrete_df['Volume'].sum() if 'Volume' in concrete_df.columns else 0,
'by_category': concrete_df.groupby('Category')['Volume'].sum().to_dict() if 'Volume' in concrete_df.columns else {},
'element_count': len(concrete_df)
}
def calculate_wall_quantities(self, df: pd.DataFrame) -> dict:
"""Calculate wall quantities"""
wall_categories = ['Walls', 'Basic Wall', 'Curtain Wall']
walls = df[df['Category'].isin(wall_categories)]
result = {
'total_area_m2': 0,
'total_length_m': 0,
'by_type': {}
}
if 'Area' in walls.columns:
result['total_area_m2'] = walls['Area'].sum()
if 'Length' in walls.columns:
result['total_length_m'] = walls['Length'].sum()
if 'Type Name' in walls.columns:
for type_name, group in walls.groupby('Type Name'):
result['by_type'][type_name] = {
'count': len(group),
'area': group['Area'].sum() if 'Area' in group.columns else 0,
'length': group['Length'].sum() if 'Length' in group.columns else 0
}
return result
def generate_qto_report(
self,
quantities: List[QuantityItem],
output_path: str,
project_name: str = "Project"
) -> str:
"""Generate QTO Excel report"""
# Convert to DataFrame
records = []
for q in quantities:
records.append({
'Category': q.category,
'Type': q.type_name,
'Count': q.count,
'Area (m²)': round(q.area, 2),
'Volume (m³)': round(q.volume, 3),
'Length (m)': round(q.length, 2),
'Level': q.level
})
df = pd.DataFrame(records)
# Sort by category and type
df = df.sort_values(['Category', 'Type'])
# Write to Excel with formatting
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
# Summary sheet
summary = df.groupby('Category').agg({
'Count': 'sum',
'Area (m²)': 'sum',
'Volume (m³)': 'sum',
'Length (m)': 'sum'
}).round(2)
summary.to_excel(writer, sheet_name='Summary')
# Detail sheet
df.to_excel(writer, sheet_name='Detail', index=False)
# By Level sheet
if 'Level' in df.columns and df['Level'].notna().any():
level_summary = df.groupby(['Level', 'Category']).agg({
'Count': 'sum',
'Area (m²)': 'sum',
'Volume (m³)': 'sum'
}).round(2)
level_summary.to_excel(writer, sheet_name='By Level')
return output_path
def generate_html_report(
self,
quantities: List[QuantityItem],
output_path: str,
project_name: str = "Project"
) -> str:
"""Generate interactive HTML QTO report"""
# Group by category
by_category = {}
for q in quantities:
if q.category not in by_category:
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
91.2kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
74.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
ai-job-search
45.0kThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.
claude-howto
41.7kA visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
