diff --git a/Environment_Engine/Compute/ElementsInSpace.cs b/Environment_Engine/Compute/ElementsInSpace.cs new file mode 100644 index 000000000..9d75b9889 --- /dev/null +++ b/Environment_Engine/Compute/ElementsInSpace.cs @@ -0,0 +1,69 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2023, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using BH.oM.Environment.Elements; +using BH.oM.Architecture.Elements; + +using BH.Engine.Geometry; +using BH.oM.Geometry; + +using BH.oM.Base.Attributes; +using System.ComponentModel; + +using BH.oM.Analytical.Elements; +using BH.oM.Dimensional; + +namespace BH.Engine.Environment +{ + public static partial class Compute + { + [Description("Gets the elements that lie within the provided space.")] + [Input("space", "An Environment Space object defining a perimeter to build a 3D volume from and check if the volume contains the provided point.")] + [Input("spaceHeight", "The height of the space.", typeof(BH.oM.Quantities.Attributes.Length))] + [Input("elements", "The elements being checked to see if they are contained within the bounds of the 3D volume.")] + [Input("acceptOnEdges", "Decide whether to allow elements which sit on the edge of the space, default false.")] + [Input("acceptPartial", "Decide whether to include elements only partially within the space, default false.")] + [Output("elements", "The elements from the provided elements that are within the space.")] + public static List ElementsInSpace(this Space space, double spaceHeight, List elements, bool acceptOnEdges = false, bool acceptPartial = false) + { + if (space == null) + return new List(); + + List isContaining = space.IsContaining(spaceHeight, elements, acceptOnEdges, acceptPartial); + + return elements + .Zip(isContaining, (elem, inSpace) => new { + elem, + inSpace, + }) + .Where(item => item.inSpace) + .Select(item => item.elem) + .ToList(); + } + } +} diff --git a/Environment_Engine/Query/IsContaining.cs b/Environment_Engine/Query/IsContaining.cs index 2ff0113d8..744f7d2d5 100644 --- a/Environment_Engine/Query/IsContaining.cs +++ b/Environment_Engine/Query/IsContaining.cs @@ -20,21 +20,16 @@ * along with this code. If not, see . */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using BH.oM.Environment; -using BH.oM.Environment.Elements; -using BH.oM.Base; - -using BH.oM.Geometry; using BH.Engine.Geometry; - +using BH.Engine.Spatial; using BH.oM.Base.Attributes; +using BH.oM.Dimensional; +using BH.oM.Environment.Elements; +using BH.oM.Geometry; +using System; +using System.Collections.Generic; using System.ComponentModel; +using System.Linq; namespace BH.Engine.Environment { @@ -88,16 +83,33 @@ public static bool IsContaining(this Panel panel, Point pt, bool acceptOnEdges = [Output("isContaining", "True if the point is contained within the bounds of the panels, false if it is not")] public static bool IsContaining(this List panels, Point point, bool acceptOnEdges = false, double tolerance = BH.oM.Geometry.Tolerance.Distance) { - if(panels == null) + if (panels == null) { BH.Engine.Base.Compute.RecordError("Cannot query if a collection of panels contains a point if the panels are null."); return false; } - if(point == null) + List planes = new List(); + foreach (Panel be in panels) + planes.Add(be.Polyline().IControlPoints().FitPlane(tolerance)); + + List ctrPoints = panels.SelectMany(x => x.Polyline().IControlPoints()).ToList(); + BoundingBox boundingBox = BH.Engine.Geometry.Query.Bounds(ctrPoints); + + return IsContaining(panels, planes, boundingBox, point, acceptOnEdges); + } + + [Description("Defines whether a collection of Environment Panels contains each of a provided list of points.")] + [Input("panels", "A collection of Environment Panels to check with.")] + [Input("points", "The points to check to see if each point is contained within the bounds of the panels.")] + [Input("acceptOnEdges", "Decide whether to allow the point to sit on the edge of the panel, default false.")] + [Output("isContaining", "True if the point is contained within the bounds of the panels, false if it is not for each point provided.")] + public static List IsContaining(this List panels, List points, bool acceptOnEdges = false, double tolerance = BH.oM.Geometry.Tolerance.Distance) + { + if (panels == null) { - BH.Engine.Base.Compute.RecordError("Cannot query is a collection of panels contains a point if the point is null."); - return false; + BH.Engine.Base.Compute.RecordError("Cannot query if a collection of panels contains a point if the panels are null."); + return new List() { false }; } List planes = new List(); @@ -107,6 +119,62 @@ public static bool IsContaining(this List panels, Point point, bool accep List ctrPoints = panels.SelectMany(x => x.Polyline().IControlPoints()).ToList(); BoundingBox boundingBox = BH.Engine.Geometry.Query.Bounds(ctrPoints); + return points.Select(point => IsContaining(panels, planes, boundingBox, point, acceptOnEdges)).ToList(); + } + + [Description("Defines whether an Environment Space contains each of a provided list of points.")] + [Input("space", "An Environment Space object defining a perimeter to build a 3D volume from and check if the volume contains the provided point.")] + [Input("spaceHeight", "The height of the space.", typeof(BH.oM.Quantities.Attributes.Length))] + [Input("points", "The points being checked to see if it is contained within the bounds of the 3D volume.")] + [Input("acceptOnEdges", "Decide whether to allow the point to sit on the edge of the space, default false.")] + [Output("isContaining", "True if the point is contained within the space, false if it is not.")] + public static List IsContaining(this Space space, double spaceHeight, List points, bool acceptOnEdges = false) + { + List panelsFromSpace = space.ExtrudeToVolume(spaceHeight); + return panelsFromSpace.IsContaining(points, acceptOnEdges); + } + + [Description("Defines whether an Environment Space contains a provided Element.")] + [Input("space", "An Environment Space object defining a perimeter to build a 3D volume from and check if the volume contains the provided element.")] + [Input("spaceHeight", "The height of the space.", typeof(BH.oM.Quantities.Attributes.Length))] + [Input("elements", "The elements being checked to see if they are contained within the bounds of the 3D volume.")] + [Input("acceptOnEdges", "Decide whether to allow the element's point to sit on the edge of the space, default false.")] + [Output("isContaining", "True if the point is contained within the space, false if it is not.")] + public static List IsContaining(this Space space, double spaceHeight, List elements, bool acceptOnEdges = false, bool acceptPartialContainment = false) + { + List panelsFromSpace = space.ExtrudeToVolume(spaceHeight); + List> pointLists = new List>(); + + foreach (IElement elem in elements) + { + List points = elem.IControlPoints(); + pointLists.Add(points); + } + return panelsFromSpace.IsContaining(pointLists, acceptOnEdges, acceptPartialContainment); + } + + + /***************************************************/ + /**** Private Methods ****/ + /***************************************************/ + + [Description("Defines whether a point lies within a collection of panels using their primitive planes and bounds.")] + [Input("panels", "A collection of Environment Panels to check with.")] + [Input("planes", "Planes corresponding to each panel for intersection calculations.")] + [Input("boundingBox", "The bounding box of the collection of panels.")] + [Input("point", "The point to check to see if it is contained within the bounds of the panels.")] + [Input("acceptOnEdges", "Decide whether to allow the point to sit on the edge of the panel, default false.")] + [Input("tolerance", "Distance tolerance to use to determine intersections.")] + [Output("isContaining", "True if the point is contained within the bounds of the panels, false if it is not for each point provided.")] + private static bool IsContaining(this List panels, List planes, BoundingBox boundingBox, Point point, bool acceptOnEdges = false, double tolerance = BH.oM.Geometry.Tolerance.Distance) + { + //Return if point is null even without checking boundingBox.IsContaining(point) + if (point == null) + { + BH.Engine.Base.Compute.RecordError("Cannot query if a collection of panels contains a point if the point is null."); + return false; + } + if (!BH.Engine.Geometry.Query.IsContaining(boundingBox, point, true, tolerance)) return false; @@ -168,20 +236,40 @@ public static bool IsContaining(this List panels, Point point, bool accep return isContained; //If the number of intersections is odd the point is outsde the space } - [Description("Defines whether an Environment Space contains a provided point.")] - [Input("space", "An Environment Space object defining a perimeter to build a 3D volume from and check if the volume contains the provided point.")] - [Input("spaceHeight", "The height of the space.", typeof(BH.oM.Quantities.Attributes.Length))] - [Input("points", "The points being checked to see if it is contained within the bounds of the 3D volume.")] - [Input("acceptOnEdges", "Decide whether to allow the point to sit on the edge of the space, default false.")] - [Output("isContaining", "True if the point is contained within the space, false if it is not.")] - public static List IsContaining(this Space space, double spaceHeight, List points, bool acceptOnEdges = false) + [Description("Defines whether a collection of Environment Panels contains each of a provided list of list of points.")] + [Input("panels", "A collection of Environment Panels to check with.")] + [Input("pointLists", "The List of Lists of points to check to see if each List of points are contained within the bounds of the panels.")] + [Input("acceptOnEdges", "Decide whether to allow the points to sit on the edge of the panel, default false.")] + [Input("acceptPartialContainment", "Decide whether to allow some of the points to sit outside the panels as long as at least one is within them.")] + [Output("isContaining", "True if the points of each sublist are contained within the bounds of the panels, false if it is not for each sublist of points provided.")] + private static List IsContaining(this List panels, List> pointLists, bool acceptOnEdges = false, bool acceptPartialContainment = false, double tolerance = BH.oM.Geometry.Tolerance.Distance) { - List panelsFromSpace = space.ExtrudeToVolume(spaceHeight); - return points.Select(x => panelsFromSpace.IsContaining(x, acceptOnEdges)).ToList(); - } - } -} + if (panels == null) + { + BH.Engine.Base.Compute.RecordError("Cannot query if a collection of panels contains a point if the panels are null."); + return new List() { false }; + } + List planes = new List(); + foreach (Panel be in panels) + planes.Add(be.Polyline().IControlPoints().FitPlane(tolerance)); + List ctrPoints = panels.SelectMany(x => x.Polyline().IControlPoints()).ToList(); + BoundingBox boundingBox = BH.Engine.Geometry.Query.Bounds(ctrPoints); + List areContained = new List(); + foreach (List pts in pointLists) + { + bool isContained = false; + if (acceptPartialContainment) + isContained = pts.Any(point => IsContaining(panels, planes, boundingBox, point, acceptOnEdges)); + else + isContained = pts.All(point => IsContaining(panels, planes, boundingBox, point, acceptOnEdges)); + areContained.Add(isContained); + } + + return areContained; + } + } +} \ No newline at end of file diff --git a/Lighting_Engine/Query/Geometry.cs b/Lighting_Engine/Query/Geometry.cs new file mode 100644 index 000000000..ede100a55 --- /dev/null +++ b/Lighting_Engine/Query/Geometry.cs @@ -0,0 +1,53 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2023, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using BH.oM.Lighting; +using BH.oM.Base.Attributes; +using System.ComponentModel; +using BH.oM.Geometry; +using BH.oM.Lighting.Elements; + +namespace BH.Engine.Lighting +{ + public static partial class Query + { + [Description("Gets the geometry of a Luminaire as a Point.")] + [Input("luminaire", "Element to get the Point from.")] + [Output("point", "The geometry of the Element.")] + public static Point Geometry(this Luminaire luminaire) + { + if(luminaire == null) + { + BH.Engine.Base.Compute.RecordError("Cannot query the geometry of a null luminaire."); + return null; + } + + return luminaire.Position; + } + } +}