Quantity Takeoff tools for data-savvy BIM rebels
Ahoy! Tired of manual takeoffs and spreadsheet gymnastics? QTO Buccaneer is your Python-powered toolkit for exploring, extracting, and calculating quantities from IFC models. Built for architects, engineers, and construction pros who know their way around Excel more than Python. If you've wrangled a spreadsheet before β you're already 80% there. The rest? This library will help you plunder it with ease.
- What This Is
- Designed for IFC, optimized for abstractBIM Data
- Quick Start
- Project Structure
- Dependencies
- Development Pipeline
- Contributing
A general-purpose Python library for calculating and managing quantity takeoffs from IFC models using open standards and open-source tools.
What QTO Buccaneer lets you do:
- Calculate project-wide metrics based on your own definition-
- Calculate metrics per room or space
- Benchmark different projects to spot trends and outlier-
- Export results to Excel and other report formats used by your team
- Create beautiful reports with plans, making information visible and manageable
- Define metric logic using a user-friendly YAML config file β no need to write code or click through complex software
- Enrich and clean up IFC files more easily than working directly with raw ifcopenshell
- Repair IFC Models based on rules
- Build up project specific workflows and apply the same rules consecutive to the models. E.g.
- For architectural competitions
- Benchmarking Portfolios
- Calculating costs in different project phases / times
- Doing design to cost
QTO Buccaneer is built for those who believe in owning their workflow.
You don't need paid services to sail these seas:
Everything you need to calculate metrics, enrich models, and create reports is included here β free, open-source, and ready for action.
Our compass points to open standards, hands-on knowledge, and giving you full control over your quantity takeoffs.
True pirates don't depend on kings.
They build their own ships β and borrow a map when it saves time.
While QTO Buccaneer is fully independent, some parts of the journey can be rough:
| Challenge | Fast Lane Solution |
|---|---|
| Getting clean, consistent architectural models is hard. | π abstractBIM templates provide clean IFC models with predictable naming, structure, and geometry. |
| Extracting structured geometry from IFC files is tedious and messy. | π abstractBIM IFC-to-JSON API delivers clean, structured model data ready for figures and floorplan visualizations. |
These fast lanes are optional.
You can always chart your own course β but when you want smoother sailing, they're ready for you.
- Convert any architectural BIM with Spaces into a consistent ifc with walls, slabs, ...
- Clean IFC models
- Consistent structure
- Predictable naming conventions
- Optimized for automation
π Try abstractBIM
Alternative: - Good modeling practice that provides consistent clean data.
- Transform raw IFC into clean structured JSON
- Quickly generate floorplans, element overviews, and spatial figures
- Skip the tedious IFC parsing setups
π Contact Simon Dilhas for access to the api
Alternative: - Set up your own, converter with IfcOpenshell Geom modul. - BlenderBIM -> dotBIM -> to expected Json format (converter will come)
Welcome aboard β and congrats on making it this far! Ten years ago, I was right where you are now. The black screens, the weird acronyms, the cryptic error messages β they all freaked me out too. It took time (and plenty of coffee) to feel at home with code. And honestly? I'm still learning new tricks every day.
That's exactly why I am the right pirate to guide you. I know the waters, I've hit the reefs β and I've mapped a path to help you sail around the fear and dive straight into the good stuff.
This tutorial is your first step into a world that's surprisingly rewarding β and not nearly as scary as it seems.
I believe in hands-on learning. That means you're gonna roll up your sleeves and set up your environment.
Check out this video for a quick start: Webinar
Head over to Google Colab β this will be your coding playground, no installations needed. It's like a Notebook in the cloud that can execute code and document transparently the steps you take.
*Pro Lingo Tip: These kind of Notebooks are called Jupyter notebooks
-
Click "Open Notebook".
-
Navigate to the GitHub tab.
-
Paste the following URL into the search bar:
-
The notebook will open.
Pro Lingo Tip: GitHub is like a pirate's cloud vault for code β it tracks changes, keeps everything versioned, and makes collaboration easy across your crew.
Once the notebook is open, you're in the captain's seat. You'll:
-
Get introduced to pandas β the data wrangler's version of Excel (but with more firepower).
-
Calculate quantity metrics using the general tools of panda.
-
Open a BIM model and use the built-in QTO Buccaneer shortcuts to speed up your takeoff workflow.
# Option 1: Clone and install locally
git clone https://github.com/simondilhas/qto-buccaneer.git
cd qto-buccaneer
pip install -r requirements.txt
# Option 2: Install directly from GitHub
pip install git+https://github.com/simondilhas/qto-buccaneer.gitFor developers who want to work on the codebase:
- Clone the repository:
git clone https://github.com/simondilhas/qto-buccaneer.git
cd qto-buccaneer- Create and activate a virtual environment:
# Create virtual environment
python -m venv .venv
# Activate it
# On Linux/Mac:
source .venv/bin/activate
# On Windows:
.venv\Scripts\activate- Install development dependencies:
# Upgrade pip and install build tools
pip install --upgrade pip setuptools wheel
# Install the package in development mode
pip install -e .
# Install development dependencies
pip install -r requirements_dev.txtNow you can:
- Import the package from anywhere in your code:
from qto_buccaneer import ... - Make changes to the code and see them reflected immediately
- Run tests and contribute to the project
Look bellow or in the folder examples for more detailed once or in the documentation:
https://simondilhas.github.io/qto_buccaneer/qto_buccaneer/index.html
from qto_buccaneer.metrics import calculate_all_metrics
import yaml
def main():
# Load config
with open("path/to/metrics_config.yaml", "r") as f:
config = yaml.safe_load(f)
# Calculate metrics
metrics_df = calculate_all_metrics(
config=config,
ifc_path="path/to/your/model.ifc"
)
# Save results
metrics_df.to_excel("results.xlsx")
if __name__ == "__main__":
main()import pandas as pd
from qto_buccaneer.enrich import enrich_ifc_with_df
def main():
# Load enrichment data
df_enrichment = pd.read_excel("path/to/enrichment_data.xlsx")
# Enrich IFC file
enriched_ifc_path = enrich_ifc_with_df(
ifc_file="path/to/your/model.ifc",
df_for_ifc_enrichment=df_enrichment,
key="LongName", # column name to match IFC elements
pset_name="Pset_Enrichment", # optional
file_postfix="_enriched", # optional
output_dir="path/to/output/directory" # optional
)
print(f"Created enriched IFC file: {enriched_ifc_path}")
if __name__ == "__main__":
main()from qto_buccaneer.preprocess_ifc import add_spatial_data_to_ifc
def main():
# Add spatial data to IFC
spatial_data_path = add_spatial_data_to_ifc(
ifc_file="path/to/your/model.ifc",
pset_name="Pset_SpatialData", # optional
ifc_entity="IfcSpace", # optional
output_dir="path/to/output/directory" # optional
)
print(f"Added spatial data: {spatial_data_path}")
if __name__ == "__main__":
main()from pathlib import Path
from qto_buccaneer.utils.config_loader import load_config
from qto_buccaneer.preprocess_ifc import add_spatial_data_to_ifc
from qto_buccaneer.enrich import enrich_ifc_with_df
from qto_buccaneer.metrics import calculate_all_metrics
from qto_buccaneer.reports import export_to_excel
import pandas as pd
def process_building(building_name: str, ifc_path: str, config_dir: str) -> None:
# Set up paths
building_dir = Path("buildings") / building_name
building_dir.mkdir(parents=True, exist_ok=True)
# Step 1: Add spatial data
spatial_data_path = add_spatial_data_to_ifc(
ifc_file=ifc_path,
output_dir=str(building_dir / "02_enriched_spatial_data")
)
# Step 2: Enrich with additional data
df_enrichment = pd.read_excel(Path(config_dir) / "enrichment_space_table.xlsx")
enriched_ifc_path = enrich_ifc_with_df(
ifc_file=spatial_data_path,
df_for_ifc_enrichment=df_enrichment,
output_dir=str(building_dir / "03_enriched_ifc")
)
# Step 3: Calculate metrics
metrics_config = load_config(Path(config_dir) / "metrics_config.yaml")
metrics_df = calculate_all_metrics(
config=metrics_config,
ifc_path=enriched_ifc_path
)
# Step 4: Export results
export_to_excel(
df=metrics_df,
output_dir=str(building_dir / "04_metrics"),
building_name=building_name
)
if __name__ == "__main__":
process_building(
building_name="MyBuilding",
ifc_path="path/to/model.ifc",
config_dir="path/to/config"
)from qto_buccaneer.reports import generate_metrics_report
from qto_buccaneer.plots import create_all_plots
def main():
# Create plots first
plots_path = create_all_plots(
geometry_dir="path/to/geometry_json",
properties_path="path/to/metadata.json",
config_path="path/to/plots_config.yaml",
output_dir="path/to/plots_output"
)
# Generate PDF report
generate_metrics_report(
metrics_df=metrics_df, # Your metrics DataFrame
building_name="MyBuilding",
plots_dir=plots_path,
output_dir="path/to/report_output",
template_path="path/to/report_template.html"
)
if __name__ == "__main__":
main()from qto_buccaneer.reports import create_project_comparison_df
import pandas as pd
def main():
# Load metrics from multiple projects
project_metrics = []
for project_path in ["project1.ifc", "project2.ifc", "project3.ifc"]:
metrics_df = calculate_all_metrics(
config=metrics_config,
ifc_path=project_path
)
metrics_df['file_name'] = project_path
project_metrics.append(metrics_df)
# Combine metrics
combined_df = pd.concat(project_metrics)
# Create comparison table
comparison_df = create_project_comparison_df(
df=combined_df,
metrics=["gross_floor_area", "net_floor_area", "window_area"] # optional
)
# Save comparison
comparison_df.to_excel("project_comparison.xlsx")
if __name__ == "__main__":
main()# workflow_config.yaml
buildings:
- name: "my_building"
repairs:
- name: "Fix space names"
filter: "type=IfcSpace AND LongName=TRH"
actions:
- change_value:
field: LongName
value: "Technical Room"
- name: "Update door names"
filter: "type=IfcDoor"
actions:
- change_value:
field: "Name"
value: "Standard Door"
- name: "Update property values"
filter: "type=IfcSpace"
actions:
- change_value:
field: "ePset_abstractBIM.Normal"
value: "90"from pathlib import Path
from qto_buccaneer.utils.config_loader import load_config
from qto_buccaneer.repairs import apply_repairs
def main():
# Load repair configuration
config = load_config("path/to/workflow_config.yaml")
# Apply repairs to IFC model
repaired_ifc_path = apply_repairs(
ifc_path_or_model="path/to/your/model.ifc",
config=config,
building_name="my_building",
output_dir="path/to/output/directory" # optional
)
print(f"Created repaired IFC file: {repaired_ifc_path}")
if __name__ == "__main__":
main()The repair system supports:
- Filtering elements by type and properties
- Changing direct attributes (like Name, LongName)
- Changing property set values (using dot notation: PsetName.PropertyName)
- Multiple repair rules per building
- Case-insensitive property matching
For more complex repairs, you can combine multiple actions in a single rule:
- name: "Complex space update"
filter: "type=IfcSpace AND IsExternal=true"
actions:
- change_value:
field: "ePset_abstractBIM.Normal"
value: "90"
- change_value:
field: "ePset_abstractBIM.IsExternal"
value: "true"
- change_value:
field: "Name"
value: "External Space"For more examples and detailed configuration options, check the configs/ directory in the repository.
When creating the library, I realized, that having all the singel tools available is nice, but true power comes when they are chained together.
for this I added the Project folder and workflow.
-
A Project is a collection of building the same rules apply to. So a building could be the same building in different phases, different buildings that need comparison / benchmarking, ... e.g. for cost benchmarking or architectural competitions.
-
So the workflow is:
- create a new project with 00_run_create_new_project.py (script that does this from the template structure)
- When configure the projects with a 00_workflow_config.yaml
- Specify which buildings are inside the project (either through the list, or by copying the ifc files in the folder all_models)
- Specify the folder names for each project, that should be created
project_name: "002_test_project__public"
project_description: "This is a test project to test the workflow"
buildings:
- name: "test_building_001"
building_folder:
- "00_original_input_data"
- "01_abstractbim_model"3. run the script 01_create_new_buildings.py to create the buildings
4. speify the workflow of which steps should be done in which order in the script 02_execute_workflows.py. E.g,
- first create abstractBIM
- enrich it with additional information
- calculate metrics and benchmarks
- calculate plots for visualizations
- crreate a pdf report
Pro Tip: To make your project private, so that it does not sync with github, add a __private to your folder name
Following this structured approach, you will build a pipline and truly benefit from structured data
qto-buccaneer/
βββ src/
β βββ qto_buccaneer/
β βββ configs/ # Configuration files
β βββ plots_utils/ # Plotting utilities
β βββ scripts/ # Utility scripts
β βββ utils/ # Utility functions
β βββ __init__.py # Package initialization
β βββ _version.py # Version information
β βββ enrich.py # IFC enrichment functionality
β βββ geometry.py # Geometry processing
β βββ metrics.py # Main metrics calculation interface
β βββ plots.py # Plotting functionality
β βββ preprocess_ifc.py # IFC preprocessing utilities
β βββ reports.py # Report generation
β βββ test.py # Test utilities
βββ projects/ # Project directories
β βββ 00_run_create_new_project.py # Project creation script
β βββ 002_example_project__public/ # Example project
β βββ __init__.py # Package marker
βββ templates/ # Template files
βββ tests/ # Test files
βββ tutorial/ # Tutorial materials
βββ docs/ # Documentation
βββ examples/ # Example scripts
βββ .github/ # GitHub configuration
βββ .vscode/ # VS Code configuration
βββ .env # Environment variables
βββ .env.example # Example environment variables
βββ .gitignore # Git ignore rules
βββ CONTRIBUTING.md # Contribution guidelines
βββ LICENSE.md # License information
βββ README.md # Project documentation
βββ add_building # Building addition script
βββ create_project # Project creation script
βββ pyproject.toml # Project configuration
βββ pytest.ini # Pytest configuration
βββ requirements.txt # Project dependencies
βββ requirements_dev.txt # Development dependencies
βββ setup.py # Package installation configuration
βββ setup_scripts.sh # Setup scriptsThis project relies on several key dependencies:
- IfcOpenShell: Open-source library for working with IFC files
- License: GNU Lesser General Public License v3.0
- Used for: IFC file parsing and geometric operations
pandas: Data manipulation and analysisnumpy: Numerical computationspyyaml: YAML configuration file handlingtyping: Type hints support
pytest: For running the test suiteblack: Code formattingmypy: Static type checkingsphinx: Documentation generation
- Python >= 3.8
- IfcOpenShell >= 0.7.0
You can install all required dependencies using:
pip install -r requirements.txtFor development dependencies:
pip install -r requirements-dev.txtNote: IfcOpenShell might require additional system-level dependencies depending on your operating system. Please refer to the IfcOpenShell installation guide for platform-specific instructions.
We're charting a course for more features! Here's what's on the horizon:
-
Refacturing for config pattern
- Tests$
- Documentation
- Bugfixes with metrics config
-
Data Enrichment & Classifications
- Adding support for various classification systems
- Enhanced data enrichment capabilities
- More sophisticated calculation rules
-
Predefined Visualization
- Ready-to-use graphs and charts
- Standard reporting templates
- Visual comparison tools
-
Multi-Project Analysis
- Compare quantities across projects
- Benchmark capabilities
- Portfolio-level insights
-
Real-World Testing
- Validation in live projects
- Performance optimization
- Edge case handling
-
Library Development
- Package distribution via PyPI
- Comprehensive documentation
- Extended API support
Want to help with any of these? Check out our Contributing section!
Ahoy fellow BIM pirates! We're excited about every form of contribution, whether it's:
- Ideas for new features
- Bug reports
- Code contributions
- Use cases we haven't thought of
- Or anything else you think could make this better
Let's figure it out together! Drop a line to simon.dilhas@abstract.build and let's make quantity takeoffs better for everyone.