Разрезать Region

Автор Тема: Разрезать Region  (Прочитано 37981 раз)

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

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Разрезать Region
« : 26-05-2014, 14:08:29 »
Необходимо некоторый region нарезать сеткой с заданным шагом по оси X (dx) и по оси Y (dy). На выходе должны получиться новые объекты region.

На данный момент программно делаю так:
1. Выдавливаю исходный Region в Solid3D.
2. Нарезаю полученный Solid3d сеткой (по оси X и по оси Y). На выходе - огромное количество "ломтиков" (новых объектов Solid3d).
3. Выполняю Explode для каждого Solid3d и удаляю все полученные объекты Region, кроме того, который лежит в основании.

Примечание: Все промежуточные Solid3d инициализирую в блоке using, тем самым автоматически вызывая для них Dispose, т.к. не добавляю их в Database. Добавляю в Database только новые Region.

Хотелось бы выполнять операцию более быстро, минуя промежуточные шаги с использованием Solid3D. Есть ли более быстрый способ сделать это средствами API AutoCAD?

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #1 : 26-05-2014, 14:31:02 »
Хотелось бы выполнять операцию более быстро, минуя промежуточные шаги с использованием Solid3D. Есть ли более быстрый способ сделать это средствами API AutoCAD?
У класса Region есть метод BooleanOperation, который теоретически может помочь. Т.е. можно создать эталонный Region размером [dx dy] и, сдвигая его по сетке в границах исходного региона, выполнить пересечение (BoolIntersect) исходного Region с эталонным.
Не уверен, что этот способ будет более быстрым, но попробовать можешь.
Тут возможна еще оптимизация при помощи Brep, если границы эталонного Region находятся внутри исходного Region и не пересекают его, то результирующий Region равен эталонному, а если пересечения границ нет вообще, то эталонный Region вне исходного.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн German

  • ADN Club
  • **
  • Сообщений: 84
  • Карма: 13
Re: Разрезать Region
« Ответ #2 : 26-05-2014, 15:19:01 »
Т.е. можно создать эталонный Region размером [dx dy] и, сдвигая его по сетке в границах исходного региона
Может не сдвигать, а сразу прямоугольный массив создать?

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #3 : 26-05-2014, 15:24:36 »
Может не сдвигать, а сразу прямоугольный массив создать?
Думаю что тут будут большие расходы по памяти если достаточно большой исходный регион.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #4 : 26-05-2014, 18:05:07 »
Не уверен, что этот способ будет более быстрым, но попробовать можешь.
Я думаю производительность алгоритмов в данном случае будет зависеть от исходных данных (то есть будут случаи когда выигрывает один на одних исходных данных, и проигрывает на других) - в общем смотреть что ближе к "среднестатистическому использованию".
з.ы. но в общем да способ "кривоватый"...

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #5 : 27-05-2014, 22:37:46 »
У класса Region есть метод BooleanOperation, который теоретически может помочь. Т.е. можно создать эталонный Region размером [dx dy] и, сдвигая его по сетке в границах исходного региона, выполнить пересечение (BoolIntersect) исходного Region с эталонным.
Не уверен, что этот способ будет более быстрым, но попробовать можешь.
Так и сделал. Прироста производительности по сравнению с этим не наблюдаю (примерно то на то и выходит по времени), однако есть и положительный момент: корректно обрабатываются регионы, выполненные сплайнами.

Цитировать
Тут возможна еще оптимизация при помощи Brep, если границы эталонного Region находятся внутри исходного Region и не пересекают его, то результирующий Region равен эталонному, а если пересечения границ нет вообще, то эталонный Region вне исходного.
Завтра добавлю эту оптимизацию. Надеюсь, что после этого скорость работы всё же увеличится.

В качестве дополнительной оптимизации попробую распараллелить все манипуляции с регионами по разным потокам. Исхожу из того, что весь процесс происходит без привлечения Database и Application; зачистку промежуточных результатов выполняю самостоятельно посредством вызова Dispose на экземплярах классов AutoCAD .NET API. Не факт, что AutoCAD не умрёт после этого, но попробовать стоит, имхо...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #6 : 28-05-2014, 00:13:54 »
В качестве дополнительной оптимизации попробую распараллелить все манипуляции с регионами по разным потокам. Исхожу из того, что весь процесс происходит без привлечения Database и Application;
Так как все объекты из пространства имён Autodesk.AutoCAD.DatabaseServices есть ни что иное как обертки над ObjectARX классами AcDb из библиотеки acdbxx.dll, которая в свою очередь не является потокобезопасной, я бы поостерегся это делать. Во всяком случае рекомендую оставить этот вид оптимизации на потом.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #7 : 28-05-2014, 11:09:55 »
обертки над ObjectARX классами AcDb из библиотеки acdbxx.dll, которая в свою очередь не является потокобезопасной, я бы поостерегся это делать.
Ок, спасибо, пожалуй откажусь от этой идеи.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #8 : 28-05-2014, 23:12:45 »
Цитировать
    Тут возможна еще оптимизация при помощи Brep, если границы эталонного Region находятся внутри исходного Region и не пересекают его, то результирующий Region равен эталонному, а если пересечения границ нет вообще, то эталонный Region вне исходного.

Завтра добавлю эту оптимизацию. Надеюсь, что после этого скорость работы всё же увеличится.
Как оказалось, данная оптимизация оказалась невозможной, т.к. в ряде случаев приводит к некорректным результатам проверки.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #9 : 30-05-2014, 13:16:11 »
В ADN DevHelp подтвердили баг метода BrepEntity.GetMassProperties, т.е. с его помощью в AutoCAD .NET API получать Centroid для Region и Solid3d нельзя.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #10 : 30-05-2014, 13:24:01 »
В ADN DevHelp подтвердили баг
А ведь помнится вы утверждали, что в Autodesk тестируют код... Ну и как же они его тестируют, когда обозначенный функционал не работает ни в 2009-м, ни в 2015-м? Что-то мне подсказывает, что все промежуточные версии покажут тот же результат.

Практика показывает, что тестирование компании Autodesk очень напоминает способ "скомпилировалось, значит всё в порядке". Первая же проверка обозначенного функционала сразу бы выявила его неработоспособность. Отсюда вывод: этот свой код в Autodesk даже и не пытались тестировать.

Видимо у нас с вами разные понятия о тестировании...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #11 : 30-05-2014, 13:27:26 »
А ведь помнится вы утверждали, что в Autodesk тестируют код...
Это у тебя склероз проявляется. ;) Я утверждал, что тестируют сам AutoCAD, но не код. Код тестируется (как я понимаю) тот, который они сами используют. Так вот им видимо в голову не пришло использовать managed код для BREP - только native. IMHO.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #12 : 30-05-2014, 13:36:00 »
Код тестируется (как я понимаю) тот, который они сами используют.
Тогда удивляться не приходится.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #13 : 31-05-2014, 13:32:57 »
Как не странно, паралельно решал схожую проблему (не совсем ту - но тоже с region'ами), есть вариант оптимизации - нужно, как и предлагал А. Ривилис, "гнать" прямоугольник, но заниматься Intersect'ом не на каждой итерации - а анализируя геометрию прохождения границ (строки 55-65): вот "нарезал" из своих кусков:
Код - C# [Выбрать]
  1. open Autodesk.AutoCAD.ApplicationServices
  2. open Autodesk.AutoCAD.Runtime
  3. open Autodesk.AutoCAD.DatabaseServices
  4. open Autodesk.AutoCAD.Geometry
  5.  
  6. let (|AcEnt|AcNum|AcUnknow|) (x:TypedValue)=
  7.   enum<LispDataType>(x.TypeCode|>int)|>function
  8.     |LispDataType.ObjectId->AcEnt(x.Value:?>ObjectId)
  9.     |LispDataType.Int16->AcNum(x.Value:?>int16|>float)
  10.     |LispDataType.Int32->AcNum(x.Value:?>int|>float)
  11.     |LispDataType.Double->AcNum(x.Value:?>float)
  12.     |_->AcUnknow
  13.  
  14. let Rb=function
  15.   |null->[]
  16.   |(rb:ResultBuffer)->rb.AsArray()|>Array.toList
  17.  
  18. let Init()=
  19.   let doc=Application.DocumentManager.MdiActiveDocument
  20.   doc,doc.Editor,doc.Database,doc.TransactionManager.StartTransaction
  21.  
  22. [<LispFunction "NAREZ">]
  23. let Narez arg=
  24.   let doc,ed,db,trf=Init()
  25.   let MakeRegion (pt1:Point3d) width height=
  26.     let cl=new DBObjectCollection()
  27.     new Polyline2d(Poly2dType.SimplePoly,new Point3dCollection([|pt1
  28.                                                                  new Point3d(pt1.X+width,pt1.Y,pt1.Z)
  29.                                                                  new Point3d(pt1.X+width,pt1.Y+height,pt1.Z)
  30.                                                                  new Point3d(pt1.X,pt1.Y+height,pt1.Z)|]),
  31.                    0.0,true,0.0,0.0,new DoubleCollection([|0.0;0.0;0.0;0.0|]))|>cl.Add|>ignore
  32.     Region.CreateFromCurves(cl).[0]:?>Region
  33.   arg|>Rb|>function
  34.     |[AcEnt id;AcNum width;AcNum height]->
  35.             let start=System.DateTime.Now
  36.             use tr=trf()
  37.             tr.GetObject(id,OpenMode.ForWrite)|>function
  38.             | :? Region as rg->let ext=rg.GeometricExtents
  39.                                let block=tr.GetObject(rg.BlockId,OpenMode.ForWrite):?>BlockTableRecord
  40.                                let AppendEnt ent=
  41.                                    block.AppendEntity ent|>ignore
  42.                                    tr.AddNewlyCreatedDBObject(ent,true)
  43.                                let obr=MakeRegion ext.MinPoint width height
  44.                                let mtw=Matrix3d.Displacement(new Vector3d(width,0.0,0.0))
  45.                                let mth=Matrix3d.Displacement(new Vector3d(-width*(((ext.MaxPoint.X-ext.MinPoint.X)/width|>int)+1|>float),height,0.0))
  46.                                {0..(ext.MaxPoint.Y-ext.MinPoint.Y)/height|>int}
  47.                                     |>Seq.iter (fun _ ->{0..(ext.MaxPoint.X-ext.MinPoint.X)/width|>int}
  48.                                                                 |>Seq.fold (fun (next,check) _ ->
  49.                                                                                 let cl=(obr.Clone():?>Region)
  50.                                                                                 obr.TransformBy(mtw)
  51.                                                                                 let pc=new Point3dCollection()
  52.                                                                                 cl.IntersectWith(rg,Intersect.ExtendThis,pc,0,0)
  53.                                                                                 let inters()=cl.BooleanOperation(BooleanOperationType.BoolIntersect,rg.Clone():?>Region)
  54.                                                                                              cl.Area<0.0000001
  55.                                                                                 (pc.Count>0,next,check)|>function
  56.                                                                                   |true,_,_ when inters()->cl.Dispose()
  57.                                                                                                            (false,true)
  58.                                                                                   |true,_,_->AppendEnt cl
  59.                                                                                              (false,true)
  60.                                                                                   |_,_,true when inters()->cl.Dispose()
  61.                                                                                                            (false,false)
  62.                                                                                   |_,_,true|_,true,_->AppendEnt cl
  63.                                                                                                       (true,false)
  64.                                                                                   |_->cl.Dispose()
  65.                                                                                       (false,false))
  66.                                                                            (false,false)|>ignore
  67.                                                         obr.TransformBy(mth))
  68.                                obr.Dispose()
  69.             |_->ed.WriteMessage("Работаем только с Region'ами...\n")
  70.             tr.Commit()
  71.             "Затраченное время: "+string(System.DateTime.Now-start)+"\n"|>ed.WriteMessage
  72.     |_->ed.WriteMessage("Неверный тип аргументов - пример (narez (entlast) 10 10)\n")
Реализованна как лисп функция формат вызова (narez <ename> ширина_сегмента высота_сегмента); проверь идет ли с твоими тестовыми образцами и быстрее-ли.
Скомпилированную для 2014 прикладываю.
p.s. исправил код (стр. 68) - но не вложение.
p.p.s. вложение исправил - но только под 2010.
« Последнее редактирование: 03-06-2014, 12:37:37 от Дима_ »

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #14 : 02-06-2014, 14:14:35 »
Цитировать
вот "нарезал" из своих кусков:
Спасибо, правда для меня F# как китайская азбука.

Цитировать
Реализованна как лисп функция формат вызова (narez <ename> ширина_сегмента высота_сегмента); проверь идет ли с твоими тестовыми образцами и быстрее-ли.
Скомпилированную для 2014 прикладываю.
Очень неудобны следующие моменты:
1. Ctrl + Z отменяет не только то, что выполнила lisp-функция narez. Т.е. по хорошему, в коде должна быть выполнена группировка операций, которые будут отменяться по Ctrl + z, не захватывая при этом лишнего.
2. Я использовал (narez (car(entsel)) 10 10) в тестах. Очень неудобно, что выбирать приходится по одному. Попробовал так: (narez (ssget) 10 10), но не работает. Поскольку мои познания в LISP активно стремятся к нулю, то вполне возможно, что выбрать несколько можно, да я не знаю как - в этом случае прошу показать пример.

Мой вариант решения был показан здесь. На первый взгляд твой код работает быстрее (полагаю, что так будет и на второй, и на третий :) ). Но чтобы было удобно тестировать, было бы неплохо подправить моменты, обозначенные выше.

Спасибо.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #15 : 02-06-2014, 14:42:25 »
Обнаружил ошибку в результате работы своего кода... Слева направо: регион на основе сплайна, результат narez, результат meshregions. В моём результате присутствует щель между первым и вторым рядом, как показано на скрине. При резке других регионов такого нет.

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

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #16 : 02-06-2014, 14:52:22 »
ИХМО для автокада лисп хоть немного, но знать необходимо (чтоб велосипеды не делать), по первому вопросу - ну тож функция, а не команда - подразумевается, что будет во что-то завернута, а там и отмены и выбор и прочее - как-то так:
Код - Auto/Visual Lisp [Выбрать]
  1. (vl-load-com)
  2. (defun c:narez()
  3.   ((lambda (doc ss)
  4.      (if ss ((lambda (width height)
  5.                   (vla-startundomark doc)
  6.                   (mapcar '(lambda (ent) (narez ent width height))
  7.                       (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss))))
  8.                   (vla-endundomark doc))
  9.              (getdist "\nШирина ")
  10.              (getdist "\nВысота "))))
  11.    (vla-get-activedocument(vlax-get-acad-object))
  12.    (ssget '((0 . "region")))))
по неточности - то наверное привет от автокада - вполне возможно что это просто неточности отображения примитивов - попробуй регенерацию.
з.ы. подправил - форматирование "плясало"
« Последнее редактирование: 02-06-2014, 15:06:32 от Дима_ »

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #17 : 02-06-2014, 14:55:18 »
попробуй регенерацию.
Цитата: Андрей Бушман
(выполнен regen)

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #18 : 02-06-2014, 15:02:14 »
(выполнен regen)
Проскочил - скорее всего это визуализация проблемы точности вычисления float числа (типа так какой-нибудь синус посчитал)...
p.s. если есть желание "разогнать" свой вариант могу "накоментировать" код.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #19 : 02-06-2014, 15:14:19 »
твой код работает гораздо быстрее. Кроме того, в нём не вижу ошибки, обозначенной выше в моём решении. Копипаст не компилирует твой код. Полагаю, что показан фрагмент, а не весь исходник.
Цитировать
Error   11   Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'. Only the last source file of an application may omit such a declaration.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #20 : 02-06-2014, 15:29:55 »
Я просто "мелочь" компилирую из *.FSX (в начале) идут строки типа:
#r "c:/program files/autodesk/autocad 2014/acmgd.dll"
#r "c:/program files/autodesk/autocad 2014/acdbmgd.dll"
#r "c:/program files/autodesk/autocad 2014/accoremgd.dll"
а в VS сервис->внешние инструменты настроены различные компиляции (exe 2.0, exe 4.0, dll, standalone dll,...) - ихмо так удобней. В привычном варианте установи библиотеки и добавь1-ю строку типа module narez

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #21 : 02-06-2014, 15:56:17 »
Разница по скорости (поочерёдно резал объекты командами narez и meshregions):
Цитата: AutoCAD 2014
Command: NAREZ

Select objects: 1 found

Select objects:
РЁРёСЂРёРЅР° 10
Высота 10
Затраченное время: 00:00:00.7099610
nil

Command:
Command: MESHREGIONS

Выберите области (Regions) для добавления их в набор: 1 found

Выберите области (Regions) для добавления их в набор:

Всего выбрано областей (Regions): 1
dx <10>:

dy <10>:


Создано областей (region): 160
Затраченное время: 00:00:00.8574218

Command: NAREZ

Select objects: 1 found

Select objects:

РЁРёСЂРёРЅР° 10

Высота 10
Затраченное время: 00:00:00.7148438
nil

Command:
Command: MESHREGIONS

Выберите области (Regions) для добавления их в набор: 1 found

Выберите области (Regions) для добавления их в набор:

Всего выбрано областей (Regions): 1
dx <10>:

dy <10>:


Создано областей (region): 158
Затраченное время: 00:00:00.8476563

Command: NAREZ

Select objects: 1 found

Select objects:

РЁРёСЂРёРЅР° 10

Высота 10
Затраченное время: 00:00:00.5317500
nil

Command:
Command: MESHREGIONS

Выберите области (Regions) для добавления их в набор: 1 found

Выберите области (Regions) для добавления их в набор:

Всего выбрано областей (Regions): 1
dx <10>:

dy <10>:


Создано областей (region): 132
Затраченное время: 00:00:00.7197266

Command: NAREZ
Select objects: 1 found

Select objects:
РЁРёСЂРёРЅР° 10
Высота 10 Затраченное время: 00:01:05.3681641
nil

Command:
Command: MESHREGIONS

Выберите области (Regions) для добавления их в набор: 1 found

Выберите области (Regions) для добавления их в набор:
Всего выбрано областей (Regions): 1
dx <10>:
dy <10>:

Создано областей (region): 38865
Затраченное время: 00:02:16.3663656
Однако при использовании твоего кода на больших объемах исходных данных, как правило, получаю проблему:
Цитировать
---------------------------
AutoCAD Error Aborting
---------------------------


FATAL ERROR:  Out of memory - shutting down


---------------------------
ОК   
---------------------------
с последующим Fatal Error. Зачастую это происходит при первом автоматическом сохранении чертежа, в котором нарезкой уже создано огромное количество регионов. Полагаю, что у тебя происходит утечка памяти (например не все нужные Dispose вызываешь).


Цитировать
В привычном варианте установи библиотеки и добавь1-ю строку типа module narez
В строке
(rg,Intersect.ExtendThis,pc,0n,0n)получаю исключение:
Цитировать
Error   11   This expression was expected to have type
    int   
but here has type
    nativeint   

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #22 : 02-06-2014, 16:04:50 »
В строке

(rg,Intersect.ExtendThis,pc,0n,0n)получаю исключение:

Цитировать
Error   11   This expression was expected to have type
    int   
but here has type
    nativeint
   
Убрал суффиксы "n" - всё скомпилировалось. Однако в свете обозначенной выше проблемы с утечкой памяти, пока откладываю в сторону.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #23 : 02-06-2014, 16:13:02 »
заниматься Intersect'ом не на каждой итерации - а анализируя геометрию прохождения границ (строки 55-65):
можешь перевести эти строки на C#, чтобы я смог их прочесть?

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #24 : 02-06-2014, 16:21:29 »
Убрал суффиксы "n" - всё скомпилировалось.
По моему там чуть разные перегрузки метода в различных версиях автокада (под 2014 компилировал точно как в примере).
Про утечку - посмотрю - приложи dwg файлик.
"в прямую" их не перевести - вечером закоментирую.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #25 : 02-06-2014, 16:28:23 »
Про утечку - посмотрю - приложи dwg файлик.
Тестировал на этом файле, предварительно скопировав содержимое два раза и затем всё это отправив в обработку (нарезку). Windows 7x86.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #26 : 02-06-2014, 16:30:32 »
"шаг резьбы"?

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #27 : 02-06-2014, 16:35:39 »

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #28 : 02-06-2014, 16:56:12 »
Две копии одного и того же региона. Слева режется моим кодом на куски размером 52.391x52.391, а справа - на куски 52.392x52.392. Разница в 0.001, а результат различен...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #29 : 02-06-2014, 16:58:52 »
Я же писал о минимальной относительной погрешности в 1e-6. Вот похоже она и вылезла.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #30 : 02-06-2014, 17:00:50 »
Я же писал о минимальной относительной погрешности в 1e-6. Вот похоже она и вылезла.
1. Это проявляется даже если левый нижний угол границы региона находится в центре WCS.
2. Код, написанный Дима_ не даёт таких погрешностей на тех же самых исходных регионах.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #31 : 02-06-2014, 17:09:19 »
1. Это проявляется даже если левый нижний угол границы региона находится в центре WCS.
Здесь это уже не принципиально.
2. Код, написанный Дима_ не даёт таких погрешностей на тех же самых исходных регионах.
Дима сразу вырезает ячейки-прямоугольники размером [dx,dy], а ты сначала режешь строками, а потом их уже делишь на ячейки. Наверное разница в этом.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #32 : 02-06-2014, 17:24:36 »
Дима сразу вырезает ячейки-прямоугольники размером [dx,dy], а ты сначала режешь строками, а потом их уже делишь на ячейки. Наверное разница в этом.
А по другому никак: иначе я буду получать неправильные результаты, что и происходит в ряде случаев с использованием кода Дима_. Ниже прилагается дополнительный чертёж с тестовыми регионами. Берём первый "Ш"-образный регион и вызываем команду NAREZ, указывая следующие параметры:

Цитировать
Command: NAREZ
Select objects: 1 found

Select objects:
РЁРёСЂРёРЅР° 135

Высота 20
Затраченное время: 00:00:00.0595703
nil
На выходе визуально всё вроде выглядит правильно, однако это не так: выделяем верхний левый кусок и видим, что выделилась вся "строка". Возможно для Дима_ такой результат является именно тем, что нужно, однако моим пользователям для каждого из нарезанных кусков нужно получать центр масс. Соответственно в данном случае будет показан центр масс, общий для трёх кусков, а это не то, что требовалось моим юзерам. Именно поэтому у меня в коде две итерации: сначала строки, затем колонки. Собственно эти нюансы я и показывал здесь, выполняя различные логические операции над регионами.

UPD. Александр Наумович, собственно именно эту ситуацию мы и обсуждали с вами по скайпу 28 мая, в результате чего вы согласились, что обозначенная вами ранее оптимизация в данном случае не будет работать. Я как раз на примере буквы "Ш" и показывал вариант, который оптимизация не сможет корректно обработать.

P.S. Теперь мне понятно, за счёт чего код Дима_ работал быстрее, однако данный вариант решения мне не подойдёт.
« Последнее редактирование: 02-06-2014, 17:42:12 от Андрей Бушман »

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #33 : 02-06-2014, 21:39:27 »
Я же писал о минимальной относительной погрешности в 1e-6. Вот похоже она и вылезла.
Нет, это однозначно ошибка в моём коде. Завтра буду искать. Скорее всего где-то сделал Ctrl+C, Ctrl + V и не переименовал переменную (ну, или что-то вроде того).

Дима_, спасибо за код.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #34 : 02-06-2014, 22:43:00 »
По порядку: Словестное описание алгоритма - суть оптимизации такова, единожды высчитываем "сетку" по габаритным размерам которую заполняем прямоугольниками построчно и в процессе заполнения смотрим не пересекает-ли созданный сегмент границы области, если пересекает и имеет площадь - добавляем его в БД, а следующий за ним проверяем на пересечение (если пересекает - тогда все по новой) и площадь - если она около нуля - то тогда все последующие сегменты до пересечения Dispos'ируем, если площадь есть (то есть полный прямоугольник - пересечений ведь нет), то последующие сегменты рисуем без проверок, до следующего пересечения. Упрощая проверяем на "пересечение" только "граничащие" клетки и 1 следующею за ними - остальные по последней.

В коде:
Код - C# [Выбрать]
  1. Seq.fold (fun (next,check) _ -> //запускаем "свертку" с 2-мя bool аргументами "рисовать следующий" и "проверять"
  2.     let cl=(obr.Clone():?>Region) //создаем "копию" образцового прямоугольника
  3.     obr.TransformBy(mtw) // перемещаем "оригинал" на следующий столбец
  4.     let pc=new Point3dCollection() // коллекция точек пересечения
  5.     cl.IntersectWith(rg,Intersect.ExtendThis,pc,0n,0n) //заполняем коллекцию точками пересечения (если они есть)
  6.     let inters()=cl.BooleanOperation(BooleanOperationType.BoolIntersect,rg.Clone():?>Region)
  7.                  cl.Area<0.0000001 // функция "наложения" регионов, возвращает true если выходной регион "без площади"
  8.     (pc.Count>0,next,check)|>function // функция проверки от 3 аргументов: есть ли пересечения?, рисовать?, требуется ли проверка
  9.       |true,_,_ when inters()->cl.Dispose() // если было пересечение и примитив без площади
  10.                                (false,true) // уничтожаем сегмент и на след. итерации выполняем проверку
  11.       |true,_,_->AppendEnt cl//если пересечение и нормальная площадь
  12.                  (false,true)// добавляем "обрезок" и проверка на следующем
  13.       |_,_,true when inters()->cl.Dispose()//если установлен флаг проверки, но нет площади
  14.                                (false,false)// до следующего пересечения рисовать не надо
  15.       |_,_,true|_,true,_->AppendEnt cl// если была площадь, либо установленн флаг "рисования"
  16.                           (true,false)// то оставляем сегмент без изменений (его не надо подрезать)
  17.       |_->cl.Dispose()
  18.           (false,false))// во всех остальных случаях - удаляем сегмент.
  19. (false,false) // начальное значение аргументов каждой "строки"

По фаталу - да действительно если создать значительное кол-во сегментов - то автокад намертво зависает на записи (у меня x64) - либо я просто не дождался завершения, причем висит именно на записи, саму "нарезку" он делает, я попробовал еще включать dispose копиям "главных" объектов которые идут как аргумент в BooleanOperation (что по моему представлению должно быть встроено непосредственно в метод) - результата не дало. Можно просто попробывать создать эквивалентное кол-во регионов - может просто акад "не осиливает", т.к. вроде все созданное либо в БД либо в Dispose.

По "проблеме буквы Ш" - чтобы "уши" буквы были в разных областях - надо задавать соответствующие размеры "клетки", я не очень понимаю как от этого спасает алгоритм "нарезать вначале строки, потом столбцы", да строки немного "запляшут" относительно друг друга - то есть сегменты лягут "кривым кирпичиком" т.к. столбцы начинаются с физического начала строки (а не сетки - как у меня), что в некоторых частных случаях выделит "разрезанный сегмент" в разные регионы, но с той же вероятностью, на произвольном теле справедливо и обратно - если "клетка" достаточно велика, там в обоих случаях может "попасться" "несколькотельный" сегмент.

з.ы. чтоб лисп не писал "кракозябры" - сохрани в default кодировке.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #35 : 02-06-2014, 23:16:34 »
По фаталу - да действительно если создать значительное кол-во сегментов - то автокад намертво зависает на записи (у меня x64) - либо я просто не дождался завершения, причем висит именно на записи, саму "нарезку" он делает, я попробовал еще включать dispose копиям "главных" объектов которые идут как аргумент в BooleanOperation (что по моему представлению должно быть встроено непосредственно в метод) - результата не дало. Можно просто попробывать создать эквивалентное кол-во регионов - может просто акад "не осиливает", т.к. вроде все созданное либо в БД либо в Dispose.
В режиме DEBUG загляни в отладочную консоль. Если у тебя где-то пропущен вызов Dispose, то там должна появиться подсказка на эту тему, т.к. реализация метода !DBObject() следующая:
Код - C# [Выбрать]
  1. // Autodesk.AutoCAD.DatabaseServices.DBObject
  2. private void !DBObject()
  3. {
  4. object[] args = new object[]
  5. {
  6. base.GetType().ToString()
  7. };
  8. Debug.WriteLine("DisposableWrapper", string.Format(CultureInfo
  9.     .InvariantCulture, "Forgot to call Dispose? ({0})", args));
  10. }
Т.о. при "потере" Dispose должны появляться сообщения вида "Forgot to call Dispose? ...".


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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #36 : 02-06-2014, 23:29:27 »
По "проблеме буквы Ш" - чтобы "уши" буквы были в разных областях - надо задавать соответствующие размеры "клетки", я не очень понимаю как от этого спасает алгоритм "нарезать вначале строки, потом столбцы", да строки немного "запляшут"
Да, что-то меня перемкнуло: твой код запустил, чтобы проверить проблему, а свой почему-то решил не запускать, т.к. "всё должно быть пучком". Похоже я поторопился, завтра ещё подумаю. Проблема в том, что нужно как-то гарантированно резать так, чтобы в одном регионе не было нескольких сегментов (как при резке буквы Ш клеткой, равной длине региона).

Нужно как-то получить количество внешних контуров в регионе и на основе каждого такого контура (с учётом вложенных контуров- отверстий, если такие есть) создать отдельные регионы. Тут дополнительная проблема возникает: если в одном из таких контуров имеется отверстие, в составе которого будет ещё один контур (островок в отверстии), то и его нужно отдельно обрабатывать и т.д. рекурсивно анализируя структуру контуров... Т.е. всё не так просто, как хотелось бы.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #37 : 02-06-2014, 23:58:47 »
то и его нужно отдельно обрабатывать и т.д. рекурсивно анализируя структуру контуров...
... это не слабое такое уточнение...
боюсь через текущий .Net API тут глухо, ихмо надо лезть в расшифровку ACIS (что само по себе гемор, а для тебя еще и лисп-гемор), тут надо на поклон к Елпанову Евгению - он по моему в этом "хорошо шагнул". Либо методом Ньютона обрезать регион до допустимых ограничений и искать - но тогда время выполнения "немножко" прибавится (хоть ньютон и быстр, на раз в 10-15 вынь да полож) Или "врзрывать и смотреть" - короче по хорошему сложно (очень), по "быстрому" не быстро и "криво".

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #38 : 03-06-2014, 00:04:11 »
... это не слабое такое уточнение...
Согласен. Просто когда я показал юзеру эту ситуацию на конкретных примерах, и уточнил насчёт рекурсивного анализа (островки в отверстиях и т.п.), то ответ был "ну конечно же, это обязательно".
Цитировать
короче по хорошему сложно (очень), по "быстрому" не быстро и "криво".
Буду пытаться найти "консенсус" с юзерами.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #39 : 03-06-2014, 00:18:43 »
боюсь через текущий .Net API тут глухо
Для этого есть BREP .NET API
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #40 : 03-06-2014, 00:28:48 »
Маэстро! раз и Вы не спите - на что похожи "симптомы" когда много (очень) объектов создано, но потом не сохранится? (Dispose пропущен или еще что). Про Brep Вы же сами здесь писали - что не прокатит?

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #41 : 03-06-2014, 00:33:45 »
Буду пытаться найти "консенсус" с юзерами.
ИХМО - по моему, в данном случае, это наиболее верное решение.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #42 : 03-06-2014, 00:36:32 »
Про Brep Вы же сами здесь писали - что не прокатит?
Там ошибка в одном из методов, который к этой теме отношения не имеет.  Да и тот метод можно реализовать через P/Invoke.
Маэстро! раз и Вы не спите - на что похожи "симптомы" когда много (очень) объектов создано, но потом не сохранится? (Dispose пропущен или еще что).
Вполне возможно, что пропущен Dispose. Но на 100% уверенно сказать не могу. Особенно в AutoCAD 2014, в котором переписали работу с Solid3d и Region таким образом, что быстродействие упало при прочих равных условиях в два раза по сравнению с AutoCAD 2013 (факт подтвержденный в ADN DevHelp).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #43 : 03-06-2014, 07:57:30 »
Особенно в AutoCAD 2014, в котором переписали работу с Solid3d и Region таким образом, что быстродействие упало при прочих равных условиях в два раза по сравнению с AutoCAD 2013 (факт подтвержденный в ADN DevHelp).
А в 2015-м как дела обстоят?

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #44 : 03-06-2014, 10:58:12 »
А в 2015-м как дела обстоят?
Пока также как и в 2015 - я слишком поздно отправил этот баг.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #45 : 03-06-2014, 11:19:51 »
P.S.: Кстати, последите за размером файла UNDO. Его максимально допустимое значение 2Гб. Вполне возможно, что на очень больших объемах добавления примитивов к базе это значение достигается. Можно попробовать это исправить отключив запись UNDO при помощи вызова Database.DisableUndoRecording(true);
« Последнее редактирование: 03-06-2014, 11:35:42 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #46 : 03-06-2014, 11:24:25 »
Нет, это однозначно ошибка в моём коде. Завтра буду искать. Скорее всего где-то сделал Ctrl+C, Ctrl + V и не переименовал переменную (ну, или что-то вроде того).
Нашёл ошибку: при рассечении на "столбцы" габариты расчитывались относительно региона "строки". А поскольку в ряде случаев строка может содержать в составе контура куски сплайнов, то и габариты показываются не те, что видны визуально (по понятным причинам). Внёс исправление - все смещения dx, dy выполняю относительно габаритов базового региона. Заодно и сетка ровная получается. Сейчас добавлю некоторые дополнительные изменения. Посмотрю, что быстрее: клонировать и смещать регион, или же создавать новый на основе вычисленных точек и контура.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #47 : 03-06-2014, 12:22:06 »
Можно попробовать это исправить отключив запись UNDO при помощи вызова Database.DisableUndoRecording(true);
Это первое про что я подумал и в dll и в лиспе - но не оно.
Нашел таки:
Подходит стажер ПТУшник к мастеру опустив взгляд, стоит молчит...
Мастер - что запарол?
 - да - все 11 запарол.
 - я ж тебе всго 10 давал.
 - а я и образец запорол.

Вот так и я я "гонял" "образец" по сетке и копировал его, копии тщательно или записывал или "запарывал", а что в конце образец надо "запороть" забыл. На "небольших" количествах прокатывало, а на многотысячных накладывались дескрипторы и привет. В общем исправил в коде - сейчас файл Андрея "пережевывает" на ура. Выкладывать не стал - т.к. 24 метра.
з.ы. да кстати - сейчас под рукой 2010 - там действительно перегрузка метода IntersectWith только с целыми (а в 2014*64 - нативы).
з.з.ы. Сейчас автор в соседней теме найдет как считать наиболее "правильные" границы через brep, и можно будет еще разогнать на "сплайновых" областях - хотя и "пустые" участки алгоритм пробегает достаточно быстро (без булевых операций с регионами), но все равно делать их незачем.
« Последнее редактирование: 03-06-2014, 15:40:51 от Дима_ »

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #48 : 03-06-2014, 20:05:58 »
Цитата: Дима_ link=topic=750.msg2969#msg2969
з.з.ы. Сейчас автор в соседней теме найдет как считать наиболее "правильные" границы через brep, и можно будет еще разогнать на "сплайновых" областях - хотя и "пустые" участки алгоритм пробегает достаточно быстро (без булевых операций с регионами), но все равно делать их незачем.
Угу. Найдено и было показано здесь ещё в 14:28. Обновил здесь описание, скрины и код. Осталось решить проблему объединённых регионов. Но это уже не сегодня. Завтра заодно оптимизирую код GetVisualBoundary, чтобы половинить расстояния, те опять половинить и т.д. а не приращать на значения dx и dy (а то текущий вариант похож на пузырьковую сортировку :)).
« Последнее редактирование: 03-06-2014, 20:25:07 от Андрей Бушман »

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #49 : 03-06-2014, 21:57:05 »
Стал проверять 2014x64 - не работает - все тоже самое, после записи - висим. Поняв что это все-же не та ошибка что нашел на 2010x32 (здесь она не проявляется даже если Dispose() убрать, видимо из-за разрядности дескрипторов - их коллизийность на порядок меньше) - но проделал простой эксперимент - берем чистый акад, создаем регион, делаем 50 тыс. копий вручную (это не долго, делаем 10 копий, потом еще 10 копий копий итд - за несколько движений получаем нужное количество), нажимаем запись сохраняется tmp файл и виснет намертво (ну или я такой не терпеливый)... Видимо эта то самое обновление работы с регионами. Можно передать"привет" автодеску.
p/s/ От массива эффект аналогичный...
p.p.s По поводу нахождения границ методом Ньютона - ту можно попасть в просак т.к. метод подразумевает непрерывную функцию - проще говоря если регион из двух кусков, можно запросто попасть между ними - в общем есть вариант оставить "как есть".
« Последнее редактирование: 03-06-2014, 23:16:12 от Дима_ »

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #50 : 03-06-2014, 23:37:26 »
проще говоря если регион из двух кусков, можно запросто попасть между ними - в общем есть вариант оставить "как есть".
Хм... Как вариант, можно с помощью Brep попробовать проанализировать границы каждого Face и вычислить для них (minX, minY) и (maxX, maxY).

Пользователи ставят перед фактом, что объединённых регионов обязательно не должно быть. Т.о. на эту тему ещё придётся думать... Вот если бы можно было на основе Face создать Region, то тогда проблема бы отвалилась. Пока что юзеры предлагают, мол: "если всё так сложно, то просто скачай с Инета прогу, которая будет по точкам делать триангуляцию на основе объектов Region или Solid3d (делов-то). Таких программ в Инете полным полно."...

Правда при мне так и не смогли ни одной такой найти. Те, что видели на тему триангуляции, строят треугольные объекты Face (это годится) по точкам, и не учитывают отверстия (а это уже не то...). Предложил им пока самостоятельно выбрать любое из "огромного количества доступных в Интернете решений" (раз всё так просто и быстро находится), а я пока попробую допилить текущий вариант с регионами. Может чего и накопают интересного.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #51 : 03-06-2014, 23:56:00 »
пока вижу только вариант брать заведомо меньший размер клетки

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #52 : 04-06-2014, 00:02:29 »
пока вижу только вариант брать заведомо меньший размер клетки
Тут видишь ли в чём дело... Проектировщикам нужно сечение конструкции в разных местах кромсать по разному. Т.е. они сначала могут дать команду разрезать регион на три строки (не рассекая их на столбцы), а затем к каждой строке применить свою собственную команду нарезки со своим размером ячейки. Как правило, крайние строки им нужно резать на как можно меньшие ячейки, в то время как строки ближе к центру можно резать на бОльшие куски.

Можно, конечно, визуально сразу выбрать подходящий размер ячейки, но по закону подлости у них обязательно "зачастят" хитрые случаи, где будут присутствовать объединённые регионы. Причём ситуация почти перестанет встречаться сразу после того, как программно будет найдено решение проблемы (закон жизни).

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #53 : 04-06-2014, 00:06:22 »
Предлагаю завести отдельную ветку форума, аля "Клуб любителей резьбы по дереву по регионам\солидам... ;D

Шутки юмора шучу...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #54 : 04-06-2014, 00:42:26 »
Хм... Как вариант, можно с помощью Brep попробовать проанализировать границы каждого Face и вычислить для них (minX, minY) и (maxX, maxY).
"Я эту идею породил - я её и убью". Она будет несправедлива в случае если внутренние контура могут быть не выпуклыми.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #55 : 04-06-2014, 00:45:13 »
Она будет несправедлива в случае если внутренние контура не выпуклые.
Поясните. Какая разница "выпуклые" или "впуклые"? Границы-то один хрен: двумя точками кажет (левый нижний и правый верхний).

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #56 : 04-06-2014, 01:45:01 »
Поясните. Какая разница "выпуклые" или "впуклые"? Границы-то один хрен: двумя точками кажет (левый нижний и правый верхний).
Подумай как будут выглядеть окаймляющие прямоугольники у этих двух фигур и как они будут располагаться один относительно другого:

« Последнее редактирование: 04-06-2014, 02:31:18 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #57 : 04-06-2014, 02:18:39 »
Вот если бы можно было на основе Face создать Region, то тогда проблема бы отвалилась.
Ну в принципе можно. Только не на основе Face, а на основе Loop ты должен создавать Region. Фактически в указанном тобой "неправильном" Region вместо одного несколько Loop. Каждый Loop состоит из одной или нескольких Edge, которую можно превратить в  Curve3d. Из Curve3d можно получить (с заданной точностью) набор точек, которые её представляют. Как это сделать я показал тут: http://adn-cis.org/forum/index.php?topic=495.msg2990#msg2990
Ну и из набора точек несложно создать Polyline из которой создать Region. Как-то так пока.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #58 : 04-06-2014, 11:11:08 »
Всё оказалось гораздо проще... :)
 
1. Если мы взрываем одиночные регионы (с отверстиями или без - это не важно), то на выходе получаем примитивы, которыми вычерчен их контур, т.е. линии, дуги, сплайны, окружности.

2. Если мы взрываем объединённые регионы, то при первом взрыве мы получаем набор отдельных регионов, с сохранением отверстий (если таковые имеются). Повторный взрыв делает то же самое, что и в п.1.

Т.о. если я вижу, что Face Complexes более 1, то взрываю регион и полученные новые регионы добавляю в набор. Проверил, работает. Подправил код в блоге.
« Последнее редактирование: 04-06-2014, 11:21:53 от Андрей Бушман »

Оффлайн bargool

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Re: Разрезать Region
« Ответ #59 : 04-06-2014, 11:43:52 »
Те, что видели на тему триангуляции, строят треугольные объекты Face (это годится) по точкам, и не учитывают отверстия (а это уже не то...)
Вот эта библиотека делает триангуляцию по точкам, при этом есть возможность указать отверстия и контуры.. недавно с ней пришлось основательно поиграться..
Алексей

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #60 : 04-06-2014, 11:51:24 »
Если мы взрываем объединённые регионы, то при первом взрыве мы получаем набор отдельных регионов,
Ну это просто сказачное везение - тогда проблемма буквы Ш решаеться 5-тью строками, но предложенная мной оптимизация идет лесом - т.к. "островок" может попастся внутри клетки и пересечения не будет - то есть каждую клетку надо "булеанить", а потом еще и проверить brepom - в общем процесс будет совсем не быстрый...
В общем реально только если клетки не такие маленькие как в примере (т.к. все равно будут взрываться).

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #61 : 04-06-2014, 11:52:17 »
bargool,
Спасибо, посмотрю обязательно.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #62 : 04-06-2014, 11:54:42 »
то есть каждую клетку надо "булеанить", а потом еще и проверить brepom - в общем процесс будет совсем не быстрый...
Именно так я и делаю. Пользователя скорость устраивает, по его заявлению, т.к. написанный им вариант на VBA работал ещё медленнее.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #63 : 04-06-2014, 12:16:08 »
Перед тем как делать ниженаписанное вначале надо ответить на главный вопрос "Надо-ли":
Чтоб не "булеанить" каждую клетку, можно brep'ом "собрать" все точки кривых region'а, одновременно индексируя их по координатам будующих клеткок (точнее пометить клетки в которых есть хотя-бы одна точка). Далее все непроиндексированные клетки рисуются как есть, а "попавшие под индекс" булеаняться и рекурсивно взрываются (или там 1-го взрыва всегда достаточно?) , для проверки клетки "внутри\снаружи" применять тот-же алгоритм, что и с пересечением.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #64 : 04-06-2014, 12:21:00 »
или там 1-го взрыва всегда достаточно?
Цитата: Андрей Бушман
2. Если мы взрываем объединённые регионы, то при первом взрыве мы получаем набор отдельных регионов, с сохранением отверстий (если таковые имеются). Повторный взрыв делает то же самое, что и в п.1.
рекурсивный взрыв не требуется, всё "как надо" после первого взрыва.

Перед тем как делать ниженаписанное вначале надо ответить на главный вопрос "Надо-ли"
На данный момент не надо.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #65 : 04-06-2014, 17:29:17 »
Т.о. если я вижу, что Face Complexes более 1, то взрываю регион и полученные новые регионы добавляю в набор. Проверил, работает.
Отлично. Если это всегда так, то совсем замечательно. Можно например написать свой вариант команды EXPLODE, которая расчленяет только Region/Solid3d, но только тогда, когда они состоят из отдельных частей и расчленяются на составляющие Region/Solid3d.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #66 : 07-06-2014, 14:12:00 »
Я тут приболел, но если в голове есть алгоритм (да еще и понимание, что его реализация лежит в весьма ограниченном числе строк), то для хорошего человека его и реализовать не грех - и вот когда появились "умственные просветы"... В общем реализация вышеописанного алгоритма оказалась даже меньше чем я ожидал (тем паче что практически весь brep я скопипастил в соседней теме у А. Ривилиса - думаю он не против :) ) - и почуствовав, что как-то больно быстро получилось - еще и перетащил функцию в команду:
Код - C# [Выбрать]
  1. open Autodesk.AutoCAD.ApplicationServices
  2. open Autodesk.AutoCAD.Runtime
  3. open Autodesk.AutoCAD.DatabaseServices
  4. open Autodesk.AutoCAD.Geometry
  5. open Autodesk.AutoCAD.EditorInput
  6. open Autodesk.AutoCAD.BoundaryRepresentation
  7.  
  8. let Init()=
  9.   let doc=Application.DocumentManager.MdiActiveDocument
  10.   doc,doc.Editor,doc.Database,doc.TransactionManager.StartTransaction
  11.  
  12. let RegExplode (rg:Region)=
  13.   let brep=new Brep(rg)
  14.   seq{for f in brep.Faces->f}|>function
  15.     |faces when faces|>Seq.skip 1|>Seq.isEmpty->[rg]
  16.     |_->let coll=new DBObjectCollection()
  17.         rg.Explode(coll)
  18.         rg.Dispose()
  19.         [for x in coll->x:?>Region]
  20.  
  21. let IndexRegion (rg:Region) width height=
  22.   let deltaX=width/10.0
  23.   let deltaY=height/10.0
  24.   let x0,y0=let pt=rg.GeometricExtents.MinPoint
  25.             pt.X,pt.Y
  26.   use br=new Brep(rg)
  27.   seq{for face in br.Faces->
  28.        seq{for lop in face.Loops->
  29.             seq{for edge in lop.Edges->
  30.                  use curve=edge.Curve
  31.                  let intr=curve.GetInterval()
  32.                  let p1,p2=intr.LowerBound,intr.UpperBound          
  33.                  {p1..(p2-p1)/(curve.GetLength(p1,p2,(min deltaX deltaY)/2.0)/(min deltaX deltaY))..p2}
  34.                    |>Seq.map (curve.EvaluatePoint)|>Seq.toArray}}}
  35.                    |>Seq.concat|>Seq.concat|>Seq.concat //seq point3d
  36.     |>Seq.fold (fun set pt->let x,y=(pt.X-x0)/width,(pt.Y-y0)/height
  37.                             set|>Set.add(x|>int,y|>int)
  38.                                |>Set.add(x|>int,y+0.1|>int)
  39.                                |>Set.add(x|>int,y-0.1|>int)
  40.                                |>Set.add(x+0.1|>int,y|>int)
  41.                                |>Set.add(x+0.1|>int,y+0.1|>int)
  42.                                |>Set.add(x+0.1|>int,y-0.1|>int)
  43.                                |>Set.add(x-0.1|>int,y|>int)
  44.                                |>Set.add(x-0.1|>int,y+0.1|>int)
  45.                                |>Set.add(x-0.1|>int,y-0.1|>int))
  46.                (Set [])
  47.  
  48. let MakeRegion (pt1:Point3d) width height=
  49.   let cl=new DBObjectCollection()
  50.   new Polyline2d(Poly2dType.SimplePoly,new Point3dCollection([|pt1
  51.                                                                new Point3d(pt1.X+width,pt1.Y,pt1.Z)
  52.                                                                new Point3d(pt1.X+width,pt1.Y+height,pt1.Z)
  53.                                                                new Point3d(pt1.X,pt1.Y+height,pt1.Z)|]),
  54.                  0.0,true,0.0,0.0,new DoubleCollection([|0.0;0.0;0.0;0.0|]))|>cl.Add|>ignore
  55.   Region.CreateFromCurves(cl).[0]:?>Region
  56.  
  57. [<CommandMethod "Narez">]
  58. let Narez()=
  59.   let doc,ed,db,trf=Init()
  60.   let Slice width height id=
  61.     let start=System.DateTime.Now
  62.     use tr=trf()
  63.     let rg=tr.GetObject(id,OpenMode.ForWrite):?>Region
  64.     let ext=rg.GeometricExtents
  65.     let block=tr.GetObject(rg.BlockId,OpenMode.ForWrite):?>BlockTableRecord
  66.     let AppendEnt (ent:Entity)=
  67.         block.AppendEntity ent|>ignore
  68.         tr.AddNewlyCreatedDBObject(ent,true)    
  69.     let obr=MakeRegion ext.MinPoint width height
  70.     let mtw=Matrix3d.Displacement(new Vector3d(width,0.0,0.0))
  71.     let mth=Matrix3d.Displacement(new Vector3d(-width*(((ext.MaxPoint.X-ext.MinPoint.X)/width|>int)+1|>float),height,0.0))
  72.     let index=IndexRegion rg width height
  73.     "\n"+string(System.DateTime.Now-start)+" - индексация выполненна; "|>ed.WriteMessage
  74.     {0..(ext.MaxPoint.Y-ext.MinPoint.Y)/height|>int}
  75.       |>Seq.iter (fun y ->{0..(ext.MaxPoint.X-ext.MinPoint.X)/width|>int}
  76.                              |>Seq.fold (fun (next,check) x ->
  77.                                 (Set.contains (x,y) index,next,check)|>function
  78.                                    |true,_,_->let cl=(obr.Clone():?>Region)
  79.                                               obr.TransformBy(mtw)
  80.                                               cl.BooleanOperation(BooleanOperationType.BoolIntersect,rg.Clone():?>Region)
  81.                                               if cl.Area<0.0001
  82.                                                  then cl.Dispose()
  83.                                                  else cl|>RegExplode|>Seq.iter AppendEnt
  84.                                               false,true
  85.                                    |_,_,true->let cl=(obr.Clone():?>Region)
  86.                                               obr.TransformBy(mtw)
  87.                                               cl.BooleanOperation(BooleanOperationType.BoolIntersect,rg.Clone():?>Region)
  88.                                               if cl.Area<0.0001
  89.                                                  then cl.Dispose()
  90.                                                       false,false
  91.                                                  else cl|>RegExplode|>Seq.iter AppendEnt
  92.                                                       true,false
  93.                                    |_,true,_->let cl=(obr.Clone():?>Region)
  94.                                               obr.TransformBy(mtw)
  95.                                               AppendEnt cl
  96.                                               true,false
  97.                                    |_->obr.TransformBy(mtw)
  98.                                        false,false) (false,false)|>ignore
  99.                           obr.TransformBy(mth))
  100.     obr.Dispose()
  101.     tr.Commit()
  102.     "всего затраченно: "+string(System.DateTime.Now-start)+"\n"|>ed.WriteMessage
  103.   let inline (|PromptOk|_|) (pr:^a)=(^a:(member Status:PromptStatus)pr)=PromptStatus.OK|>function
  104.                                       |true->Some(pr)
  105.                                       |false->None
  106.   let ErrInput()=ed.WriteMessage("\nКоманда отменена")
  107.   ed.GetSelection(new SelectionFilter([|new TypedValue(int(DxfCode.Start),"REGION")|]))|>function
  108.     |PromptOk(ss)->ed.GetDistance("\nШирина: ")|>function
  109.       |PromptOk(width)->ed.GetDistance("\nВысота:")|>function
  110.         |PromptOk(height)->let start=System.DateTime.Now
  111.                            seq{for ssid in ss.Value->ssid.ObjectId}
  112.                             |>Seq.iter (Slice width.Value height.Value)
  113.                            "\nОбщее время: "+string(System.DateTime.Now-start)|>ed.WriteMessage
  114.         |_->ErrInput()
  115.       |_->ErrInput()
  116.     |_->ErrInput()
Имя то-же - narez, в итоге получилось побыстрее чем предыдущая версия (без стойкости к букве Ш).
т.к. написанный им вариант на VBA работал ещё медленнее.
Уповать на скорость API против алгоритма никогда не стоит - рано или поздно тыкнут носом - вот мол на такой ...не пишут, а работает в Х-раз быстрее, а ты тут извращаешся, а результату...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #67 : 08-06-2014, 01:40:07 »
Дима. Интересно насколько изменится скорость если использовать не edge.Curve, а edge.Curve.NativeCurve, как я использовал здесь.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #68 : 08-06-2014, 02:38:04 »
Маэстро спасибо за дружеский анализ. Я откровенно говоря отношусь скептически к "битве за урожай", мне например, гораздо больше смущают в моем-же коде строки 37-47, эту "самокопипасту", чуть что исправлять замучаешься - а завернуть во что-то более приемлемое глазу ее конечно стоит - ну ладно болею - простят. По существу вопроса т.к. по крайней мере на "экземпляре" Андрея, индексация занимат не значительную часть времени, то и приросту изменения даст не много - даже если время индексации обнулиться совсем - по факту на первом прогоне, Ваш вариант получился даже медленней - хотя я считаю, что это погрешность измерений - но по моему твердому убеждению, все что лежит в ее пределах - принебрегаем и выбираем более надежный, либо читабельный. Вот логи (Ваш вариант NAREZNAT запускался вторым после отмены работы первого), я не считал отдельно индексацию - но там ИХМО +- одинаково (значительный отрыв результата первого региона грешу на подгрузку и пр. предварительную работу).

з.ы. Я в этом коде пренебрег подсчетом нулевой точки - последовательность можно преобразовать в массив (например), расчитать минимальные X и Y и "плясать" от них (то есть преобразовать эту-же последовательность), а не от GetBoundingBox как в примере, но т.к. индескации в этих "пустых" клетках нет, то по ней просто пробежиться TransformBy - даже не создавая клон, и тем паче не анализируя его - в общем проверять даст ли это выйгрыш мне просто лень, но вполне возможно на элипсах процентов 5 там прячется от общей производительности. Я не люблю хранить большие массивы данных без особой на то необходимости (хотя преобразование последовательности в массив по каждому контуру таки есть - т.к. он должен быть Dispose'ен - инчае вылезит фатальный привет на следующем вызове) - а считать их два раза в данном случае вобще глупо - точно "прироста" не даст - а скорее наоборот.
« Последнее редактирование: 08-06-2014, 03:08:26 от Дима_ »

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #69 : 08-06-2014, 02:52:19 »
Понятно. Я не оценил тот факт, что вклад определения BoundingBox в общий алгоритм мизерный. Тем более, что часть регионов вообще не имеют сплайновых образующих.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #70 : 09-06-2014, 10:40:29 »
Порой твои записи меня удивляют...
Уповать на скорость API против алгоритма никогда не стоит
Я никогда и не полагаюсь на это. Похоже, что ты меня неверно понял.
Цитата: Андрей Бушман
Пользователя скорость устраивает, по его заявлению, т.к. написанный им вариант на VBA работал ещё медленнее.
Эта фраза означает, что пользователь предварительно написал свой вариант реализации, используя для этого язык VBA и конечный результат работал медленней моего. Язык программирования, используемый пользователем, был мною указан лишь в качестве дополнительной информации. Я не вкладывал в это предложение смысл, мол "у юзера медленней, потому что он пишет на VBA". Алгоритм реализации у пользователя был свой: половинить до тех пор, пока очередная половина не станет меньше либо равной обозначенным dx и dy.

Цитата: Дима_
в итоге получилось побыстрее чем предыдущая версия (без стойкости к букве Ш).
Как я уже писал выше корректная обработка "Ш" и ей подобных ситуаций - обязательное требование проектировщиков. В виду этого выбираю алгоритм менее быстрый, но дающий именно те результаты, которые от него ожидают во всех (а не "почти во всех") возможных ситуациях (во всяком случае в тех, которые я использовал в ходе тестирования).
Цитата: Дима_
Я тут приболел
Ты это дело брось! :)

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #71 : 09-06-2014, 11:13:48 »
Как я уже писал выше корректная обработка "Ш" и ей подобных ситуаций
Вобщем опять не там запятая - этот как раз и устойчивый к букве Ш (собсвеннно из-за чего и пришлось проверку пересечения заменить индексацией) - то есть корректно обработает.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #72 : 09-06-2014, 13:11:31 »
Дима_, первое, что мне бросилось в глаза - это орда записей:
Цитата: IDE Output in Debug mode
Forgot to call Dispose? (Autodesk.AutoCAD.DatabaseServices.Region): DisposableWrapper
Поскольку в твоём варианте нет возможности указать значение delta, то мне не удаётся проверить твой код на тех же условиях, когда вариант А.Н. выдавал исключение для delta = 0.1.

Цитата: Дима_
Вобщем опять не там запятая - этот как раз и устойчивый к букве Ш (собсвеннно из-за чего и пришлось проверку пересечения заменить индексацией) - то есть корректно обработает.
Да, "Ш" обрабатывается корректно и в целом всё работает весьма шустро. Я через ILSpy конвертну твой код в C#, дабы посмотреть алгоритм.
« Последнее редактирование: 09-06-2014, 13:21:48 от Андрей Бушман »

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #73 : 09-06-2014, 13:28:45 »
С диспосами посмотрю - по коду не вижу (достал меня этот автокад - угадывай где надо, где нет). Delta проверки =1/10 = меньшего шага, + если ближе 1/10 к краю индексирует и соседнеий сегмент.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #74 : 09-06-2014, 13:29:03 »
Не... результат декомпиляции ILSpy таков, что это мне будет нужно не один день потратить, чтобы понять, что есть что (море кракозяблов в наименованиях классов, непонятная иерархия и т.п.). Оставляю всё как есть.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #75 : 09-06-2014, 14:01:38 »
Не... результат декомпиляции ILSpy таков, что это мне будет нужно не один день потратить
Ну этого стоило ожидать т.к. по сути тебе ковырять F# библиотеку придется (а она как не крути лучше исходника не станет) + то что в обобщенных методах было она в свои несколько перевела. Алгоритм если надо могу расписать.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #76 : 09-06-2014, 14:08:43 »
Алгоритм если надо могу расписать.
Буду признателен. При этом хочу обратить внимание на "корректную расстановку запятых", т.к. порой мне либо сложно понять то, что ты пишешь, либо понимаю неверно.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #77 : 09-06-2014, 14:57:48 »
Про запятые - меня, в этом вопросе, к сожалению только компьютер и понимает.
Общая суть такова - через brep получаем контура всех "кривых" и "проходимся" по ним с шагом=1/10 меньшей стороны будующей клетки записывая координату клекти (которую мы высчитываем простым делением без остатка, от начала GeometricExtents.MinPoint) в "словарь", причем если точка лежит "на краю" клетки индексируем, на всякий случай и соседнею, (на случай если клетку кривая таки пересекает, но мы этого "пропустили"). Таким образом мы получаем словарь координат клеток в которых предполагаем, что есть контур. Далее идет основной цикл, в GeometricsExtends.MinPoint создаем регион и высчитываем 2 матрицы - сдвига на клетку вправо и вернуться на начало следующей строки. И перемещая построчно регион смотрим не попадает-ли он на "индексированную" клетку. Если попадает - то делаем BoolIntersect с копией основного региона, и проверив площадь на минимальное значение (у меня 0.0001 ед/рис - то есть не пустая-ли она) добавляем в БД чертежа предварительно прогнав через функцию разбивки на "подрегионы" - проблема буквы Ш. После индекированной клетки - проверяем следующею по строке за ней (только если она тоже без индекса - иначе заново как с индексированной). Проверяем на наличие площади после BoolIntersect если ее нет, то Disposim и до следующего пересечения, просто гоним образец ничего не рисуя, если площадь таки есть, то значит мы попали внутрь региона, прогоняем через функцию "буква Ш" (в коде она идет как RegExplode), а следующие за ней до первой индексированной клекти мы просто заносим в БД, ни на что не проверяя (т.к. пересечения гарантированно нет). Чтоб понять наглядней я добавил различный цвет регионам - красные - индексированные, голубые - проверочные (те которые не ушли по Dispose()), и белые нарисованные без всяких проверок. 

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #78 : 09-06-2014, 15:10:34 »
Спасибо, поразбираюсь...

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #79 : 09-06-2014, 16:38:57 »
С "диспозами"  разобрался, но если меня не перемыкает в других версиях автокада такой диспоз (объекта который будут интерсектить вел к фаталу), что сейчас мне не проверить - посему ставлю просто еще версию - которая не "ругаеться" в отладочную консоль (плюс еще подправил в индексации - сделал более читабельно, и нашел-таки действительно пропущенный диспоз полилинии образующий начальную область клетки):
Код - C# [Выбрать]
  1. open Autodesk.AutoCAD.ApplicationServices
  2. open Autodesk.AutoCAD.Runtime
  3. open Autodesk.AutoCAD.DatabaseServices
  4. open Autodesk.AutoCAD.Geometry
  5. open Autodesk.AutoCAD.EditorInput
  6. open Autodesk.AutoCAD.BoundaryRepresentation
  7.  
  8. let Init()=
  9.   let doc=Application.DocumentManager.MdiActiveDocument
  10.   doc,doc.Editor,doc.Database,doc.TransactionManager.StartTransaction
  11.  
  12. let RegExplode (rg:Region)=
  13.   let brep=new Brep(rg)
  14.   seq{for f in brep.Faces->f}|>function
  15.     |faces when faces|>Seq.skip 1|>Seq.isEmpty->[rg]
  16.     |_->let coll=new DBObjectCollection()
  17.         rg.Explode(coll)
  18.         rg.Dispose()
  19.         [for x in coll->x:?>Region]
  20.  
  21. let IndexRegion (rg:Region) width height=
  22.   let deltaX=width/10.0
  23.   let deltaY=height/10.0
  24.   let x0,y0=let pt=rg.GeometricExtents.MinPoint
  25.             pt.X,pt.Y
  26.   use br=new Brep(rg)
  27.   seq{for face in br.Faces->
  28.        seq{for lop in face.Loops->
  29.             seq{for edge in lop.Edges->
  30.                  use curve=edge.Curve
  31.                  let intr=curve.GetInterval()
  32.                  let p1,p2=intr.LowerBound,intr.UpperBound          
  33.                  {p1..(p2-p1)/(curve.GetLength(p1,p2,(min deltaX deltaY)/2.0)/(min deltaX deltaY))..p2}
  34.                    |>Seq.map (curve.EvaluatePoint)|>Seq.toArray}}}
  35.                    |>Seq.concat|>Seq.concat|>Seq.concat //seq point3d
  36.     |>Seq.fold (fun set pt->let x,y=(pt.X-x0)/width,(pt.Y-y0)/height
  37.                             [0.0,0.0;0.0,0.1;0.0,-0.1;0.1,0.0;0.1,0.1;0.1,-0.1;-0.1,0.0;-0.1,0.1;-0.1,-0.1]
  38.                              |>List.fold (fun set (a,b)->(x+a|>int,y+b|>int)|>function
  39.                                                            |x when Set.contains x set|>not->Set.add x set
  40.                                                            |_->set) set) (Set [])
  41.  
  42. let MakeRegion (pt1:Point3d) width height=
  43.   let cl=new DBObjectCollection()
  44.   use pl=new Polyline2d(Poly2dType.SimplePoly,new Point3dCollection([|pt1
  45.                                                                       new Point3d(pt1.X+width,pt1.Y,pt1.Z)
  46.                                                                       new Point3d(pt1.X+width,pt1.Y+height,pt1.Z)
  47.                                                                       new Point3d(pt1.X,pt1.Y+height,pt1.Z)|]),
  48.                         0.0,true,0.0,0.0,new DoubleCollection([|0.0;0.0;0.0;0.0|]))
  49.   pl|>cl.Add|>ignore
  50.   Region.CreateFromCurves(cl).[0]:?>Region
  51.  
  52. [<CommandMethod "Narez">]
  53. let Narez()=
  54.   let doc,ed,db,trf=Init()
  55.   let Slice width height id=
  56.     let start=System.DateTime.Now
  57.     use tr=trf()
  58.     let rg=tr.GetObject(id,OpenMode.ForWrite):?>Region
  59.     let ext=rg.GeometricExtents
  60.     let block=tr.GetObject(rg.BlockId,OpenMode.ForWrite):?>BlockTableRecord
  61.     let AppendEnt (ent:Entity)=
  62.         block.AppendEntity ent|>ignore
  63.         tr.AddNewlyCreatedDBObject(ent,true)    
  64.     use obr=MakeRegion ext.MinPoint width height
  65.     let mtw=Matrix3d.Displacement(new Vector3d(width,0.0,0.0))
  66.     let mth=Matrix3d.Displacement(new Vector3d(-width*(((ext.MaxPoint.X-ext.MinPoint.X)/width|>int)+1|>float),height,0.0))
  67.     let index=IndexRegion rg width height
  68.     "\n"+string(System.DateTime.Now-start)+" - индексация выполненна; "|>ed.WriteMessage
  69.     {0..(ext.MaxPoint.Y-ext.MinPoint.Y)/height|>int}
  70.       |>Seq.iter (fun y ->{0..(ext.MaxPoint.X-ext.MinPoint.X)/width|>int}
  71.                              |>Seq.fold (fun (next,check) x ->
  72.                                 (Set.contains (x,y) index,next,check)|>function
  73.                                    |true,_,_->let cl=(obr.Clone():?>Region)
  74.                                               obr.TransformBy(mtw)
  75.                                               use rgx=rg.Clone():?>Region
  76.                                               cl.BooleanOperation(BooleanOperationType.BoolIntersect,rgx)
  77.                                               if cl.Area<0.0001
  78.                                                  then cl.Dispose()
  79.                                                  else cl|>RegExplode|>Seq.iter AppendEnt
  80.                                               false,true
  81.                                    |_,_,true->let cl=(obr.Clone():?>Region)
  82.                                               obr.TransformBy(mtw)
  83.                                               use rgx=rg.Clone():?>Region
  84.                                               cl.BooleanOperation(BooleanOperationType.BoolIntersect,rgx)
  85.                                               if cl.Area<0.0001
  86.                                                  then cl.Dispose()
  87.                                                       false,false
  88.                                                  else cl|>RegExplode|>Seq.iter AppendEnt
  89.                                                       true,false
  90.                                    |_,true,_->let cl=(obr.Clone():?>Region)
  91.                                               obr.TransformBy(mtw)
  92.                                               AppendEnt cl
  93.                                               true,false
  94.                                    |_->obr.TransformBy(mtw)
  95.                                        false,false) (false,false)|>ignore
  96.                           obr.TransformBy(mth))
  97.     tr.Commit()
  98.     "всего затраченно: "+string(System.DateTime.Now-start)+"\n"|>ed.WriteMessage
  99.   let inline (|PromptOk|_|) (pr:^a)=(^a:(member Status:PromptStatus)pr)=PromptStatus.OK|>function
  100.                                       |true->Some(pr)
  101.                                       |false->None
  102.   let ErrInput()=ed.WriteMessage("\nКоманда отменена")
  103.   ed.GetSelection(new SelectionFilter([|new TypedValue(int(DxfCode.Start),"REGION")|]))|>function
  104.     |PromptOk(ss)->ed.GetDistance("\nШирина: ")|>function
  105.       |PromptOk(width)->ed.GetDistance("\nВысота:")|>function
  106.         |PromptOk(height)->let start=System.DateTime.Now
  107.                            seq{for ssid in ss.Value->ssid.ObjectId}
  108.                             |>Seq.iter (Slice width.Value height.Value)
  109.                            "\nОбщее время: "+string(System.DateTime.Now-start)|>ed.WriteMessage
  110.         |_->ErrInput()
  111.       |_->ErrInput()
  112.     |_->ErrInput()
p.s. Внес несущественное исправление (синтаксическое).

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Разрезать Region
« Ответ #80 : 09-06-2014, 20:45:08 »
С "диспозами"  разобрался, но если меня не перемыкает в других версиях автокада такой диспоз (объекта который будут интерсектить вел к фаталу)
Я могу запустить твой код в AutoCAD версий 2009-2015. Могу попробовать, если обозначишь нужную версию. Погоди, а ты что, сейчас где-то диспозишь объект, который потом интерсектишь? :)
« Последнее редактирование: 09-06-2014, 21:38:53 от Андрей Бушман »

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #81 : 10-06-2014, 00:01:58 »
Было так:
Код - C# [Выбрать]
  1. let cl=(obr.Clone():?>Region)
  2. obr.TransformBy(mtw)
  3. cl.BooleanOperation(BooleanOperationType.BoolIntersect,rg.Clone():?>Region)
  4. if cl.Area<0.0001
  5.     then cl.Dispose()
  6.     else cl|>RegExplode|>Seq.iter AppendEnt
Стало так:
Код - C# [Выбрать]
  1. let cl=(obr.Clone():?>Region)
  2. obr.TransformBy(mtw)
  3. use rgx=rg.Clone():?>Region
  4. cl.BooleanOperation(BooleanOperationType.BoolIntersect,rgx)
  5. if cl.Area<0.0001
  6.     then cl.Dispose()
  7.     else cl|>RegExplode|>Seq.iter AppendEnt
Мне казалось, что раньше, объект который передавался в BooleanOperation как аргумент автоматом диспозился этим-же методом (что по логике правильно т.к. его фактически уничтожает), а может и глюк.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Разрезать Region
« Ответ #82 : 10-06-2014, 00:28:55 »
Мне казалось, что раньше, объект который передавался в BooleanOperation как аргумент автоматом диспозился этим-же методом (что по логике правильно т.к. его фактически уничтожает), а может и глюк.
Нет. Это тебе только казалось. Его нужно уничтожать самому. Он становится IsNull (что означает что он "пустой", т.е. не имеет геометрии), но не уничтожается.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: Разрезать Region
« Ответ #83 : 10-06-2014, 00:37:34 »
Возможно - с чем-то перепутал, если в других версиях не "икнет" - считаем "готовой".