关于 bim-to-schedule-4d
用于将建筑信息模型与项目进度计划关联的 Python 技能,面向开展 4D BIM 协调的施工团队。
主要功能
- 01导入进度活动
- 02关联 BIM 构件与活动
适用场景
- 01按施工日期协调模型构件
- 02查看项目 4D 进度计划
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ datadrivenconstruction/ ddc_skills_for_ai_agents_in_construction --skill bim-to-schedule-4d安装后在 Claude Code 中输入/bim-to-schedule-4d确认已加载。
附带文件claw.jsoninstructions.md
README 原文English
来自项目 READMEREADME 暂无中文译文,以下为英文原文;中文介绍见上方。
BIM to Schedule 4D Integration
Technical Implementation
import pandas as pd
from datetime import date, timedelta
from typing import Dict, Any, List, Optional
from dataclasses import dataclass, field
from enum import Enum
class LinkStatus(Enum):
LINKED = "linked"
UNLINKED = "unlinked"
PARTIAL = "partial"
@dataclass
class ScheduleActivity:
activity_id: str
activity_name: str
start_date: date
end_date: date
duration_days: int
wbs_code: str
predecessors: List[str] = field(default_factory=list)
@dataclass
class BIMElement:
element_id: str
element_name: str
category: str
level: str
zone: str
volume: float = 0
area: float = 0
@dataclass
class BIMScheduleLink:
link_id: str
activity_id: str
element_ids: List[str]
link_type: str # install, remove, temporary
status: LinkStatus
class BIMSchedule4D:
def __init__(self, project_name: str):
self.project_name = project_name
self.activities: Dict[str, ScheduleActivity] = {}
self.elements: Dict[str, BIMElement] = {}
self.links: Dict[str, BIMScheduleLink] = {}
self._link_counter = 0
def import_schedule(self, schedule_data: List[Dict[str, Any]]):
for act in schedule_data:
activity = ScheduleActivity(
activity_id=act['id'],
activity_name=act['name'],
start_date=act['start'],
end_date=act['end'],
duration_days=(act['end'] - act['start']).days,
wbs_code=act.get('wbs', ''),
predecessors=act.get('predecessors', [])
)
self.activities[activity.activity_id] = activity
def import_elements(self, element_data: List[Dict[str, Any]]):
for elem in element_data:
element = BIMElement(
element_id=elem['id'],
element_name=elem['name'],
category=elem['category'],
level=elem.get('level', ''),
zone=elem.get('zone', ''),
volume=elem.get('volume', 0),
area=elem.get('area', 0)
)
self.elements[element.element_id] = element
def create_link(self, activity_id: str, element_ids: List[str],
link_type: str = "install") -> BIMScheduleLink:
if activity_id not in self.activities:
return None
self._link_counter += 1
link_id = f"LNK-{self._link_counter:05d}"
# Verify elements exist
valid_elements = [eid for eid in element_ids if eid in self.elements]
status = LinkStatus.LINKED if valid_elements else LinkStatus.UNLINKED
if valid_elements and len(valid_elements) < len(element_ids):
status = LinkStatus.PARTIAL
link = BIMScheduleLink(
link_id=link_id,
activity_id=activity_id,
element_ids=valid_elements,
link_type=link_type,
status=status
)
self.links[link_id] = link
return link
def auto_link_by_level(self, level: str, activity_id: str):
"""Auto-link all elements on a level to an activity."""
level_elements = [e.element_id for e in self.elements.values()
if e.level == level]
if level_elements:
return self.create_link(activity_id, level_elements)
return None
def get_elements_for_date(self, target_date: date) -> List[BIMElement]:
"""Get elements that should be visible on a specific date."""
visible_elements = []
for link in self.links.values():
activity = self.activities.get(link.activity_id)
if activity and activity.start_date <= target_date <= activity.end_date:
for elem_id in link.element_ids:
if elem_id in self.elements:
visible_elements.append(self.elements[elem_id])
return visible_elements
def get_unlinked_elements(self) -> List[BIMElement]:
linked_ids = set()
for link in self.links.values():
linked_ids.update(link.element_ids)
return [e for e in self.elements.values() if e.element_id not in linked_ids]
def get_unlinked_activities(self) -> List[ScheduleActivity]:
linked_activities = {link.activity_id for link in self.links.values()}
return [a for a in self.activities.values() if a.activity_id not in linked_activities]
def get_link_summary(self) -> Dict[str, Any]:
total_elements = len(self.elements)
linked_elements = len(set(
eid for link in self.links.values() for eid in link.element_ids
))
return {
'total_activities': len(self.activities),
'total_elements': total_elements,
'linked_elements': linked_elements,
'unlinked_elements': total_elements - linked_elements,
'total_links': len(self.links),
'link_coverage': round(linked_elements / total_elements * 100, 1) if total_elements > 0 else 0
}
def export_links(self, output_path: str):
data = []
for link in self.links.values():
activity = self.activities.get(link.activity_id)
data.append({
'Link ID': link.link_id,
'Activity': activity.activity_name if activity else '',
'Start': activity.start_date if activity else None,
'End': activity.end_date if activity else None,
'Elements': len(link.element_ids),
'Type': link.link_type,
'Status': link.status.value
})
pd.DataFrame(data).to_excel(output_path, index=False)
Quick Start
bim4d = BIMSchedule4D("Office Tower")
# Import schedule
bim4d.import_schedule([
{'id': 'A100', 'name': 'Foundation', 'start': date(2024, 1, 1), 'end': date(2024, 2, 28)},
{'id': 'A200', 'name': 'Structure L1', 'start': date(2024, 3, 1), 'end': date(2024, 4, 30)}
])
# Import elements
bim4d.import_elements([
{'id': 'E001', 'name': 'Footing F1', 'category': 'Foundation', 'level': 'Foundation'},
{'id': 'E002', 'name': 'Column C1', 'category': 'Structure', 'level': 'Level 1'}
])
# Create links
bim4d.create_link('A100', ['E001'])
bim4d.create_link('A200', ['E002'])
summary = bim4d.get_link_summary()
print(f"Link coverage: {summary['link_coverage']}%")
Resources
- DDC Book: Chapter 3.3 - 4D BIM
评论
支持 Markdown