Непонятная работа метода Solid3d.GetSection

Автор Тема: Непонятная работа метода Solid3d.GetSection  (Прочитано 4917 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Всем привет. Столкнулся с забавным случаем
Задача - имеется 3Д тело (Solid) и мне его нужно разрезать плоскостью (Plane). У солида на этот случай есть метод Solid3d.Slice. Однако, если подать ему плоскость, которая не пересекает солид, то генерируется Exception.
Решил я предварительно проверить пересечение и нашел метод, который подходит идеально - Solid3d.GetSection
Смотрим в описание и видим:
Цитировать
If the solid has no ShapeManager object, or the plane doesn’t intersect the solid, or the intersection is not a valid region (for example, it intersects at a point, along a bounding face of the solid, and so on), then the return is NULL
По описанию прям вот оно! Но на деле имеем странное поведение. Вот кусок кода:
Код - C# [Выбрать]
  1. var plane = new Plane(pt, Vector3d.XAxis);
  2. var s = solid3d.GetSection(plane);
  3. if (s != null)
  4. {
  5.     var newSideSolid = solid3d.Slice(plane, true);
  6.  
  7.     btr.AppendEntity(newSideSolid);
  8.     tr.AddNewlyCreatedDBObject(newSideSolid, true);
  9. }
В случае, когда плоскость не пересекает солид, метод GetSection не возвращает NULL, а возвращает всегда экземпляр Region. НО! При попытке обратится к любому полю экземпляра генерируется NullReferenceException! Что не соответствует описанию в справке.

Это ошибка в API или я что-то не понял?

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 806
  • Карма: 166
    • Мои плагины к Автокаду
если б Slice просто ошибку выталкивал - это было бы счастье, а то он фатал вызывает, к сожалению. по крайней мере в нескольких версиях Автокада, по крайней мере при нарезке сурфейсом. так что присоединяюсь к вопросу. я эту проблему решил жутким костылем:
Код - C# [Выбрать]
  1. Surface offs = ......
  2. using (Solid3d test = offs.Thicken(-0.00001, false))
  3. using (Solid3d clone = solid.Clone() as Solid3d)
  4.    {
  5.     clone.BooleanOperation(BooleanOperationType.BoolIntersect, test);
  6.     if (clone == null || clone.IsNull) return false;
  7.     }
  8. Solid3d sloy = solid.Slice(offs, true); // опасно! может вышибать автокад если солид не проходит Check и если offs не пересекает solid

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 806
  • Карма: 166
    • Мои плагины к Автокаду
А еще (заодно пожалуюсь на этот Slice), он может вызвать InvalidOperationException и при этом изуродует исходный солид до неузнаваемости. Поэтому приходится клон делать ДО вызова Slice
Код - C# [Выбрать]
  1.     /// <summary>
  2.     /// Разрезать солид stub плоскостью. Если не удасться - вернет null
  3.     /// </summary>
  4.     public static Solid3d TrySlice(Plane pl, ref Solid3d stub)
  5.     {
  6.       try
  7.       {
  8.         Solid3d clone = stub.Clone() as Solid3d;
  9.         Solid3d slice = clone.Slice(pl, true); // если вылезет InvalidOperationException, то clone будет изуродован
  10.         if (stub != null) stub.Dispose();
  11.         stub = clone; // если не вылез InvalidOperationException
  12.         return slice;
  13.       }
  14.       catch (InvalidOperationException)
  15.       {
  16.         return null;
  17.       }
  18.     }

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 806
  • Карма: 166
    • Мои плагины к Автокаду
метод GetSection не возвращает NULL, а возвращает всегда экземпляр Region
а если проверить этот регион на IsNull ?
Я встречал какие-то функции API, которые вместо возврата null возвращают пустой Entity, у которого Entity.IsNull==true. Тут в форуме уже ругались на это - надо ж по хорошему еще и диспозить эту пустышку. брррр

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
я эту проблему решил жутким костылем
А почему бы не обернуть в try{} catch{}? Лично я планирую именно так. Хотя, возможно в вашем случае не подходит. Мне подойдет
а если проверить этот регион на IsNull ?
Я уже писал в топике:
При попытке обратится к любому полю экземпляра генерируется NullReferenceException

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 806
  • Карма: 166
    • Мои плагины к Автокаду
А почему бы не обернуть в try{} catch{}
а потому что он никак не спасает от фатала. увы

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
А почему бы не обернуть в try{} catch{}
а потому что он никак не спасает от фатала. увы
Серьезно? Это плохо (( Сейчас проверю...

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 806
  • Карма: 166
    • Мои плагины к Автокаду
При попытке обратится к любому полю экземпляра генерируется NullReferenceException
и к UnmanagedObject тоже? может его на ноль проверить?

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
а потому что он никак не спасает от фатала. увы
Серьезно? Это плохо (( Сейчас проверю...
Проверил. Все нормально:
Код - C# [Выбрать]
  1. try
  2. {
  3.     var newSideSolid = solid3d.Slice(plane, true);
  4.  
  5.     btr.AppendEntity(newSideSolid);
  6.     tr.AddNewlyCreatedDBObject(newSideSolid, true);
  7. }
  8. catch (InvalidOperationException)
  9. {
  10.     // ignored
  11. }


и к UnmanagedObject тоже? может его на ноль проверить?
Я уже переделал на try{} catch{} =))

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 806
  • Карма: 166
    • Мои плагины к Автокаду
Проверил. Все нормально
Может зависеть от версии Автокада. И у меня в коде танцы с бубном только вокруг перегрузки Slice(Surface surface, bool negativeHalfToo) , а где плоскостью режу - вроде обходится try-catch

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Re: Непонятная работа метода Solid3d.GetSection
« Ответ #10 : 07-12-2017, 12:06:29 »
Проверил. Все нормально
Может зависеть от версии Автокада. И у меня в коде танцы с бубном только вокруг перегрузки Slice(Surface surface, bool negativeHalfToo) , а где плоскостью режу - вроде обходится try-catch
Для того, куда мы это делаем, мы можем сами задать версию автокада =)) Но вообще - 2017

Спорить не буду - я секу не surface'ом, а plane'ом. В моем случае все хорошо.

Еще вариант - использовать метод GetSection, а потом обернуть в try{} catch{} попытку обращения к любому полю. Например так (пишу на коленке):
Код - C# [Выбрать]
  1. bool intersected = false;
  2. try{
  3.     var s = solid3d.GetSection(plane);
  4.     var a = s.IsNull;
  5. }
  6. catch{
  7. intersected = false;
  8. }
  9.  
  10. if(intersected)
  11. {
  12.     // ваш код
  13. }

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 806
  • Карма: 166
    • Мои плагины к Автокаду
Re: Непонятная работа метода Solid3d.GetSection
« Ответ #11 : 07-12-2017, 12:09:52 »
а потом обернуть в try
если не фаталит (а я все-таки советую потестить по дольше и на сложных солидах), то какой смысл вызывать GetSection? точно так же можно обернуть в try сам Slice

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Re: Непонятная работа метода Solid3d.GetSection
« Ответ #12 : 07-12-2017, 12:16:20 »
а потом обернуть в try
если не фаталит (а я все-таки советую потестить по дольше и на сложных солидах), то какой смысл вызывать GetSection? точно так же можно обернуть в try сам Slice
А такой, что плагин может зависеть от наличия нового порезанного солида. В общем - это все зависит от контекста приложения

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: Непонятная работа метода Solid3d.GetSection
« Ответ #13 : 07-12-2017, 12:42:46 »
Что-то похожее как-то давно Андрей Бушман описывал, может что-то оттуда взять получится: http://adn-cis.org/forum/index.php?topic=495.0