一个使用 XBIM 库的 C# 程序,它从 IFC 找到最接近给定点的空间

问题描述 投票:0回答:1

我正在使用以下 C# 代码通过坐标查找元素的空间信息。这是我的第一个 BIM 程序。

效果很好,但有时点会落在房间边界之外。我需要一个程序来找到离这些点最近的空间。它应该是最近的空间表面。


using Xbim.Ifc;
using Xbim.Ifc4.Interfaces;
using System.IO;
using Xbim.ModelGeometry.Scene;
using Xbim.Ifc.Extensions;
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;

public static void OutputSpacesAtPoints()
        {
            var PathToIFC = GetPathToIFC();

            if (!UserConfirmationToStart(PathToIFC))
            {
                return;
            }

            Console.WriteLine($"Connecting to IFC model: {PathToIFC}");

            using (var model = IfcStore.Open(PathToIFC))
            {
                var DeviceListIn = LoadFromJSON();

                Console.WriteLine($"Initializing Context ...");
                Xbim3DModelContext context = new Xbim3DModelContext(model);
                Console.WriteLine($"Creating Context (slow) ...");
                context.CreateContext();
                
                var spaces = model.Instances.OfType<IIfcSpace>().ToList();
                Console.WriteLine($"Spaces found: {spaces.Count}");
                Console.WriteLine($"Looping spaces ...");
                foreach (var space in spaces)
                {
                    var geometries = context.ShapeInstancesOf(space);
                    foreach (var geometry in geometries)
                    {
                        var bblocal = geometry.BoundingBox;
                        var transform = space.ObjectPlacement.ToMatrix3D();
                        var bb = bblocal.Transform(transform);

                        foreach (var d in DeviceListIn)
                        {
                            if (!string.IsNullOrEmpty(d.RoomName))
                            {
                                continue;
                            }

                            if (bb.Contains(d.x, d.y, d.z))
                            {
                                Console.WriteLine($"Point {d.id} is inside space: {space.Name} {space.LongName} ");
                                d.RoomNumber = space.Name;
                                d.RoomName = space.LongName;
                                continue;
                            }
                        }
                    }
                }

                SaveRoomNumbersToJSON(DeviceListIn);

                Console.WriteLine($"Found roomnumbers: {DeviceListIn.Where(x => !string.IsNullOrEmpty(x.RoomNumber)).Count()} still empty: {DeviceListIn.Where(x => string.IsNullOrEmpty(x.RoomNumber)).Count()}");
                Console.ReadLine();
            }
        }
    This program works only on .NET Framework 4.7.2. .NET6 gives an error - DLL not found.
    
    I'm new to BIM. Any help is greatly appreciated.

我尝试在互联网上搜索但找不到任何有用的东西

c# geometry ifc bim xbim
1个回答
0
投票

我用 python 使用 ifcopenshell 做到了:

import ifcopenshell
import json
import ifcopenshell.geom
import shapely
from shapely.geometry import Polygon, Point

def is_not_blank(s):
    return bool(s and not s.isspace())

print("Getting path to IFC ...")
f = open(r'C:\ ... \DeviceListSettings.json')
data = json.load(f)
FilePathIFC = data['FilePathIFC']
print(FilePathIFC)
f.close()

print("Getting device list to process ...")
f = open(r'C:\ ... \DeviceList.json')
DeviceListIn = json.load(f)
print(f"Loaded devices: {len(DeviceListIn)}")
f.close()


print("Opening IFC file ...")
ifc = ifcopenshell.open(FilePathIFC)

print(f"IFC schema: {ifc.schema}")

spaces = ifc.by_type('IfcSpace')
print(f"Spaces found: {len(spaces)}")


settings = ifcopenshell.geom.settings()
settings.set(settings.USE_WORLD_COORDS, True)

found_count = 0

for space in spaces:
    shape = ifcopenshell.geom.create_shape(settings, space)
    verts_m = shape.geometry.verts
    verts = [v * 1000 for v in verts_m] # Vertices in meters
    grouped_verts = [[verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)] # Group vertices to coordinates x,y,z
    min_z = min(grouped_verts, key=lambda x: x[2])[2] # lowest
    max_z = max(grouped_verts, key=lambda x: x[2])[2] # hightst
    grouped_verts = [x for x in grouped_verts if x[2] == min_z] # flatten floor pojection. Filter out higher coordinates.
    polygon = Polygon(grouped_verts)

    for d in DeviceListIn:

        if is_not_blank(d['RoomNumber']):
            continue
        if not (min_z <= d['z'] <= max_z):
            continue

        point = Point(d['x'],d['y'],d['z'])

        if shapely.contains_xy(polygon,point.x,point.y):
            d['RoomNumber'] = space.Name
            d['RoomName'] = space.LongName
            found_count += 1
            print(f"{found_count} {d['id']} is inside {space.Name}")


for d in DeviceListIn:
    min_distance = 1000
    
    if is_not_blank(d['RoomNumber']):
            continue
    print(f"Search closest space to: {d['id']}")

    point = Point(d['x'],d['y'],d['z'])

    for space in spaces:
        shape = ifcopenshell.geom.create_shape(settings, space)
        verts_m = shape.geometry.verts
        verts = [v * 1000 for v in verts_m] # Vertices in meters
        grouped_verts = [[verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)] # Group vertices to coordinates x,y,z
        min_z = min(grouped_verts, key=lambda x: x[2])[2] # lowest
        max_z = max(grouped_verts, key=lambda x: x[2])[2] # hightst
        grouped_verts = [x for x in grouped_verts if x[2] == min_z] # flatten floor pojection. Filter out higher coordinates.
        polygon = Polygon(grouped_verts)

        if not (min_z <= d['z'] <= max_z):
            continue

        distance = polygon.distance(point)
        if distance < min_distance:
            min_distance = distance
            d['RoomNumber'] = space.Name
            d['RoomName'] = space.LongName
            print(f"{d['id']} Distance: {distance} {space.Name}")
    if min_distance < 1000:
        found_count += 1
        print(f"{found_count} {d['id']} is inside {d['RoomNumber']}")


with open(r'C:\ ... \DeviceListPython.json', 'w') as f:
    # Write the modified JSON data back to the file
    json.dump(DeviceListIn, f, indent=4)

之前的代码有问题。边界框不是解决此任务的合适工具。

Python代码过滤2d投影坐标,判断点是否在形状内。有没有更好的方法来完成这个任务?如果能够直接搜索 3d 形状中的 3d 点就好了。

节目的第二部分很慢。我正在优化它以按楼层搜索最近的空间。

© www.soinside.com 2019 - 2024. All rights reserved.