Сообщество программистов Autodesk в СНГ

ADN Club => Civil 3D API => Тема начата: Разживин Алексей от 08-09-2015, 13:33:25

Название: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Разживин Алексей от 08-09-2015, 13:33:25
Всем привет! После повторной классификации точки при выставлении свойств вылетает исключение о том, что такого свойства не обнаружено.
Код, который это делает:

Код - C# [Выбрать]
  1. private static void Classify(ObjectId objectId, string className, params string[] properties)
  2. {
  3.         var manager = HostMapApplicationServices.Application.ActiveProject.ClassificationManager;
  4.  
  5.         // здесь классифицируем
  6.         using (var ids = new ObjectIdCollection { objectId })
  7.         using (var failIds = new ObjectIdCollection())
  8.         {
  9.                 var errorCodes = new FeatureClassErrorCodeCollection();
  10.                 // manager.Unclassify(objectId); <-- Не помогает
  11.                 manager.Classify(failIds, errorCodes, ids, className, true, true);
  12.         }
  13.  
  14.         // ниже выставляем значения свойств
  15.         using (var featureClassDefinition = manager[className])
  16.         {
  17.                 var collection = new StringCollection { "Пользовательский" };
  18.  
  19.                 foreach (var propertyName in properties)
  20.                 {
  21.                         using (var property = featureClassDefinition.GetProperty(collection, propertyName))
  22.                         {
  23.                                 var value = property.FromString(DateTime.Now.Millisecond.ToString());
  24.                                 try
  25.                                 {
  26.                                         property.SetValue(objectId, value, true);
  27.                                 }
  28.                                 catch (MapFeatureClassException mfce)
  29.                                 {
  30.                                         Trace.WriteLine((FeatureClassErrorCode)mfce.ErrorCode);
  31.                                         throw;
  32.                                 }
  33.                         }
  34.                 }
  35.         }
  36. }
  37.  

Пусть у нас в файле описаний будет 2 класса: Класс 1 со свойствами Свойство 1 и Свойство 2 и Класс 2 (Свойство 3 и Свойство 4).
При классификации точки в первый раз, мы можем увидеть что для объекта успешно задан класс и заполнены свойства:

(https://adn-cis.org/forum/proxy.php?request=http%3A%2F%2Fi.imgur.com%2FQ1IPyU7.png&hash=4757adaeb7ee93d2d5db167ce51a9174)

При переклассификации на выставлении значений свойств вылетает MapFeatureClassException с (FeatureClassErrorCode)mfce.ErrorCode == FeatureClassErrorCode.PropertyNotFound.
И правда, если мы взглянем в свойства объекта, то увидим что одного из свойств Класса 2 нет:

(https://adn-cis.org/forum/proxy.php?request=http%3A%2F%2Fi.imgur.com%2FmZonaHk.png&hash=270e5193bb359a05f85a554c78882714)

Собственно, вопрос: как это можно обойти?

Тестовый проект, чертеж с коготочкой, файл описаний и картинка-инструкция по его присоединению в аттаче.

Для того, чтобы воспроизвести ошибку, надо:
  1. Открыть приложенный чертеж с коготочкой (или вообще любой чертеж с коготочками),
  2. Присоединить файл описаний (приложена картинка из моей предыдущей темы, для 15 цивила шаги аналогичны),
  3. Вызвать последовательно команды CLASSIFY1 и CLASSIFY2 из приложенного проекта.

P.S. Совсем вылетело из головы. Цивил для приложенного тестового проекта должен быть русским, так как в других локализациях категория Пользовательский имеет другое название.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 08-09-2015, 14:37:22
Надеюсь, что это версия Civil 3D со всеми обновлениями? Вечером попробую и если у меня такое поведение воспроизведётся - отправлю в ADN DevHelp.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Разживин Алексей от 08-09-2015, 14:49:26
Надеюсь, что это версия Civil 3D со всеми обновлениями?
На момент написания первого сообщения в теме стоял SP1, после накатывания SP2 поведение не изменилось.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 08-09-2015, 14:51:36
после накатывания SP2 поведение не изменилось
А если накатить ещё и ServicePack 3: http://knowledge.autodesk.com/support/autocad-civil-3d/downloads/caas/downloads/content/autodesk-C2-AE-autocad-C2-AE-civil-3d-C2-AE-2015-service-pack-3.html ?
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Разживин Алексей от 08-09-2015, 15:28:29
А если накатить ещё и ServicePack 3: http://knowledge.autodesk.com/support/autocad-civil-3d/downloads/caas/downloads/content/autodesk-C2-AE-autocad-C2-AE-civil-3d-C2-AE-2015-service-pack-3.html
Видимо, третий пак прошел мимо меня. Спасибо за ссылку :), но это не помогло :(.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 08-09-2015, 15:30:26
Очень похоже на баг. Осталось убедится, что его не исправили в Civil 3D 2016.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Дмитрий Загорулькин от 08-09-2015, 23:03:16
Поведение подтверждаю, AutoCAD Civil 3D 2016 SP1 Rus.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 08-09-2015, 23:26:59
Мне вот интересно можно ли один примитив классифицировать двумя разными классами? По логике такое должно быть невозможным. Соответственно manager.Unclassify(objectId) должно бы убирать старый класс и позволить классифицировать новым классом. Но и это тоже не работает.
Проверил на таком коде:
Код - C# [Выбрать]
  1. using (var ids = new ObjectIdCollection { objectId })
  2. using (var failIds = new ObjectIdCollection())
  3. using (var clsdIds = manager.GetClassifiedEntities())
  4. {
  5.   if (clsdIds.Contains(objectId))
  6.   {
  7.     manager.Unclassify(objectId);
  8.   }
  9.   manager.Classify(objectId, className, true, true);
  10. }
Исключение возникает на строке 3. Так что похоже это вообще всё не работает.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Дмитрий Загорулькин от 08-09-2015, 23:55:02

И еще наблюдения. Когда классификация с объекта снимается, у объекта остаются значения свойств для класса. Вот если бы понять, где они сохраняются... Может быть, тогда удалось бы их "подчищать" перед новой классификацией.

И напоследок. Если у классов одинаковые свойства - переклассификация проходит без ошибок (см. вложенный XML файл).
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 09-09-2015, 00:56:33
Отправил вопрос в ADN DevHelp.
P.S.: Судя по всему мало кто использует возможности Map 3D API, так как я практически не нашел на просторах интернета примеров его использования. Во всяком случае в плане классификации.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 09-09-2015, 01:28:13
В составе ObjectARX for AutoCAD Map 3D (http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=868220) есть куча примеров, в том числе и на C#.
Решил проверить пример ClassificationCS оттуда. Результат такой же самый:

Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Разживин Алексей от 09-09-2015, 12:34:48
Ждем ответа от ADN DevHelp, чтобы документально подтвердился баг (опционально с путями его обхода).

Извините, вам запрещён просмотр содержимого спойлеров.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Дмитрий Загорулькин от 09-09-2015, 12:59:36
У меня есть предположение, что это некоторая особенность. При переназначении класса, мы ожидаем, что свойства 1 и 2 будут удалены - ведь их нет в классе 2. Но в них могут содержаться важные данные и Map не дает этого сделать. В результате возникает внутренняя ошибка.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Разживин Алексей от 09-09-2015, 13:04:18
Дмитрий Загорулькин, хорошее предположение, но против него говорит тот факт, что при назначении второго класса не появляется свойство 4.

И это предположение не выдержало проверку тестом, в котором свойства предыдущего класса перед классификацией выставлялись в null.

(https://adn-cis.org/forum/proxy.php?request=http%3A%2F%2Fi.imgur.com%2Fk2RqYKF.png&hash=7ef56d4d81096606104c25bb2f513860)
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Дмитрий Загорулькин от 09-09-2015, 13:49:44
но против него говорит тот факт, что при назначении второго класса не появляется свойство 4.
Мы не знаем внутренних механизмов этих методов. Я заглянул внутрь этой dll - она просто является оберткой для ARX объектов. Так что, остается только гадать, как там и что. Поэтому, я пока что не вижу противоречий между моим предположением и фактом, что 4-е свойство не появляется.
И это предположение не выдержало проверку тестом, в котором свойства предыдущего класса перед классификацией выставлялись в null.
А я и не говорил, что проверяется значение свойства.
Но:
Если у классов одинаковые свойства - переклассификация проходит без ошибок
Это меня наводит на такие мысли.
Но это все гадание на кофейной гуще... посмотрим, что ответят в ADN.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Дмитрий Загорулькин от 09-09-2015, 19:42:37
На основе вот этого (http://forum.dwg.ru/showthread.php?t=63075).
Вроде работает. Код написан по-быстрому и без проверок.
Код - C# [Выбрать]
  1. [assembly: Autodesk.AutoCAD.Runtime.CommandClass(typeof(TestProject.TestClass))]
  2.  
  3. namespace TestProject
  4. {
  5.     using System;
  6.     using System.Collections.Specialized;
  7.  
  8.     using Autodesk.AutoCAD.ApplicationServices.Core;
  9.     using Autodesk.AutoCAD.DatabaseServices;
  10.     using Autodesk.AutoCAD.Runtime;
  11.     using Autodesk.Civil.DatabaseServices;
  12.     using Autodesk.Gis.Map;
  13.     using Autodesk.Gis.Map.Classification;
  14.  
  15.     using Trace = System.Diagnostics.Trace;
  16.     using System.Collections;
  17.     using Autodesk.Gis.Map.ObjectData;
  18.     using Autodesk.Gis.Map.Project;
  19.  
  20.     /// <summary>
  21.     /// Тестовый класс для демонстрации ошибки, связанной с повторной классификацией объекта.
  22.     /// </summary>
  23.     public class TestClass : IExtensionApplication
  24.     {
  25.         /// <summary>
  26.         /// Инициализация расширения.
  27.         /// </summary>
  28.         public void Initialize()
  29.         {
  30.             HostMapApplicationServices.Application.LogIn("SuperUser", "SUPERUSER");
  31.         }
  32.  
  33.         /// <summary>
  34.         /// Закрытие расширения.
  35.         /// </summary>
  36.         public void Terminate()
  37.         {
  38.         }
  39.  
  40.         /// <summary>
  41.         /// Классификация точки первым классом.
  42.         /// </summary>
  43.         [CommandMethod("CLASSIFY1")]
  44.         public void ClassifyOne()
  45.         {
  46.             var objId = GetCogoPoint();
  47.             Classify(objId, "Класс 1", "Свойство 1", "Свойство 2");
  48.         }
  49.  
  50.        
  51.  
  52.         /// <summary>
  53.         /// Классификация точки вторым классом.
  54.         /// </summary>
  55.         [CommandMethod("CLASSIFY2")]
  56.         public void ClassyfyTwo()
  57.         {
  58.             var objId = GetCogoPoint();
  59.             Unclassify(objId, "Класс 1");
  60.             Classify(objId, "Класс 2", "Свойство 3", "Свойство 4");
  61.         }
  62.  
  63.  
  64.        
  65.  
  66.         /// <summary>
  67.         /// Классификация объекта и выставление ему пользовательских свойств.
  68.         /// </summary>
  69.         /// <param name="objectId">Идентификатор объекта.</param>
  70.         /// <param name="className">Имя результирующего класса.</param>
  71.         /// <param name="properties">Массив имен свойств.</param>>
  72.         private static void Classify(ObjectId objectId, string className, params string[] properties)
  73.         {
  74.             var manager = HostMapApplicationServices.Application.ActiveProject.ClassificationManager;
  75.  
  76.             // здесь классифицируем
  77.             using (var ids = new ObjectIdCollection { objectId })
  78.             using (var failIds = new ObjectIdCollection())
  79.             {
  80.                 var errorCodes = new FeatureClassErrorCodeCollection();
  81.                 // manager.Unclassify(objectId); <-- Не помогает
  82.                 manager.Classify(failIds, errorCodes, ids, className, true, true);
  83.                 manager.Audit(objectId, true, true);
  84.             }
  85.  
  86.             // ниже выставляем значения свойств
  87.             using (var featureClassDefinition = manager[className])
  88.             {
  89.                 var collection = new StringCollection { "Пользовательский" };
  90.  
  91.                 foreach (var propertyName in properties)
  92.                 {
  93.                     using (var property = featureClassDefinition.GetProperty(collection, propertyName))
  94.                     {
  95.                         var value = property.FromString(DateTime.Now.Millisecond.ToString());
  96.                         try
  97.                         {
  98.                             property.SetValue(objectId, value, true);
  99.                         }
  100.                         catch (MapFeatureClassException mfce)
  101.                         {
  102.                             Trace.WriteLine((FeatureClassErrorCode)mfce.ErrorCode);
  103.                             throw;
  104.                         }
  105.                     }
  106.                 }
  107.             }
  108.         }
  109.  
  110.         /// <summary>
  111.         /// Получение идентификатора первой попавшейся коготочки.
  112.         /// </summary>
  113.         /// <returns>Идентификатор коготочки.</returns>
  114.         private static ObjectId GetCogoPoint()
  115.         {
  116.             var doc = Application.DocumentManager.MdiActiveDocument;
  117.  
  118.             using (var trans = doc.TransactionManager.StartTransaction())
  119.             using (var bt = (BlockTable)trans.GetObject(doc.Database.BlockTableId, OpenMode.ForRead))
  120.             using (var btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead))
  121.             {
  122.                 foreach (var objectId in btr)
  123.                 {
  124.                     using (var dbObj = trans.GetObject(objectId, OpenMode.ForRead))
  125.                     {
  126.                         if (dbObj is CogoPoint)
  127.                         {
  128.                             return objectId;
  129.                         }
  130.                     }
  131.                 }
  132.  
  133.                 trans.Commit();
  134.             }
  135.  
  136.             return ObjectId.Null;
  137.         }      
  138.  
  139.         /// <summary>
  140.                 /// Деклассификация объекта и удаление его пользовательских свойств.
  141.                 /// </summary>
  142.                 /// <param name="objectId">Идентификатор объекта.</param>
  143.                 /// <param name="className">Имя класса.</param>               
  144.                 private static void Unclassify(ObjectId objectId, string className)
  145.         {
  146.             var manager = HostMapApplicationServices.Application
  147.                 .ActiveProject.ClassificationManager;
  148.             manager.Unclassify(objectId);            
  149.  
  150.             MapApplication mapApp = HostMapApplicationServices.Application;
  151.  
  152.             ProjectModel activeProj = mapApp.ActiveProject;
  153.  
  154.             Tables odTables = activeProj.ODTables;
  155.  
  156.             try
  157.             {
  158.                 using (Transaction tr = objectId.Database.TransactionManager.StartTransaction())
  159.                 {
  160.                     ObjectId nodId = objectId.Database.NamedObjectsDictionaryId;
  161.                     DBDictionary nod = tr.GetObject(nodId, OpenMode.ForRead) as DBDictionary;
  162.                     ObjectId acadOCId = nod.GetAt("ACAD_OC");
  163.                     DBDictionary acadOc = tr.GetObject(acadOCId, OpenMode.ForRead) as DBDictionary;
  164.                     ObjectId defFileId = acadOc.GetAt("DefinitionFile");
  165.                     DBDictionary defFile = tr.GetObject(defFileId, OpenMode.ForRead) as DBDictionary;
  166.                     ObjectId classDataId = defFile.GetAt(className);
  167.                     DataTable classData = tr.GetObject(classDataId, OpenMode.ForWrite) as DataTable;
  168.                     for (int i = 0; i < classData.NumRows; i++)
  169.                     {
  170.                         if (classData.GetCellAt(i, 0).Value.Equals(objectId))
  171.                         {
  172.                             classData.RemoveRowAt(i);
  173.                             break;
  174.                         }
  175.                     }
  176.                     tr.Commit();
  177.                 }
  178.  
  179.             }
  180.             catch (MapException exc)
  181.             {
  182.  
  183.             }
  184.         }
  185.  
  186.        
  187.     }
  188. }
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 09-09-2015, 19:48:48
Вроде работает. Код написан по-быстрому и без проверок.
Очень интересно. Как я понимаю manager.Unclassify(objectId); должно делать то, что ты делаешь дальше в коде. Но по какой-то причине это не происходит.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Дмитрий Загорулькин от 09-09-2015, 21:24:59
Да, наверное упустили это. Или есть в этом какой-то скрытый смысл. Кто знает, может после такой чистки где-нибудь нарушится связанность данных и вылезет потом в самый неподходящий момент...
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Разживин Алексей от 11-09-2015, 05:51:45
Большое спасибо Дмитрию Загорулькину и всем соучастным. Решение потестировал на всяких граничных условиях, вроде работает как надо. Посмотрим что скажут тестировщики.
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 12-09-2015, 18:03:17
Получил ответ от ADN DevHelp, что воспроизвести такое поведение они смогли и обсудят эту проблему с командой профильных инженеров. Я сообщил что Дмитрий Загорулькин нашёл работающий workaround, но попросил всё-таки уточнить возможность тоже самое сделать используя стандартное Map 3D API.
Дима! Твой workaround Augusto Goncalves обозвал Excellent и поблагодарил тебя за то, что ты им поделился. Так что принимай поздравления  ;)
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Дмитрий Загорулькин от 12-09-2015, 18:11:26
О... ничего себе :) Спасибо!
Название: Re: Map 3D. Ошибка при переклассификации COGO-точек. Civil 3D 2015, .NET 4.5
Отправлено: Александр Ривилис от 21-09-2015, 23:50:03
Получил новый ответ от Augusto Goncalves - штатного workaround нет. Создан запрос команде инженеров на изменение поведения программы, но с учетом найденного Дмитрий Загорулькин решения я бы не рассчитывал на исправление в ближайшей версии.