public static bool IsOutlineRectangular <TEdge, TOpening>(this IPanel <TEdge, TOpening> panel) where TEdge : IEdge where TOpening : IOpening <TEdge> { PolyCurve polycurve = ExternalPolyCurve(panel); if (polycurve == null) { return(false); } if (polycurve.SubParts().Any(x => !x.IIsLinear())) { return(false); } List <Point> points = polycurve.DiscontinuityPoints(); if (points.Count != 4) { return(false); } if (!points.IsCoplanar()) { return(false); } List <Vector> vectors = VectorsBetweenPoints(points); List <double> angles = AnglesBetweenVectors(vectors); //Check the three angles are pi/2 degrees within tolerance return((angles.Any(x => Math.Abs(Math.PI / 2 - x) > Tolerance.Angle)) ? false : true); }
public static bool IsOutlineQuad <TEdge, TOpening>(this IPanel <TEdge, TOpening> panel) where TEdge : IEdge where TOpening : IOpening <TEdge> { PolyCurve polycurve = ExternalPolyCurve(panel); if (polycurve == null) { return(false); } if (polycurve.SubParts().Any(x => !x.IIsLinear())) { return(false); } List <Point> points = polycurve.DiscontinuityPoints(); if (points.Count != 4) { return(false); } return(points.IsCoplanar()); }
/***************************************************/ public static IStory GetStory(this Panel panel, IStories ramStories) { double elev; List <double> panelHeights = new List <double>(); List <Point> panelPoints = new List <Point>(); // Get heights of wall and floor corners to create levels PolyCurve panelOutline = Engine.Spatial.Query.OutlineCurve(panel); panelPoints = panelOutline.DiscontinuityPoints(); foreach (Point pt in panelPoints) { panelHeights.Add(Math.Round(pt.Z, 0)); } // Get elevation of panel per max elevation elev = panelHeights.Max().ToInch(); //There must be a better way to iterate over IStories List <IStory> storeys = new List <IStory>(); int numStories = ramStories.GetCount(); for (int i = 0; i < numStories; i++) { storeys.Add(ramStories.GetAt(i)); } return(storeys.OrderBy(x => Math.Abs(x.dElevation - elev)).First()); }
public static bool IsOutlineSquare <TEdge, TOpening>(this IPanel <TEdge, TOpening> panel) where TEdge : IEdge where TOpening : IOpening <TEdge> { PolyCurve polycurve = ExternalPolyCurve(panel); if (polycurve == null) { return(false); } if (polycurve.SubParts().Any(x => !x.IIsLinear())) { return(false); } List <Point> points = polycurve.DiscontinuityPoints(); if (points.Count != 4) { return(false); } if (!points.IsCoplanar()) { return(false); } List <Vector> vectors = VectorsBetweenPoints(points); List <double> angles = AnglesBetweenVectors(vectors); //Check the three angles are pi/2 degrees within tolerance if (angles.Any(x => Math.Abs(Math.PI / 2 - x) > Tolerance.Angle)) { return(false); } //Check all lengths are the same within tolerance double length = vectors.First().Length(); return(vectors.Skip(0).All(x => (Math.Abs(x.Length() - length) < Tolerance.Distance)) ? true : false); }
public static PolyCurve Offset(this PolyCurve curve, double offset, Vector normal = null, bool tangentExtensions = false, double tolerance = Tolerance.Distance) { if (curve == null || curve.Length() < tolerance) { return(null); } //if there are only Line segmensts switching to polyline method which is more reliable if (curve.Curves.All(x => x is Line)) { Polyline polyline = ((Polyline)curve).Offset(offset, normal, tangentExtensions, tolerance); if (polyline == null) { return(null); } return(new PolyCurve { Curves = polyline.SubParts().Cast <ICurve>().ToList() }); } List <ICurve> subParts = curve.SubParts(); //Check if contains any circles, if so, handle them explicitly, and offset any potential leftovers by backcalling this method if (subParts.Any(x => x is Circle)) { IEnumerable <Circle> circles = subParts.Where(x => x is Circle).Cast <Circle>().Select(x => x.Offset(offset, normal, tangentExtensions, tolerance)); PolyCurve nonCirclePolyCurve = new PolyCurve { Curves = curve.Curves.Where(x => !(x is Circle)).ToList() }; if (nonCirclePolyCurve.Curves.Count != 0) { nonCirclePolyCurve = nonCirclePolyCurve.Offset(offset, normal, tangentExtensions, tolerance); } nonCirclePolyCurve.Curves.AddRange(circles); return(nonCirclePolyCurve); } if (!curve.IsPlanar(tolerance)) { BH.Engine.Reflection.Compute.RecordError("Offset works only on planar curves"); return(null); } if (curve.IsSelfIntersecting(tolerance)) { BH.Engine.Reflection.Compute.RecordError("Offset works only on non-self intersecting curves"); return(null); } if (offset == 0) { return(curve); } bool isClosed = curve.IsClosed(tolerance); if (normal == null) { if (!isClosed) { BH.Engine.Reflection.Compute.RecordError("Normal is missing. Normal vector is not needed only for closed curves"); return(null); } else { normal = curve.Normal(); } } if (offset > 0.05 * curve.Length()) { return((curve.Offset(offset / 2, normal, tangentExtensions, tolerance))?.Offset(offset / 2, normal, tangentExtensions, tolerance)); } PolyCurve result = new PolyCurve(); Vector normalNormalised = normal.Normalise(); //First - offseting each individual element List <ICurve> offsetCurves = new List <ICurve>(); foreach (ICurve crv in subParts) { if (crv.IOffset(offset, normal, false, tolerance) != null) { offsetCurves.Add(crv.IOffset(offset, normal, false, tolerance)); } } int counter = 0; //removing curves that are on a wrong side of the main curve for (int i = 0; i < offsetCurves.Count; i++) { Point sp = offsetCurves[i].IStartPoint(); Point ep = offsetCurves[i].IEndPoint(); Point mp = offsetCurves[i].IPointAtParameter(0.5); Point spOnCurve = curve.ClosestPoint(sp); Point epOnCurve = curve.ClosestPoint(ep); Point mpOnCurve = curve.ClosestPoint(mp); Vector sTan = curve.TangentAtPoint(spOnCurve, tolerance); Vector eTan = curve.TangentAtPoint(epOnCurve, tolerance); Vector mTan = curve.TangentAtPoint(mpOnCurve, tolerance); Vector sCheck = sp - spOnCurve; Vector eCheck = ep - epOnCurve; Vector mCheck = mp - mpOnCurve; Vector sCP = sTan.CrossProduct(sCheck).Normalise(); Vector eCP = eTan.CrossProduct(eCheck).Normalise(); Vector mCP = mTan.CrossProduct(mCheck).Normalise(); if (offset > 0) { if (sCP.IsEqual(normalNormalised, tolerance) && eCP.IsEqual(normalNormalised, tolerance) && mCP.IsEqual(normalNormalised, tolerance)) { offsetCurves.RemoveAt(i); i--; counter++; } } else { if (!sCP.IsEqual(normalNormalised, tolerance) && !eCP.IsEqual(normalNormalised, tolerance) && !mCP.IsEqual(normalNormalised, tolerance)) { offsetCurves.RemoveAt(i); i--; counter++; } } } //Again if there are only Line segments switching to polyline method as it is more reliable if (offsetCurves.All(x => x is Line)) { Polyline polyline = new Polyline { ControlPoints = curve.DiscontinuityPoints() }; result.Curves.AddRange(polyline.Offset(offset, normal, tangentExtensions, tolerance).SubParts()); return(result); } bool connectingError = false; //Filleting offset curves to create continuous curve for (int i = 0; i < offsetCurves.Count; i++) { int j; if (i == offsetCurves.Count - 1) { if (isClosed) { j = 0; } else { break; } } else { j = i + 1; } PolyCurve temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance); if (temp == null) //trying to fillet with next curve { offsetCurves.RemoveAt(j); if (j == 0) { i--; } if (j == offsetCurves.Count) { j = 0; } temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance); } if (!(temp == null)) //inserting filetted curves { if (j != 0) { offsetCurves.RemoveRange(i, 2); offsetCurves.InsertRange(i, temp.Curves); } else { offsetCurves.RemoveAt(i); offsetCurves.RemoveAt(0); offsetCurves.InsertRange(i - 1, temp.Curves); } i = i + temp.Curves.Count - 2; } else { connectingError = true; } } //removing curves that are to close to the main curve for (int i = 0; i < offsetCurves.Count; i++) { if ((offsetCurves[i].IPointAtParameter(0.5).Distance(curve) + tolerance < Math.Abs(offset) && (offsetCurves[i].IStartPoint().Distance(curve) + tolerance < Math.Abs(offset) || offsetCurves[i].IEndPoint().Distance(curve) + tolerance < Math.Abs(offset)))) { PolyCurve temp = offsetCurves[((i - 1) + offsetCurves.Count) % offsetCurves.Count].Fillet(offsetCurves[(i + 1) % offsetCurves.Count], tangentExtensions, true, false, tolerance); if (temp != null) { if (i == 0) { offsetCurves.RemoveRange(0, 2); offsetCurves.RemoveAt(offsetCurves.Count - 1); offsetCurves.InsertRange(0, temp.Curves); i = temp.Curves.Count - 1; } else if (i == offsetCurves.Count - 1) { offsetCurves.RemoveRange(i - 1, 2); offsetCurves.RemoveAt(0); offsetCurves.InsertRange(offsetCurves.Count - 1, temp.Curves); i = offsetCurves.Count - 1; } else { offsetCurves.RemoveRange(i - 1, 3); offsetCurves.InsertRange(i - 1, temp.Curves); i = i - 3 + temp.Curves.Count; } } if (offsetCurves.Count < 1) { Reflection.Compute.ClearCurrentEvents(); Reflection.Compute.RecordError("Method failed to produce correct offset. Returning null."); return(null); } counter++; } } Reflection.Compute.ClearCurrentEvents(); if (connectingError) { Reflection.Compute.RecordWarning("Couldn't connect offset subCurves properly."); } if (offsetCurves.Count == 0) { Reflection.Compute.RecordError("Method failed to produce correct offset. Returning null."); return(null); } List <PolyCurve> resultList = Compute.IJoin(offsetCurves, tolerance); if (resultList.Count == 1) { result = resultList[0]; } else { result.Curves = offsetCurves; Reflection.Compute.RecordWarning("Offset may be wrong. Please inspect the results."); } if (counter > 0) { Reflection.Compute.RecordWarning("Reduced " + counter + " line(s). Please inspect the results."); } if (result.IsSelfIntersecting(tolerance) || result.CurveIntersections(curve, tolerance).Count != 0) { Reflection.Compute.RecordWarning("Intersections occured. Please inspect the results."); } if (isClosed && !result.IsClosed(tolerance)) { Reflection.Compute.RecordError("Final curve is not closed. Please inspect the results."); } return(result); }
/***************************************************/ /**** Private methods ****/ /***************************************************/ private bool CreateCollection(IEnumerable <Panel> bhomPanels) { //Code for creating a collection of floors and walls in the software List <Panel> panels = bhomPanels.ToList(); // Register Floor types IFloorType ramFloorType; IStories ramStories; IStory ramStory; //Create wall and floor lists with individual heights List <Panel> wallPanels = new List <Panel>(); List <Panel> floors = new List <Panel>(); List <double> panelHeights = new List <double>(); List <Point> panelPoints = new List <Point>(); // Split walls and floors and get all elevations foreach (Panel panel in panels) { double panelNormZ = panel.Normal().Z; //Split walls and floors if (Math.Abs(panelNormZ) < 0.707) // check normal against 45 degree slope { wallPanels.Add(panel); } else { floors.Add(panel); } } ramStories = m_Model.GetStories(); #region Create Floors // Cycle through floors and create on story foreach (Panel panel in floors) { RAMId RAMId = new RAMId(); string name = panel.Name; PolyCurve outlineExternal = panel.OutlineCurve(); ramStory = panel.GetStory(ramStories); ramFloorType = ramStory.GetFloorType(); try { // Set slab edges on FloorType in RAM for external edges ISlabEdges ramSlabEdges = ramFloorType.GetAllSlabEdges(); ISlabEdges ramOpeningEdges = ramFloorType.GetAllSlabOpenings(); // Get external and internal edges of floor panel List <PolyCurve> panelOutlines = new List <PolyCurve>(); List <PolyCurve> openingOutlines = new List <PolyCurve>(); Vector zDown = BH.Engine.Geometry.Create.Vector(0, 0, -1); // RAM requires edges clockwise, flip if counterclockwise PolyCurve cwOutline = (outlineExternal.IsClockwise(zDown) == false) ? outlineExternal.Flip() : outlineExternal; List <ICurve> edgeCrvs = cwOutline.Curves; foreach (ICurve crv in edgeCrvs) { Point startPt = crv.IStartPoint(); Point endPt = crv.IEndPoint(); ramSlabEdges.Add(startPt.X.ToInch(), startPt.Y.ToInch(), endPt.X.ToInch(), endPt.Y.ToInch(), 0); } List <Opening> panelOpenings = panel.Openings; foreach (Opening opening in panelOpenings) { PolyCurve outlineOpening = opening.OutlineCurve(); openingOutlines.Add(outlineOpening); } foreach (PolyCurve outline in openingOutlines) { // RAM requires edges clockwise, flip if counterclockwise PolyCurve cwOpenOutline = (outline.IsClockwise(zDown) == false) ? outline.Flip() : outline; if (!(outlineExternal.IsContaining(cwOpenOutline, false))) { cwOpenOutline = outlineExternal.BooleanIntersection(cwOpenOutline)[0]; Engine.Base.Compute.RecordWarning("Panel " + name + " opening intersects floor boundary. Boolean intersection was used to get opening extents on panel, confirm opening extents in RAM."); } List <ICurve> openEdgeCrvs = cwOpenOutline.Curves; foreach (ICurve crv in openEdgeCrvs) { Point startPt = crv.IStartPoint(); Point endPt = crv.IEndPoint(); ramOpeningEdges.Add(startPt.X.ToInch(), startPt.Y.ToInch(), endPt.X.ToInch(), endPt.Y.ToInch(), 0); } } // Create Deck List <Point> ctrlPoints = cwOutline.ControlPoints(); if (ctrlPoints.First() != ctrlPoints.Last()) { ctrlPoints.Add(ctrlPoints.Last().DeepClone()); } ISurfaceProperty srfProp = panel.Property; int deckProplUID = GetAdapterId <int>(srfProp); //Add decks, then set deck points per outline IDecks ramDecks = ramFloorType.GetDecks(); IDeck ramDeck = ramDecks.Add(deckProplUID, ctrlPoints.Count); IPoints ramPoints = ramDeck.GetPoints(); // Create list of SCoordinates for floor outlines List <SCoordinate> cornersExt = new List <SCoordinate>(); foreach (Point point in ctrlPoints) { SCoordinate cornerExt = point.ToRAM(); cornersExt.Add(cornerExt); } for (int k = 0; k < cornersExt.Count; k++) { ramPoints.Delete(k); ramPoints.InsertAt(k, cornersExt[k]); } ramDeck.SetPoints(ramPoints); // Add warning to report floors flattened to level as required for RAM if (Math.Abs(panel.Normal().Z) < 1) { Engine.Base.Compute.RecordWarning("Panel " + name + " snapped to level " + ramStory.strLabel + "."); } } catch { CreateElementError("panel", name); } } #endregion #region Create Walls //Cycle through walls; if wall crosses level place at level foreach (Panel wallPanel in wallPanels) { string name = wallPanel.Name; try { double thickness = 0.2; // default thickness if (wallPanel.Property is ConstantThickness) { ConstantThickness prop = (ConstantThickness)wallPanel.Property; thickness = prop.Thickness; } // Find outline of planar panel PolyCurve outline = BH.Engine.Spatial.Query.OutlineCurve(wallPanel); List <Point> wallPts = outline.DiscontinuityPoints(); List <Point> sortedWallPts = wallPts.OrderBy(p => p.X).ToList(); Point leftPt = sortedWallPts.First(); Point rtPt = sortedWallPts.Last(); bool downToRight = leftPt.Y > rtPt.Y; BoundingBox wallBounds = BH.Engine.Geometry.Query.Bounds(outline); Point wallMin = wallBounds.Min; Point wallMax = wallBounds.Max; double tempY = wallMin.Y; wallMin.Y = downToRight ? wallMax.Y : wallMin.Y; wallMax.Y = downToRight ? tempY : wallMax.Y; for (int i = 0; i < ramStories.GetCount(); i++) { ramStory = ramStories.GetAt(i); // If wall crosses level, add wall to ILayoutWalls for that level if (Math.Round(wallMax.Z.ToInch(), 0) >= ramStory.dElevation && Math.Round(wallMin.Z.ToInch(), 0) < ramStory.dElevation) { ramFloorType = ramStory.GetFloorType(); //Get ILayoutWalls of FloorType and add wall ILayoutWalls ramLayoutWalls = ramFloorType.GetLayoutWalls(); ILayoutWall ramLayoutWall = ramLayoutWalls.Add(EMATERIALTYPES.EWallPropConcreteMat, wallMin.X.ToInch(), wallMin.Y.ToInch(), 0, 0, wallMax.X.ToInch(), wallMax.Y.ToInch(), 0, 0, thickness.ToInch()); //Set lateral ramLayoutWall.eFramingType = EFRAMETYPE.MemberIsLateral; IWalls ramWalls = ramLayoutWall.GetAssociatedStoryWalls(); IWall ramWall = ramWalls.GetAt(0); // Find opening location, width, and height from outline and apply foreach (Opening open in wallPanel.Openings) { PolyCurve openOutline = open.OutlineCurve(); BoundingBox openBounds = BH.Engine.Geometry.Query.Bounds(openOutline); Point openMin = openBounds.Min; Point openMax = openBounds.Max; if ((openMin.Z.ToInch() >= ramStory.dElevation - ramStory.dFlrHeight) && (openMin.Z.ToInch() < ramStory.dElevation)) { IFinalWallOpenings ramWallOpenings = ramWall.GetFinalOpenings(); int openOverlapCount = 0; for (int j = 0; i < ramWallOpenings.GetCount(); j++) { IFinalWallOpening testOpen = ramWallOpenings.GetAt(j); IPoints openingPts = testOpen.GetOpeningVertices(); //Re-add first point to close Polygon IPoint firstOPt = openingPts.GetAt(0); SCoordinate firstOCoord = new SCoordinate(); firstOPt.GetCoordinate(ref firstOCoord); openingPts.Add(firstOCoord); Polyline wallOpeningOutline = openingPts.ToPolyline(); List <Point> intPts = wallOpeningOutline.ICurveIntersections(openOutline); if (wallOpeningOutline.IsContaining(openOutline) || openOutline.IsContaining(wallOpeningOutline) || intPts.Count > 0) { openOverlapCount += 1; } } if (openOverlapCount == 0) { //Get opening on wall extents if (!(outline.IsContaining(openOutline, false))) { openOutline = outline.BooleanIntersection(openOutline)[0]; Engine.Base.Compute.RecordWarning("Panel " + name + " opening intersects wall boundary. Boolean intersection was used to get opening extents on panel."); } Point closestOpenPt = BH.Engine.Geometry.Query.ClosestPoint(wallMin, openOutline.ControlPoints()); double distX = Math.Sqrt(Math.Pow(closestOpenPt.X - wallMin.X, 2) + Math.Pow(closestOpenPt.Y - wallMin.Y, 2)); double distZinch = openBounds.Min.Z.ToInch() - (ramStory.dElevation - ramStory.dFlrHeight); double openWidth = Math.Sqrt(Math.Pow(openBounds.Max.X - openBounds.Min.X, 2) + Math.Pow(openBounds.Max.Y - openBounds.Min.Y, 2)); double openHt = openBounds.Max.Z - openBounds.Min.Z; //Add opening to RAM IRawWallOpenings ramRawWallOpenings = ramWall.GetRawOpenings(); ramRawWallOpenings.Add(EDA_MEMBER_LOC.eBottomStart, distX.ToInch(), distZinch, openWidth.ToInch(), openHt.ToInch()); } } } } } } catch { CreateElementError("panel", name); } } #endregion //Save file m_IDBIO.SaveDatabase(); return(true); }