using System; using System.Collections.Generic; using Autodesk.Revit.DB; using Autodesk.Revit.UI; // Blends generated by Hermite Splines // Ritchie Jackson : November 2010 /* * Note: Code provided 'as is' for development purposes only * Error-checking minimal and code not optimised */ namespace AAC_Thesis { class Blend_Spline_01 { // Conversion Revit Default Imperial 'foot' to Metric 'millimeter' static double ftMM = 1 / 304.8; // 'Blend' Element Radial Thickness public double skinThick = 150.0; // Setout Points for Facade Perimeter derived from Mullions - // Extracted from a Project in Development, hence values hereunder:- // Setout Radii for Mullion Arcs - // -18.0° public static double r00BaseInn = 15250.0 * ftMM; // Lvl 00 public static double r00ApexInn = 11360.0 * ftMM; // Lvl 04 public static double r00MidlInn = r00ApexInn - 900.0 * ftMM; // Lvl 02 // 0.0° public static double r01BaseInn = 17200.0 * ftMM; public static double r01ApexInn = 13390.0 * ftMM; public static double r01MidlInn = r01ApexInn - 900.0 * ftMM; // 18.0° public static double r02BaseInn = 16480.0 * ftMM; public static double r02ApexInn = 12630.0 * ftMM; public static double r02MidlInn = r02ApexInn - 900.0 * ftMM; // 36.0° public static double r03BaseInn = 17200.0 * ftMM; public static double r03ApexInn = 13230.0 * ftMM; public static double r03MidlInn = r03ApexInn - 900.0 * ftMM; // 54.0° public static double r04BaseInn = 15250.0 * ftMM; public static double r04ApexInn = 11400.0 * ftMM; public static double r04MidlInn = r04ApexInn - 900.0 * ftMM; // Angle conversions - Degrees to Radians - Typical Levels double angle18 = Math.PI / 10.0; double angle36 = Math.PI / 5.0; double angle54 = Math.PI * 3.0 / 10.0; // Floor-to-Floor Height double floorHeight = 3600.0 * ftMM; // Arrays to hold Perimeter Setout Points at each Level - // Use 'IList' to facilitate 'HermiteSpline' creation IList lvl001 = new List(); // 00 Floor IList lvl002 = new List(); // 00 Transom-0900mm IList lvl003 = new List(); // 00 Transom-2700mm IList lvl011 = new List(); // 01 Floor IList lvl012 = new List(); // 01 Transom-0900mm IList lvl013 = new List(); // 01 Transom-2700mm IList lvl021 = new List(); // 02 Floor IList lvl022 = new List(); // 02 Transom-0900mm IList lvl023 = new List(); // 02 Transom-2700mm IList lvl031 = new List(); // 03 Floor IList lvl032 = new List(); // 03 Transom-0900mm IList lvl033 = new List(); // 03 Transom-2700mm IList lvl041 = new List(); // 04 Floor // Array to hold Perimeter Setout Points for all Levels in 1st Quadrant - IList> skinPnt = new List>(); // Origin & Normal for Sketch Plane ||el to Floors XYZ orig = new XYZ(); XYZ norm = XYZ.BasisZ; Plane plane; SketchPlane planeSK; // Constructor public Blend_Spline_01(Document doc) { // Populate Lists for Lvl00, Lvl02 & Lvl04 Floors // with 1st Quadrant Values so that // Mullion Arcs can be setout and // Transom Intersection Points can be calculated // Anti-Clockwise Order used to facilitate Blend creation // Lvl00:- lvl001.Add(radiusXYZ(r04BaseInn, angle54, floorHeight * 0)); lvl001.Add(radiusXYZ(r03BaseInn, angle36, floorHeight * 0)); lvl001.Add(radiusXYZ(r02BaseInn, angle18, floorHeight * 0)); lvl001.Add(radiusXYZ(r01BaseInn, 0.0, floorHeight * 0)); lvl001.Add(radiusXYZ(r00BaseInn, -angle18, floorHeight * 0)); // Lvl01:- lvl021.Add(radiusXYZ(r04MidlInn, angle54, floorHeight * 2)); lvl021.Add(radiusXYZ(r03MidlInn, angle36, floorHeight * 2)); lvl021.Add(radiusXYZ(r02MidlInn, angle18, floorHeight * 2)); lvl021.Add(radiusXYZ(r01MidlInn, 0.0, floorHeight * 2)); lvl021.Add(radiusXYZ(r00MidlInn, -angle18, floorHeight * 2)); // Lvl04:- lvl041.Add(radiusXYZ(r04ApexInn, angle54, floorHeight * 4)); lvl041.Add(radiusXYZ(r03ApexInn, angle36, floorHeight * 4)); lvl041.Add(radiusXYZ(r02ApexInn, angle18, floorHeight * 4)); lvl041.Add(radiusXYZ(r01ApexInn, 0.0, floorHeight * 4)); lvl041.Add(radiusXYZ(r00ApexInn, -angle18, floorHeight * 4)); // Create Sketch Plane for Transoms plane = doc.Application.Create.NewPlane(norm, orig); planeSK = doc.FamilyCreate.NewSketchPlane(plane); // Create Mullion Arcs joining Lvls 00, 02 & 04 mullionArc(doc); // Add External Points to Spline Arrays lvl001 = transomPntsOut(lvl001); lvl002 = transomPntsOut(lvl002); lvl003 = transomPntsOut(lvl003); lvl011 = transomPntsOut(lvl011); lvl012 = transomPntsOut(lvl012); lvl013 = transomPntsOut(lvl013); lvl021 = transomPntsOut(lvl021); lvl022 = transomPntsOut(lvl022); lvl023 = transomPntsOut(lvl023); lvl031 = transomPntsOut(lvl031); lvl032 = transomPntsOut(lvl032); lvl033 = transomPntsOut(lvl033); lvl041 = transomPntsOut(lvl041); // Create Facade Panels skinPanel(doc); } // Setout Point at End of Each Radius public XYZ radiusXYZ(double radius, double angle, double lvl) { XYZ end = new XYZ(radius * Math.Cos(angle), radius * Math.Sin(angle), lvl); return end; } // Mullion Arcs public void mullionArc(Document doc) { // Setout Radius Angle double angle = 0.0; // Only the Inner Spline points required for (int i = 0; i < lvl001.Count; i++) { // Create the Mullions Arc current = doc.Application.Create.NewArc(lvl001[i], lvl041[i], lvl021[i]); // Create Sketch Plane - only required for Model Line display during Debugging CurveArray currentAr = new CurveArray(); currentAr.Append(current); Plane planeA = doc.Application.Create.NewPlane(currentAr); SketchPlane planeASK = doc.FamilyCreate.NewSketchPlane(planeA); // Display of Arcs to verify correct position - Useful for Debugging /* ModelCurve mullion = doc.FamilyCreate.NewModelCurve(current, planeASK) as ModelArc; */ // SetOut Angle for Radial Intersection Lines angle = (3 - i) * angle18; // Create Horizontal Intersection Lines @900mm c/c for (int j = 0; j < 17; j++) { // Each Floor has Transoms at +0900mm and +2700mm only if ((j + 2) % 4 != 0) { // Intersection Line Start and End XYZ head = new XYZ(0.0, 0.0, j * 900.0 * ftMM); XYZ tail = new XYZ(Math.Cos(angle), Math.Sin(angle), j * 900.0 * ftMM); // Direction Vector for Unbound Line XYZ vect = tail.Subtract(head); // Unbound Intersection Line Line intersectLine = doc.Application.Create.NewLine(head, vect, false); // Determine Intersection Point of Mullion Arc with Intersection Line IntersectionResultArray results = new IntersectionResultArray(); SetComparisonResult result = new SetComparisonResult(); result = intersectLine.Intersect(current, out results); IntersectionResult iResult = new IntersectionResult(); iResult = results.get_Item(0); XYZ intersect = iResult.XYZPoint; // Add Intersection Points to Transom Setout Arrays transomArray(j, intersect); // Display of Lines to verify correct position - Useful for Debugging /* Line transomLine = doc.Application.Create.NewLine(head, intersect, true); ModelLine transomLineM = doc.FamilyCreate.NewModelCurve(transomLine, planeASK) as ModelLine; */ } } } } // Add Intersection Points to Transom Setout Arrays public void transomArray(int index, XYZ intersect) { // Lvls 001, 021 and 041 already accounted for switch (index) { case 1: lvl002.Add(intersect); break; case 3: lvl003.Add(intersect); break; case 4: lvl011.Add(intersect); break; case 5: lvl012.Add(intersect); break; case 7: lvl013.Add(intersect); break; case 9: lvl022.Add(intersect); break; case 11: lvl023.Add(intersect); break; case 12: lvl031.Add(intersect); break; case 13: lvl032.Add(intersect); break; case 15: lvl033.Add(intersect); break; } } // Add Outer Spline Points to Intermediary Floors and Transoms public IList transomPntsOut(IList now) { IList addList = now; int size = addList.Count; for (int i = size-1; i >=0; i--) { double angle = Math.Atan(addList[i].Y / addList[i].X); XYZ current = new XYZ(addList[i].X + skinThick * ftMM * Math.Cos(angle), addList[i].Y + skinThick * ftMM * Math.Sin(angle), addList[i].Z); addList.Add(current); } skinPnt.Add(addList); return addList; } // Create Facade Panels public void skinPanel(Document doc) { // Fetch all Transom Point Arrays except Topmost for (int i = 0; i < skinPnt.Count - 1; i++) { CurveArrArray transomLoHi = new CurveArrArray(); // Setup pairs of Transoms for Blend Function for (int j = 0; j < 2; j++) { CurveArray transProfile1 = new CurveArray(); // Half the number of points in 'skinPnt' Array // defines Inner or Outer Spline int getPnts = skinPnt[i + j].Count / 2; // Inner Spline IList splineInnPnts1 = new List(); // Hermite Spline - Inner for (int k = 0; k < getPnts; k++) { splineInnPnts1.Add(skinPnt[i+j][k]); } HermiteSpline splineInn1 = doc.Application.Create.NewHermiteSpline(splineInnPnts1, false); // Hermite Spline - Outer IList splineOutPnts1 = new List(); // Hermite Spline : Outer for (int k = getPnts; k < getPnts * 2; k++) { splineOutPnts1.Add(skinPnt[i + j][k]); } HermiteSpline splineOut1 = doc.Application.Create.NewHermiteSpline(splineOutPnts1, false); // Connecting Lines for Inner and Outer Splines Line innOut1 = doc.Application.Create.NewLine(skinPnt[i + j][getPnts - 1], skinPnt[i + j][getPnts], true); Line outInn1 = doc.Application.Create.NewLine(skinPnt[i + j][getPnts * 2 - 1], skinPnt[i + j][0], true); // Create Lower or Upper Profile for Blend // NB: Ensure 1st Element is NOT a Hermite Spline to avoid error transProfile1.Append(outInn1); transProfile1.Append(splineInn1); transProfile1.Append(innOut1); transProfile1.Append(splineOut1); transomLoHi.Append(transProfile1); // Display of Lines to verify correct position - Useful for Debugging /* Plane plane = doc.Application.Create.NewPlane(transProfile1); SketchPlane planeSK = doc.FamilyCreate.NewSketchPlane(plane); ModelCurve splineInn1T = doc.FamilyCreate.NewModelCurve(splineInn1, planeSK); ModelCurve splineOut1T = doc.FamilyCreate.NewModelCurve(splineOut1, planeSK); ModelCurve innOut1T = doc.FamilyCreate.NewModelCurve(innOut1, planeSK); ModelCurve outInn1T = doc.FamilyCreate.NewModelCurve(outInn1, planeSK); */ } // Create Plane for Lower Blend Profile Plane planeBase = doc.Application.Create.NewPlane(transomLoHi.get_Item(0)); SketchPlane planeBaseSK = doc.FamilyCreate.NewSketchPlane(planeBase); // Create Blend between successive Transoms Blend current1 = doc.FamilyCreate.NewBlend(true, transomLoHi.get_Item(1), transomLoHi.get_Item(0), planeBaseSK); } } } }