module SierpinskiChallenge
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime
type AcAp = Autodesk.AutoCAD.ApplicationServices.Application
let drawSierpinski nbi p1 p2 p3 =
let db = AcAp.DocumentManager.MdiActiveDocument.Database
use tr = db.TransactionManager.StartTransaction()
let cSpace = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) :?> BlockTableRecord
let draw p1 p2 p3 =
let s = new Solid(p1, p2, p3)
cSpace.AppendEntity(s) |> ignore
tr.AddNewlyCreatedDBObject(s, true)
let mid (p1 : Point3d) p2 = p1 + (p2 - p1) / 2.0
let rec loop i p1 p2 p3 =
if i > 0 then fract (i - 1) p1 p2 p3
else draw p1 p2 p3
and fract i p1 p2 p3 =
let m1, m2, m3 = mid p1 p2, mid p2 p3, mid p3 p1
loop i p1 m1 m3
loop i m1 p2 m2
loop i m3 m2 p3
loop nbi p1 p2 p3
tr.Commit()
[<CommandMethod("CMD1")>]
let cmd1() =
let ed = AcAp.DocumentManager.MdiActiveDocument.Editor
let ppr = ed.GetPoint("\nCenter: ")
if ppr.Status = PromptStatus.OK then
let cen = ppr.Value
let pdo = PromptDistanceOptions("\nRadius: ", BasePoint = cen, UseBasePoint = true)
let pdr = ed.GetDistance(pdo)
if pdr.Status = PromptStatus.OK then
let pio =
PromptIntegerOptions("\nNumber of iterations: ", LowerLimit = 1, UpperLimit = 12, DefaultValue = 8)
let pir = ed.GetInteger(pio)
if pir.Status = PromptStatus.OK then
let rad = pdr.Value
let cen = cen.TransformBy(ed.CurrentUserCoordinateSystem)
let p1 = cen + Vector3d(rad * -sqrt 0.75, rad * -0.5, 0.0)
let p2 = cen + Vector3d(rad * sqrt 0.75, rad * -0.5, 0.0)
let p3 = cen + Vector3d(0.0, rad, 0.0)
drawSierpinski pir.Value p1 p2 p3
[<CommandMethod("CMD2")>]
let cmd2() =
let ed = AcAp.DocumentManager.MdiActiveDocument.Editor
let ppo = PromptPointOptions("\nFirst point: ")
let ppr = ed.GetPoint(ppo)
if ppr.Status = PromptStatus.OK then
let p1 = ppr.Value
ppo.UseBasePoint <- true
ppo.BasePoint <- p1
ppo.Message <- "\nSecond point: "
let ppr = ed.GetPoint(ppo)
if ppr.Status = PromptStatus.OK then
let p2 = ppr.Value
ppo.Message <- "\nThird point: "
let ppr = ed.GetPoint(ppo)
if ppr.Status = PromptStatus.OK then
let p3 = ppr.Value
let pio =
PromptIntegerOptions("\nNumber of iterations: ", LowerLimit = 1, UpperLimit = 12, DefaultValue = 8)
let pir = ed.GetInteger(pio)
if pir.Status = PromptStatus.OK then
let ucs = ed.CurrentUserCoordinateSystem
drawSierpinski pir.Value (p1.TransformBy(ucs)) (p2.TransformBy(ucs)) (p3.TransformBy(ucs))