Разрезать Region

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

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

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

  • 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
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь 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 »
Возможно - с чем-то перепутал, если в других версиях не "икнет" - считаем "готовой".