我正在使用以下 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.
我尝试在互联网上搜索但找不到任何有用的东西
我用 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 点就好了。
节目的第二部分很慢。我正在优化它以按楼层搜索最近的空间。