diff --git a/Grids/SketchGrids/.gitignore b/Grids/SketchGrids/.gitignore
new file mode 100644
index 00000000..f1d4f671
--- /dev/null
+++ b/Grids/SketchGrids/.gitignore
@@ -0,0 +1,9 @@
+
+bin/
+obj/
+*.glb
+output.json
+input.json
+.vs/
+server/
+test/Generated/
\ No newline at end of file
diff --git a/Grids/SketchGrids/README.md b/Grids/SketchGrids/README.md
new file mode 100644
index 00000000..4338cc1f
--- /dev/null
+++ b/Grids/SketchGrids/README.md
@@ -0,0 +1,21 @@
+
+
+# Sketch Grids
+
+Generate grids automatically from conceptual masses or sketch grid lines.
+
+|Input Name|Type|Description|
+|---|---|---|
+|Offset Distance From Conceptual Mass|number|The default grid offset from the conceptual mass.|
+|Add Skeleton Grids|boolean|Add grids along conceptual mass skeletons.|
+
+
+
+
+|Output Name|Type|Description|
+|---|---|---|
+
+
+
+
+## Additional Information
\ No newline at end of file
diff --git a/Grids/SketchGrids/SketchGrids.sln b/Grids/SketchGrids/SketchGrids.sln
new file mode 100644
index 00000000..31e43d88
--- /dev/null
+++ b/Grids/SketchGrids/SketchGrids.sln
@@ -0,0 +1,62 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SketchGrids", "src\SketchGrids.csproj", "{EAA286E4-3EE3-4017-945A-18189AE2FDDC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SketchGrids.Dependencies", "dependencies\SketchGrids.Dependencies.csproj", "{C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SketchGrids.Tests", "test\SketchGrids.Tests.csproj", "{6B5FECA2-A2AB-4D74-B89A-A37E33408D91}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Debug|x64.Build.0 = Debug|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Debug|x86.Build.0 = Debug|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Release|x64.ActiveCfg = Release|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Release|x64.Build.0 = Release|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Release|x86.ActiveCfg = Release|Any CPU
+ {EAA286E4-3EE3-4017-945A-18189AE2FDDC}.Release|x86.Build.0 = Release|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Debug|x64.Build.0 = Debug|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Debug|x86.Build.0 = Debug|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Release|x64.ActiveCfg = Release|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Release|x64.Build.0 = Release|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Release|x86.ActiveCfg = Release|Any CPU
+ {C3DC1E0D-A438-4CC9-9DBB-61B81DD1929F}.Release|x86.Build.0 = Release|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Debug|x64.Build.0 = Debug|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Debug|x86.Build.0 = Debug|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Release|x64.ActiveCfg = Release|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Release|x64.Build.0 = Release|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Release|x86.ActiveCfg = Release|Any CPU
+ {6B5FECA2-A2AB-4D74-B89A-A37E33408D91}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Grids/SketchGrids/dependencies/ConceptualMass.g.cs b/Grids/SketchGrids/dependencies/ConceptualMass.g.cs
new file mode 100644
index 00000000..fa933a87
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/ConceptualMass.g.cs
@@ -0,0 +1,69 @@
+//----------------------
+//
+// Generated using the NJsonSchema v10.1.21.0 (Newtonsoft.Json v13.0.0.0) (http://NJsonSchema.org)
+//
+//----------------------
+using Elements;
+using Elements.GeoJSON;
+using Elements.Geometry;
+using Elements.Geometry.Solids;
+using Elements.Spatial;
+using Elements.Validators;
+using Elements.Serialization.JSON;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Line = Elements.Geometry.Line;
+using Polygon = Elements.Geometry.Polygon;
+
+namespace Elements
+{
+ #pragma warning disable // Disable all warnings
+
+ /// Represents an early stage building massing volume. Its boundary typically represents the nominal edge of slab, and may be articulated further by subsequent functions.
+ [JsonConverter(typeof(Elements.Serialization.JSON.JsonInheritanceConverter), "discriminator")]
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+ public partial class ConceptualMass : Envelope
+ {
+ [JsonConstructor]
+ public ConceptualMass(IList @skeleton, string @primaryUseCategory, System.Guid? @building, IList @levelIds, Transform @localCoordinateSystem, Profile @profile, double @elevation, double @height, Vector3 @direction, double @rotation, IList @floorToFloorHeights, Transform @transform, Material @material, Representation @representation, bool @isElementDefinition, System.Guid @id, string @name)
+ : base(profile, elevation, height, direction, rotation, floorToFloorHeights, transform, material, representation, isElementDefinition, id, name)
+ {
+ this.Skeleton = @skeleton;
+ this.PrimaryUseCategory = @primaryUseCategory;
+ this.Building = @building;
+ this.LevelIds = @levelIds;
+ this.LocalCoordinateSystem = @localCoordinateSystem;
+ }
+
+
+ // Empty constructor
+ public ConceptualMass()
+ : base()
+ {
+ }
+
+ /// A collection of lines which indicate a "centerline" of the mass.
+ [JsonProperty("Skeleton", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public IList Skeleton { get; set; }
+
+ /// The primary programmatic use for this mass, e.g. Residential, Office, Parking, Retail. Some levels or spaces within the mass may have other uses.
+ [JsonProperty("Primary Use Category", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public string PrimaryUseCategory { get; set; }
+
+ /// The building this mass belongs to, if any.
+ [JsonProperty("Building", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public System.Guid? Building { get; set; }
+
+ /// The ids of the levels this conceptual mass contains
+ [JsonProperty("Level Ids", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public IList LevelIds { get; set; }
+
+ /// A transform representing the local coordinate system for this mass
+ [JsonProperty("Local Coordinate System", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public Transform LocalCoordinateSystem { get; set; }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/dependencies/Envelope.g.cs b/Grids/SketchGrids/dependencies/Envelope.g.cs
new file mode 100644
index 00000000..a5a575de
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/Envelope.g.cs
@@ -0,0 +1,74 @@
+//----------------------
+//
+// Generated using the NJsonSchema v10.1.21.0 (Newtonsoft.Json v13.0.0.0) (http://NJsonSchema.org)
+//
+//----------------------
+using Elements;
+using Elements.GeoJSON;
+using Elements.Geometry;
+using Elements.Geometry.Solids;
+using Elements.Spatial;
+using Elements.Validators;
+using Elements.Serialization.JSON;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Line = Elements.Geometry.Line;
+using Polygon = Elements.Geometry.Polygon;
+
+namespace Elements
+{
+ #pragma warning disable // Disable all warnings
+
+ /// Represents one part of a building enclosure.
+ [JsonConverter(typeof(Elements.Serialization.JSON.JsonInheritanceConverter), "discriminator")]
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+ public partial class Envelope : GeometricElement
+ {
+ [JsonConstructor]
+ public Envelope(Profile @profile, double @elevation, double @height, Vector3 @direction, double @rotation, IList @floorToFloorHeights, Transform @transform = null, Material @material = null, Representation @representation = null, bool @isElementDefinition = false, System.Guid @id = default, string @name = null)
+ : base(transform, material, representation, isElementDefinition, id, name)
+ {
+ this.Profile = @profile;
+ this.Elevation = @elevation;
+ this.Height = @height;
+ this.Direction = @direction;
+ this.Rotation = @rotation;
+ this.FloorToFloorHeights = @floorToFloorHeights;
+ }
+
+
+ // Empty constructor
+ public Envelope()
+ : base()
+ {
+ }
+
+ /// The profile to extrude.
+ [JsonProperty("Profile", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public Profile Profile { get; set; }
+
+ /// The elevation of the envelope.
+ [JsonProperty("Elevation", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public double Elevation { get; set; }
+
+ /// The height of the envelope.
+ [JsonProperty("Height", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public double Height { get; set; }
+
+ /// The direction in which to extrude.
+ [JsonProperty("Direction", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public Vector3 Direction { get; set; }
+
+ /// The rotation of the envelope, in degrees.
+ [JsonProperty("Rotation", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public double Rotation { get; set; }
+
+ /// An optional list of floor-to-floor heights for this envelope. If provided, levels can be generated from these floor-to-floor heights.
+ [JsonProperty("Floor To Floor Heights", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public IList FloorToFloorHeights { get; set; }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/dependencies/GridLinesOverride.g.cs b/Grids/SketchGrids/dependencies/GridLinesOverride.g.cs
new file mode 100644
index 00000000..2a8fa601
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/GridLinesOverride.g.cs
@@ -0,0 +1,153 @@
+using Elements;
+using System.Collections.Generic;
+using System;
+using System.Linq;
+
+namespace SketchGrids
+{
+ ///
+ /// Override metadata for GridLinesOverride
+ ///
+ public partial class GridLinesOverride : IOverride
+ {
+ public static string Name = "Grid Lines";
+ public static string Dependency = null;
+ public static string Context = "[*discriminator=Elements.GridLine]";
+ public static string Paradigm = "Edit";
+
+ ///
+ /// Get the override name for this override.
+ ///
+ public string GetName() {
+ return Name;
+ }
+
+ public object GetIdentity() {
+
+ return Identity;
+ }
+
+ }
+ public static class GridLinesOverrideExtensions
+ {
+ ///
+ /// Apply Grid Lines edit overrides to a collection of existing elements
+ ///
+ /// The Grid Lines Overrides to apply
+ /// A collection of existing elements to which to apply the overrides.
+ /// A function returning a boolean which indicates whether an element is a match for an override's identity.
+ /// A function to modify a matched element, returning the modified element.
+ /// The element type this override applies to. Should match the type(s) in the override's context.
+ /// A collection of elements, including unmodified and modified elements from the supplied collection.
+ public static List Apply(
+ this IList overrideData,
+ IEnumerable existingElements,
+ Func identityMatch,
+ Func modifyElement) where T : Element
+ {
+ var resultElements = new List(existingElements);
+ if (overrideData != null)
+ {
+ foreach (var overrideValue in overrideData)
+ {
+ // Assuming there will only be one match per identity, find the first element that matches.
+ var matchingElement = existingElements.FirstOrDefault(e => identityMatch(e, overrideValue.Identity));
+ // if we found a match,
+ if (matchingElement != null)
+ {
+ // remove the old matching element
+ resultElements.Remove(matchingElement);
+ // apply the modification function to it
+ var modifiedElement = modifyElement(matchingElement, overrideValue);
+ // set the identity
+ Identity.AddOverrideIdentity(modifiedElement, overrideValue);
+ //and re-add it to the collection
+ resultElements.Add(modifiedElement);
+ }
+ }
+ }
+ return resultElements;
+ }
+
+ ///
+ /// Apply Grid Lines edit overrides to a collection of existing elements
+ ///
+ /// A collection of existing elements to which to apply the overrides.
+ /// The Grid Lines Overrides to apply — typically `input.Overrides.GridLines`
+ /// A function returning a boolean which indicates whether an element is a match for an override's identity.
+ /// A function to modify a matched element, returning the modified element.
+ /// The element type this override applies to. Should match the type(s) in the override's context.
+ /// A collection of elements, including unmodified and modified elements from the supplied collection.
+ public static void ApplyOverrides(
+ this List existingElements,
+ IList overrideData,
+ Func identityMatch,
+ Func modifyElement
+ ) where T : Element
+ {
+ var updatedElements = overrideData.Apply(existingElements, identityMatch, modifyElement);
+ existingElements.Clear();
+ existingElements.AddRange(updatedElements);
+ }
+
+ ///
+ /// Create elements from add/removeoverrides, and apply any edits.
+ ///
+ /// The collection of edit overrides (Overrides.GridLines)
+ /// The collection of add overrides (Overrides.Additions.GridLines)
+ /// The collection of remove overrides (Overrides.Removals.GridLines) /// A function returning a boolean which indicates whether an element is a match for an override's identity.
+ /// A function to create a new element, returning the created element.
+ /// A function to modify a matched element, returning the modified element.
+ /// An optional collection of existing elements to which to apply any edit overrides, or remove if remove overrides are found.
+ /// The element type this override applies to. Should match the type(s) in the override's context.
+ /// A collection of elements, including new, unmodified, and modified elements from the supplied collection.
+ public static List CreateElements(
+ this IList edits,
+ IList additions,
+ IList removals, Func createElement,
+ Func identityMatch,
+ Func modifyElement,
+ IEnumerable existingElements = null
+ ) where T : Element
+ {
+ List resultElements = existingElements == null ? new List() : new List(existingElements);
+ if (removals != null)
+ {
+ foreach (var removedElement in removals)
+ {
+ var elementToRemove = resultElements.FirstOrDefault(e => identityMatch(e, removedElement.Identity));
+ if (elementToRemove != null)
+ {
+ resultElements.Remove(elementToRemove);
+ }
+ }
+ } if (additions != null)
+ {
+ foreach (var addedElement in additions)
+ {
+ var elementToAdd = createElement(addedElement);
+ resultElements.Add(elementToAdd);
+ Identity.AddOverrideIdentity(elementToAdd, addedElement);
+ }
+ }
+ if (edits != null)
+ {
+ foreach (var editedElement in edits)
+ {
+ var elementToEdit = resultElements.FirstOrDefault(e => identityMatch(e, editedElement.Identity));
+ if (elementToEdit != null)
+ {
+ resultElements.Remove(elementToEdit);
+ var newElement = modifyElement(elementToEdit, editedElement);
+ resultElements.Add(newElement);
+ Identity.AddOverrideIdentity(newElement, editedElement);
+ }
+ }
+ }
+ return resultElements;
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/dependencies/GridLinesOverrideAddition.g.cs b/Grids/SketchGrids/dependencies/GridLinesOverrideAddition.g.cs
new file mode 100644
index 00000000..6f1b6f8b
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/GridLinesOverrideAddition.g.cs
@@ -0,0 +1,32 @@
+using Elements;
+using System.Collections.Generic;
+using System;
+using System.Linq;
+
+namespace SketchGrids
+{
+ ///
+ /// Override metadata for GridLinesOverrideAddition
+ ///
+ public partial class GridLinesOverrideAddition : IOverride
+ {
+ public static string Name = "Grid Lines Addition";
+ public static string Dependency = null;
+ public static string Context = "[*discriminator=Elements.GridLine]";
+ public static string Paradigm = "Edit";
+
+ ///
+ /// Get the override name for this override.
+ ///
+ public string GetName() {
+ return Name;
+ }
+
+ public object GetIdentity() {
+
+ return Identity;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/dependencies/GridLinesOverrideRemoval.g.cs b/Grids/SketchGrids/dependencies/GridLinesOverrideRemoval.g.cs
new file mode 100644
index 00000000..46e7c6f9
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/GridLinesOverrideRemoval.g.cs
@@ -0,0 +1,32 @@
+using Elements;
+using System.Collections.Generic;
+using System;
+using System.Linq;
+
+namespace SketchGrids
+{
+ ///
+ /// Override metadata for GridLinesOverrideRemoval
+ ///
+ public partial class GridLinesOverrideRemoval : IOverride
+ {
+ public static string Name = "Grid Lines Removal";
+ public static string Dependency = null;
+ public static string Context = "[*discriminator=Elements.GridLine]";
+ public static string Paradigm = "Edit";
+
+ ///
+ /// Get the override name for this override.
+ ///
+ public string GetName() {
+ return Name;
+ }
+
+ public object GetIdentity() {
+
+ return Identity;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/dependencies/LocalEdge.cs b/Grids/SketchGrids/dependencies/LocalEdge.cs
new file mode 100644
index 00000000..b76f0b7d
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/LocalEdge.cs
@@ -0,0 +1,83 @@
+using System;
+
+namespace SketchGrids
+{
+ ///
+ /// Provides graph edge info
+ ///
+ public class LocalEdge
+ {
+ [Flags]
+ private enum VisitDirections
+ {
+ None,
+ Straight,
+ Opposite
+ }
+
+ ///
+ /// Creates a new instance of Edge class
+ ///
+ /// The index of the first vertex
+ /// The index of the second vertex
+ public LocalEdge(int vertexIndex1, int vertexIndex2)
+ {
+ visitDirections = VisitDirections.None;
+ VertexIndex1 = vertexIndex1;
+ VertexIndex2 = vertexIndex2;
+ }
+
+ public int VertexIndex1 { get; }
+ public int VertexIndex2 { get; }
+
+ ///
+ /// Added record that edge was visited from the vertex index
+ ///
+ /// The index of the vertex where the edge is visited from
+ public void MarkAsVisited(int vertexIndex)
+ {
+ if (vertexIndex == VertexIndex1)
+ {
+ visitDirections |= VisitDirections.Straight;
+ }
+ else if (vertexIndex == VertexIndex2)
+ {
+ visitDirections |= VisitDirections.Opposite;
+ }
+ }
+
+ ///
+ /// Returns if this edge is between input vertex indeces
+ ///
+ /// The index of the first vertex
+ /// The index of the second vertex
+ /// Returns True if edge is between input vertex indeces
+ public bool IsBetweenVertices(int vertexIndex1, int vertexIndex2)
+ {
+ return (VertexIndex1 == vertexIndex1 && VertexIndex2 == vertexIndex2) ||
+ (VertexIndex1 == vertexIndex2 && VertexIndex2 == vertexIndex1);
+ }
+
+ ///
+ /// Gets if the edge was visited from the vertex
+ ///
+ /// The index of the vertex where the edge is visited from
+ /// Returns True if the edge was visited from the vertex
+ public bool IsVisitedFromVertex(int vertexIndex)
+ {
+ if (VertexIndex1 == vertexIndex)
+ {
+ return visitDirections.HasFlag(VisitDirections.Straight);
+ }
+
+ if (VertexIndex2 == vertexIndex)
+ {
+ return visitDirections.HasFlag(VisitDirections.Opposite);
+ }
+
+ return false;
+ }
+
+ private VisitDirections visitDirections;
+ }
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/dependencies/SketchGrids.Dependencies.csproj b/Grids/SketchGrids/dependencies/SketchGrids.Dependencies.csproj
new file mode 100644
index 00000000..91caf5c0
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/SketchGrids.Dependencies.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net6.0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Grids/SketchGrids/dependencies/SketchGridsInputs.g.cs b/Grids/SketchGrids/dependencies/SketchGridsInputs.g.cs
new file mode 100644
index 00000000..3a05b48e
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/SketchGridsInputs.g.cs
@@ -0,0 +1,350 @@
+// This code was generated by Hypar.
+// Edits to this code will be overwritten the next time you run 'hypar init'.
+// DO NOT EDIT THIS FILE.
+
+using Elements;
+using Elements.GeoJSON;
+using Elements.Geometry;
+using Elements.Geometry.Solids;
+using Elements.Validators;
+using Elements.Serialization.JSON;
+using Hypar.Functions;
+using Hypar.Functions.Execution;
+using Hypar.Functions.Execution.AWS;
+using Hypar.Model;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Line = Elements.Geometry.Line;
+using Polygon = Elements.Geometry.Polygon;
+
+namespace SketchGrids
+{
+ #pragma warning disable // Disable all warnings
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public class SketchGridsInputs : ArgsBase
+
+ {
+ [Newtonsoft.Json.JsonConstructor]
+
+ public SketchGridsInputs(double @offsetDistanceFromConceptualMass, bool @addSkeletonGrids, Overrides @overrides, Dictionary modelInputKeys, string gltfKey, string elementsKey, string ifcKey):
+ base(modelInputKeys, gltfKey, elementsKey, ifcKey)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @offsetDistanceFromConceptualMass, @addSkeletonGrids, @overrides});
+ }
+
+ this.OffsetDistanceFromConceptualMass = @offsetDistanceFromConceptualMass;
+ this.AddSkeletonGrids = @addSkeletonGrids;
+ this.Overrides = @overrides ?? this.Overrides;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ /// The default grid offset from the conceptual mass.
+ [Newtonsoft.Json.JsonProperty("Offset Distance From Conceptual Mass", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public double OffsetDistanceFromConceptualMass { get; set; } = 1.5D;
+
+ /// Add grids along conceptual mass skeletons.
+ [Newtonsoft.Json.JsonProperty("Add Skeleton Grids", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public bool AddSkeletonGrids { get; set; } = false;
+
+ [Newtonsoft.Json.JsonProperty("overrides", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public Overrides Overrides { get; set; } = new Overrides();
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class Overrides
+
+ {
+ public Overrides() { }
+
+ [Newtonsoft.Json.JsonConstructor]
+ public Overrides(OverrideAdditions @additions, OverrideRemovals @removals, IList @gridLines)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @additions, @removals, @gridLines});
+ }
+
+ this.Additions = @additions ?? this.Additions;
+ this.Removals = @removals ?? this.Removals;
+ this.GridLines = @gridLines ?? this.GridLines;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("Additions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public OverrideAdditions Additions { get; set; } = new OverrideAdditions();
+
+ [Newtonsoft.Json.JsonProperty("Removals", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public OverrideRemovals Removals { get; set; } = new OverrideRemovals();
+
+ [Newtonsoft.Json.JsonProperty("Grid Lines", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public IList GridLines { get; set; } = new List();
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class OverrideAdditions
+
+ {
+ public OverrideAdditions() { }
+
+ [Newtonsoft.Json.JsonConstructor]
+ public OverrideAdditions(IList @gridLines)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @gridLines});
+ }
+
+ this.GridLines = @gridLines ?? this.GridLines;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("Grid Lines", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public IList GridLines { get; set; } = new List();
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class OverrideRemovals
+
+ {
+ public OverrideRemovals() { }
+
+ [Newtonsoft.Json.JsonConstructor]
+ public OverrideRemovals(IList @gridLines)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @gridLines});
+ }
+
+ this.GridLines = @gridLines ?? this.GridLines;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("Grid Lines", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public IList GridLines { get; set; } = new List();
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class GridLinesOverride
+
+ {
+ [Newtonsoft.Json.JsonConstructor]
+ public GridLinesOverride(string @id, GridLinesIdentity @identity, GridLinesValue @value)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @id, @identity, @value});
+ }
+
+ this.Id = @id;
+ this.Identity = @identity;
+ this.Value = @value;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public string Id { get; set; }
+
+ [Newtonsoft.Json.JsonProperty("Identity", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public GridLinesIdentity Identity { get; set; }
+
+ [Newtonsoft.Json.JsonProperty("Value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public GridLinesValue Value { get; set; }
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class GridLinesOverrideAddition
+
+ {
+ [Newtonsoft.Json.JsonConstructor]
+ public GridLinesOverrideAddition(string @id, GridLinesIdentity @identity, GridLinesOverrideAdditionValue @value)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @id, @identity, @value});
+ }
+
+ this.Id = @id;
+ this.Identity = @identity;
+ this.Value = @value;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public string Id { get; set; }
+
+ [Newtonsoft.Json.JsonProperty("Identity", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public GridLinesIdentity Identity { get; set; }
+
+ [Newtonsoft.Json.JsonProperty("Value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public GridLinesOverrideAdditionValue Value { get; set; }
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class GridLinesOverrideRemoval
+
+ {
+ [Newtonsoft.Json.JsonConstructor]
+ public GridLinesOverrideRemoval(string @id, GridLinesIdentity @identity)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @id, @identity});
+ }
+
+ this.Id = @id;
+ this.Identity = @identity;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public string Id { get; set; }
+
+ [Newtonsoft.Json.JsonProperty("Identity", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public GridLinesIdentity Identity { get; set; }
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class GridLinesIdentity
+
+ {
+ [Newtonsoft.Json.JsonConstructor]
+ public GridLinesIdentity(Line @curve)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @curve});
+ }
+
+ this.Curve = @curve;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("Curve", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public Line Curve { get; set; }
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class GridLinesValue
+
+ {
+ [Newtonsoft.Json.JsonConstructor]
+ public GridLinesValue(Line @curve, string @name)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @curve, @name});
+ }
+
+ this.Curve = @curve;
+ this.Name = @name;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("Curve", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public Line Curve { get; set; }
+
+ /// The name of the grid line.
+ [Newtonsoft.Json.JsonProperty("Name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public string Name { get; set; } = "XXX";
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
+
+ public partial class GridLinesOverrideAdditionValue
+
+ {
+ [Newtonsoft.Json.JsonConstructor]
+ public GridLinesOverrideAdditionValue(Line @curve, string @name)
+ {
+ var validator = Validator.Instance.GetFirstValidatorForType();
+ if(validator != null)
+ {
+ validator.PreConstruct(new object[]{ @curve, @name});
+ }
+
+ this.Curve = @curve;
+ this.Name = @name;
+
+ if(validator != null)
+ {
+ validator.PostConstruct(this);
+ }
+ }
+
+ [Newtonsoft.Json.JsonProperty("Curve", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public Line Curve { get; set; }
+
+ /// The name of the grid line.
+ [Newtonsoft.Json.JsonProperty("Name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
+ public string Name { get; set; } = "XXX";
+
+ }
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/dependencies/SketchGridsOutputs.g.cs b/Grids/SketchGrids/dependencies/SketchGridsOutputs.g.cs
new file mode 100644
index 00000000..159d236e
--- /dev/null
+++ b/Grids/SketchGrids/dependencies/SketchGridsOutputs.g.cs
@@ -0,0 +1,29 @@
+// This code was generated by Hypar.
+// Edits to this code will be overwritten the next time you run 'hypar init'.
+// DO NOT EDIT THIS FILE.
+
+using Elements;
+using Elements.GeoJSON;
+using Elements.Geometry;
+using Hypar.Functions;
+using Hypar.Functions.Execution;
+using Hypar.Functions.Execution.AWS;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using System.Collections.Generic;
+
+namespace SketchGrids
+{
+ public class SketchGridsOutputs: SystemResults
+ {
+
+ ///
+ /// Construct a SketchGridsOutputs with default inputs.
+ /// This should be used for testing only.
+ ///
+ public SketchGridsOutputs() : base()
+ {
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/hypar.json b/Grids/SketchGrids/hypar.json
new file mode 100644
index 00000000..ab810eef
--- /dev/null
+++ b/Grids/SketchGrids/hypar.json
@@ -0,0 +1,77 @@
+{
+ "$schema": "https://hypar.io/Schemas/Function.json",
+ "id": "7b53fd3e-d94a-4333-9127-045722dddbd8",
+ "name": "Sketch Grids",
+ "description": "Generate grids automatically from conceptual masses or sketch grid lines.",
+ "language": "C#",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "Offset Distance From Conceptual Mass": {
+ "description": "The default grid offset from the conceptual mass.",
+ "type": "number",
+ "default": 1.5,
+ "$hyparUnitType": "length"
+ },
+ "Add Skeleton Grids": {
+ "description": "Add grids along conceptual mass skeletons.",
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "overrides": {
+ "Grid Lines": {
+ "context": "[*discriminator=Elements.GridLine]",
+ "identity": {
+ "Curve": {
+ "$ref": "https://hypar.io/Schemas/Geometry/Line.json"
+ }
+ },
+ "schema": {
+ "Curve": {
+ "$ref": "https://hypar.io/Schemas/Geometry/Line.json",
+ "$hyparAllowIntersection": true,
+ "$hyparContinueDrawing": false
+ },
+ "Name": {
+ "description": "The name of the grid line.",
+ "type": "string",
+ "default": "XXX"
+ }
+ },
+ "behaviors": {
+ "add": {
+ "schema": {
+ "Curve": {
+ "$ref": "https://hypar.io/Schemas/Geometry/Line.json",
+ "$hyparAllowIntersection": true,
+ "$hyparContinueDrawing": false
+ },
+ "Name": {
+ "description": "The name of the grid line.",
+ "type": "string",
+ "default": "XXX"
+ }
+ }
+ },
+ "remove": true
+ }
+ }
+ },
+ "outputs": [],
+ "model_dependencies": [
+ {
+ "name": "Conceptual Mass",
+ "autohide": false,
+ "optional": true
+ }
+ ],
+ "element_types": [
+ "https://schemas.hypar.io/ConceptualMass.json"
+ ],
+ "model_output": "Grids",
+ "repository_url": "https://github.com/hypar-io/function",
+ "last_updated": "0001-01-01T00:00:00",
+ "cli_version": "1.1.1"
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/src/Function.g.cs b/Grids/SketchGrids/src/Function.g.cs
new file mode 100644
index 00000000..3d88030c
--- /dev/null
+++ b/Grids/SketchGrids/src/Function.g.cs
@@ -0,0 +1,73 @@
+// This code was generated by Hypar.
+// Edits to this code will be overwritten the next time you run 'hypar init'.
+// DO NOT EDIT THIS FILE.
+
+using Amazon.Lambda.Core;
+using Hypar.Functions.Execution;
+using Hypar.Functions.Execution.AWS;
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
+namespace SketchGrids
+{
+ public class Function
+ {
+ // Cache the model store for use by subsequent
+ // executions of this lambda.
+ private UrlModelStore store;
+
+ public async Task Handler(SketchGridsInputs args)
+ {
+ // Preload dependencies (if they exist),
+ // so that they are available during model deserialization.
+
+ var sw = System.Diagnostics.Stopwatch.StartNew();
+ var asmLocation = this.GetType().Assembly.Location;
+ var asmDir = Path.GetDirectoryName(asmLocation);
+
+ // Explicitly load the dependencies project, it might have types
+ // that aren't used in the function but are necessary for correct
+ // deserialization.
+ var asmName = Path.GetFileNameWithoutExtension(asmLocation);
+ var depPath = Path.Combine(asmDir, $"{asmName}.Dependencies.dll");
+ if(File.Exists(depPath))
+ {
+ Console.WriteLine($"Loading dependencies assembly from: {depPath}...");
+ Assembly.LoadFrom(depPath);
+ Console.WriteLine("Dependencies assembly loaded.");
+ }
+
+ // Load all reference assemblies.
+ Console.WriteLine($"Loading all referenced assemblies.");
+ foreach (var asm in this.GetType().Assembly.GetReferencedAssemblies())
+ {
+ try
+ {
+ Console.WriteLine($"Assembly Name: {asm.FullName}");
+ Assembly.Load(asm);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Failed to load {asm.FullName}");
+ Console.WriteLine(e.Message);
+ }
+ }
+ sw.Stop();
+ Console.WriteLine($"Time to load assemblies: {sw.Elapsed.TotalSeconds})");
+
+ if(this.store == null)
+ {
+ this.store = new UrlModelStore();
+ }
+
+
+ var l = new InvocationWrapper (store, SketchGrids.Execute);
+ var output = await l.InvokeAsync(args);
+ return output;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/src/SketchGrids.cs b/Grids/SketchGrids/src/SketchGrids.cs
new file mode 100644
index 00000000..8e152629
--- /dev/null
+++ b/Grids/SketchGrids/src/SketchGrids.cs
@@ -0,0 +1,207 @@
+using Elements;
+using Elements.Geometry;
+using Elements.Search;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SketchGrids
+{
+ public static class SketchGrids
+ {
+ ///
+ /// The SketchGrids function.
+ ///
+ /// The input model.
+ /// The arguments to the execution.
+ /// A SketchGridsOutputs instance containing computed results and the model with any new elements.
+ public static SketchGridsOutputs Execute(Dictionary inputModels, SketchGridsInputs input)
+ {
+ var output = new SketchGridsOutputs();
+ var edgeDisplaySettings = new EdgeDisplaySettings()
+ {
+ WidthMode = EdgeDisplayWidthMode.ScreenUnits,
+ LineWidth = 1,
+ DashSize = 40,
+ // DashMode = EdgeDisplayDashMode.ScreenUnits
+ };
+
+ var gridMaterial = new Material("Grid Line", Colors.Darkgray)
+ {
+ EdgeDisplaySettings = edgeDisplaySettings
+ };
+
+ var gridLines = new List();
+
+ if (inputModels.ContainsKey("Conceptual Mass"))
+ {
+ CreateGridLinesForConceptualMass(inputModels, input, gridMaterial, gridLines);
+ }
+
+ gridLines = input.Overrides.GridLines.CreateElements(input.Overrides.Additions.GridLines, input.Overrides.Removals.GridLines,
+ (add) =>
+ {
+ var gridLine = new GridLine()
+ {
+ Curve = add.Value.Curve,
+ Material = gridMaterial,
+ Name = add.Value.Name ?? "XXX"
+ };
+ gridLine.AdditionalProperties["Creation Id"] = add.Id;
+ return gridLine;
+ }, (gl, identity) =>
+ {
+ return identity.Curve != null && ((Line)gl.Curve).IsAlmostEqualTo(identity.Curve, false);
+ }, (gl, @override) =>
+ {
+ gl.Curve = @override.Value.Curve;
+ gl.Name = @override.Value.Name ?? "XXX";
+ return gl;
+ }, gridLines);
+
+ output.Model.AddElements(gridLines);
+
+ var texts = new List<(Vector3 location, Vector3 facingDirection, Vector3 lineDirection, string text, Color? color)>();
+ foreach (var gridLine in gridLines)
+ {
+ var t = gridLine.GetCircleTransform();
+ texts.Add(((t.Origin.X, t.Origin.Y), Vector3.ZAxis, Vector3.XAxis, $"{gridLine.Name ?? "XXX"}", Colors.Black));
+ }
+ output.Model.AddElement(new ModelText(texts, FontSize.PT60, scale: 50));
+
+ return output;
+ }
+
+ private static void CreateGridLinesForConceptualMass(Dictionary inputModels,
+ SketchGridsInputs input,
+ Material gridMaterial,
+ List gridLines)
+ {
+ var conceptualMasses = inputModels["Conceptual Mass"].AllElementsOfType();
+
+ var gridIndex = 0;
+ var allVoids = new List();
+
+ foreach (var conceptualMass in conceptualMasses)
+ {
+ var offsetHull = conceptualMass.Profile.Perimeter.Offset(1)[0];
+
+ conceptualMass.UpdateRepresentations();
+ conceptualMass.UpdateBoundsAndComputeSolid();
+
+ if (conceptualMass.Skeleton != null)
+ {
+ // Create grids for the skeleton
+ if (input.AddSkeletonGrids)
+ {
+ foreach (var edge in conceptualMass.Skeleton)
+ {
+ var newGridLine = edge.ExtendTo(offsetHull);
+ CheckAndCreateGridline(newGridLine, gridLines, ref gridIndex, gridMaterial, input);
+ }
+ }
+
+ var allPerimeters = new List();
+
+ if (conceptualMass.Profile != null && conceptualMass.Profile.Voids != null)
+ {
+ allPerimeters.Add(conceptualMass.Profile.Perimeter);
+ foreach (var profileVoid in conceptualMass.Profile.Voids)
+ {
+ allVoids.Add(profileVoid);
+ }
+ }
+
+ // Offset perimeters to the inside.
+ foreach (var cutPerimeter in allPerimeters)
+ {
+ foreach (var segment in cutPerimeter.Offset(-input.OffsetDistanceFromConceptualMass)[0].Segments())
+ {
+ var newGridLine = segment.ExtendTo(offsetHull);
+ CheckAndCreateGridline(newGridLine, gridLines, ref gridIndex, gridMaterial, input);
+ }
+ }
+
+ // TODO: Are there ever holes in a skeleton mass?
+ // Offset holes to the outside.
+ // foreach (var cutVoid in allVoids)
+ // {
+ // foreach (var segment in cutVoid.Offset(-structuralOffset)[0].Segments())
+ // {
+ // var newGridLine = segment.ExtendTo(offsetHull);
+ // CheckAndCreateGridline(newGridLine, gridLines, ref gridIndex, gridMaterial);
+ // }
+ // }
+ }
+ else
+ {
+ foreach (var segment in conceptualMass.Profile.Perimeter.Offset(-input.OffsetDistanceFromConceptualMass)[0].Segments())
+ {
+ var newGridLine = segment.ExtendTo(offsetHull);
+ CheckAndCreateGridline(newGridLine, gridLines, ref gridIndex, gridMaterial, input);
+ }
+
+ if (conceptualMass.Profile.Voids != null)
+ {
+ allVoids.AddRange(conceptualMass.Profile.Voids);
+ }
+ }
+ }
+
+ // We process the voids last so that we have all grids
+ // created from the faces of the conceptual masses to respond
+ // to. This will create the shortest spanning edge grids for holes.
+ foreach (var profileVoid in allVoids)
+ {
+ var holeGridLines = new List();
+ var offsetHull = profileVoid.Offset(input.OffsetDistanceFromConceptualMass)[0];
+
+ foreach (var segment in offsetHull.Segments())
+ {
+ holeGridLines.Add(segment);
+ }
+
+ foreach (var holeGridLine in holeGridLines)
+ {
+ CheckAndCreateGridline(holeGridLine, gridLines, ref gridIndex, gridMaterial, input);
+ }
+ }
+ }
+
+ private static void CheckAndCreateGridline(Line newGridLine,
+ List gridLines,
+ ref int gridIndex,
+ Material gridMaterial,
+ SketchGridsInputs input)
+ {
+ if (gridLines.Any(gl => (gl.Curve as Line).IsAlmostEqualTo(newGridLine, false)))
+ {
+ return;
+ }
+
+ GridLinesOverride matchingEditOverride = null;
+ if (input.Overrides?.GridLines != null)
+ {
+ matchingEditOverride = input.Overrides.GridLines.FirstOrDefault((glo) => glo.Identity.Curve != null && glo.Identity.Curve.IsAlmostEqualTo(newGridLine, false));
+ if (matchingEditOverride != null)
+ {
+ newGridLine = matchingEditOverride.Value.Curve;
+ }
+ }
+
+ var gl = new GridLine()
+ {
+ Curve = newGridLine,
+ Name = gridIndex.ToString(),
+ Material = gridMaterial
+ };
+ gridLines.Add(gl);
+ gridIndex++;
+
+ if (matchingEditOverride != null)
+ {
+ Identity.AddOverrideIdentity(gl, matchingEditOverride);
+ }
+ }
+ }
+}
diff --git a/Grids/SketchGrids/src/SketchGrids.csproj b/Grids/SketchGrids/src/SketchGrids.csproj
new file mode 100644
index 00000000..4c86d152
--- /dev/null
+++ b/Grids/SketchGrids/src/SketchGrids.csproj
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+ net6.0
+
+
\ No newline at end of file
diff --git a/Grids/SketchGrids/src/VectorEqualityComparer.cs b/Grids/SketchGrids/src/VectorEqualityComparer.cs
new file mode 100644
index 00000000..9028988c
--- /dev/null
+++ b/Grids/SketchGrids/src/VectorEqualityComparer.cs
@@ -0,0 +1,29 @@
+using Elements.Geometry;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+
+namespace SketchGrids
+{
+ public class VectorEqualityComparer : IEqualityComparer
+ {
+ public bool Equals([AllowNull] Vector3 x, [AllowNull] Vector3 y)
+ {
+ return x.IsAlmostEqualTo(y);
+ }
+
+ public int GetHashCode([DisallowNull] Vector3 obj)
+ {
+ // Stolen from the vector 3 class, but using
+ // less precision to enforce matches.
+ unchecked
+ {
+ int hash = 17;
+ hash = hash * 23 + Math.Round(obj.X, 5).GetHashCode();
+ hash = hash * 23 + Math.Round(obj.Y, 5).GetHashCode();
+ hash = hash * 23 + Math.Round(obj.Z, 5).GetHashCode();
+ return hash;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/test/FunctionTest.g.cs b/Grids/SketchGrids/test/FunctionTest.g.cs
new file mode 100644
index 00000000..de92b88c
--- /dev/null
+++ b/Grids/SketchGrids/test/FunctionTest.g.cs
@@ -0,0 +1,24 @@
+// This code was generated by Hypar.
+// Edits to this code will be overwritten the next time you run 'hypar init'.
+// DO NOT EDIT THIS FILE.
+
+using Xunit;
+using System.IO;
+using System.Reflection;
+using System.Threading.Tasks;
+using Xunit.Abstractions;
+using System;
+using System.Collections.Generic;
+
+namespace SketchGrids.Tests
+{
+ public class FunctionTests
+ {
+ private readonly ITestOutputHelper output;
+
+ public FunctionTests(ITestOutputHelper output)
+ {
+ this.output = output;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Grids/SketchGrids/test/SketchGrids.Tests.csproj b/Grids/SketchGrids/test/SketchGrids.Tests.csproj
new file mode 100644
index 00000000..f2953633
--- /dev/null
+++ b/Grids/SketchGrids/test/SketchGrids.Tests.csproj
@@ -0,0 +1,16 @@
+
+
+
+ net6.0
+ false
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Structure/StructureByEnvelope/dependencies/Camera.g.cs b/Structure/StructureByEnvelope/dependencies/Camera.g.cs
index f8f7fb70..292f181e 100644
--- a/Structure/StructureByEnvelope/dependencies/Camera.g.cs
+++ b/Structure/StructureByEnvelope/dependencies/Camera.g.cs
@@ -19,12 +19,12 @@
namespace Elements
{
- #pragma warning disable // Disable all warnings
+#pragma warning disable // Disable all warnings
/// Represents camera settings
[JsonConverter(typeof(Elements.Serialization.JSON.JsonInheritanceConverter), "discriminator")]
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
- public partial class Camera
+ public partial class Camera
{
[JsonConstructor]
public Camera(Vector3 @angle, CameraNamedPosition? @namedPosition, CameraProjection? @projection)
@@ -32,28 +32,28 @@ public Camera(Vector3 @angle, CameraNamedPosition? @namedPosition, CameraProject
this.Angle = @angle;
this.NamedPosition = @namedPosition;
this.Projection = @projection;
- }
-
-
+ }
+
+
// Empty constructor
public Camera()
{
}
-
+
/// A unit vector in model coordinates indicating which direction the camera is pointing.
[JsonProperty("angle", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public Vector3 Angle { get; set; }
-
+
/// Camera positions, viewing from this direction to the opposite direction. Do not set angle if setting this.
[JsonProperty("named_position", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public CameraNamedPosition? NamedPosition { get; set; }
-
+
/// How the camera collapses the 3d scene into a 2d image
[JsonProperty("projection", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public CameraProjection? Projection { get; set; }
-
-
+
+
}
}
\ No newline at end of file
diff --git a/Structure/StructureByEnvelope/dependencies/LevelVolume.g.cs b/Structure/StructureByEnvelope/dependencies/LevelVolume.g.cs
index d437122c..32be11bf 100644
--- a/Structure/StructureByEnvelope/dependencies/LevelVolume.g.cs
+++ b/Structure/StructureByEnvelope/dependencies/LevelVolume.g.cs
@@ -19,7 +19,7 @@
namespace Elements
{
- #pragma warning disable // Disable all warnings
+#pragma warning disable // Disable all warnings
/// Describes the volume of occupiable space between a level and the next level above it.
[JsonConverter(typeof(Elements.Serialization.JSON.JsonInheritanceConverter), "discriminator")]
@@ -38,47 +38,47 @@ public LevelVolume(Profile @profile, double @height, double @area, string @build
this.Mass = @mass;
this.PlanView = @planView;
this.Profiles = @profiles;
- }
-
-
+ }
+
+
// Empty constructor
public LevelVolume()
: base()
{
}
-
+
/// The profile of the level Volume
[JsonProperty("Profile", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public Profile Profile { get; set; }
-
+
/// The floor-to-floor height of this level
[JsonProperty("Height", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public double Height { get; set; }
-
+
/// The area of the level's profile.
[JsonProperty("Area", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public double Area { get; set; }
-
+
/// The name of the building or mass this level belongs to (optional)
[JsonProperty("Building Name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string BuildingName { get; set; }
-
+
/// The Level this volume was created from.
[JsonProperty("Level", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Guid? Level { get; set; }
-
+
/// The Conceptual Mass this volume was created from.
[JsonProperty("Mass", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Guid? Mass { get; set; }
-
+
/// The default plan view for this level
[JsonProperty("Plan View", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Guid? PlanView { get; set; }
-
+
/// Multiple profiles used for a collection of volumes
[JsonProperty("Profiles", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public IList Profiles { get; set; }
-
-
+
+
}
}
\ No newline at end of file
diff --git a/Structure/StructureByEnvelope/dependencies/ViewScope.g.cs b/Structure/StructureByEnvelope/dependencies/ViewScope.g.cs
index aeff1468..a0404035 100644
--- a/Structure/StructureByEnvelope/dependencies/ViewScope.g.cs
+++ b/Structure/StructureByEnvelope/dependencies/ViewScope.g.cs
@@ -19,65 +19,65 @@
namespace Elements
{
- #pragma warning disable // Disable all warnings
+#pragma warning disable // Disable all warnings
- /// Represents a preset view attached to an element.
- [JsonConverter(typeof(Elements.Serialization.JSON.JsonInheritanceConverter), "discriminator")]
- [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")]
- public partial class ViewScope : Element
- {
- [JsonConstructor]
- public ViewScope(BBox3 @boundingBox, Camera @camera, bool? @lockRotation, bool? @clipWithBoundingBox, ViewScopeClippingBehavior? @clippingBehavior, bool? @modal, System.Collections.Generic.IDictionary @functionVisibility, IList