Нарезка 3D тел

Автор Тема: Нарезка 3D тел  (Прочитано 27469 раз)

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

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Нарезка 3D тел
« Ответ #15 : 03-06-2014, 15:18:46 »
P.S.: Кстати, вместо манипуляций с minX/minY и maxX/maxY можно пользоваться методом BoundBlock3d.Extend
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нарезка 3D тел
« Ответ #16 : 03-06-2014, 15:23:58 »
А что если вместо edge.BoundBlock использовать edge.Curve.BoundBlock

Код - C# [Выбрать]
  1. Gm.Point3d min = edge.Curve.BoundBlock.GetMinimumPoint();
  2. Gm.Point3d max = edge.Curve.BoundBlock.GetMaximumPoint();

На скрине видим, что границы изменились, но при этом "пошли лесом" и границы лиловых регионов.

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нарезка 3D тел
« Ответ #17 : 03-06-2014, 15:26:38 »
А что если вместо edge.BoundBlock использовать ... или edge.Curve.OrthoBoundBlock ?

Код - C# [Выбрать]
  1. Gm.Point3d min = edge.Curve.OrthoBoundBlock.GetMinimumPoint();
  2. Gm.Point3d max = edge.Curve.OrthoBoundBlock.GetMaximumPoint();

Результат получаю такой же, как на предыдущем скрине.

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нарезка 3D тел
« Ответ #18 : 03-06-2014, 15:33:54 »
P.S.: Кстати, вместо манипуляций с minX/minY и maxX/maxY можно пользоваться методом BoundBlock3d.Extend

Из SDK:
Цитата: AutoCAD 2009 SDK
BoundBlock3d.Extend Method
Extends the block to include the new point.
Я не понял, о каком "расширении" идёт речь в документации, но похоже, что это ни коим боком не относится к манипуляциям с minX/minY и maxX/maxY.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Нарезка 3D тел
« Ответ #19 : 03-06-2014, 17:08:44 »
Еще один вариант: edge.GetCurveAsNurb(pres).BoundBlock
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нарезка 3D тел
« Ответ #20 : 03-06-2014, 17:32:09 »
Еще один вариант: edge.GetCurveAsNurb(pres).BoundBlock

Код - C# [Выбрать]
  1. Gm.Point3d min = edge.GetCurveAsNurb(0.1).BoundBlock.GetMinimumPoint();
  2. Gm.Point3d max = edge.GetCurveAsNurb(0.1).BoundBlock.GetMaximumPoint();

Результат получаю тот же, что и в предыдущих двух случаях. Заниматься гаданием и метанием туда-сюда не хочется. Способ, показанный мною выше работает. На нём и остановился. Если будут конкретные, проверенные на практике альтернативы - с интересом гляну.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Нарезка 3D тел
« Ответ #21 : 04-06-2014, 01:35:27 »
Если будут конкретные, проверенные на практике альтернативы - с интересом гляну.
Вот проверенная на практике альтернатива:


Кстати, она сразу даёт понять как можно пользоваться методом BoundBlock3d.Extend.

Код - C# [Выбрать]
  1. private void GetVisualBoundary(AcDb.Region region, double dx, double dy,
  2.   ref AcGe.Point2d minPoint, ref AcGe.Point2d maxPoint)
  3. {
  4.   double hord = (dx + dy) * 0.5;
  5.   using (AcGe.BoundBlock3d boundBlk = new AcGe.BoundBlock3d()) {
  6.     using (AcBr.Brep brep = new AcBr.Brep(region)) {
  7.       foreach (AcBr.Edge edge in brep.Edges) {
  8.         AcGe.Curve3d curve = edge.Curve;
  9.         AcGe.Interval interval = curve.GetInterval();
  10.         AcGe.PointOnCurve3d[] pnts =
  11.           curve.GetSamplePoints(interval.LowerBound, interval.UpperBound, hord);
  12.         foreach (AcGe.PointOnCurve3d pt in pnts) {
  13.           if (!boundBlk.IsBox)
  14.             boundBlk.Set(pt.Point, pt.Point);
  15.           else
  16.             boundBlk.Extend(pt.Point);
  17.         }
  18.       }
  19.     }
  20.     // Возвращаем вычисленный результат
  21.     minPoint =
  22.        new AcGe.Point2d(boundBlk.GetMinimumPoint().X, boundBlk.GetMinimumPoint().Y);
  23.     maxPoint =
  24.        new AcGe.Point2d(boundBlk.GetMaximumPoint().X, boundBlk.GetMaximumPoint().Y);
  25.   }
  26. }
P.S.: Передавать оба значения dx и dy в данном случае излишество.
P.S.S.: Я заменил твои алиасы на те, которые использую сам. Думаю, что обратная процедура не должна доставить тебе труда.
« Последнее редактирование: 04-06-2014, 02:26:08 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нарезка 3D тел
« Ответ #22 : 04-06-2014, 12:13:02 »
Я подправил ваш код, избавившись от dx и dy (заменил их на одно значение, у себя в коде сделал аналогичные замены):

Код - C# [Выбрать]
  1. public static void GetVisualBoundary2(this Db.Region region, Double delta,
  2.   ref Gm.Point2d minPoint, ref Gm.Point2d maxPoint) {
  3.  
  4.   using(Gm.BoundBlock3d boundBlk = new Gm.BoundBlock3d()) {
  5.     using(Br.Brep brep = new Br.Brep(region)) {
  6.       foreach(Br.Edge edge in brep.Edges) {
  7.         Gm.Curve3d curve = edge.Curve;
  8.         Gm.Interval interval = curve.GetInterval();
  9.         Gm.PointOnCurve3d[] pnts =
  10.           curve.GetSamplePoints(interval.LowerBound, interval.UpperBound,
  11.           delta);
  12.         foreach(Gm.PointOnCurve3d pt in pnts) {
  13.           if(!boundBlk.IsBox)
  14.             boundBlk.Set(pt.Point, pt.Point);
  15.           else
  16.             boundBlk.Extend(pt.Point);
  17.         }
  18.       }
  19.     }
  20.     // Возвращаем вычисленный результат
  21.     minPoint = new Gm.Point2d(boundBlk.GetMinimumPoint().X,
  22.       boundBlk.GetMinimumPoint().Y);
  23.     maxPoint = new Gm.Point2d(boundBlk.GetMaximumPoint().X,
  24.       boundBlk.GetMaximumPoint().Y);
  25.   }
  26. }
Однако в процессе работы кода возникает исключение.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Нарезка 3D тел
« Ответ #23 : 04-06-2014, 16:05:00 »
Уточни:
1. Исключение возникает у тебя всегда или только на конкретных Region?
2. Если на конкретных, то нужен файл с указанием на каком Region исключение.
3. Версия AutoCAD?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нарезка 3D тел
« Ответ #24 : 04-06-2014, 16:09:23 »
1. Я запустил код всего два раза. В обоих случаях выделил сразу все регионы (обрабатываются в цикле). На отдельных не запускал (код уже удалил из проекта).
2. Тестировал на том же DWG, который в этой теме прилагался выше. Он же прилагался и в соседней теме о регионах.
3. AutoCAD 2009.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Нарезка 3D тел
« Ответ #25 : 04-06-2014, 16:11:36 »
Ну тогда видимо баг в 2009-ом. Как видишь в 2014 код отработал без исключений - результат на картинке выше.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нарезка 3D тел
« Ответ #26 : 04-06-2014, 16:13:27 »
Ну тогда видимо баг в 2009-ом. Как видишь в 2014 код отработал без исключений - результат на картинке выше.
Можете замерить скорость в обоих вариантах? Интересно, какой будет шустрее. С учётом правок текущий вариант таков:
Код - C# [Выбрать]
  1.     /// <summary>
  2.     /// Получить координаты границ левого нижнего и правого верхнего углов для
  3.     /// визуального "GeometricExtents" региона.
  4.     /// </summary>
  5.     /// <param name="region">Регион, для которого следует получить координаты
  6.     /// границ визуального "GeometricExtents".</param>
  7.     /// <param name="delta">Предельная арифметическая погрешность вычислений.
  8.     /// </param>
  9.     /// <param name="minPoint">Ссылка на переменную Point2d, в которой следует
  10.     /// сохранить координаты левого нижнего угла визуального
  11.     /// "GeometricExtents".</param>
  12.     /// <param name="maxPoint">Ссылка на переменную Point2d, в которой следует
  13.     /// сохранить координаты правого верхнего угла визуального
  14.     /// "GeometricExtents".</param>
  15.     internal static void GetVisualBoundary(this Db.Region region, double delta,
  16.       ref Gm.Point2d minPoint, ref Gm.Point2d maxPoint) {
  17.  
  18.       if(region == null)
  19.         throw new ArgumentNullException("region");
  20.       if(region.IsDisposed)
  21.         throw new ArgumentException("region.IsDisposed == true");
  22.       if(delta <= 0)
  23.         throw new ArgumentException("delta <= 0");
  24.  
  25.       using(Br.Brep brep = new Br.Brep(region)) {
  26.  
  27.         // Находим min X
  28.         Double minX = Double.MinValue;
  29.         Gm.Point3d startPoint = region.GeometricExtents.MinPoint;
  30.         Gm.Point3d endPoint = new Gm.Point3d(
  31.           region.GeometricExtents.MinPoint.X,
  32.           region.GeometricExtents.MaxPoint.Y,
  33.           region.GeometricExtents.MinPoint.Z);
  34.  
  35.         while(startPoint.X < region.GeometricExtents.MaxPoint.X) {
  36.           using(Gm.Line3d line = new Gm.Line3d(startPoint, endPoint)) {
  37.             Br.Hit[] hits = brep.GetLineContainment(line, 1);
  38.             if(hits != null) {
  39.               foreach(Br.Hit hit in hits) {
  40.                 if(!hit.IsDisposed)
  41.                   hit.Dispose();
  42.               }
  43.               // чтобы регион полностью находился в границах
  44.               minX = startPoint.X == region.GeometricExtents.MinPoint.X ?
  45.                 startPoint.X : startPoint.X - delta;
  46.               break;
  47.             }
  48.             else {
  49.               startPoint = new Gm.Point3d(startPoint.X + delta, startPoint.Y,
  50.                 startPoint.Z);
  51.               endPoint = new Gm.Point3d(endPoint.X + delta, endPoint.Y,
  52.                 endPoint.Z);
  53.             }
  54.           }
  55.         }
  56.  
  57.         // Находим min Y
  58.         Double minY = Double.MinValue;
  59.         startPoint = region.GeometricExtents.MinPoint;
  60.         endPoint = new Gm.Point3d(
  61.           region.GeometricExtents.MaxPoint.X,
  62.           region.GeometricExtents.MinPoint.Y,
  63.           region.GeometricExtents.MinPoint.Z);
  64.  
  65.         while(startPoint.Y < region.GeometricExtents.MaxPoint.Y) {
  66.           using(Gm.Line3d line = new Gm.Line3d(startPoint, endPoint)) {
  67.             Br.Hit[] hits = brep.GetLineContainment(line, 1);
  68.             if(hits != null) {
  69.               foreach(Br.Hit hit in hits) {
  70.                 if(!hit.IsDisposed)
  71.                   hit.Dispose();
  72.               }
  73.               // чтобы регион полностью находился в границах
  74.               minY = startPoint.Y == region.GeometricExtents.MinPoint.Y ?
  75.                 startPoint.Y : startPoint.Y - delta;
  76.               break;
  77.             }
  78.             else {
  79.               startPoint = new Gm.Point3d(startPoint.X, startPoint.Y + delta,
  80.                 startPoint.Z);
  81.               endPoint = new Gm.Point3d(endPoint.X, endPoint.Y + delta,
  82.                 endPoint.Z);
  83.             }
  84.           }
  85.         }
  86.  
  87.         // Находим max X
  88.         Double maxX = Double.MinValue;
  89.         startPoint = region.GeometricExtents.MaxPoint;
  90.         endPoint = new Gm.Point3d(
  91.           region.GeometricExtents.MaxPoint.X,
  92.           region.GeometricExtents.MinPoint.Y,
  93.           region.GeometricExtents.MinPoint.Z);
  94.  
  95.         while(startPoint.X > region.GeometricExtents.MinPoint.X) {
  96.           using(Gm.Line3d line = new Gm.Line3d(startPoint, endPoint)) {
  97.             Br.Hit[] hits = brep.GetLineContainment(line, 1);
  98.             if(hits != null) {
  99.               foreach(Br.Hit hit in hits) {
  100.                 if(!hit.IsDisposed)
  101.                   hit.Dispose();
  102.               }
  103.               // чтобы регион полностью находился в границах
  104.               maxX = startPoint.X == region.GeometricExtents.MaxPoint.X ?
  105.                 startPoint.X : startPoint.X + delta;
  106.               break;
  107.             }
  108.             else {
  109.               startPoint = new Gm.Point3d(startPoint.X - delta, startPoint.Y,
  110.                 startPoint.Z);
  111.               endPoint = new Gm.Point3d(endPoint.X - delta, endPoint.Y,
  112.                 endPoint.Z);
  113.             }
  114.           }
  115.         }
  116.  
  117.         // Находим max Y
  118.         Double maxY = Double.MinValue;
  119.         startPoint = region.GeometricExtents.MaxPoint;
  120.         endPoint = new Gm.Point3d(
  121.           region.GeometricExtents.MinPoint.X,
  122.           region.GeometricExtents.MaxPoint.Y,
  123.           region.GeometricExtents.MinPoint.Z);
  124.  
  125.         while(startPoint.Y > region.GeometricExtents.MinPoint.Y) {
  126.           using(Gm.Line3d line = new Gm.Line3d(startPoint, endPoint)) {
  127.             Br.Hit[] hits = brep.GetLineContainment(line, 1);
  128.             if(hits != null) {
  129.               foreach(Br.Hit hit in hits) {
  130.                 if(!hit.IsDisposed)
  131.                   hit.Dispose();
  132.               }
  133.               // чтобы регион полностью находился в границах
  134.               maxY = startPoint.Y == region.GeometricExtents.MaxPoint.Y ?
  135.                 startPoint.Y : startPoint.Y + delta;
  136.               break;
  137.             }
  138.             else {
  139.               startPoint = new Gm.Point3d(startPoint.X, startPoint.Y - delta,
  140.                 startPoint.Z);
  141.               endPoint = new Gm.Point3d(endPoint.X, endPoint.Y - delta,
  142.                 endPoint.Z);
  143.             }
  144.           }
  145.         }
  146.         // Возвращаем вычисленный результат
  147.         minPoint = new Gm.Point2d(minX, minY);
  148.         maxPoint = new Gm.Point2d(maxX, maxY);
  149.       }
  150.     }

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Нарезка 3D тел
« Ответ #27 : 04-06-2014, 16:58:21 »
Мой алгоритм пошутрее будет:
Цитировать
Время 1=15.4038811 сек. - твой алгоритм
Время 2=1.504086 сек. - мой алгоритм
Интересно, что повторный запуск привел к еще большей разнице в результатах:
Цитировать
Время 1=28.8376495 сек.
Время 2=1.5920911 сек.
Это на тестовом чертеже по сто раз для каждого из Region получался BoundingBox обоими способами.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Нарезка 3D тел
« Ответ #28 : 04-06-2014, 17:25:00 »
Еще улучшил результат, обработав ситуацию когда не все контуры региона сплайны. В этом случае нет необходимости в аппроксимации и BoundigBox и та вычисляется правильно:
Код - C# [Выбрать]
  1. private void GetVisualBoundary(AcDb.Region region, double delta,
  2.   ref AcGe.Point2d minPoint, ref AcGe.Point2d maxPoint)
  3. {
  4.   double hord = delta;
  5.   using (AcGe.BoundBlock3d boundBlk = new AcGe.BoundBlock3d()) {
  6.     using (AcBr.Brep brep = new AcBr.Brep(region)) {
  7.       foreach (AcBr.Edge edge in brep.Edges) {
  8.         using (AcGe.Curve3d curve = edge.Curve) {
  9.           AcGe.ExternalCurve3d curve3d = curve as AcGe.ExternalCurve3d;
  10.           // Делать точный расчет нужно только если образующая - сплайн
  11.           // в противном случае достаточно получить BoundBlock
  12.           if (curve3d != null && curve3d.IsNurbCurve) {
  13.             AcGe.Interval interval = curve.GetInterval();
  14.             AcGe.PointOnCurve3d[] pnts =
  15.               curve.GetSamplePoints(interval.LowerBound, interval.UpperBound, hord);
  16.             foreach (AcGe.PointOnCurve3d pt in pnts) {
  17.               if (!boundBlk.IsBox)
  18.                 boundBlk.Set(pt.Point, pt.Point);
  19.               else
  20.                 boundBlk.Extend(pt.Point);
  21.             }
  22.           } else {
  23.             if (!boundBlk.IsBox) {
  24.               boundBlk.Set(edge.BoundBlock.GetMinimumPoint(), edge.BoundBlock.GetMaximumPoint());
  25.             } else {
  26.               boundBlk.Extend(edge.BoundBlock.GetMinimumPoint());
  27.               boundBlk.Extend(edge.BoundBlock.GetMaximumPoint());
  28.             }
  29.           }
  30.         }
  31.       }
  32.     }
  33.     // Возвращаем вычисленный результат
  34.     minPoint = new AcGe.Point2d(boundBlk.GetMinimumPoint().X, boundBlk.GetMinimumPoint().Y);
  35.     maxPoint = new AcGe.Point2d(boundBlk.GetMaximumPoint().X, boundBlk.GetMaximumPoint().Y);
  36.   }
  37. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нарезка 3D тел
« Ответ #29 : 05-06-2014, 10:49:14 »
1. Исключение возникает у тебя всегда или только на конкретных Region?
В AutoCAD 2009 возникает при обработке любого сплайна из обозначенного примера.