diff --git a/.github/workflows/publish.RevitRoundingOfAreas.yml b/.github/workflows/publish.RevitRoundingOfAreas.yml
new file mode 100644
index 000000000..b52d46d6a
--- /dev/null
+++ b/.github/workflows/publish.RevitRoundingOfAreas.yml
@@ -0,0 +1,37 @@
+name: publish RevitRoundingOfAreas
+
+on:
+ workflow_dispatch:
+ pull_request:
+ types: [ closed, synchronize, review_requested ]
+ branches: [ main, master ]
+ paths:
+ - '**RevitRoundingOfAreas**.cs'
+ - '**RevitRoundingOfAreas**.xaml'
+
+env:
+ plugin-name: "RevitRoundingOfAreas"
+
+jobs:
+ build:
+ name: build
+ runs-on: windows-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ # Install the .NET workload
+ - name: Install .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ # Add DevExrepress package source: https://nuget.devexpress.com/
+ - name: Add DevExpress package source
+ run: dotnet nuget add source https://nuget.devexpress.com/api -n DXFeed -u DevExpress -p ${{ secrets.DEVEXPRESS_FEED_AUTHORIZATION_KEY }}
+
+ - name: Run './build.cmd '
+ run: ./build.cmd publish --profile ${{ env.plugin-name }} --pull-request-merged ${{ github.event.pull_request.merged }} --extensions-app-token ${{ secrets.EXTENSIONS_APP_TOKEN }} --revit-plugins-app-token ${{ secrets.REVIT_PLUGINS_APP_TOKEN }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.nuke/parameters.RevitRoundingOfAreas.json b/.nuke/parameters.RevitRoundingOfAreas.json
new file mode 100644
index 000000000..0e49b3e5b
--- /dev/null
+++ b/.nuke/parameters.RevitRoundingOfAreas.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "./build.schema.json",
+ "Solution": "RevitPlugins.slnx",
+ "PluginName": "RevitRoundingOfAreas",
+ "PublishDirectory": "02.AR.extension\\АР.tab\\bin",
+ "RevitVersions": [
+ "Rv2022",
+ "Rv2023",
+ "Rv2024"
+ ],
+ "IconUrl": "https://icons8.com/icon/79538/decrease-decimal",
+ "BundleName": "Рассчитать площади (соц. объекты)",
+ "BundleType": "InvokeButton",
+ "BundleOutput": "02.AR.extension\\АР.tab\\Квартирография.panel\\Помещения.pulldown"
+}
diff --git a/RevitPlugins.slnx b/RevitPlugins.slnx
index d615afbfa..6cb2eedff 100644
--- a/RevitPlugins.slnx
+++ b/RevitPlugins.slnx
@@ -187,6 +187,9 @@
+
+
+
diff --git a/src/RevitRoundingOfAreas/Models/CheckProjectParams.cs b/src/RevitRoundingOfAreas/Models/CheckProjectParams.cs
new file mode 100644
index 000000000..f3d54456d
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/CheckProjectParams.cs
@@ -0,0 +1,26 @@
+using Autodesk.Revit.ApplicationServices;
+using Autodesk.Revit.DB;
+
+using dosymep.Bim4Everyone.Templates;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class CheckProjectParams(SystemPluginConfig systemPluginConfig, Application application, Document document) {
+ private readonly ProjectParameters _projectParameters = ProjectParameters.Create(application);
+ private readonly bool _isChecked = true;
+
+ ///
+ /// Метод проверки загрузки параметров
+ ///
+ public bool GetIsChecked() {
+ return _isChecked;
+ }
+
+ ///
+ /// Метод копирования параметров проекта
+ ///
+ public CheckProjectParams CopyProjectParams() {
+ _projectParameters.SetupRevitParams(document, systemPluginConfig.RoomAreaParam);
+ return this;
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Models/ConfigSettings.cs b/src/RevitRoundingOfAreas/Models/ConfigSettings.cs
new file mode 100644
index 000000000..88aa8f624
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/ConfigSettings.cs
@@ -0,0 +1,12 @@
+using Autodesk.Revit.DB;
+
+using dosymep.Bim4Everyone;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class ConfigSettings {
+ public ElementId SelectedPhaseId { get; set; }
+ public RevitParam SourceParam { get; set; }
+ public RevitParam TargetParam { get; set; }
+ public int Accuracy { get; set; }
+}
diff --git a/src/RevitRoundingOfAreas/Models/Enums/ElementsProviderType.cs b/src/RevitRoundingOfAreas/Models/Enums/ElementsProviderType.cs
new file mode 100644
index 000000000..227a39a93
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Enums/ElementsProviderType.cs
@@ -0,0 +1,6 @@
+namespace RevitRoundingOfAreas.Models.Enums;
+internal enum ElementsProviderType {
+ AllElementsProvider,
+ CurrentViewProvider,
+ SelectedElementsProvider
+}
diff --git a/src/RevitRoundingOfAreas/Models/Enums/WarningType.cs b/src/RevitRoundingOfAreas/Models/Enums/WarningType.cs
new file mode 100644
index 000000000..bcfc1e195
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Enums/WarningType.cs
@@ -0,0 +1,6 @@
+namespace RevitRoundingOfAreas.Models.Enums;
+internal enum WarningType {
+ NotEnclosed,
+ Redundant,
+ BrokenContour
+}
diff --git a/src/RevitRoundingOfAreas/Models/Factories/ProvidersFactory.cs b/src/RevitRoundingOfAreas/Models/Factories/ProvidersFactory.cs
new file mode 100644
index 000000000..39f17eaa1
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Factories/ProvidersFactory.cs
@@ -0,0 +1,19 @@
+using RevitRoundingOfAreas.Models.Enums;
+using RevitRoundingOfAreas.Models.Interfaces;
+using RevitRoundingOfAreas.Models.Providers;
+
+namespace RevitRoundingOfAreas.Models.Factories;
+
+internal class ProvidersFactory(RevitRepository revitRepository) {
+ ///
+ /// Метод получения провайдера элементов по Enum
+ ///
+ public IElementsProvider GetElementsProvider(ElementsProviderType type) {
+ return type switch {
+ ElementsProviderType.AllElementsProvider => new ElementsProviderAll(revitRepository),
+ ElementsProviderType.CurrentViewProvider => new ElementsProviderCurrentView(revitRepository),
+ ElementsProviderType.SelectedElementsProvider => new ElementsProviderSelected(revitRepository),
+ _ => new ElementsProviderAll(revitRepository)
+ };
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Models/Interfaces/IElementsProvider.cs b/src/RevitRoundingOfAreas/Models/Interfaces/IElementsProvider.cs
new file mode 100644
index 000000000..5d8c50c80
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Interfaces/IElementsProvider.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+using Autodesk.Revit.DB;
+
+using RevitRoundingOfAreas.Models.Enums;
+
+namespace RevitRoundingOfAreas.Models.Interfaces;
+
+internal interface IElementsProvider {
+ ///
+ /// Тип провайдера элементов
+ ///
+ ElementsProviderType Type { get; }
+ ///
+ /// Метод получения элементов модели по стадиям
+ ///
+ List GetSpatialElements(ElementId phaseId);
+}
diff --git a/src/RevitRoundingOfAreas/Models/Interfaces/IWindowService.cs b/src/RevitRoundingOfAreas/Models/Interfaces/IWindowService.cs
new file mode 100644
index 000000000..3f9ef52e7
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Interfaces/IWindowService.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+using RevitRoundingOfAreas.Models.Warnings;
+
+namespace RevitRoundingOfAreas.Models.Interfaces;
+
+internal interface IWindowService {
+ ///
+ /// Метод закрытия основного окна
+ ///
+ ///
+ /// В данном методе производится закрытие основного окна при появлении предупреждений
+ ///
+ ///
+ /// Void.
+ ///
+ void CloseMainWindow();
+ ///
+ /// Метод открытия окна.
+ ///
+ ///
+ /// В данном методе производится открытие кона предупреждений для отображения WarningElement.
+ ///
+ /// Коллекция предупреждений WarningElement.
+ ///
+ /// Void.
+ ///
+ void ShowWarningWindow(IReadOnlyCollection warningElements);
+}
diff --git a/src/RevitRoundingOfAreas/Models/ParamService.cs b/src/RevitRoundingOfAreas/Models/ParamService.cs
new file mode 100644
index 000000000..55059cb30
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/ParamService.cs
@@ -0,0 +1,83 @@
+using System.Collections.Generic;
+using System.Linq;
+
+using Autodesk.Revit.DB;
+
+using dosymep.Bim4Everyone;
+using dosymep.Bim4Everyone.SharedParams;
+using dosymep.Bim4Everyone.SimpleServices;
+using dosymep.Bim4Everyone.SystemParams;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class ParamService {
+ private readonly RevitRepository _revitRepository;
+ private readonly SystemPluginConfig _systemPluginConfig;
+ private readonly IRevitParamFactory _revitParamFactory;
+ private readonly ICollection _allParamElementIds;
+
+ public ParamService(
+ RevitRepository revitRepository,
+ SystemPluginConfig systemPluginConfig,
+ IRevitParamFactory revitParamFactory) {
+
+ _revitRepository = revitRepository;
+ _systemPluginConfig = systemPluginConfig;
+ _revitParamFactory = revitParamFactory;
+
+ _allParamElementIds = GetAllParamElementIds();
+
+ AllRevitParams = GetAllRevitParams().AsReadOnly();
+
+ DefaultSourceParam = GetDefaultSourceParam();
+ DefaultTargetParam = GetDefaultTargetParam();
+ }
+
+ public IReadOnlyList AllRevitParams { get; }
+ public RevitParam DefaultSourceParam { get; }
+ public RevitParam DefaultTargetParam { get; }
+
+ private ICollection GetAllParamElementIds() {
+ var categoryId = new ElementId(BuiltInCategory.OST_Rooms);
+
+ return ParameterFilterUtilities
+ .GetFilterableParametersInCommon(_revitRepository.Document, [categoryId]);
+ }
+
+ private RevitParam GetDefaultSourceParam() {
+ return AllRevitParams
+ .OfType()
+ .FirstOrDefault(x => x.SystemParamId == _systemPluginConfig.SystemRoomAreaParamId);
+ }
+
+ private RevitParam GetDefaultTargetParam() {
+ return AllRevitParams
+ .OfType()
+ .FirstOrDefault(x => x.Name.Equals(_systemPluginConfig.RoomAreaParam.Name));
+ }
+
+ private List GetAllRevitParams() {
+ if(_allParamElementIds.Count == 0) {
+ return [];
+ }
+
+ List parameters = [];
+
+ foreach(var elementId in _allParamElementIds) {
+ var revitParam = _revitParamFactory.Create(_revitRepository.Document, elementId);
+
+ if(revitParam is null) {
+ continue;
+ }
+
+ if(IsSupportedStorageType(revitParam)) {
+ parameters.Add(revitParam);
+ }
+ }
+ return parameters;
+ }
+
+ private static bool IsSupportedStorageType(RevitParam revitParam) {
+ return revitParam.StorageType == StorageType.Double;
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Models/PhaseModel.cs b/src/RevitRoundingOfAreas/Models/PhaseModel.cs
new file mode 100644
index 000000000..7646dd52c
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/PhaseModel.cs
@@ -0,0 +1,8 @@
+using Autodesk.Revit.DB;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class PhaseModel {
+ public ElementId ElementId { get; set; }
+ public string Name { get; set; }
+}
diff --git a/src/RevitRoundingOfAreas/Models/PluginConfig.cs b/src/RevitRoundingOfAreas/Models/PluginConfig.cs
new file mode 100644
index 000000000..175585939
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/PluginConfig.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Autodesk.Revit.DB;
+
+using dosymep.Bim4Everyone;
+using dosymep.Bim4Everyone.ProjectConfigs;
+using dosymep.Bim4Everyone.SharedParams;
+
+using pyRevitLabs.Json;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class PluginConfig : ProjectConfig {
+
+ [JsonIgnore]
+ public override string ProjectConfigPath { get; set; }
+
+ [JsonIgnore]
+ public override IConfigSerializer Serializer { get; set; }
+
+ ///
+ /// Метод создания конфигурации плагина.
+ ///
+ ///
+ /// Сериализатор конфигурации.
+ /// Возвращает прочитанную конфигурацию плагина, либо созданный конфиг по умолчанию.
+ ///
+ public static PluginConfig GetPluginConfig(IConfigSerializer configSerializer) {
+ return new ProjectConfigBuilder()
+ .SetSerializer(configSerializer)
+ .SetPluginName(nameof(RevitRoundingOfAreas))
+ .SetRevitVersion(ModuleEnvironment.RevitVersion)
+ .SetProjectConfigName(nameof(PluginConfig) + ".json")
+ .Build();
+ }
+}
+
+internal class RevitSettings : ProjectSettings {
+ ///
+ /// Наименование проекта.
+ ///
+ public override string ProjectName { get; set; }
+
+ ///
+ /// Выбранная стадия проекта
+ ///
+ public ConfigSettings ConfigSettings { get; set; }
+}
+
+internal class SystemPluginConfig {
+ // Название стадии по умолчанию
+ public string DefaultPhaseName => "Основная планировка";
+
+ // Количество вариантов знаков по умолчанию
+ public int DefaultAccuracyRange => 3;
+
+ // Количество знаков по умолчанию
+ public int DefaultAccuracy => 1;
+
+ // Сторона округления
+ public MidpointRounding MidpointRounding => MidpointRounding.AwayFromZero;
+
+ // Системный параметр площади помещений по умолчанию
+ public BuiltInParameter SystemRoomAreaParamId => BuiltInParameter.ROOM_AREA;
+
+ // Общий параметр площади помещений по умолчанию
+ public RevitParam RoomAreaParam => SharedParamsConfig.Instance.RoomArea;
+}
diff --git a/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderAll.cs b/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderAll.cs
new file mode 100644
index 000000000..3939df5e7
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderAll.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+using Autodesk.Revit.DB;
+
+using RevitRoundingOfAreas.Models.Enums;
+using RevitRoundingOfAreas.Models.Interfaces;
+
+namespace RevitRoundingOfAreas.Models.Providers;
+
+internal class ElementsProviderAll(RevitRepository revitRepository) : IElementsProvider {
+ public ElementsProviderType Type => ElementsProviderType.AllElementsProvider;
+
+ public List GetSpatialElements(ElementId phaseId) {
+ return revitRepository.GetAllSpatialModels(phaseId);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderCurrentView.cs b/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderCurrentView.cs
new file mode 100644
index 000000000..4a473a248
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderCurrentView.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+using Autodesk.Revit.DB;
+
+using RevitRoundingOfAreas.Models.Enums;
+using RevitRoundingOfAreas.Models.Interfaces;
+
+namespace RevitRoundingOfAreas.Models.Providers;
+
+internal class ElementsProviderCurrentView(RevitRepository revitRepository) : IElementsProvider {
+ public ElementsProviderType Type => ElementsProviderType.CurrentViewProvider;
+
+ public List GetSpatialElements(ElementId phaseId) {
+ return revitRepository.GetActiveViewSpatialModels(phaseId);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderSelected.cs b/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderSelected.cs
new file mode 100644
index 000000000..83de7dc0f
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Providers/ElementsProviderSelected.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+using Autodesk.Revit.DB;
+
+using RevitRoundingOfAreas.Models.Enums;
+using RevitRoundingOfAreas.Models.Interfaces;
+
+namespace RevitRoundingOfAreas.Models.Providers;
+
+internal class ElementsProviderSelected(RevitRepository revitRepository) : IElementsProvider {
+ public ElementsProviderType Type => ElementsProviderType.SelectedElementsProvider;
+
+ public List GetSpatialElements(ElementId phaseId) {
+ return revitRepository.GetSelectedSpatialModels(phaseId);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Models/RevitRepository.cs b/src/RevitRoundingOfAreas/Models/RevitRepository.cs
new file mode 100644
index 000000000..66920121e
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/RevitRepository.cs
@@ -0,0 +1,198 @@
+using System;
+using System.Collections.Generic;
+
+using System.Linq;
+
+using Autodesk.Revit.ApplicationServices;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Architecture;
+using Autodesk.Revit.UI;
+
+using dosymep.Bim4Everyone;
+using dosymep.Revit;
+using dosymep.SimpleServices;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class RevitRepository(
+ UIApplication uiApplication,
+ ILocalizationService localizationService,
+ SystemPluginConfig systemPluginConfig) {
+ private UIApplication UiApplication { get; } = uiApplication;
+ private UIDocument ActiveUiDocument => UiApplication.ActiveUIDocument;
+ public Application Application => UiApplication.Application;
+ public Document Document => ActiveUiDocument.Document;
+
+ ///
+ /// Основной метод округления площадей
+ ///
+ public void RoundingOfAreas(List spatialModels, RevitParam sourceParam, RevitParam targetParam, int accuracy) {
+ foreach(var spatialModel in spatialModels) {
+ double sourceValue = spatialModel.SpatialElement.GetParamValueOrDefault(sourceParam);
+
+ if(sourceValue is 0) {
+ continue;
+ }
+
+ double roundedValue = RoundWithAccuracy(sourceValue, accuracy);
+
+ if(roundedValue is 0) {
+ continue;
+ }
+ spatialModel.SpatialElement.SetParamValue(targetParam, ConvertValueToInternalUnits(roundedValue));
+ }
+ }
+
+ ///
+ /// Метод получения всех помещений
+ ///
+ public List GetAllSpatialElements() {
+ return new FilteredElementCollector(Document)
+ .OfCategory(BuiltInCategory.OST_Rooms)
+ .WhereElementIsNotElementType()
+ .OfType()
+ .ToList();
+ }
+
+ ///
+ /// Метод получения всех помещений SpatialModel
+ ///
+ public List GetAllSpatialModels(ElementId phaseId) {
+ return GetAllSpatialElements()
+ .Where(spatial => ValidatePhase(spatial, phaseId))
+ .Select(CreateSpatialModel)
+ .ToList();
+ }
+
+ ///
+ /// Метод получения всех помещений SpatialModel на активном виде
+ ///
+ public List GetActiveViewSpatialModels(ElementId phaseId) {
+ return new FilteredElementCollector(Document, Document.ActiveView.Id)
+ .OfCategory(BuiltInCategory.OST_Rooms)
+ .WhereElementIsNotElementType()
+ .OfType()
+ .Where(spatial => ValidatePhase(spatial, phaseId))
+ .Select(CreateSpatialModel)
+ .ToList();
+ }
+
+ ///
+ /// Метод получения всех выделенных помещений SpatialModel
+ ///
+ public List GetSelectedSpatialModels(ElementId phaseId) {
+ return !HasSelectedRooms()
+ ? []
+ : GetSelectedElements()
+ .OfType()
+ .Where(spatial => ValidatePhase(spatial, phaseId))
+ .Select(CreateSpatialModel)
+ .ToList();
+ }
+
+ ///
+ /// Метод проверки, есть ли выделенные помещения
+ ///
+ public bool HasSelectedRooms() {
+ var selected = GetSelectedElements().ToArray();
+ return selected.Count() != 0
+ && selected.Any(element => element is Room);
+ }
+
+ ///
+ /// Метод проверки, есть ли помещения на активном виде
+ ///
+ public bool HasRoomsOnCurrentView() {
+ var viewId = Document.ActiveView.Id;
+
+ return new FilteredElementCollector(Document, viewId)
+ .OfCategory(BuiltInCategory.OST_Rooms)
+ .WhereElementIsNotElementType()
+ .Any();
+ }
+
+ ///
+ /// Метод выделения элементов в документе
+ ///
+ public void SetSelected(ElementId elementId) {
+ List listElements = [elementId];
+ ActiveUiDocument.SetSelectedElements(listElements);
+ }
+
+ ///
+ /// Метод получения стадий проекта
+ ///
+ public IEnumerable GetPhaseModels() {
+ var phases = Document.Phases;
+ return phases
+ .Cast()
+ .Select(phase => new PhaseModel {
+ ElementId = phase.Id,
+ Name = phase.Name
+ });
+ }
+
+ ///
+ /// Метод получения стадии по имени
+ ///
+ public ElementId GetPhaseIdByName(string name) {
+ return GetPhaseModels()
+ .FirstOrDefault(phase => phase != null && phase.Name == name)
+ ?.ElementId
+ ?? ElementId.InvalidElementId;
+ }
+
+ // Метод получения всех выделенных элементов модели
+ private IEnumerable GetSelectedElements() {
+ return ActiveUiDocument.GetSelectedElements();
+ }
+
+ // Создания объекта SpatialModel
+ private SpatialModel CreateSpatialModel(SpatialElement spatialElement) {
+ return new SpatialModel {
+ SpatialElement = spatialElement,
+ LevelName = GetLevelName(spatialElement)
+ };
+ }
+
+ // Получение уровня помещения
+ private string GetLevelName(SpatialElement spatialElement) {
+ if(spatialElement is null) {
+ localizationService.GetLocalizedString("RevitRepository.NoLevel");
+ }
+ var levelId = spatialElement?.LevelId;
+ if(levelId == ElementId.InvalidElementId) {
+ localizationService.GetLocalizedString("RevitRepository.NoLevel");
+ }
+ return Document.GetElement(levelId)?.Name
+ ?? localizationService.GetLocalizedString("RevitRepository.NoLevel");
+ }
+
+ // Метод валидации стадии
+ private bool ValidatePhase(SpatialElement spatialElement, ElementId phaseId) {
+ var spatialPhaseId = spatialElement.GetParamValueOrDefault(
+ BuiltInParameter.ROOM_PHASE,
+ ElementId.InvalidElementId);
+ return spatialPhaseId != ElementId.InvalidElementId && spatialPhaseId == phaseId;
+ }
+
+ // Метод округления числа с заданной точкой после запятой
+ private double RoundWithAccuracy(double? value, int accuracy) {
+ return value.HasValue
+ ? Math.Round(
+ ConvertValueFromInternalUnits(value.Value),
+ accuracy,
+ systemPluginConfig.MidpointRounding)
+ : 0;
+ }
+
+ // Метод конвертации в миллиметры
+ private double ConvertValueFromInternalUnits(double value) {
+ return UnitUtils.ConvertFromInternalUnits(value, UnitTypeId.SquareMeters);
+ }
+
+ // Метод конвертации в футы
+ private double ConvertValueToInternalUnits(double value) {
+ return UnitUtils.ConvertToInternalUnits(value, UnitTypeId.SquareMeters);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Models/SpatialElementCheckService.cs b/src/RevitRoundingOfAreas/Models/SpatialElementCheckService.cs
new file mode 100644
index 000000000..f52329a0e
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/SpatialElementCheckService.cs
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+
+using Autodesk.Revit.DB.Architecture;
+
+using dosymep.Revit;
+
+using RevitRoundingOfAreas.Models.Enums;
+using RevitRoundingOfAreas.Models.Warnings;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class SpatialElementCheckService {
+
+ public IReadOnlyCollection CheckSpatialElements(List spatialModels) {
+ if(spatialModels.Count == 0) {
+ return [];
+ }
+ List warnings = [];
+ foreach(var spatialModel in spatialModels) {
+ var room = spatialModel.SpatialElement as Room;
+ if(room.IsRedundant()) {
+ warnings.Add(new WarningRedundantElement {
+ WarningType = WarningType.Redundant,
+ SpatialModel = spatialModel
+ });
+ } else if(room.IsNotEnclosed()) {
+ warnings.Add(new WarningNotEnclosedElement {
+ WarningType = WarningType.NotEnclosed,
+ SpatialModel = spatialModel
+ });
+ }
+ }
+ return warnings;
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Models/SpatialModel.cs b/src/RevitRoundingOfAreas/Models/SpatialModel.cs
new file mode 100644
index 000000000..83df94209
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/SpatialModel.cs
@@ -0,0 +1,8 @@
+using Autodesk.Revit.DB;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class SpatialModel {
+ public SpatialElement SpatialElement { get; set; }
+ public string LevelName { get; set; }
+}
diff --git a/src/RevitRoundingOfAreas/Models/Warnings/WarningElement.cs b/src/RevitRoundingOfAreas/Models/Warnings/WarningElement.cs
new file mode 100644
index 000000000..2e1e63e73
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Warnings/WarningElement.cs
@@ -0,0 +1,8 @@
+using RevitRoundingOfAreas.Models.Enums;
+
+namespace RevitRoundingOfAreas.Models.Warnings;
+
+internal class WarningElement {
+ public WarningType WarningType { get; set; }
+ public SpatialModel SpatialModel { get; set; }
+}
diff --git a/src/RevitRoundingOfAreas/Models/Warnings/WarningNotEnclosedElement.cs b/src/RevitRoundingOfAreas/Models/Warnings/WarningNotEnclosedElement.cs
new file mode 100644
index 000000000..53e68696c
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Warnings/WarningNotEnclosedElement.cs
@@ -0,0 +1,3 @@
+namespace RevitRoundingOfAreas.Models.Warnings;
+internal class WarningNotEnclosedElement : WarningElement {
+}
diff --git a/src/RevitRoundingOfAreas/Models/Warnings/WarningRedundantElement.cs b/src/RevitRoundingOfAreas/Models/Warnings/WarningRedundantElement.cs
new file mode 100644
index 000000000..afbabf923
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/Warnings/WarningRedundantElement.cs
@@ -0,0 +1,3 @@
+namespace RevitRoundingOfAreas.Models.Warnings;
+internal class WarningRedundantElement : WarningElement {
+}
diff --git a/src/RevitRoundingOfAreas/Models/WindowService.cs b/src/RevitRoundingOfAreas/Models/WindowService.cs
new file mode 100644
index 000000000..71d93f80e
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Models/WindowService.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+
+using Ninject;
+using Ninject.Syntax;
+
+using RevitRoundingOfAreas.Models.Interfaces;
+using RevitRoundingOfAreas.Models.Warnings;
+using RevitRoundingOfAreas.ViewModels.Warnings;
+using RevitRoundingOfAreas.Views;
+
+namespace RevitRoundingOfAreas.Models;
+
+internal class WindowService(IResolutionRoot resolutionRoot) : IWindowService {
+ public void CloseMainWindow() {
+ var mainWindow = resolutionRoot.Get();
+ mainWindow.Close();
+ }
+
+ public void ShowWarningWindow(IReadOnlyCollection warningElements) {
+ var warningViewModel = resolutionRoot.Get();
+ warningViewModel.WarningElementsCollection = warningElements;
+ var warningsWindow = resolutionRoot.Get();
+ warningsWindow.DataContext = warningViewModel;
+ warningViewModel.LoadView();
+ warningsWindow.Show();
+ }
+}
diff --git a/src/RevitRoundingOfAreas/README.md b/src/RevitRoundingOfAreas/README.md
new file mode 100644
index 000000000..11648ab3a
--- /dev/null
+++ b/src/RevitRoundingOfAreas/README.md
@@ -0,0 +1,12 @@
+# RevitRoundingOfAreas (Рассчитать площади (соц. объекты))
+Плагин для автоматического округления системной площади в текстовый параметр. Для социальных объектов
+
+# Сборка проекта
+```
+nuke compile --profile RevitRoundingOfAreas
+```
+
+# Публикация проекта
+```
+nuke publish --profile RevitRoundingOfAreas
+```
diff --git a/src/RevitRoundingOfAreas/RevitRoundingOfAreas.csproj b/src/RevitRoundingOfAreas/RevitRoundingOfAreas.csproj
new file mode 100644
index 000000000..ae3efaefb
--- /dev/null
+++ b/src/RevitRoundingOfAreas/RevitRoundingOfAreas.csproj
@@ -0,0 +1,6 @@
+
+
+ true
+ 12
+
+
diff --git a/src/RevitRoundingOfAreas/RevitRoundingOfAreasCommand.cs b/src/RevitRoundingOfAreas/RevitRoundingOfAreasCommand.cs
new file mode 100644
index 000000000..8b2804789
--- /dev/null
+++ b/src/RevitRoundingOfAreas/RevitRoundingOfAreasCommand.cs
@@ -0,0 +1,127 @@
+using System;
+using System.Globalization;
+using System.Reflection;
+using System.Windows;
+
+
+using Autodesk.Revit.Attributes;
+using Autodesk.Revit.UI;
+
+using dosymep.Bim4Everyone;
+using dosymep.Bim4Everyone.ProjectConfigs;
+using dosymep.Bim4Everyone.SimpleServices;
+using dosymep.SimpleServices;
+using dosymep.WpfCore.Ninject;
+using dosymep.WpfUI.Core.Ninject;
+
+using Ninject;
+
+using RevitRoundingOfAreas.Models;
+using RevitRoundingOfAreas.Models.Interfaces;
+using RevitRoundingOfAreas.ViewModels;
+using RevitRoundingOfAreas.ViewModels.Warnings;
+using RevitRoundingOfAreas.Views;
+
+namespace RevitRoundingOfAreas;
+
+///
+/// Класс команды Revit плагина.
+///
+///
+/// В данном классе должна быть инициализация контейнера плагина и указание названия команды.
+///
+[Transaction(TransactionMode.Manual)]
+public class RevitRoundingOfAreasCommand : BasePluginCommand {
+ ///
+ /// Инициализирует команду плагина.
+ ///
+ public RevitRoundingOfAreasCommand() {
+ PluginName = "Рассчитать площади (соц. объекты)";
+ }
+
+ ///
+ /// Метод выполнения основного кода плагина.
+ ///
+ /// Интерфейс взаимодействия с Revit.
+ ///
+ /// В случаях, когда не используется конфигурация
+ /// или локализация, требуется удалять их использование полностью во всем проекте.
+ ///
+ protected override void Execute(UIApplication uiApplication) {
+ // Создание контейнера зависимостей плагина с сервисами из платформы
+ using var kernel = uiApplication.CreatePlatformServices();
+
+ // Создание системных настроек
+ kernel.Bind()
+ .ToSelf()
+ .InSingletonScope();
+
+ // Настройка доступа к Revit
+ kernel.Bind()
+ .ToSelf()
+ .InSingletonScope();
+
+ // Настройка доступа к классу параметров
+ kernel.Bind()
+ .ToSelf()
+ .InSingletonScope();
+
+ // Настройка доступа к классу проверок
+ kernel.Bind()
+ .ToSelf()
+ .InSingletonScope();
+
+ // Настройка доступа к сервису по управлению окнами
+ kernel.Bind()
+ .To()
+ .InSingletonScope();
+
+ // Настройка конфигурации плагина
+ kernel.Bind()
+ .ToMethod(c => PluginConfig.GetPluginConfig(c.Kernel.Get()));
+
+ // Настройка сервиса окошек сообщений
+ kernel.UseWpfUIMessageBox();
+
+ // Используем сервис обновления тем для WinUI
+ kernel.UseWpfUIThemeUpdater();
+
+ // Настройка запуска окна
+ kernel.BindMainWindow();
+
+ // Настройка запуска окна предупреждений
+ kernel.BindOtherWindow();
+
+ // Настройка локализации,
+ // получение имени сборки откуда брать текст
+ string assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
+
+ // Настройка локализации,
+ // установка дефолтной локализации "ru-RU"
+ kernel.UseWpfLocalization(
+ $"/{assemblyName};component/assets/localization/language.xaml",
+ CultureInfo.GetCultureInfo("ru-RU"));
+
+ var messageBoxService = kernel.Get();
+ var localizationService = kernel.Get();
+ var systemPluginConfig = kernel.Get();
+
+ // Загрузка параметров проекта
+ bool isParamChecked = new CheckProjectParams(
+ systemPluginConfig, uiApplication.Application, uiApplication.ActiveUIDocument.Document)
+ .CopyProjectParams()
+ .GetIsChecked();
+
+ if(!isParamChecked) {
+ messageBoxService.Show(
+ localizationService.GetLocalizedString("Common.ParamErrorMessageBody"),
+ localizationService.GetLocalizedString("Common.ConfigErrorMessageTitle"),
+ MessageBoxButton.OK,
+ MessageBoxImage.Exclamation);
+ throw new OperationCanceledException();
+ }
+
+ // Вызывает стандартное уведомление
+ Notification(kernel.Get());
+ }
+}
diff --git a/src/RevitRoundingOfAreas/ViewModels/AccuracyViewModel.cs b/src/RevitRoundingOfAreas/ViewModels/AccuracyViewModel.cs
new file mode 100644
index 000000000..c9743e561
--- /dev/null
+++ b/src/RevitRoundingOfAreas/ViewModels/AccuracyViewModel.cs
@@ -0,0 +1,14 @@
+using dosymep.WPF.ViewModels;
+
+namespace RevitRoundingOfAreas.ViewModels;
+
+internal class AccuracyViewModel : BaseViewModel {
+ private string _name;
+
+ public int Accuracy { get; set; }
+
+ public string Name {
+ get => _name;
+ set => RaiseAndSetIfChanged(ref _name, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/ViewModels/MainViewModel.cs b/src/RevitRoundingOfAreas/ViewModels/MainViewModel.cs
new file mode 100644
index 000000000..12c9c8d05
--- /dev/null
+++ b/src/RevitRoundingOfAreas/ViewModels/MainViewModel.cs
@@ -0,0 +1,278 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows.Input;
+
+using Autodesk.Revit.DB;
+
+using dosymep.Revit;
+using dosymep.SimpleServices;
+using dosymep.WPF.Commands;
+using dosymep.WPF.ViewModels;
+
+using RevitRoundingOfAreas.Models;
+using RevitRoundingOfAreas.Models.Enums;
+using RevitRoundingOfAreas.Models.Factories;
+using RevitRoundingOfAreas.Models.Interfaces;
+
+namespace RevitRoundingOfAreas.ViewModels;
+
+internal class MainViewModel : BaseViewModel {
+ private readonly PluginConfig _pluginConfig;
+ private readonly SystemPluginConfig _systemPluginConfig;
+ private readonly RevitRepository _revitRepository;
+ private readonly ParamService _paramService;
+ private readonly ProvidersFactory _providersFactory;
+ private readonly SpatialElementCheckService _spatialElementCheckService;
+ private readonly IWindowService _windowService;
+ private readonly ILocalizationService _localizationService;
+ private ConfigSettings _configSettings;
+ private ObservableCollection _range;
+ private RangeViewModel _selectedRange;
+ private ObservableCollection _phases;
+ private PhaseViewModel _selectedPhase;
+ private ObservableCollection _sourceParams;
+ private ParamViewModel _selectedSourceParam;
+ private ObservableCollection _targetParams;
+ private ParamViewModel _selectedTargetParam;
+ private ObservableCollection _accuracy;
+ private AccuracyViewModel _selectedAccuracy;
+ private string _errorText;
+
+ public MainViewModel(
+ PluginConfig pluginConfig,
+ SystemPluginConfig systemPluginConfig,
+ RevitRepository revitRepository,
+ ParamService paramService,
+ ProvidersFactory providersFactory,
+ ILocalizationService localizationService,
+ IWindowService windowService,
+ SpatialElementCheckService spatialElementCheckService) {
+
+ _pluginConfig = pluginConfig;
+ _systemPluginConfig = systemPluginConfig;
+ _revitRepository = revitRepository;
+ _paramService = paramService;
+ _providersFactory = providersFactory;
+ _localizationService = localizationService;
+ _windowService = windowService;
+ _spatialElementCheckService = spatialElementCheckService;
+
+ LoadViewCommand = RelayCommand.Create(LoadView);
+ AcceptViewCommand = RelayCommand.Create(AcceptView, CanAcceptView);
+ }
+
+ public ICommand LoadViewCommand { get; }
+ public ICommand AcceptViewCommand { get; }
+
+
+ public ObservableCollection Range {
+ get => _range;
+ set => RaiseAndSetIfChanged(ref _range, value);
+ }
+ public RangeViewModel SelectedRange {
+ get => _selectedRange;
+ set => RaiseAndSetIfChanged(ref _selectedRange, value);
+ }
+ public ObservableCollection Phases {
+ get => _phases;
+ set => RaiseAndSetIfChanged(ref _phases, value);
+ }
+ public PhaseViewModel SelectedPhase {
+ get => _selectedPhase;
+ set => RaiseAndSetIfChanged(ref _selectedPhase, value);
+ }
+ public ObservableCollection SourceParams {
+ get => _sourceParams;
+ set => RaiseAndSetIfChanged(ref _sourceParams, value);
+ }
+ public ParamViewModel SelectedSourceParam {
+ get => _selectedSourceParam;
+ set => RaiseAndSetIfChanged(ref _selectedSourceParam, value);
+ }
+ public ObservableCollection TargetParams {
+ get => _targetParams;
+ set => RaiseAndSetIfChanged(ref _targetParams, value);
+ }
+ public ParamViewModel SelectedTargetParam {
+ get => _selectedTargetParam;
+ set => RaiseAndSetIfChanged(ref _selectedTargetParam, value);
+ }
+ public ObservableCollection Accuracy {
+ get => _accuracy;
+ set => RaiseAndSetIfChanged(ref _accuracy, value);
+ }
+ public AccuracyViewModel SelectedAccuracy {
+ get => _selectedAccuracy;
+ set => RaiseAndSetIfChanged(ref _selectedAccuracy, value);
+ }
+ public string ErrorText {
+ get => _errorText;
+ set => RaiseAndSetIfChanged(ref _errorText, value);
+ }
+
+ // Метод получения коллекции AccuracyViewModel для Accuracy
+ private IEnumerable GetAccuracyViewModels() {
+ for(int i = 1; i <= _systemPluginConfig.DefaultAccuracyRange; i++) {
+ yield return new AccuracyViewModel {
+ Accuracy = i,
+ Name = i.ToString(),
+ };
+ }
+ }
+
+ // Метод получения коллекции ParamViewModel для SourceParams
+ private IEnumerable GetSourceParamViewModels() {
+ return _paramService.AllRevitParams
+ .Select(param => new ParamViewModel {
+ Name = param.Name,
+ RevitParam = param
+ });
+ }
+
+ // Метод получения коллекции ParamViewModel для TargetParams
+ private IEnumerable GetTargetParamViewModels() {
+ return _paramService.AllRevitParams
+ .Where(revitParam => {
+ var spatialElements = _revitRepository.GetAllSpatialElements();
+ var randomSpatialElement = spatialElements.FirstOrDefault();
+ if(randomSpatialElement is null) {
+ return false;
+ }
+ var param = revitParam.GetParam(randomSpatialElement);
+ return !param.IsReadOnly;
+ })
+ .Select(param => new ParamViewModel {
+ Name = param.Name,
+ RevitParam = param
+ });
+ }
+
+ // Метод получения коллекции PhaseViewModel для Phases
+ private IEnumerable GetPhaseViewModels() {
+ return _revitRepository.GetPhaseModels()
+ .Select(phase => new PhaseViewModel {
+ Name = phase.Name,
+ ElementId = phase.ElementId
+ });
+ }
+
+ // Метод получения коллекции RangeElementsViewModel для RangeElements
+ private IEnumerable GetRangeViewModels() {
+ var providers = Enum.GetValues(typeof(ElementsProviderType)).Cast();
+ return providers
+ .Select(provider => new RangeViewModel {
+ Name = _localizationService.GetLocalizedString($"MainViewModel.{provider}"),
+ ElementsProvider = _providersFactory.GetElementsProvider(provider)
+ });
+ }
+
+ private void LoadView() {
+ LoadConfig();
+
+ Range = new ObservableCollection(GetRangeViewModels());
+ SelectedRange = ResolveDefaultRange() ?? Range.FirstOrDefault();
+
+ Phases = new ObservableCollection(GetPhaseViewModels());
+ SelectedPhase = Phases
+ .FirstOrDefault(phase => phase.ElementId == _configSettings.SelectedPhaseId)
+ ?? Phases.LastOrDefault();
+
+ SourceParams = new ObservableCollection(GetSourceParamViewModels());
+ SelectedSourceParam = SourceParams
+ .FirstOrDefault(param => param.RevitParam.Id == _configSettings.SourceParam?.Id)
+ ?? SourceParams.FirstOrDefault();
+
+ TargetParams = new ObservableCollection(GetTargetParamViewModels());
+ SelectedTargetParam = TargetParams
+ .FirstOrDefault(param => param.RevitParam.Id == _configSettings.TargetParam?.Id)
+ ?? TargetParams.FirstOrDefault();
+
+ Accuracy = new ObservableCollection(GetAccuracyViewModels());
+ SelectedAccuracy = Accuracy
+ .FirstOrDefault(accuracy => accuracy.Accuracy == _configSettings.Accuracy)
+ ?? Accuracy.FirstOrDefault();
+ }
+
+ private RangeViewModel ResolveDefaultRange() {
+ return _revitRepository.HasSelectedRooms()
+ ? Range.FirstOrDefault(x => x.ElementsProvider.Type == ElementsProviderType.SelectedElementsProvider)
+ : _revitRepository.HasRoomsOnCurrentView()
+ ? Range.FirstOrDefault(x => x.ElementsProvider.Type == ElementsProviderType.CurrentViewProvider)
+ : Range.FirstOrDefault(x => x.ElementsProvider.Type == ElementsProviderType.AllElementsProvider);
+ }
+
+ private void AcceptView() {
+ SaveConfig();
+ var spatialElements = SelectedRange.ElementsProvider.GetSpatialElements(SelectedPhase.ElementId);
+ var warnings = _spatialElementCheckService.CheckSpatialElements(spatialElements);
+
+ if(warnings.Count != 0) {
+ _windowService.CloseMainWindow();
+ _windowService.ShowWarningWindow(warnings);
+ return;
+ }
+
+ string transactionName = _localizationService.GetLocalizedString("MainViewModel.TransactionName");
+ using var t = _revitRepository.Document.StartTransaction(transactionName);
+ _revitRepository.RoundingOfAreas(
+ spatialElements,
+ SelectedSourceParam.RevitParam,
+ SelectedTargetParam.RevitParam,
+ SelectedAccuracy.Accuracy
+ );
+ t.Commit();
+ }
+
+ private bool CanAcceptView() {
+ if(SelectedRange != null) {
+ if(SelectedRange.ElementsProvider.Type == ElementsProviderType.SelectedElementsProvider
+ && !_revitRepository.HasSelectedRooms()) {
+ ErrorText = _localizationService.GetLocalizedString("MainViewModel.NoSelection");
+ return false;
+ }
+ if(SelectedRange.ElementsProvider.Type == ElementsProviderType.CurrentViewProvider
+ && !_revitRepository.HasRoomsOnCurrentView()) {
+ ErrorText = _localizationService.GetLocalizedString("MainViewModel.NoRoomsOnView");
+ return false;
+ }
+ }
+ ErrorText = null;
+ return true;
+ }
+
+ private void LoadConfig() {
+ var setting = _pluginConfig.GetSettings(_revitRepository.Document);
+ _configSettings = setting?.ConfigSettings ?? new ConfigSettings();
+ ApplyDefaultsConfig();
+ }
+
+ // Метод применения дефолтных значений настроек.
+ private void ApplyDefaultsConfig() {
+ if(_configSettings.SelectedPhaseId is null || _configSettings.SelectedPhaseId == ElementId.InvalidElementId) {
+ _configSettings.SelectedPhaseId = _revitRepository.GetPhaseIdByName(_systemPluginConfig.DefaultPhaseName);
+ }
+
+ _configSettings.SourceParam ??= _paramService.DefaultSourceParam;
+ _configSettings.TargetParam ??= _paramService.DefaultTargetParam;
+
+ if(_configSettings.Accuracy <= 0) {
+ _configSettings.Accuracy = _systemPluginConfig.DefaultAccuracy;
+ }
+ }
+
+ private void SaveConfig() {
+ var setting = _pluginConfig.GetSettings(_revitRepository.Document)
+ ?? _pluginConfig.AddSettings(_revitRepository.Document);
+
+ setting.ConfigSettings = new ConfigSettings {
+ SelectedPhaseId = SelectedPhase?.ElementId ?? ElementId.InvalidElementId,
+ SourceParam = SelectedSourceParam?.RevitParam,
+ TargetParam = SelectedTargetParam?.RevitParam,
+ Accuracy = SelectedAccuracy?.Accuracy ?? _systemPluginConfig.DefaultAccuracy
+ };
+
+ _pluginConfig.SaveProjectConfig();
+ }
+}
diff --git a/src/RevitRoundingOfAreas/ViewModels/ParamViewModel.cs b/src/RevitRoundingOfAreas/ViewModels/ParamViewModel.cs
new file mode 100644
index 000000000..bf4d2f9f4
--- /dev/null
+++ b/src/RevitRoundingOfAreas/ViewModels/ParamViewModel.cs
@@ -0,0 +1,15 @@
+using dosymep.Bim4Everyone;
+using dosymep.WPF.ViewModels;
+
+namespace RevitRoundingOfAreas.ViewModels;
+
+internal class ParamViewModel : BaseViewModel {
+ private string _name;
+
+ public RevitParam RevitParam { get; set; }
+
+ public string Name {
+ get => _name;
+ set => RaiseAndSetIfChanged(ref _name, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/ViewModels/PhaseViewModel.cs b/src/RevitRoundingOfAreas/ViewModels/PhaseViewModel.cs
new file mode 100644
index 000000000..3bee7900d
--- /dev/null
+++ b/src/RevitRoundingOfAreas/ViewModels/PhaseViewModel.cs
@@ -0,0 +1,16 @@
+using Autodesk.Revit.DB;
+
+using dosymep.WPF.ViewModels;
+
+namespace RevitRoundingOfAreas.ViewModels;
+
+internal class PhaseViewModel : BaseViewModel {
+ private string _name;
+
+ public ElementId ElementId { get; set; }
+
+ public string Name {
+ get => _name;
+ set => RaiseAndSetIfChanged(ref _name, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/ViewModels/RangeViewModel.cs b/src/RevitRoundingOfAreas/ViewModels/RangeViewModel.cs
new file mode 100644
index 000000000..2c076ce3e
--- /dev/null
+++ b/src/RevitRoundingOfAreas/ViewModels/RangeViewModel.cs
@@ -0,0 +1,17 @@
+using dosymep.WPF.ViewModels;
+
+using RevitRoundingOfAreas.Models.Interfaces;
+
+namespace RevitRoundingOfAreas.ViewModels;
+
+internal class RangeViewModel : BaseViewModel {
+
+ private string _name;
+
+ public IElementsProvider ElementsProvider { get; set; }
+
+ public string Name {
+ get => _name;
+ set => RaiseAndSetIfChanged(ref _name, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningElementViewModel.cs b/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningElementViewModel.cs
new file mode 100644
index 000000000..a9377cb21
--- /dev/null
+++ b/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningElementViewModel.cs
@@ -0,0 +1,36 @@
+using System.Windows.Input;
+
+using Autodesk.Revit.DB;
+
+using dosymep.WPF.ViewModels;
+
+using RevitRoundingOfAreas.Models;
+
+namespace RevitRoundingOfAreas.ViewModels.Warnings;
+
+internal class WarningElementViewModel : BaseViewModel {
+ private ElementId _elementId;
+ private string _name;
+ private string _levelName;
+
+ public WarningElementViewModel(SpatialModel spatialModel) {
+ Name = spatialModel.SpatialElement.Name;
+ LevelName = spatialModel.LevelName;
+ ElementId = spatialModel.SpatialElement.Id;
+ }
+
+ public ICommand ShowElementCommand { get; set; }
+
+ public string Name {
+ get => _name;
+ set => RaiseAndSetIfChanged(ref _name, value);
+ }
+ public string LevelName {
+ get => _levelName;
+ set => RaiseAndSetIfChanged(ref _levelName, value);
+ }
+ public ElementId ElementId {
+ get => _elementId;
+ set => RaiseAndSetIfChanged(ref _elementId, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningGroupViewModel.cs b/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningGroupViewModel.cs
new file mode 100644
index 000000000..97fbc55f2
--- /dev/null
+++ b/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningGroupViewModel.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows.Input;
+
+using dosymep.WPF.ViewModels;
+
+using RevitRoundingOfAreas.Models.Warnings;
+
+namespace RevitRoundingOfAreas.ViewModels.Warnings;
+
+internal class WarningGroupViewModel : BaseViewModel {
+ private ObservableCollection _warnings;
+ private string _caption;
+ private string _description;
+ private string _warningQuantity;
+
+ public IReadOnlyCollection WarningElements { get; set; } = [];
+ public ICommand ShowElementCommand { get; set; }
+
+ public ObservableCollection Warnings {
+ get => _warnings;
+ set => RaiseAndSetIfChanged(ref _warnings, value);
+ }
+ public string Caption {
+ get => _caption;
+ set => RaiseAndSetIfChanged(ref _caption, value);
+ }
+ public string Description {
+ get => _description;
+ set => RaiseAndSetIfChanged(ref _description, value);
+ }
+ public string WarningQuantity {
+ get => _warningQuantity;
+ set => RaiseAndSetIfChanged(ref _warningQuantity, value);
+ }
+
+ ///
+ /// Метод загрузки окна
+ ///
+ public void LoadView() {
+ Warnings = new(GetWarningElementViewModel());
+ }
+
+ // Метод получения списка WarningElementViewModel
+ private IEnumerable GetWarningElementViewModel() {
+ return WarningElements
+ .Select(warningElement => new WarningElementViewModel(warningElement.SpatialModel) {
+ ShowElementCommand = ShowElementCommand
+ });
+ }
+}
diff --git a/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningsViewModel.cs b/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningsViewModel.cs
new file mode 100644
index 000000000..7f9750181
--- /dev/null
+++ b/src/RevitRoundingOfAreas/ViewModels/Warnings/WarningsViewModel.cs
@@ -0,0 +1,72 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows.Input;
+
+using Autodesk.Revit.DB;
+
+using dosymep.SimpleServices;
+using dosymep.WPF.Commands;
+using dosymep.WPF.ViewModels;
+
+using RevitRoundingOfAreas.Models;
+using RevitRoundingOfAreas.Models.Warnings;
+
+namespace RevitRoundingOfAreas.ViewModels.Warnings;
+internal class WarningsViewModel : BaseViewModel {
+ private readonly ILocalizationService _localizationService;
+ private readonly RevitRepository _revitRepository;
+ private ObservableCollection _warningViewModels;
+ private string _warningQuantity;
+
+ public WarningsViewModel(ILocalizationService localizationService, RevitRepository revitRepository) {
+ _localizationService = localizationService;
+ _revitRepository = revitRepository;
+
+ ShowElementCommand = RelayCommand.Create(ShowElement);
+ }
+
+ public ICommand ShowElementCommand { get; }
+ public IReadOnlyCollection WarningElementsCollection { get; set; }
+
+ public ObservableCollection WarningViewModels {
+ get => _warningViewModels;
+ set => RaiseAndSetIfChanged(ref _warningViewModels, value);
+ }
+ public string WarningQuantity {
+ get => _warningQuantity;
+ set => RaiseAndSetIfChanged(ref _warningQuantity, value);
+ }
+
+ ///
+ /// Метод загрузки окна
+ ///
+ public void LoadView() {
+ WarningViewModels = new ObservableCollection(GetWarningGroupViewModels());
+ WarningQuantity = WarningViewModels.Count.ToString();
+ }
+
+ // Метод выделения элемента
+ private void ShowElement(ElementId elementId) {
+ _revitRepository.SetSelected(elementId);
+ }
+
+ // Метод формирования списка WarningGroupViewModel
+ private IEnumerable GetWarningGroupViewModels() {
+ var regularGroups = WarningElementsCollection
+ .GroupBy(w => w.WarningType)
+ .Select(group => {
+ var vm = new WarningGroupViewModel {
+ Caption = _localizationService.GetLocalizedString($"WarningsViewModel.{group.Key}"),
+ Description = _localizationService.GetLocalizedString($"WarningsViewModel.{group.Key}Description"),
+ WarningElements = group.ToList(),
+ WarningQuantity = group.Count().ToString(),
+ ShowElementCommand = ShowElementCommand
+ };
+ vm.LoadView();
+ return vm;
+ });
+
+ return regularGroups;
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Views/Edits/CustomEditControl.xaml b/src/RevitRoundingOfAreas/Views/Edits/CustomEditControl.xaml
new file mode 100644
index 000000000..801d9a3d9
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Edits/CustomEditControl.xaml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/RevitRoundingOfAreas/Views/Edits/CustomEditControl.xaml.cs b/src/RevitRoundingOfAreas/Views/Edits/CustomEditControl.xaml.cs
new file mode 100644
index 000000000..e4275cfa5
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Edits/CustomEditControl.xaml.cs
@@ -0,0 +1,47 @@
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Markup;
+
+using Wpf.Ui.Controls;
+
+namespace RevitRoundingOfAreas.Views.Edits;
+
+[DefaultProperty(nameof(EditControl))]
+[ContentProperty(nameof(EditControl))]
+public partial class CustomEditControl {
+ public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
+ nameof(Icon), typeof(IconElement), typeof(CustomEditControl), new PropertyMetadata(default(IconElement)));
+
+ public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
+ nameof(Header), typeof(string), typeof(CustomEditControl), new PropertyMetadata(default(string)));
+
+ public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
+ nameof(Description), typeof(string), typeof(CustomEditControl), new PropertyMetadata(default(string)));
+
+ public static readonly DependencyProperty EditControlProperty = DependencyProperty.Register(
+ nameof(EditControl), typeof(object), typeof(CustomEditControl), new PropertyMetadata(default(object)));
+
+ public CustomEditControl() {
+ InitializeComponent();
+ }
+
+ public IconElement Icon {
+ get => (IconElement) GetValue(IconProperty);
+ set => SetValue(IconProperty, value);
+ }
+
+ public string Header {
+ get => (string) GetValue(HeaderProperty);
+ set => SetValue(HeaderProperty, value);
+ }
+
+ public string Description {
+ get => (string) GetValue(DescriptionProperty);
+ set => SetValue(DescriptionProperty, value);
+ }
+
+ public object EditControl {
+ get => GetValue(EditControlProperty);
+ set => SetValue(EditControlProperty, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Views/Edits/CustomGroupEditControl.xaml b/src/RevitRoundingOfAreas/Views/Edits/CustomGroupEditControl.xaml
new file mode 100644
index 000000000..2d408dc76
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Edits/CustomGroupEditControl.xaml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/RevitRoundingOfAreas/Views/Edits/CustomGroupEditControl.xaml.cs b/src/RevitRoundingOfAreas/Views/Edits/CustomGroupEditControl.xaml.cs
new file mode 100644
index 000000000..48d3a00fe
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Edits/CustomGroupEditControl.xaml.cs
@@ -0,0 +1,112 @@
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Markup;
+
+using Wpf.Ui.Controls;
+
+namespace RevitRoundingOfAreas.Views.Edits;
+
+[DefaultProperty(nameof(EditControl))]
+[ContentProperty(nameof(EditControl))]
+public partial class CustomGroupEditControl {
+ public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
+ nameof(Icon), typeof(IconElement), typeof(CustomGroupEditControl), new PropertyMetadata(default(IconElement)));
+
+ public static readonly DependencyProperty ExtraIconProperty = DependencyProperty.Register(
+ nameof(ExtraIcon), typeof(IconElement), typeof(CustomGroupEditControl), new PropertyMetadata(default(IconElement)));
+
+ public static readonly DependencyProperty ExtraTextProperty = DependencyProperty.Register(
+ nameof(ExtraText), typeof(string), typeof(CustomGroupEditControl), new PropertyMetadata(default(string)));
+
+ public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
+ nameof(Header), typeof(string), typeof(CustomGroupEditControl), new PropertyMetadata(default(string)));
+
+ public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
+ nameof(Description), typeof(string), typeof(CustomGroupEditControl), new PropertyMetadata(default(string)));
+
+ public static readonly DependencyProperty EditControlProperty = DependencyProperty.Register(
+ nameof(EditControl), typeof(object), typeof(CustomGroupEditControl), new PropertyMetadata(default(object)));
+
+ public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
+ nameof(IsChecked), typeof(bool), typeof(CustomGroupEditControl), new PropertyMetadata(true));
+
+ public static readonly DependencyProperty ToggleSwitchVisibleProperty = DependencyProperty.Register(
+ nameof(ToggleSwitchVisible), typeof(bool), typeof(CustomGroupEditControl), new PropertyMetadata(false));
+
+ public static readonly DependencyProperty ExtraIconVisibleProperty = DependencyProperty.Register(
+ nameof(ExtraIconVisible), typeof(bool), typeof(CustomGroupEditControl), new PropertyMetadata(false));
+
+ public static readonly DependencyProperty ExtraTextVisibleProperty = DependencyProperty.Register(
+ nameof(ExtraTextVisible), typeof(bool), typeof(CustomGroupEditControl), new PropertyMetadata(false));
+
+ public static readonly DependencyProperty SwitchOnContentProperty = DependencyProperty.Register(
+ nameof(SwitchOnContent), typeof(string), typeof(CustomGroupEditControl), new PropertyMetadata(default(string)));
+
+ public static readonly DependencyProperty SwitchOffContentProperty = DependencyProperty.Register(
+ nameof(SwitchOffContent), typeof(string), typeof(CustomGroupEditControl), new PropertyMetadata(default(string)));
+
+
+ public CustomGroupEditControl() {
+ InitializeComponent();
+ }
+
+ public IconElement Icon {
+ get => (IconElement) GetValue(IconProperty);
+ set => SetValue(IconProperty, value);
+ }
+
+ public IconElement ExtraIcon {
+ get => (IconElement) GetValue(ExtraIconProperty);
+ set => SetValue(ExtraIconProperty, value);
+ }
+
+ public string ExtraText {
+ get => (string) GetValue(ExtraTextProperty);
+ set => SetValue(ExtraIconProperty, value);
+ }
+
+ public string Header {
+ get => (string) GetValue(HeaderProperty);
+ set => SetValue(HeaderProperty, value);
+ }
+
+ public string Description {
+ get => (string) GetValue(DescriptionProperty);
+ set => SetValue(DescriptionProperty, value);
+ }
+
+ public object EditControl {
+ get => GetValue(EditControlProperty);
+ set => SetValue(EditControlProperty, value);
+ }
+
+ public bool IsChecked {
+ get => (bool) GetValue(IsCheckedProperty);
+ set => SetValue(IsCheckedProperty, value);
+ }
+
+ public bool ToggleSwitchVisible {
+ get => (bool) GetValue(ToggleSwitchVisibleProperty);
+ set => SetValue(ToggleSwitchVisibleProperty, value);
+ }
+
+ public string SwitchOnContent {
+ get => (string) GetValue(SwitchOnContentProperty);
+ set => SetValue(SwitchOnContentProperty, value);
+ }
+
+ public string SwitchOffContent {
+ get => (string) GetValue(SwitchOffContentProperty);
+ set => SetValue(SwitchOffContentProperty, value);
+ }
+
+ public bool ExtraIconVisible {
+ get => (bool) GetValue(ExtraIconVisibleProperty);
+ set => SetValue(ExtraIconVisibleProperty, value);
+ }
+
+ public bool ExtraTextVisible {
+ get => (bool) GetValue(ExtraTextVisibleProperty);
+ set => SetValue(ExtraTextVisibleProperty, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Views/Edits/ItemControl.xaml b/src/RevitRoundingOfAreas/Views/Edits/ItemControl.xaml
new file mode 100644
index 000000000..2e8b3ac4c
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Edits/ItemControl.xaml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/RevitRoundingOfAreas/Views/Edits/ItemControl.xaml.cs b/src/RevitRoundingOfAreas/Views/Edits/ItemControl.xaml.cs
new file mode 100644
index 000000000..e410d36de
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Edits/ItemControl.xaml.cs
@@ -0,0 +1,38 @@
+using System.Windows;
+
+namespace RevitRoundingOfAreas.Views.Edits;
+
+public partial class ItemControl {
+ public static readonly DependencyProperty ItemNameProperty = DependencyProperty.Register(
+ nameof(ItemName), typeof(string), typeof(ItemControl), new PropertyMetadata(default(string)));
+
+ public static readonly DependencyProperty WarningDescriptionProperty = DependencyProperty.Register(
+ nameof(WarningDescription), typeof(string), typeof(ItemControl), new PropertyMetadata(default(string)));
+
+ public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
+ nameof(IsChecked), typeof(bool), typeof(ItemControl), new PropertyMetadata(true));
+
+ public static readonly DependencyProperty HasWarningProperty = DependencyProperty.Register(
+ nameof(HasWarning), typeof(bool), typeof(ItemControl), new PropertyMetadata(true));
+
+ public ItemControl() {
+ InitializeComponent();
+ }
+
+ public string ItemName {
+ get => (string) GetValue(ItemNameProperty);
+ set => SetValue(ItemNameProperty, value);
+ }
+ public string WarningDescription {
+ get => (string) GetValue(WarningDescriptionProperty);
+ set => SetValue(WarningDescriptionProperty, value);
+ }
+ public bool IsChecked {
+ get => (bool) GetValue(IsCheckedProperty);
+ set => SetValue(IsCheckedProperty, value);
+ }
+ public bool HasWarning {
+ get => (bool) GetValue(HasWarningProperty);
+ set => SetValue(HasWarningProperty, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Views/Edits/ModeSwitcherControl.xaml b/src/RevitRoundingOfAreas/Views/Edits/ModeSwitcherControl.xaml
new file mode 100644
index 000000000..8677dc138
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Edits/ModeSwitcherControl.xaml
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/RevitRoundingOfAreas/Views/Edits/ModeSwitcherControl.xaml.cs b/src/RevitRoundingOfAreas/Views/Edits/ModeSwitcherControl.xaml.cs
new file mode 100644
index 000000000..23854aa81
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Edits/ModeSwitcherControl.xaml.cs
@@ -0,0 +1,67 @@
+using System.Collections;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace RevitRoundingOfAreas.Views.Edits;
+
+public partial class ModeSwitcherControl : UserControl {
+ ///
+ /// Источник данных.
+ ///
+ public static readonly DependencyProperty ItemsSourceProperty =
+ DependencyProperty.Register(
+ nameof(ItemsSource),
+ typeof(IEnumerable),
+ typeof(ModeSwitcherControl),
+ new PropertyMetadata(null));
+
+ ///
+ /// Выбранный элемент.
+ ///
+ public static readonly DependencyProperty SelectedItemProperty =
+ DependencyProperty.Register(
+ nameof(SelectedItem),
+ typeof(object),
+ typeof(ModeSwitcherControl),
+ new FrameworkPropertyMetadata(
+ null,
+ FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
+
+ ///
+ /// Путь к отображаемому свойству.
+ ///
+ public static readonly DependencyProperty DisplayMemberPathProperty =
+ DependencyProperty.Register(
+ nameof(DisplayMemberPath),
+ typeof(string),
+ typeof(ModeSwitcherControl),
+ new PropertyMetadata("Name"));
+
+ public ModeSwitcherControl() {
+ InitializeComponent();
+ }
+
+ ///
+ /// Источник данных.
+ ///
+ public IEnumerable ItemsSource {
+ get => (IEnumerable) GetValue(ItemsSourceProperty);
+ set => SetValue(ItemsSourceProperty, value);
+ }
+
+ ///
+ /// Выбранный элемент.
+ ///
+ public object SelectedItem {
+ get => GetValue(SelectedItemProperty);
+ set => SetValue(SelectedItemProperty, value);
+ }
+
+ ///
+ /// Путь к отображаемому свойству.
+ ///
+ public string DisplayMemberPath {
+ get => (string) GetValue(DisplayMemberPathProperty);
+ set => SetValue(DisplayMemberPathProperty, value);
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Views/MainWindow.xaml b/src/RevitRoundingOfAreas/Views/MainWindow.xaml
new file mode 100644
index 000000000..617d2328d
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/MainWindow.xaml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/RevitRoundingOfAreas/Views/MainWindow.xaml.cs b/src/RevitRoundingOfAreas/Views/MainWindow.xaml.cs
new file mode 100644
index 000000000..d0c42a1ab
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/MainWindow.xaml.cs
@@ -0,0 +1,49 @@
+using System.Windows;
+
+using dosymep.SimpleServices;
+
+namespace RevitRoundingOfAreas.Views;
+
+///
+/// Класс главного окна плагина.
+///
+public partial class MainWindow {
+ ///
+ /// Иницализирует главное окно плагина.
+ ///
+ public MainWindow(
+ ILoggerService loggerService,
+ ISerializationService serializationService,
+ ILanguageService languageService, ILocalizationService localizationService,
+ IUIThemeService uiThemeService, IUIThemeUpdaterService themeUpdaterService)
+ : base(loggerService,
+ serializationService,
+ languageService, localizationService,
+ uiThemeService, themeUpdaterService) {
+ InitializeComponent();
+ }
+
+ ///
+ /// Наименование плагина.
+ ///
+ ///
+ /// Используется для сохранения положения окна.
+ ///
+ public override string PluginName => nameof(RevitRoundingOfAreas);
+
+ ///
+ /// Наименование файла конфигурации.
+ ///
+ ///
+ /// Используется для сохранения положения окна.
+ ///
+ public override string ProjectConfigName => nameof(MainWindow);
+
+ private void ButtonOk_Click(object sender, RoutedEventArgs e) {
+ DialogResult = true;
+ }
+
+ private void ButtonCancel_Click(object sender, RoutedEventArgs e) {
+ DialogResult = false;
+ }
+}
diff --git a/src/RevitRoundingOfAreas/Views/Styles.xaml b/src/RevitRoundingOfAreas/Views/Styles.xaml
new file mode 100644
index 000000000..69e6613b9
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/Styles.xaml
@@ -0,0 +1,287 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/RevitRoundingOfAreas/Views/WarningsWindow.xaml b/src/RevitRoundingOfAreas/Views/WarningsWindow.xaml
new file mode 100644
index 000000000..ed5547611
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/WarningsWindow.xaml
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/RevitRoundingOfAreas/Views/WarningsWindow.xaml.cs b/src/RevitRoundingOfAreas/Views/WarningsWindow.xaml.cs
new file mode 100644
index 000000000..7f784e503
--- /dev/null
+++ b/src/RevitRoundingOfAreas/Views/WarningsWindow.xaml.cs
@@ -0,0 +1,35 @@
+using dosymep.SimpleServices;
+
+namespace RevitRoundingOfAreas.Views;
+///
+/// Interaction logic for WarningWindow.xaml
+///
+public partial class WarningsWindow {
+ public WarningsWindow(
+ ILoggerService loggerService,
+ ISerializationService serializationService,
+ ILanguageService languageService, ILocalizationService localizationService,
+ IUIThemeService uiThemeService, IUIThemeUpdaterService themeUpdaterService)
+ : base(loggerService,
+ serializationService,
+ languageService, localizationService,
+ uiThemeService, themeUpdaterService) {
+ InitializeComponent();
+ }
+
+ ///
+ /// Наименование плагина.
+ ///
+ ///
+ /// Используется для сохранения положения окна.
+ ///
+ public override string PluginName => nameof(RevitRoundingOfAreas);
+
+ ///
+ /// Наименование файла конфигурации.
+ ///
+ ///
+ /// Используется для сохранения положения окна.
+ ///
+ public override string ProjectConfigName => nameof(WarningsWindow);
+}
diff --git a/src/RevitRoundingOfAreas/assets/Localization/Language.en-US.xaml b/src/RevitRoundingOfAreas/assets/Localization/Language.en-US.xaml
new file mode 100644
index 000000000..868b85ee6
--- /dev/null
+++ b/src/RevitRoundingOfAreas/assets/Localization/Language.en-US.xaml
@@ -0,0 +1,50 @@
+
+
+ Calculate Areas (Social Facilities)
+ Model Element Processing Range
+ Select how to process model elements
+
+ Room Phase
+ Select the phase for the rooms to be processed
+
+ Read Parameter
+ Parameter from which the area will be read
+
+ Write Parameter
+ Parameter to which the area will be written
+
+ Number of Decimal Places
+ Number of decimal places to round to
+
+ Calculate
+ Cancel
+
+ All elements
+ Selected
+ Visible in view
+
+ Area Calculation (Social Facilities)
+
+ Error loading parameters
+ Plugin configuration error
+
+ Redundant zones
+ Zones located within the same enclosed area
+ Unenclosed zones / Unplaced zones
+ Zones that have no boundaries or are not placed on the plan
+
+ No rooms selected
+ No rooms on the view
+
+ - No level -
+
+ Calculate Areas (Social Facilities) - Warnings
+
+ Highlight
+ Room ID
+ Room name
+ Room level
+
+
diff --git a/src/RevitRoundingOfAreas/assets/Localization/Language.ru-RU.xaml b/src/RevitRoundingOfAreas/assets/Localization/Language.ru-RU.xaml
new file mode 100644
index 000000000..0ee9a769a
--- /dev/null
+++ b/src/RevitRoundingOfAreas/assets/Localization/Language.ru-RU.xaml
@@ -0,0 +1,50 @@
+
+
+ Рассчитать площади (соц. объекты)
+ Диапазон обработки элементов модели
+ Выбор варианта обработки элементов модели
+
+ Стадия помещений
+ Выбор стадии для обрабатываемых помещений
+
+ Параметр для чтения
+ Параметр, с которого будет считываться площадь
+
+ Параметр для записи
+ Параметр, в который будет записываться площадь
+
+ Количество знаков после запятой
+ До которого будет происходить округление
+
+ Рассчитать
+ Отмена
+
+ Все элементы
+ Выделенные
+ Видимые на виде
+
+ Расчёт площадей (соц. объекты)
+
+ Ошибка загрузки параметров
+ Ошибка настройки плагина
+
+ Избыточные зоны
+ Зоны, находящиеся в одной окруженной области
+ Не окруженные зоны / Не размещенные зоны
+ Зоны, не имеющие границ или не размещенные на плане
+
+ Не выделены помещения
+ Нет помещений на виде
+
+ - Нет уровня -
+
+ Рассчитать площади (соц. объекты) - предупреждения
+
+ Выделить
+ ИД помещения
+ Имя помещения
+ Уровень помещения
+
+