Возможно ли правильно высчитать площадь штриховки?

Автор Тема: Возможно ли правильно высчитать площадь штриховки?  (Прочитано 8269 раз)

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

Оффлайн VetalBYАвтор темы

  • ADN Club
  • Сообщений: 44
  • Карма: 3
Предложенный пример посмотрел на 2013 и 2017 акадах. Файл прислали, случай конечно неординарный, присутствует мультилиния. Но всё же оригинал штриховки (который прислал пользователь) команда _AREA считает правильно в AutoCAD 2013, а в 2017 говорит, что объект не обладает площадью. GeomProps даёт другой результат (такой же и мне удалось получить). Как видим, даже разные версии акада дают разный результат. И что делать?  :)

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
В 2013 для левой и правой штриховки команда _AREA у меня тоже не видит площадь:

Реального решения я в этой ситуации не вижу. Просто сообщать, что штриховка неправильная.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн VetalBYАвтор темы

  • ADN Club
  • Сообщений: 44
  • Карма: 3
А правильной считать штриховку, у которой площадь можно получить с помощью getArea? Александр, Ваш способ основан на этом алгоритме? http://adn-cis.org/perimetr-shtrixovki-s-pomoshhyu-objectarx-i-.net-api.html

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Проанализируй при помощи ARXDBG эту штриховку и увидишь, что вместо 2-ух loop, как должно быть по логике у неё только один:



И фактически получается, что площади этих двух контуров суммируются вместо того, чтобы вычитаться.
Алгоритм вычисления площади для штриховки у меня более сложный, чем в том примере.
Если pHatch->getArea(ar) == Acad::eOk  && ar > 1e-6 - используется эта площадь, если нет, то:

Код - C++ [Выбрать]
  1. double GetHatchArea(AcDbHatch *pHatch)
  2. {
  3.   double area = 0;
  4.   int nLoop = pHatch->numLoops();
  5.   Adesk::Int32 loopType;
  6.   for (int i = 0; i < nLoop; i++) {
  7.     double looparea = 0;
  8.     if ((loopType = pHatch->loopTypeAt(i)) & AcDbHatch::kPolyline) {
  9.       AcGePoint2dArray  vertices;
  10.       AcGeDoubleArray   bulges;
  11.       if (pHatch->getLoopAt(i, loopType, vertices, bulges) == Acad::eOk) {
  12.         AcDbPolyline *pPoly = new AcDbPolyline(vertices.length());
  13.         for (int j = 0; j < vertices.length(); j++) {
  14.           pPoly->addVertexAt(j, vertices[j], (bulges.length() < vertices.length()) ? 0.0 : bulges[j]);
  15.         }
  16.         pPoly->setClosed(!(loopType & AcDbHatch::kNotClosed));
  17.         pPoly->getArea(looparea);
  18.         if (loopType & AcDbHatch::kExternal) area += fabs(looparea); else area -= fabs(looparea);
  19.         delete pPoly;
  20.       }
  21.     }
  22.     else {
  23.       AcGeVoidPointerArray edgePtrs;
  24.       AcGeIntArray edgeTypes;
  25.       pHatch->getLoopAt(i, loopType, edgePtrs, edgeTypes);
  26.       AcGeCompositeCurve2d compCurve(edgePtrs);
  27.       AcGeInterval interval;  compCurve.getInterval(interval);
  28.       double pmin, pmax; interval.getBounds(pmin, pmax);
  29.       if (fabs(pmax - pmin) > 1e-6) {
  30.         if (compCurve.area(interval.lowerBound(), interval.upperBound(), looparea)) {
  31.           if (loopType & AcDbHatch::kExternal) area += fabs(looparea); else area -= fabs(looparea);
  32.         }
  33.         else {
  34.           AcGePoint2dArray pts; AcGeDoubleArray pars;
  35.           AcGePoint2d pmin, pmax;
  36.           AcGeBoundBlock2d blk2d = compCurve.boundBlock(interval);
  37.           blk2d.getMinMaxPoints(pmin, pmax);
  38.           double diag = pmin.distanceTo(pmax);
  39.           compCurve.getSamplePoints(interval.lowerBound(), interval.upperBound(), 1e-6 * max(1.0, diag), pts, pars);
  40.           int np = pts.length();
  41.           for (int i = 0; i < np; i++) {
  42.             looparea += 0.5 * pts[i][X] * (pts[(i + 1) % np][Y] - pts[(i + np - 1) % np][Y]);
  43.           }
  44.           if (loopType & AcDbHatch::kExternal) area += fabs(looparea); else area -= fabs(looparea);
  45.         }
  46.       }
  47.     }
  48.   }
  49.   return fabs(area);
  50. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн VetalBYАвтор темы

  • ADN Club
  • Сообщений: 44
  • Карма: 3
Да, я видел, что там один loop. В результате получилось, что внутренний контур вместо вычета прибавился. Беда в том, что его никак не "видно".
Спасибо за код! Получается, что через AcGeCompositeCurve2d результату доверять нельзя.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Беда в том, что его никак не "видно".
Вообще-то видно. Обрати внимание на то, что первые четыре Edge образуют полный loop и у них у всех конец очередного Edge совпадает с началом следующего. А вот начиная с пятого Edge идёт новый loop. Т.е. теоретически можно собрать их в правильные loop'ы и посчитать правильную площадь.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн VetalBYАвтор темы

  • ADN Club
  • Сообщений: 44
  • Карма: 3
Теоретически можно, и в конкретно этом случае (акад похоже и сделал, но loop'ы сложил), как-то не надежно всё это. Думаю, что в любом случае пользователя буду предупреждать, что площадь может быть посчитана не верно. А вообще получается, что вычертить акад штриховку может, а площадь посчитать - нет, забавно) Есть под рукой Bricscad 13, у него проблем с этой штриховкой не возникло, даже в окне свойств показал.