Загрузка данных


using System;
using System.Collections.Generic;
using System.Linq;
using Xbim.Ifc;
using Xbim.Ifc4.Interfaces;
using Xbim.Ifc4.Kernel;
using Xbim.Ifc4.PropertyResource;
using Xbim.Ifc4.MeasureResource;

namespace IfcBimEditor
{
    public sealed class ElementItem
    {
        public IIfcObject Element { get; set; }
        public string Display => $"{Element.ExpressType.Name} | {Element.Name} | {Element.GlobalId}";
    }

    public static class IfcEditor
    {
        public static List<IIfcObject> FindSimilar(IfcStore model, IIfcObject selected, int mode)
        {
            var all = model.Instances.OfType<IIfcObject>();
            switch (mode)
            {
                case 1:
                    return all.Where(x => string.Equals(
                        x.Name.ToString(), selected.Name.ToString(),
                        StringComparison.OrdinalIgnoreCase)).ToList();
                case 2:
                    var type = selected.IsTypedBy.FirstOrDefault()?.RelatingType;
                    return type == null
                        ? new List<IIfcObject> { selected }
                        : all.Where(x => x.IsTypedBy.Any(r =>
                            r.RelatingType != null && r.RelatingType.GlobalId == type.GlobalId)).ToList();
                default:
                    return all.Where(x => x.ExpressType.Name == selected.ExpressType.Name).ToList();
            }
        }

        // Редактирует строковое свойство IFC4. Для IFC2x3 нужен отдельный обработчик.
        // Не изменяет исходный общий Pset: создаёт новый для каждого выбранного объекта.
        public static int SetStringProperty(IfcStore model, IEnumerable<IIfcObject> objects,
            string psetName, string propertyName, string value, bool createMissing)
        {
            if (string.IsNullOrWhiteSpace(psetName) || string.IsNullOrWhiteSpace(propertyName))
                throw new ArgumentException("Укажите имя набора свойств и свойства.");
            var targets = objects.Distinct().ToList();
            // Проверяем совместимость до начала транзакции.
            if (targets.Any(o => !(o is IfcObjectDefinition)))
                throw new NotSupportedException("Этот редактор поддерживает запись только в IFC4. Для IFC2x3 требуется отдельная реализация.");

            int changed = 0;
            using (var tx = model.BeginTransaction("Bulk property edit"))
            {
                foreach (var obj in targets)
                {
                    var relation = obj.IsDefinedBy
                        .OfType<IIfcRelDefinesByProperties>()
                        .FirstOrDefault(r => r.RelatingPropertyDefinition is IIfcPropertySet ps &&
                                             ps.Name.ToString() == psetName);
                    var set = relation?.RelatingPropertyDefinition as IIfcPropertySet;
                    var existing = set?.HasProperties.OfType<IIfcPropertySingleValue>()
                        .FirstOrDefault(p => p.Name.ToString() == propertyName);
                    if (existing == null && !createMissing) continue;

                    var newSet = model.Instances.New<IfcPropertySet>(p => p.Name = psetName);
                    if (set != null)
                    {
                        foreach (var oldProp in set.HasProperties)
                        {
                            if (oldProp.Name.ToString() == propertyName) continue;
                            // Сохраняем остальные свойства как ссылки, не изменяя их значения.
                            // Изменяемое свойство создаётся заново ниже.
                            var concrete = oldProp as IfcProperty;
                            if (concrete == null)
                                throw new NotSupportedException("Набор содержит свойства несовместимой IFC-схемы.");
                            newSet.HasProperties.Add(concrete);
                        }
                    }
                    newSet.HasProperties.Add(model.Instances.New<IfcPropertySingleValue>(p =>
                    {
                        p.Name = propertyName;
                        p.NominalValue = new IfcText(value ?? string.Empty);
                    }));
                    model.Instances.New<IfcRelDefinesByProperties>(r =>
                    {
                        r.RelatingPropertyDefinition = newSet;
                        r.RelatedObjects.Add((IfcObjectDefinition)obj);
                    });
                    if (relation != null)
                    {
                        var oldRelation = relation as IfcRelDefinesByProperties;
                        if (oldRelation == null)
                            throw new NotSupportedException("Связь Pset не относится к IFC4.");
                        oldRelation.RelatedObjects.Remove((IfcObjectDefinition)obj);
                        if (!oldRelation.RelatedObjects.Any()) model.Delete(oldRelation);
                    }
                    changed++;
                }
                tx.Commit();
            }
            return changed;
        }
    }
}