module ConnectPointChallenge
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime
type AcAp = Autodesk.AutoCAD.ApplicationServices.Application
let connectAll (pts: Point3d[]) dist =
let getExtents pts =
Seq.
fold(fun (s: Extents3d
) p
-> s.
AddPoint(p
); s
) (new Extents3d
()) pts
let ext = getExtents pts
let xMax, yMax = ext.MaxPoint.X, ext.MaxPoint.Y
let xMin, yMin = ext.MinPoint.X, ext.MinPoint.Y
let col, row = int ((xMax - xMin) / dist) + 2, int ((yMax - yMin) / dist) + 3
let table
= Array2D.
create col row
[] let i, j = int ((p.X - xMin) / dist), int ((p.Y - yMin) / dist) + 1
table.[i, j] <- p :: table.[i, j])
let dist = dist * dist
let getConnexions i j =
let sqrDist2d (p1: Point3d) (p2: Point3d) =
(p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y)
let connect pt pts acc =
List.
fold(fun s p
-> if sqrDist2d pt p
<= dist
then (pt, p
) :: s
else s
) acc pts
let connectInside pts =
let rec loop acc = function
| [] -> acc
| h :: t -> loop (connect h t acc) t
loop [] pts
let connectOutside pts acc =
List.
fold(fun s p
-> connect p pts s
) acc table.
[i,j
] table.[i,j]
|> connectInside
|> connectOutside table.[i + 1, j - 1]
|> connectOutside table.[i + 1, j]
|> connectOutside table.[i + 1, j + 1]
|> connectOutside table.[i, j + 1]
[| for i in 0 .. col - 2 do
for j in 1 .. row - 2 do yield! getConnexions i j |]
[<CommandMethod("ConnectFs")>]
let connectFs () =
let sw = new System.Diagnostics.Stopwatch()
let doc = AcAp.DocumentManager.MdiActiveDocument
let db = doc.Database
let ed = doc.Editor
sw.Start()
use ms = SymbolUtilityServices.GetBlockModelSpaceId(db).Open(OpenMode.ForWrite)
:?> BlockTableRecord
let rxc = RXClass.GetClass(typeof<DBPoint>)
let pts = [| for id in ms -> id |]
|> Array.
filter(fun id
-> id.
ObjectClass = rxc
) use pt = id.Open(OpenMode.ForRead) :?> DBPoint
pt.Position)
let t0 = sw.ElapsedMilliseconds
let pairs = connectAll pts 70.0
let t1 = sw.ElapsedMilliseconds
pairs
|> Array.
iter (fun (p1, p2
) -> use line = new Line(p1, p2)
ms.AppendEntity(line) |> ignore)
sw.Stop()
let t2 = sw.ElapsedMilliseconds
ed.WriteMessage(
"\nGet points:{0,9}\nConnect points:{1,5}\nDraw lines:{2,9}\nTotal:{3,14}",
t0, t1 - t0, t2 - t1, t2);