-
-
Save goswinr/d88b7860a85d47568be7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Based on the SDK Sampl GeometryCreation_BooleanOperations | |
// This is testing code. Many improvements can be made before use in real work | |
#r @"C:\Program Files\Autodesk\Revit 2016\RevitAPI.dll" | |
#r @"C:\Program Files\Autodesk\Revit 2016\RevitDBAPI.dll" | |
#r @"C:\Program Files\Autodesk\Revit 2016\RevitAPIUI.dll" | |
#r @"C:\Program Files\Mantis\Tsunami.IDEDesktop.dll" | |
open Autodesk.Revit | |
open Autodesk.Revit.UI | |
open System | |
open System.Linq | |
open System.Collections.Generic | |
open Autodesk.Revit.DB | |
open Autodesk.Revit.DB.Analysis | |
open Autodesk.Revit.DB.Architecture | |
open Autodesk.Revit.UI | |
open Autodesk.Revit.UI.Selection | |
open Autodesk.Revit.ApplicationServices | |
open Autodesk.Revit.Attributes | |
open System.Collections.Generic | |
open System.Collections.Concurrent | |
let memoize f = | |
let cache = new ConcurrentDictionary<'a,'b>() | |
fun x -> | |
match cache.TryGetValue(x) with | |
| (true,y) -> y | |
| (false,_) -> | |
let y = f x | |
cache.[x] <- y | |
y | |
module Option = | |
/// nullable | |
let ofNullable (x : 'a) = if box x <> null then Some x else None | |
/// System.Nullable | |
let ofSystemNullable (x : System.Nullable<'a>) = if x.HasValue then Some x.Value else None | |
let tryGetAll (xs:'a option []) = | |
if xs |> Array.exists (function | None -> true | _ -> false) | |
then None | |
else xs |> Array.map (Option.get) |> Some | |
let tryNull (x:'a) = if box x <> null then Some(x) else None | |
let ofType<'Out> : obj -> 'Out option = function | :? 'Out as x -> Some x | _ -> None | |
let tryNullOfType<'Out>(x:obj) : 'Out option = x |> tryNull |> ofType<'Out> | |
let ofUnrelatedType<'In, 'Out> (x : 'In) = box x |> ofType<'Out> | |
let isOfType<'a> (x:obj) = match x with | :? 'a -> true | _ -> false | |
let orElse (second:'a option) (first:'a option) = match first with | Some(x) -> Some(x) | None -> match second with | Some(y) -> Some(y) | None -> None | |
let tryFind (predicate:'a -> bool) (x:'a option) = match x with | Some(x) when predicate x -> Some(x) | _ -> None | |
let orDefault (d:'a) (x:'a option) = match x with | Some(x) -> x | None -> d | |
let ofRef (result:bool,byref:'a) = if result then Some(byref) else None | |
module Seq = | |
let ofType<'Out> = Seq.choose (Option.ofType<'Out>) | |
let ofUnrelatedType<'In, 'Out> : 'In seq -> 'Out seq = Seq.choose (Option.ofUnrelatedType<'In, 'Out>) | |
let tryLast (xs: 'a seq) = xs |> Seq.fold (fun _ x -> Some x) None | |
let tryHead (xs:'a seq) = | |
let ys = xs.GetEnumerator() | |
if ys.MoveNext() then Some(ys.Current) else None | |
module BooleanOperations = | |
let inline (<||>) (s1:Solid) (s2:Solid) = BooleanOperationsUtils.ExecuteBooleanOperation(s1,s2,BooleanOperationsType.Union) | |
let inline (<->) (s1:Solid) (s2:Solid) = BooleanOperationsUtils.ExecuteBooleanOperation(s1,s2,BooleanOperationsType.Difference) | |
let inline (<&&>) (s1:Solid) (s2:Solid) = BooleanOperationsUtils.ExecuteBooleanOperation(s1,s2,BooleanOperationsType.Intersect) | |
type CylinderDirection = | |
| BasisX | |
| BasisY | |
| BasisZ | |
let π = Math.PI | |
let getViewByName(name:string) (doc:Document) = | |
use xs = new FilteredElementCollector(doc) | |
seq { for x in xs.OfClass(typeof<View>) -> x} |> Seq.ofUnrelatedType<Element,View> |> Seq.filter (fun x -> x.Name = name) |> Seq.tryHead | |
let getView3DByName(name:string) (doc:Document) = | |
use xs = new FilteredElementCollector(doc) | |
seq { for x in xs.OfClass(typeof<View3D>) -> x} |> Seq.ofUnrelatedType<Element,View3D> |> Seq.filter (fun x -> x.Name = name) |> Seq.tryHead | |
let get3DViewElementId(doc:Document) = | |
use xs = new FilteredElementCollector(doc) | |
seq { for x in xs.OfClass(typeof<ViewFamilyType>) -> x} |> Seq.ofUnrelatedType<Element,ViewFamilyType> |> Seq.filter (fun e -> e.Name = "3D View") |> Seq.tryHead |> Option.map (fun e -> e.Id) | |
let create3DView = | |
memoize (fun (name:string) (doc:Document) -> | |
let view3DId = get3DViewElementId(doc).Value | |
let view = View3D.CreateIsometric(doc, view3DId) | |
let viewOrientation3D = new ViewOrientation3D(XYZ(1.,-1.,-1.), XYZ(1.,1.,1.), XYZ(1.,1.,-2.)) | |
view.SetOrientation(viewOrientation3D) | |
view.SaveOrientation() | |
view.Name <- name | |
view) | |
let createCenterBasedBox(center:XYZ, edgelength:float) = | |
let halfedgelength = edgelength / 2.0 | |
let profileloops = List<CurveLoop>() | |
let profileloop = new CurveLoop(); | |
[| | |
(-1.,-1.,-1.), (-1., 1.,-1.) | |
(-1., 1.,-1.), ( 1., 1.,-1.) | |
( 1., 1.,-1.), ( 1.,-1.,-1.) | |
( 1.,-1.,-1.), (-1.,-1.,-1.) | |
|] |> Array.iter (fun ((a,b,c),(x,y,z)) -> | |
let h = halfedgelength | |
profileloop.Append(Line.CreateBound(XYZ(center.X + (h*a), center.Y + (h*b), center.Z + (h*c)), | |
XYZ(center.X + (h*x), center.Y + (h*y), center.Z + (h*z))))) | |
profileloops.Add(profileloop) | |
let extrusiondir = XYZ.BasisZ | |
GeometryCreationUtilities.CreateExtrusionGeometry(profileloops, extrusiondir, edgelength) | |
let createCenterBasedSphere(center:XYZ, radius:float) = | |
let frame = new Frame(center, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ) | |
let profileloops = List<CurveLoop>() | |
let profileloop = new CurveLoop() | |
let cemiEllipse = Ellipse.Create(center, radius, radius, XYZ.BasisX, XYZ.BasisZ, -π / 2., π / 2.) | |
profileloop.Append(cemiEllipse) | |
profileloop.Append(Line.CreateBound(XYZ(center.X, center.Y, center.Z + radius), XYZ(center.X, center.Y, center.Z - radius))) | |
profileloops.Add(profileloop) | |
GeometryCreationUtilities.CreateRevolvedGeometry(frame, profileloops, -π, π) | |
let createCenterBasedCylinder(center:XYZ, bottomradius:double, height:float, cylinderdirections:CylinderDirection) = | |
let halfheight = height / 2. | |
let bottomcenter,topcenter = | |
match cylinderdirections with | |
| BasisX -> XYZ(center.X - halfheight, center.Y, center.Z),XYZ(center.X + halfheight, center.Y, center.Z) | |
| BasisY -> XYZ(center.X, center.Y - halfheight, center.Z),XYZ(center.X, center.Y + halfheight, center.Z) | |
| BasisZ -> XYZ(center.X, center.Y, center.Z - halfheight),XYZ(center.X, center.Y, center.Z + halfheight) | |
let sweepPath = new CurveLoop() | |
sweepPath.Append(Line.CreateBound(bottomcenter, topcenter)) | |
let profileloops = List<CurveLoop>() | |
let profileloop = new CurveLoop() | |
let cemiEllipse1 = | |
Ellipse.Create(bottomcenter, bottomradius, bottomradius, | |
(if cylinderdirections = BasisX then XYZ.BasisY else XYZ.BasisX), | |
(if cylinderdirections = BasisZ then XYZ.BasisY else XYZ.BasisZ), | |
-π, 0.) | |
let cemiEllipse2 = | |
Ellipse.Create(bottomcenter, bottomradius, bottomradius, | |
(if cylinderdirections = BasisX then XYZ.BasisY else XYZ.BasisX), | |
(if cylinderdirections = BasisZ then XYZ.BasisY else XYZ.BasisZ), | |
0., π) | |
profileloop.Append(cemiEllipse1) | |
profileloop.Append(cemiEllipse2) | |
profileloops.Add(profileloop) | |
GeometryCreationUtilities.CreateSweptGeometry(sweepPath,0,0., profileloops) | |
let mutable private schemaId = Option<int>.None | |
let paintSolid(s:Solid, viewName:string, doc:Document) = | |
let view = create3DView viewName doc | |
let sfm = | |
match SpatialFieldManager.GetSpatialFieldManager(view) |> Option.ofNullable with | |
| Some(x) -> x | |
| None -> SpatialFieldManager.CreateSpatialFieldManager(view,1) | |
let getSchema() = | |
let resultSchema1 = new AnalysisResultSchema("PaintedSolid" + viewName, "Description") | |
let displayStyle = AnalysisDisplayStyle.CreateAnalysisDisplayStyle(doc, "Real_Color_Surface" + viewName, | |
new AnalysisDisplayColoredSurfaceSettings(), | |
new AnalysisDisplayColorSettings(), | |
new AnalysisDisplayLegendSettings()) | |
resultSchema1.AnalysisDisplayStyleId <- displayStyle.Id | |
sfm.RegisterResult(resultSchema1) | |
let sId = | |
match schemaId with | |
| None -> | |
let sId = getSchema() | |
schemaId <- Some(sId) | |
sId | |
| Some(x) when not (sfm.GetRegisteredResults().Contains(x)) -> | |
let sId = getSchema() | |
schemaId <- Some(sId) | |
sId | |
| Some(x) -> x | |
//sfm.GetRegisteredResults() | |
for face in s.Faces do | |
let idx = sfm.AddSpatialFieldPrimitive(face,Transform.Identity) | |
let compteValueAtPointForFace(face:Face,measurementNo:int) : (UV[]*ValueAtPoint[]) = | |
let bb = face.GetBoundingBox() | |
[| | |
for u in seq {bb.Min.U .. (bb.Max.U - bb.Min.U) .. bb.Max.U + 0.0000001 } do | |
for v in seq {bb.Min.V .. (bb.Max.V - bb.Min.V) .. bb.Max.V + 0.0000001} do // Note original code devides by one which is weird | |
let uvPnt = UV(u,v) | |
let faceXYZ = face.Evaluate(uvPnt) | |
let valPnt = new ValueAtPoint([|for ii = 1 to measurementNo do yield faceXYZ.DistanceTo(XYZ.Zero) * (float ii)|]) | |
yield (uvPnt,valPnt) | |
|] |> fun xs -> (xs |> Array.map fst),(xs |> Array.map snd) | |
let (uvPts,valList) = compteValueAtPointForFace(face,1) | |
let pnts = new FieldDomainPointsByUV(uvPts) | |
let vals = new FieldValues(valList) | |
sfm.UpdateSpatialFieldPrimitive(idx,pnts, vals, sId) | |
open BooleanOperations | |
let zero = XYZ.Zero | |
let xaxis = CylinderDirection.BasisX | |
let yaxis = CylinderDirection.BasisY | |
let zaxis = CylinderDirection.BasisZ | |
let box(p,size) = createCenterBasedBox(p, size) | |
let sphere(p,r) = createCenterBasedSphere(p, r) | |
let cylinder(p,radius,length,direction) = createCenterBasedCylinder(p, radius, length, direction) | |
let union y x = x <||> y | |
let difference y x = x <-> y | |
let intersect y x = x <&&> y | |
let paint doc s = paintSolid(s, "CSGTree", doc) | |
module Mantis = | |
let transaction (f:Document->unit) = | |
Mantis.run (fun app -> | |
let document = app.ActiveUIDocument.Document | |
let tran = new Transaction(document, "GeometryCreation_BooleanOperation"); | |
tran.Start() |> ignore | |
f document | |
tran.Commit() |> ignore | |
) | |
Mantis.transaction (fun doc -> | |
sphere(zero,20.) | |
|> intersect (box(zero,25.)) | |
|> difference | |
([ | |
cylinder(zero, 5., 40., xaxis) | |
cylinder(zero, 5., 40., yaxis) | |
cylinder(zero, 5., 40., zaxis) | |
] |> Seq.reduce union) | |
|> paint doc | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment