{
  "schemaVersion": "1.0",
  "item": {
    "slug": "ifc-to-excel",
    "name": "Ifc To Excel",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/datadrivenconstruction/ifc-to-excel",
    "canonicalUrl": "https://clawhub.ai/datadrivenconstruction/ifc-to-excel",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/ifc-to-excel",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=ifc-to-excel",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "claw.json",
      "instructions.md",
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/ifc-to-excel"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/ifc-to-excel",
    "agentPageUrl": "https://openagent3.xyz/skills/ifc-to-excel/agent",
    "manifestUrl": "https://openagent3.xyz/skills/ifc-to-excel/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/ifc-to-excel/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Problem Statement",
        "body": "IFC (Industry Foundation Classes) is the open BIM standard, but:\n\nReading IFC requires specialized software\nProperty extraction needs programming knowledge\nBatch processing is manual and time-consuming\nIntegration with analytics tools is complex"
      },
      {
        "title": "Solution",
        "body": "IfcExporter.exe converts IFC files to structured Excel databases, making BIM data accessible for analysis, validation, and reporting."
      },
      {
        "title": "Business Value",
        "body": "Open standard - Process any IFC file (2x3, 4x, 4.3)\nNo licenses - Works offline without BIM software\nData extraction - All properties, quantities, materials\n3D geometry - Export to Collada DAE format\nPipeline ready - Integrate with ETL workflows"
      },
      {
        "title": "CLI Syntax",
        "body": "IfcExporter.exe <input_ifc> [options]"
      },
      {
        "title": "Supported IFC Versions",
        "body": "VersionSchemaDescriptionIFC2x3MVDMost common exchange formatIFC4ADD1Enhanced propertiesIFC4x1AlignmentInfrastructure supportIFC4x3LatestFull infrastructure"
      },
      {
        "title": "Output Formats",
        "body": "OutputDescription.xlsxExcel database with elements and properties.daeCollada 3D geometry with matching IDs"
      },
      {
        "title": "Options",
        "body": "OptionDescriptionbboxInclude element bounding boxes-no-xlsxSkip Excel export-no-colladaSkip 3D geometry export"
      },
      {
        "title": "Examples",
        "body": "# Basic conversion (XLSX + DAE)\nIfcExporter.exe \"C:\\Models\\Building.ifc\"\n\n# With bounding boxes\nIfcExporter.exe \"C:\\Models\\Building.ifc\" bbox\n\n# Excel only (no 3D geometry)\nIfcExporter.exe \"C:\\Models\\Building.ifc\" -no-collada\n\n# Batch processing\nfor /R \"C:\\IFC_Models\" %f in (*.ifc) do IfcExporter.exe \"%f\" bbox"
      },
      {
        "title": "Python Integration",
        "body": "import subprocess\nimport pandas as pd\nfrom pathlib import Path\nfrom typing import List, Optional, Dict, Any, Set\nfrom dataclasses import dataclass, field\nfrom enum import Enum\nimport json\n\n\nclass IFCVersion(Enum):\n    \"\"\"IFC schema versions.\"\"\"\n    IFC2X3 = \"IFC2X3\"\n    IFC4 = \"IFC4\"\n    IFC4X1 = \"IFC4X1\"\n    IFC4X3 = \"IFC4X3\"\n\n\nclass IFCEntityType(Enum):\n    \"\"\"Common IFC entity types.\"\"\"\n    IFCWALL = \"IfcWall\"\n    IFCWALLSTANDARDCASE = \"IfcWallStandardCase\"\n    IFCSLAB = \"IfcSlab\"\n    IFCCOLUMN = \"IfcColumn\"\n    IFCBEAM = \"IfcBeam\"\n    IFCDOOR = \"IfcDoor\"\n    IFCWINDOW = \"IfcWindow\"\n    IFCROOF = \"IfcRoof\"\n    IFCSTAIR = \"IfcStair\"\n    IFCRAILING = \"IfcRailing\"\n    IFCFURNISHINGELEMENT = \"IfcFurnishingElement\"\n    IFCSPACE = \"IfcSpace\"\n    IFCBUILDINGSTOREY = \"IfcBuildingStorey\"\n    IFCBUILDING = \"IfcBuilding\"\n    IFCSITE = \"IfcSite\"\n\n\n@dataclass\nclass IFCElement:\n    \"\"\"Represents an IFC element.\"\"\"\n    global_id: str\n    ifc_type: str\n    name: str\n    description: Optional[str]\n    object_type: Optional[str]\n    level: Optional[str]\n\n    # Quantities\n    area: Optional[float] = None\n    volume: Optional[float] = None\n    length: Optional[float] = None\n    height: Optional[float] = None\n    width: Optional[float] = None\n\n    # Bounding box (if exported)\n    bbox_min_x: Optional[float] = None\n    bbox_min_y: Optional[float] = None\n    bbox_min_z: Optional[float] = None\n    bbox_max_x: Optional[float] = None\n    bbox_max_y: Optional[float] = None\n    bbox_max_z: Optional[float] = None\n\n    # Properties\n    properties: Dict[str, Any] = field(default_factory=dict)\n    materials: List[str] = field(default_factory=list)\n\n\n@dataclass\nclass IFCProperty:\n    \"\"\"Represents an IFC property.\"\"\"\n    pset_name: str\n    property_name: str\n    value: Any\n    value_type: str\n\n\n@dataclass\nclass IFCMaterial:\n    \"\"\"Represents an IFC material.\"\"\"\n    name: str\n    category: Optional[str]\n    thickness: Optional[float]\n    layer_position: Optional[int]\n\n\nclass IFCExporter:\n    \"\"\"IFC to Excel converter using DDC IfcExporter CLI.\"\"\"\n\n    def __init__(self, exporter_path: str = \"IfcExporter.exe\"):\n        self.exporter = Path(exporter_path)\n        if not self.exporter.exists():\n            raise FileNotFoundError(f\"IfcExporter not found: {exporter_path}\")\n\n    def convert(self, ifc_file: str,\n                include_bbox: bool = True,\n                export_xlsx: bool = True,\n                export_collada: bool = True) -> Path:\n        \"\"\"Convert IFC file to Excel.\"\"\"\n        ifc_path = Path(ifc_file)\n        if not ifc_path.exists():\n            raise FileNotFoundError(f\"IFC file not found: {ifc_file}\")\n\n        cmd = [str(self.exporter), str(ifc_path)]\n\n        if include_bbox:\n            cmd.append(\"bbox\")\n        if not export_xlsx:\n            cmd.append(\"-no-xlsx\")\n        if not export_collada:\n            cmd.append(\"-no-collada\")\n\n        result = subprocess.run(cmd, capture_output=True, text=True)\n\n        if result.returncode != 0:\n            raise RuntimeError(f\"Export failed: {result.stderr}\")\n\n        return ifc_path.with_suffix('.xlsx')\n\n    def batch_convert(self, folder: str,\n                      include_subfolders: bool = True,\n                      include_bbox: bool = True) -> List[Dict[str, Any]]:\n        \"\"\"Convert all IFC files in folder.\"\"\"\n        folder_path = Path(folder)\n        pattern = \"**/*.ifc\" if include_subfolders else \"*.ifc\"\n\n        results = []\n        for ifc_file in folder_path.glob(pattern):\n            try:\n                output = self.convert(str(ifc_file), include_bbox)\n                results.append({\n                    'input': str(ifc_file),\n                    'output': str(output),\n                    'status': 'success'\n                })\n                print(f\"✓ Converted: {ifc_file.name}\")\n            except Exception as e:\n                results.append({\n                    'input': str(ifc_file),\n                    'output': None,\n                    'status': 'failed',\n                    'error': str(e)\n                })\n                print(f\"✗ Failed: {ifc_file.name} - {e}\")\n\n        return results\n\n    def read_elements(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Read converted Excel as DataFrame.\"\"\"\n        return pd.read_excel(xlsx_file, sheet_name=\"Elements\")\n\n    def get_element_types(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get element type summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        if 'IfcType' not in df.columns:\n            raise ValueError(\"IfcType column not found\")\n\n        summary = df.groupby('IfcType').agg({\n            'GlobalId': 'count',\n            'Volume': 'sum' if 'Volume' in df.columns else 'count',\n            'Area': 'sum' if 'Area' in df.columns else 'count'\n        }).reset_index()\n\n        summary.columns = ['IFC_Type', 'Count', 'Total_Volume', 'Total_Area']\n        return summary.sort_values('Count', ascending=False)\n\n    def get_levels(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get building level summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        level_col = None\n        for col in ['Level', 'BuildingStorey', 'IfcBuildingStorey']:\n            if col in df.columns:\n                level_col = col\n                break\n\n        if level_col is None:\n            return pd.DataFrame(columns=['Level', 'Element_Count'])\n\n        summary = df.groupby(level_col).agg({\n            'GlobalId': 'count'\n        }).reset_index()\n        summary.columns = ['Level', 'Element_Count']\n        return summary\n\n    def get_materials(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get material summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        if 'Material' not in df.columns:\n            return pd.DataFrame(columns=['Material', 'Count'])\n\n        summary = df.groupby('Material').agg({\n            'GlobalId': 'count'\n        }).reset_index()\n        summary.columns = ['Material', 'Element_Count']\n        return summary.sort_values('Element_Count', ascending=False)\n\n    def get_quantities(self, xlsx_file: str,\n                       group_by: str = 'IfcType') -> pd.DataFrame:\n        \"\"\"Get quantity takeoff summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        if group_by not in df.columns:\n            raise ValueError(f\"Column {group_by} not found\")\n\n        agg_dict = {'GlobalId': 'count'}\n\n        # Add numeric columns for aggregation\n        numeric_cols = ['Volume', 'Area', 'Length', 'Width', 'Height']\n        for col in numeric_cols:\n            if col in df.columns:\n                agg_dict[col] = 'sum'\n\n        summary = df.groupby(group_by).agg(agg_dict).reset_index()\n        return summary\n\n    def filter_by_type(self, xlsx_file: str,\n                       ifc_types: List[str]) -> pd.DataFrame:\n        \"\"\"Filter elements by IFC type.\"\"\"\n        df = self.read_elements(xlsx_file)\n        return df[df['IfcType'].isin(ifc_types)]\n\n    def get_properties(self, xlsx_file: str,\n                       element_id: str) -> Dict[str, Any]:\n        \"\"\"Get all properties for specific element.\"\"\"\n        df = self.read_elements(xlsx_file)\n        element = df[df['GlobalId'] == element_id]\n\n        if element.empty:\n            return {}\n\n        # Convert row to dictionary, excluding NaN values\n        props = element.iloc[0].dropna().to_dict()\n        return props\n\n    def validate_ifc_data(self, xlsx_file: str) -> Dict[str, Any]:\n        \"\"\"Validate IFC data quality.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        validation = {\n            'total_elements': len(df),\n            'issues': []\n        }\n\n        # Check for missing GlobalIds\n        if 'GlobalId' in df.columns:\n            missing_ids = df['GlobalId'].isna().sum()\n            if missing_ids > 0:\n                validation['issues'].append(f\"{missing_ids} elements missing GlobalId\")\n\n        # Check for missing names\n        if 'Name' in df.columns:\n            missing_names = df['Name'].isna().sum()\n            if missing_names > 0:\n                validation['issues'].append(f\"{missing_names} elements missing Name\")\n\n        # Check for zero quantities\n        for col in ['Volume', 'Area']:\n            if col in df.columns:\n                zero_qty = (df[col] == 0).sum()\n                if zero_qty > 0:\n                    validation['issues'].append(f\"{zero_qty} elements with zero {col}\")\n\n        # Check for duplicate GlobalIds\n        if 'GlobalId' in df.columns:\n            duplicates = df['GlobalId'].duplicated().sum()\n            if duplicates > 0:\n                validation['issues'].append(f\"{duplicates} duplicate GlobalIds\")\n\n        validation['is_valid'] = len(validation['issues']) == 0\n        return validation\n\n\nclass IFCQuantityTakeoff:\n    \"\"\"Quantity takeoff from IFC data.\"\"\"\n\n    def __init__(self, exporter: IFCExporter):\n        self.exporter = exporter\n\n    def generate_qto(self, ifc_file: str) -> Dict[str, pd.DataFrame]:\n        \"\"\"Generate complete quantity takeoff.\"\"\"\n        xlsx = self.exporter.convert(ifc_file, include_bbox=True)\n        df = self.exporter.read_elements(str(xlsx))\n\n        qto = {}\n\n        # Walls\n        walls = df[df['IfcType'].str.contains('Wall', case=False, na=False)]\n        if not walls.empty:\n            qto['Walls'] = self._summarize_elements(walls, 'Type Name')\n\n        # Slabs\n        slabs = df[df['IfcType'].str.contains('Slab', case=False, na=False)]\n        if not slabs.empty:\n            qto['Slabs'] = self._summarize_elements(slabs, 'Type Name')\n\n        # Columns\n        columns = df[df['IfcType'].str.contains('Column', case=False, na=False)]\n        if not columns.empty:\n            qto['Columns'] = self._summarize_elements(columns, 'Type Name')\n\n        # Beams\n        beams = df[df['IfcType'].str.contains('Beam', case=False, na=False)]\n        if not beams.empty:\n            qto['Beams'] = self._summarize_elements(beams, 'Type Name')\n\n        # Doors\n        doors = df[df['IfcType'].str.contains('Door', case=False, na=False)]\n        if not doors.empty:\n            qto['Doors'] = self._summarize_elements(doors, 'Type Name')\n\n        # Windows\n        windows = df[df['IfcType'].str.contains('Window', case=False, na=False)]\n        if not windows.empty:\n            qto['Windows'] = self._summarize_elements(windows, 'Type Name')\n\n        return qto\n\n    def _summarize_elements(self, df: pd.DataFrame,\n                            group_col: str) -> pd.DataFrame:\n        \"\"\"Summarize elements by grouping column.\"\"\"\n        if group_col not in df.columns:\n            group_col = 'IfcType'\n\n        agg_dict = {'GlobalId': 'count'}\n        for col in ['Volume', 'Area', 'Length']:\n            if col in df.columns:\n                agg_dict[col] = 'sum'\n\n        summary = df.groupby(group_col).agg(agg_dict).reset_index()\n        summary.rename(columns={'GlobalId': 'Count'}, inplace=True)\n        return summary\n\n    def export_to_excel(self, qto: Dict[str, pd.DataFrame],\n                        output_file: str):\n        \"\"\"Export QTO to multi-sheet Excel.\"\"\"\n        with pd.ExcelWriter(output_file, engine='openpyxl') as writer:\n            for sheet_name, df in qto.items():\n                df.to_excel(writer, sheet_name=sheet_name, index=False)\n\n\n# Convenience functions\ndef convert_ifc_to_excel(ifc_file: str,\n                         exporter_path: str = \"IfcExporter.exe\") -> str:\n    \"\"\"Quick conversion of IFC to Excel.\"\"\"\n    exporter = IFCExporter(exporter_path)\n    output = exporter.convert(ifc_file)\n    return str(output)\n\n\ndef get_ifc_summary(xlsx_file: str) -> Dict[str, Any]:\n    \"\"\"Get summary of converted IFC data.\"\"\"\n    df = pd.read_excel(xlsx_file, sheet_name=\"Elements\")\n\n    return {\n        'total_elements': len(df),\n        'ifc_types': df['IfcType'].nunique() if 'IfcType' in df.columns else 0,\n        'levels': df['Level'].nunique() if 'Level' in df.columns else 0,\n        'total_volume': df['Volume'].sum() if 'Volume' in df.columns else 0,\n        'total_area': df['Area'].sum() if 'Area' in df.columns else 0\n    }"
      },
      {
        "title": "Excel Sheets",
        "body": "SheetContentElementsAll IFC elements with propertiesTypesElement types summaryLevelsBuilding storey dataMaterialsMaterial assignmentsPropertySetsIFC property sets"
      },
      {
        "title": "Element Columns",
        "body": "ColumnTypeDescriptionGlobalIdstringIFC GUIDIfcTypestringIFC entity typeNamestringElement nameDescriptionstringElement descriptionLevelstringBuilding storeyMaterialstringPrimary materialVolumefloatVolume (m³)AreafloatSurface area (m²)LengthfloatLength (m)HeightfloatHeight (m)WidthfloatWidth (m)"
      },
      {
        "title": "Quick Start",
        "body": "# Initialize exporter\nexporter = IFCExporter(\"C:/DDC/IfcExporter.exe\")\n\n# Convert IFC to Excel\nxlsx = exporter.convert(\"C:/Models/Building.ifc\", include_bbox=True)\n\n# Read elements\ndf = exporter.read_elements(str(xlsx))\nprint(f\"Total elements: {len(df)}\")\n\n# Get element types\ntypes = exporter.get_element_types(str(xlsx))\nprint(types)\n\n# Get quantities by type\nqto = exporter.get_quantities(str(xlsx), group_by='IfcType')\nprint(qto)"
      },
      {
        "title": "1. Model Validation",
        "body": "exporter = IFCExporter()\nxlsx = exporter.convert(\"model.ifc\")\nvalidation = exporter.validate_ifc_data(str(xlsx))\n\nif not validation['is_valid']:\n    print(\"Issues found:\")\n    for issue in validation['issues']:\n        print(f\"  - {issue}\")"
      },
      {
        "title": "2. Quantity Takeoff",
        "body": "qto_generator = IFCQuantityTakeoff(exporter)\nqto = qto_generator.generate_qto(\"building.ifc\")\n\nfor category, data in qto.items():\n    print(f\"\\n{category}:\")\n    print(data.to_string(index=False))"
      },
      {
        "title": "3. Material Schedule",
        "body": "xlsx = exporter.convert(\"building.ifc\")\nmaterials = exporter.get_materials(str(xlsx))\nprint(materials)"
      },
      {
        "title": "Integration with DDC Pipeline",
        "body": "# Full pipeline: IFC → Excel → Validation → Cost Estimate\nexporter = IFCExporter(\"C:/DDC/IfcExporter.exe\")\n\n# 1. Convert IFC\nxlsx = exporter.convert(\"project.ifc\", include_bbox=True)\n\n# 2. Validate data\nvalidation = exporter.validate_ifc_data(str(xlsx))\nprint(f\"Valid: {validation['is_valid']}\")\n\n# 3. Generate QTO\nqto = IFCQuantityTakeoff(exporter)\nquantities = qto.generate_qto(\"project.ifc\")\n\n# 4. Export for cost estimation\nqto.export_to_excel(quantities, \"project_qto.xlsx\")"
      },
      {
        "title": "Resources",
        "body": "GitHub: cad2data Pipeline\nIFC Standard: buildingSMART\nDDC Book: Chapter 2.4 - CAD/BIM Data Extraction"
      }
    ],
    "body": "IFC to Excel Conversion\nBusiness Case\nProblem Statement\n\nIFC (Industry Foundation Classes) is the open BIM standard, but:\n\nReading IFC requires specialized software\nProperty extraction needs programming knowledge\nBatch processing is manual and time-consuming\nIntegration with analytics tools is complex\nSolution\n\nIfcExporter.exe converts IFC files to structured Excel databases, making BIM data accessible for analysis, validation, and reporting.\n\nBusiness Value\nOpen standard - Process any IFC file (2x3, 4x, 4.3)\nNo licenses - Works offline without BIM software\nData extraction - All properties, quantities, materials\n3D geometry - Export to Collada DAE format\nPipeline ready - Integrate with ETL workflows\nTechnical Implementation\nCLI Syntax\nIfcExporter.exe <input_ifc> [options]\n\nSupported IFC Versions\nVersion\tSchema\tDescription\nIFC2x3\tMVD\tMost common exchange format\nIFC4\tADD1\tEnhanced properties\nIFC4x1\tAlignment\tInfrastructure support\nIFC4x3\tLatest\tFull infrastructure\nOutput Formats\nOutput\tDescription\n.xlsx\tExcel database with elements and properties\n.dae\tCollada 3D geometry with matching IDs\nOptions\nOption\tDescription\nbbox\tInclude element bounding boxes\n-no-xlsx\tSkip Excel export\n-no-collada\tSkip 3D geometry export\nExamples\n# Basic conversion (XLSX + DAE)\nIfcExporter.exe \"C:\\Models\\Building.ifc\"\n\n# With bounding boxes\nIfcExporter.exe \"C:\\Models\\Building.ifc\" bbox\n\n# Excel only (no 3D geometry)\nIfcExporter.exe \"C:\\Models\\Building.ifc\" -no-collada\n\n# Batch processing\nfor /R \"C:\\IFC_Models\" %f in (*.ifc) do IfcExporter.exe \"%f\" bbox\n\nPython Integration\nimport subprocess\nimport pandas as pd\nfrom pathlib import Path\nfrom typing import List, Optional, Dict, Any, Set\nfrom dataclasses import dataclass, field\nfrom enum import Enum\nimport json\n\n\nclass IFCVersion(Enum):\n    \"\"\"IFC schema versions.\"\"\"\n    IFC2X3 = \"IFC2X3\"\n    IFC4 = \"IFC4\"\n    IFC4X1 = \"IFC4X1\"\n    IFC4X3 = \"IFC4X3\"\n\n\nclass IFCEntityType(Enum):\n    \"\"\"Common IFC entity types.\"\"\"\n    IFCWALL = \"IfcWall\"\n    IFCWALLSTANDARDCASE = \"IfcWallStandardCase\"\n    IFCSLAB = \"IfcSlab\"\n    IFCCOLUMN = \"IfcColumn\"\n    IFCBEAM = \"IfcBeam\"\n    IFCDOOR = \"IfcDoor\"\n    IFCWINDOW = \"IfcWindow\"\n    IFCROOF = \"IfcRoof\"\n    IFCSTAIR = \"IfcStair\"\n    IFCRAILING = \"IfcRailing\"\n    IFCFURNISHINGELEMENT = \"IfcFurnishingElement\"\n    IFCSPACE = \"IfcSpace\"\n    IFCBUILDINGSTOREY = \"IfcBuildingStorey\"\n    IFCBUILDING = \"IfcBuilding\"\n    IFCSITE = \"IfcSite\"\n\n\n@dataclass\nclass IFCElement:\n    \"\"\"Represents an IFC element.\"\"\"\n    global_id: str\n    ifc_type: str\n    name: str\n    description: Optional[str]\n    object_type: Optional[str]\n    level: Optional[str]\n\n    # Quantities\n    area: Optional[float] = None\n    volume: Optional[float] = None\n    length: Optional[float] = None\n    height: Optional[float] = None\n    width: Optional[float] = None\n\n    # Bounding box (if exported)\n    bbox_min_x: Optional[float] = None\n    bbox_min_y: Optional[float] = None\n    bbox_min_z: Optional[float] = None\n    bbox_max_x: Optional[float] = None\n    bbox_max_y: Optional[float] = None\n    bbox_max_z: Optional[float] = None\n\n    # Properties\n    properties: Dict[str, Any] = field(default_factory=dict)\n    materials: List[str] = field(default_factory=list)\n\n\n@dataclass\nclass IFCProperty:\n    \"\"\"Represents an IFC property.\"\"\"\n    pset_name: str\n    property_name: str\n    value: Any\n    value_type: str\n\n\n@dataclass\nclass IFCMaterial:\n    \"\"\"Represents an IFC material.\"\"\"\n    name: str\n    category: Optional[str]\n    thickness: Optional[float]\n    layer_position: Optional[int]\n\n\nclass IFCExporter:\n    \"\"\"IFC to Excel converter using DDC IfcExporter CLI.\"\"\"\n\n    def __init__(self, exporter_path: str = \"IfcExporter.exe\"):\n        self.exporter = Path(exporter_path)\n        if not self.exporter.exists():\n            raise FileNotFoundError(f\"IfcExporter not found: {exporter_path}\")\n\n    def convert(self, ifc_file: str,\n                include_bbox: bool = True,\n                export_xlsx: bool = True,\n                export_collada: bool = True) -> Path:\n        \"\"\"Convert IFC file to Excel.\"\"\"\n        ifc_path = Path(ifc_file)\n        if not ifc_path.exists():\n            raise FileNotFoundError(f\"IFC file not found: {ifc_file}\")\n\n        cmd = [str(self.exporter), str(ifc_path)]\n\n        if include_bbox:\n            cmd.append(\"bbox\")\n        if not export_xlsx:\n            cmd.append(\"-no-xlsx\")\n        if not export_collada:\n            cmd.append(\"-no-collada\")\n\n        result = subprocess.run(cmd, capture_output=True, text=True)\n\n        if result.returncode != 0:\n            raise RuntimeError(f\"Export failed: {result.stderr}\")\n\n        return ifc_path.with_suffix('.xlsx')\n\n    def batch_convert(self, folder: str,\n                      include_subfolders: bool = True,\n                      include_bbox: bool = True) -> List[Dict[str, Any]]:\n        \"\"\"Convert all IFC files in folder.\"\"\"\n        folder_path = Path(folder)\n        pattern = \"**/*.ifc\" if include_subfolders else \"*.ifc\"\n\n        results = []\n        for ifc_file in folder_path.glob(pattern):\n            try:\n                output = self.convert(str(ifc_file), include_bbox)\n                results.append({\n                    'input': str(ifc_file),\n                    'output': str(output),\n                    'status': 'success'\n                })\n                print(f\"✓ Converted: {ifc_file.name}\")\n            except Exception as e:\n                results.append({\n                    'input': str(ifc_file),\n                    'output': None,\n                    'status': 'failed',\n                    'error': str(e)\n                })\n                print(f\"✗ Failed: {ifc_file.name} - {e}\")\n\n        return results\n\n    def read_elements(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Read converted Excel as DataFrame.\"\"\"\n        return pd.read_excel(xlsx_file, sheet_name=\"Elements\")\n\n    def get_element_types(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get element type summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        if 'IfcType' not in df.columns:\n            raise ValueError(\"IfcType column not found\")\n\n        summary = df.groupby('IfcType').agg({\n            'GlobalId': 'count',\n            'Volume': 'sum' if 'Volume' in df.columns else 'count',\n            'Area': 'sum' if 'Area' in df.columns else 'count'\n        }).reset_index()\n\n        summary.columns = ['IFC_Type', 'Count', 'Total_Volume', 'Total_Area']\n        return summary.sort_values('Count', ascending=False)\n\n    def get_levels(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get building level summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        level_col = None\n        for col in ['Level', 'BuildingStorey', 'IfcBuildingStorey']:\n            if col in df.columns:\n                level_col = col\n                break\n\n        if level_col is None:\n            return pd.DataFrame(columns=['Level', 'Element_Count'])\n\n        summary = df.groupby(level_col).agg({\n            'GlobalId': 'count'\n        }).reset_index()\n        summary.columns = ['Level', 'Element_Count']\n        return summary\n\n    def get_materials(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get material summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        if 'Material' not in df.columns:\n            return pd.DataFrame(columns=['Material', 'Count'])\n\n        summary = df.groupby('Material').agg({\n            'GlobalId': 'count'\n        }).reset_index()\n        summary.columns = ['Material', 'Element_Count']\n        return summary.sort_values('Element_Count', ascending=False)\n\n    def get_quantities(self, xlsx_file: str,\n                       group_by: str = 'IfcType') -> pd.DataFrame:\n        \"\"\"Get quantity takeoff summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        if group_by not in df.columns:\n            raise ValueError(f\"Column {group_by} not found\")\n\n        agg_dict = {'GlobalId': 'count'}\n\n        # Add numeric columns for aggregation\n        numeric_cols = ['Volume', 'Area', 'Length', 'Width', 'Height']\n        for col in numeric_cols:\n            if col in df.columns:\n                agg_dict[col] = 'sum'\n\n        summary = df.groupby(group_by).agg(agg_dict).reset_index()\n        return summary\n\n    def filter_by_type(self, xlsx_file: str,\n                       ifc_types: List[str]) -> pd.DataFrame:\n        \"\"\"Filter elements by IFC type.\"\"\"\n        df = self.read_elements(xlsx_file)\n        return df[df['IfcType'].isin(ifc_types)]\n\n    def get_properties(self, xlsx_file: str,\n                       element_id: str) -> Dict[str, Any]:\n        \"\"\"Get all properties for specific element.\"\"\"\n        df = self.read_elements(xlsx_file)\n        element = df[df['GlobalId'] == element_id]\n\n        if element.empty:\n            return {}\n\n        # Convert row to dictionary, excluding NaN values\n        props = element.iloc[0].dropna().to_dict()\n        return props\n\n    def validate_ifc_data(self, xlsx_file: str) -> Dict[str, Any]:\n        \"\"\"Validate IFC data quality.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        validation = {\n            'total_elements': len(df),\n            'issues': []\n        }\n\n        # Check for missing GlobalIds\n        if 'GlobalId' in df.columns:\n            missing_ids = df['GlobalId'].isna().sum()\n            if missing_ids > 0:\n                validation['issues'].append(f\"{missing_ids} elements missing GlobalId\")\n\n        # Check for missing names\n        if 'Name' in df.columns:\n            missing_names = df['Name'].isna().sum()\n            if missing_names > 0:\n                validation['issues'].append(f\"{missing_names} elements missing Name\")\n\n        # Check for zero quantities\n        for col in ['Volume', 'Area']:\n            if col in df.columns:\n                zero_qty = (df[col] == 0).sum()\n                if zero_qty > 0:\n                    validation['issues'].append(f\"{zero_qty} elements with zero {col}\")\n\n        # Check for duplicate GlobalIds\n        if 'GlobalId' in df.columns:\n            duplicates = df['GlobalId'].duplicated().sum()\n            if duplicates > 0:\n                validation['issues'].append(f\"{duplicates} duplicate GlobalIds\")\n\n        validation['is_valid'] = len(validation['issues']) == 0\n        return validation\n\n\nclass IFCQuantityTakeoff:\n    \"\"\"Quantity takeoff from IFC data.\"\"\"\n\n    def __init__(self, exporter: IFCExporter):\n        self.exporter = exporter\n\n    def generate_qto(self, ifc_file: str) -> Dict[str, pd.DataFrame]:\n        \"\"\"Generate complete quantity takeoff.\"\"\"\n        xlsx = self.exporter.convert(ifc_file, include_bbox=True)\n        df = self.exporter.read_elements(str(xlsx))\n\n        qto = {}\n\n        # Walls\n        walls = df[df['IfcType'].str.contains('Wall', case=False, na=False)]\n        if not walls.empty:\n            qto['Walls'] = self._summarize_elements(walls, 'Type Name')\n\n        # Slabs\n        slabs = df[df['IfcType'].str.contains('Slab', case=False, na=False)]\n        if not slabs.empty:\n            qto['Slabs'] = self._summarize_elements(slabs, 'Type Name')\n\n        # Columns\n        columns = df[df['IfcType'].str.contains('Column', case=False, na=False)]\n        if not columns.empty:\n            qto['Columns'] = self._summarize_elements(columns, 'Type Name')\n\n        # Beams\n        beams = df[df['IfcType'].str.contains('Beam', case=False, na=False)]\n        if not beams.empty:\n            qto['Beams'] = self._summarize_elements(beams, 'Type Name')\n\n        # Doors\n        doors = df[df['IfcType'].str.contains('Door', case=False, na=False)]\n        if not doors.empty:\n            qto['Doors'] = self._summarize_elements(doors, 'Type Name')\n\n        # Windows\n        windows = df[df['IfcType'].str.contains('Window', case=False, na=False)]\n        if not windows.empty:\n            qto['Windows'] = self._summarize_elements(windows, 'Type Name')\n\n        return qto\n\n    def _summarize_elements(self, df: pd.DataFrame,\n                            group_col: str) -> pd.DataFrame:\n        \"\"\"Summarize elements by grouping column.\"\"\"\n        if group_col not in df.columns:\n            group_col = 'IfcType'\n\n        agg_dict = {'GlobalId': 'count'}\n        for col in ['Volume', 'Area', 'Length']:\n            if col in df.columns:\n                agg_dict[col] = 'sum'\n\n        summary = df.groupby(group_col).agg(agg_dict).reset_index()\n        summary.rename(columns={'GlobalId': 'Count'}, inplace=True)\n        return summary\n\n    def export_to_excel(self, qto: Dict[str, pd.DataFrame],\n                        output_file: str):\n        \"\"\"Export QTO to multi-sheet Excel.\"\"\"\n        with pd.ExcelWriter(output_file, engine='openpyxl') as writer:\n            for sheet_name, df in qto.items():\n                df.to_excel(writer, sheet_name=sheet_name, index=False)\n\n\n# Convenience functions\ndef convert_ifc_to_excel(ifc_file: str,\n                         exporter_path: str = \"IfcExporter.exe\") -> str:\n    \"\"\"Quick conversion of IFC to Excel.\"\"\"\n    exporter = IFCExporter(exporter_path)\n    output = exporter.convert(ifc_file)\n    return str(output)\n\n\ndef get_ifc_summary(xlsx_file: str) -> Dict[str, Any]:\n    \"\"\"Get summary of converted IFC data.\"\"\"\n    df = pd.read_excel(xlsx_file, sheet_name=\"Elements\")\n\n    return {\n        'total_elements': len(df),\n        'ifc_types': df['IfcType'].nunique() if 'IfcType' in df.columns else 0,\n        'levels': df['Level'].nunique() if 'Level' in df.columns else 0,\n        'total_volume': df['Volume'].sum() if 'Volume' in df.columns else 0,\n        'total_area': df['Area'].sum() if 'Area' in df.columns else 0\n    }\n\nOutput Structure\nExcel Sheets\nSheet\tContent\nElements\tAll IFC elements with properties\nTypes\tElement types summary\nLevels\tBuilding storey data\nMaterials\tMaterial assignments\nPropertySets\tIFC property sets\nElement Columns\nColumn\tType\tDescription\nGlobalId\tstring\tIFC GUID\nIfcType\tstring\tIFC entity type\nName\tstring\tElement name\nDescription\tstring\tElement description\nLevel\tstring\tBuilding storey\nMaterial\tstring\tPrimary material\nVolume\tfloat\tVolume (m³)\nArea\tfloat\tSurface area (m²)\nLength\tfloat\tLength (m)\nHeight\tfloat\tHeight (m)\nWidth\tfloat\tWidth (m)\nQuick Start\n# Initialize exporter\nexporter = IFCExporter(\"C:/DDC/IfcExporter.exe\")\n\n# Convert IFC to Excel\nxlsx = exporter.convert(\"C:/Models/Building.ifc\", include_bbox=True)\n\n# Read elements\ndf = exporter.read_elements(str(xlsx))\nprint(f\"Total elements: {len(df)}\")\n\n# Get element types\ntypes = exporter.get_element_types(str(xlsx))\nprint(types)\n\n# Get quantities by type\nqto = exporter.get_quantities(str(xlsx), group_by='IfcType')\nprint(qto)\n\nCommon Use Cases\n1. Model Validation\nexporter = IFCExporter()\nxlsx = exporter.convert(\"model.ifc\")\nvalidation = exporter.validate_ifc_data(str(xlsx))\n\nif not validation['is_valid']:\n    print(\"Issues found:\")\n    for issue in validation['issues']:\n        print(f\"  - {issue}\")\n\n2. Quantity Takeoff\nqto_generator = IFCQuantityTakeoff(exporter)\nqto = qto_generator.generate_qto(\"building.ifc\")\n\nfor category, data in qto.items():\n    print(f\"\\n{category}:\")\n    print(data.to_string(index=False))\n\n3. Material Schedule\nxlsx = exporter.convert(\"building.ifc\")\nmaterials = exporter.get_materials(str(xlsx))\nprint(materials)\n\nIntegration with DDC Pipeline\n# Full pipeline: IFC → Excel → Validation → Cost Estimate\nexporter = IFCExporter(\"C:/DDC/IfcExporter.exe\")\n\n# 1. Convert IFC\nxlsx = exporter.convert(\"project.ifc\", include_bbox=True)\n\n# 2. Validate data\nvalidation = exporter.validate_ifc_data(str(xlsx))\nprint(f\"Valid: {validation['is_valid']}\")\n\n# 3. Generate QTO\nqto = IFCQuantityTakeoff(exporter)\nquantities = qto.generate_qto(\"project.ifc\")\n\n# 4. Export for cost estimation\nqto.export_to_excel(quantities, \"project_qto.xlsx\")\n\nResources\nGitHub: cad2data Pipeline\nIFC Standard: buildingSMART\nDDC Book: Chapter 2.4 - CAD/BIM Data Extraction"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/datadrivenconstruction/ifc-to-excel",
    "publisherUrl": "https://clawhub.ai/datadrivenconstruction/ifc-to-excel",
    "owner": "datadrivenconstruction",
    "version": "2.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/ifc-to-excel",
    "downloadUrl": "https://openagent3.xyz/downloads/ifc-to-excel",
    "agentUrl": "https://openagent3.xyz/skills/ifc-to-excel/agent",
    "manifestUrl": "https://openagent3.xyz/skills/ifc-to-excel/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/ifc-to-excel/agent.md"
  }
}