open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.Runtime
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.BoundaryRepresentation
let Init()=
let doc=Application.DocumentManager.MdiActiveDocument
doc,doc.Editor,doc.Database,doc.TransactionManager.StartTransaction
let RegExplode (rg:Region)=
let brep=new Brep(rg)
seq{for f in brep.Faces->f}|>function
|faces when faces|>Seq.skip 1|>Seq.isEmpty->[rg]
|_->let coll=new DBObjectCollection()
rg.Explode(coll)
rg.Dispose()
[for x in coll->x:?>Region]
let IndexRegion (rg:Region) width height=
let deltaX=width/10.0
let deltaY=height/10.0
let x0,y0=let pt=rg.GeometricExtents.MinPoint
pt.X,pt.Y
use br=new Brep(rg)
seq{for face in br.Faces->
seq{for lop in face.Loops->
seq{for edge in lop.Edges->
use curve=edge.Curve
let intr=curve.GetInterval()
let p1,p2=intr.LowerBound,intr.UpperBound
{p1..(p2-p1)/(curve.GetLength(p1,p2,(min deltaX deltaY)/2.0)/(min deltaX deltaY))..p2}
|>Seq.map (curve.EvaluatePoint)|>Seq.toArray}}}
|>Seq.concat|>Seq.concat|>Seq.concat //seq point3d
|>Seq.fold (fun set pt->let x,y=(pt.X-x0)/width,(pt.Y-y0)/height
[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]
|>List.fold (fun set (a,b)->(x+a|>int,y+b|>int)|>function
|x when Set.contains x set|>not->Set.add x set
|_->set) set) (Set [])
let MakeRegion (pt1:Point3d) width height=
let cl=new DBObjectCollection()
use pl=new Polyline2d(Poly2dType.SimplePoly,new Point3dCollection([|pt1
new Point3d(pt1.X+width,pt1.Y,pt1.Z)
new Point3d(pt1.X+width,pt1.Y+height,pt1.Z)
new Point3d(pt1.X,pt1.Y+height,pt1.Z)|]),
0.0,true,0.0,0.0,new DoubleCollection([|0.0;0.0;0.0;0.0|]))
pl|>cl.Add|>ignore
Region.CreateFromCurves(cl).[0]:?>Region
[<CommandMethod "Narez">]
let Narez()=
let doc,ed,db,trf=Init()
let Slice width height id=
let start=System.DateTime.Now
use tr=trf()
let rg=tr.GetObject(id,OpenMode.ForWrite):?>Region
let ext=rg.GeometricExtents
let block=tr.GetObject(rg.BlockId,OpenMode.ForWrite):?>BlockTableRecord
let AppendEnt (ent:Entity)=
block.AppendEntity ent|>ignore
tr.AddNewlyCreatedDBObject(ent,true)
use obr=MakeRegion ext.MinPoint width height
let mtw=Matrix3d.Displacement(new Vector3d(width,0.0,0.0))
let mth=Matrix3d.Displacement(new Vector3d(-width*(((ext.MaxPoint.X-ext.MinPoint.X)/width|>int)+1|>float),height,0.0))
let index=IndexRegion rg width height
"\n"+string(System.DateTime.Now-start)+" - индексация выполненна; "|>ed.WriteMessage
{0..(ext.MaxPoint.Y-ext.MinPoint.Y)/height|>int}
|>Seq.iter (fun y ->{0..(ext.MaxPoint.X-ext.MinPoint.X)/width|>int}
|>Seq.fold (fun (next,check) x ->
(Set.contains (x,y) index,next,check)|>function
|true,_,_->let cl=(obr.Clone():?>Region)
obr.TransformBy(mtw)
use rgx=rg.Clone():?>Region
cl.BooleanOperation(BooleanOperationType.BoolIntersect,rgx)
if cl.Area<0.0001
then cl.Dispose()
else cl|>RegExplode|>Seq.iter AppendEnt
false,true
|_,_,true->let cl=(obr.Clone():?>Region)
obr.TransformBy(mtw)
use rgx=rg.Clone():?>Region
cl.BooleanOperation(BooleanOperationType.BoolIntersect,rgx)
if cl.Area<0.0001
then cl.Dispose()
false,false
else cl|>RegExplode|>Seq.iter AppendEnt
true,false
|_,true,_->let cl=(obr.Clone():?>Region)
obr.TransformBy(mtw)
AppendEnt cl
true,false
|_->obr.TransformBy(mtw)
false,false) (false,false)|>ignore
obr.TransformBy(mth))
tr.Commit()
"всего затраченно: "+string(System.DateTime.Now-start)+"\n"|>ed.WriteMessage
let inline (|PromptOk|_|) (pr:^a)=(^a:(member Status:PromptStatus)pr)=PromptStatus.OK|>function
|true->Some(pr)
|false->None
let ErrInput()=ed.WriteMessage("\nКоманда отменена")
ed.GetSelection(new SelectionFilter([|new TypedValue(int(DxfCode.Start),"REGION")|]))|>function
|PromptOk(ss)->ed.GetDistance("\nШирина: ")|>function
|PromptOk(width)->ed.GetDistance("\nВысота:")|>function
|PromptOk(height)->let start=System.DateTime.Now
seq{for ssid in ss.Value->ssid.ObjectId}
|>Seq.iter (Slice width.Value height.Value)
"\nОбщее время: "+string(System.DateTime.Now-start)|>ed.WriteMessage
|_->ErrInput()
|_->ErrInput()
|_->ErrInput()