Skip to content

Commit

Permalink
Merge pull request #1049 from hypar-io/Snapping
Browse files Browse the repository at this point in the history
Added optional snapping points generation;
  • Loading branch information
katehryhorenko authored Nov 8, 2023
2 parents 7d6ba74 + e8bbdab commit e49f5be
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 4 deletions.
10 changes: 10 additions & 0 deletions Elements/src/CoreModels/ElementRepresentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,14 @@ internal virtual List<NodeExtension> GetNodeExtensions(GeometricElement element)
{
return new List<NodeExtension>();
}

/// <summary>
///Creates the set of snapping points
/// </summary>
/// <param name="element">The element with this representation.</param>
/// <returns></returns>
public virtual List<SnappingPoints> CreateSnappingPoints(GeometricElement element)
{
return new List<SnappingPoints>();
}
}
2 changes: 1 addition & 1 deletion Elements/src/CoreModels/RepresentationInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public RepresentationInstance(ElementRepresentation representation, Material mat
public List<string> RepresentationTypes { get; set; } = new List<string>();

/// <summary>
/// Indicates if this element representation instance is displayed by default.
/// Indicates if this element representation instance is displayed by default.
/// Element can have several default representations.
/// </summary>
public bool IsDefault { get; set; } = true;
Expand Down
32 changes: 32 additions & 0 deletions Elements/src/Geometry/Solids/Extrude.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Elements.Validators;
using Newtonsoft.Json;

Expand Down Expand Up @@ -108,6 +109,37 @@ public Extrude(Profile profile, double height, Vector3 direction, bool isVoid =
UpdateGeometry();
}

internal override List<SnappingPoints> CreateSnappingPoints(GeometricElement element)
{
var result = new List<SnappingPoints>();
var localTransform = new Transform(Direction * Height);
var bottomVertices = new List<Vector3>();
// add perimeter bottom points
result.Add(new SnappingPoints(Profile.Perimeter.Vertices, SnappingEdgeMode.LineLoop));
bottomVertices.AddRange(Profile.Perimeter.Vertices);
// add perimeter top points
result.Add(new SnappingPoints(Profile.Perimeter.TransformedPolygon(localTransform).Vertices, SnappingEdgeMode.LineLoop));

// add each void
foreach (var item in Profile.Voids)
{
result.Add(new SnappingPoints(item.Vertices, SnappingEdgeMode.LineLoop));
bottomVertices.AddRange(item.Vertices);
result.Add(new SnappingPoints(item.TransformedPolygon(localTransform).Vertices, SnappingEdgeMode.LineLoop));
}

// connect top and bottom points
var edges = new List<Vector3>();
foreach (var item in bottomVertices)
{
edges.Add(item);
edges.Add(localTransform.OfPoint(item));
}
result.Add(new SnappingPoints(edges, SnappingEdgeMode.Lines));

return result;
}

private void UpdateGeometry()
{
this._solid = Kernel.Instance.CreateExtrude(this._profile, this._height, this._direction, this._reverseWinding);
Expand Down
13 changes: 13 additions & 0 deletions Elements/src/Geometry/Solids/Lamina.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ public Lamina(Profile profile, bool isVoid = false) : this(profile.Perimeter, pr

}

internal override List<SnappingPoints> CreateSnappingPoints(GeometricElement element)
{
var result = new List<SnappingPoints>();
result.Add(new SnappingPoints(Perimeter.Vertices, SnappingEdgeMode.LineLoop));

foreach (var item in Voids)
{
result.Add(new SnappingPoints(item.Vertices, SnappingEdgeMode.LineLoop));
}

return result;
}

private void UpdateGeometry()
{
this._solid = Kernel.Instance.CreateLamina(this._perimeter, this._voids);
Expand Down
6 changes: 6 additions & 0 deletions Elements/src/Geometry/Solids/SolidOperation.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Elements.Geometry.Solids
Expand Down Expand Up @@ -53,5 +54,10 @@ protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.Cal
if (handler != null)
handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}

internal virtual List<SnappingPoints> CreateSnappingPoints(GeometricElement element)
{
return new List<SnappingPoints>();
}
}
}
6 changes: 6 additions & 0 deletions Elements/src/Geometry/Solids/Sweep.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Elements.Geometry.Solids
Expand Down Expand Up @@ -109,6 +110,11 @@ public double ProfileRotation
}
}

internal override List<SnappingPoints> CreateSnappingPoints(GeometricElement element)
{
return base.CreateSnappingPoints(element);
}

private void UpdateGeometry()
{
this._solid = Kernel.Instance.CreateSweepAlongCurve(this._profile, this._curve, this._startSetback, this._endSetback, this._profileRotation);
Expand Down
9 changes: 9 additions & 0 deletions Elements/src/Representations/CurveRepresentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,14 @@ public override bool TryToGraphicsBuffers(GeometricElement element, out List<Gra
mode = _curve.IsClosedForRendering ? glTFLoader.Schema.MeshPrimitive.ModeEnum.LINE_LOOP : glTFLoader.Schema.MeshPrimitive.ModeEnum.LINE_STRIP;
return true;
}

/// <inheritdoc/>
public override List<SnappingPoints> CreateSnappingPoints(GeometricElement element)
{
var snappingPoints = new List<SnappingPoints>();
var curvePoints = _curve.RenderVertices();
snappingPoints.Add(new SnappingPoints(curvePoints));
return snappingPoints;
}
}
}
13 changes: 13 additions & 0 deletions Elements/src/Representations/SolidRepresentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,18 @@ public List<List<Vector3>> CalculateIntersectionPoints(GeometricElement element,

return intersectionPoints;
}

/// <inheritdoc/>
public override List<SnappingPoints> CreateSnappingPoints(GeometricElement element)
{
var snappingPoints = new List<SnappingPoints>();

foreach (var solidOperation in SolidOperations)
{
snappingPoints.AddRange(solidOperation.CreateSnappingPoints(element));
}

return snappingPoints;
}
}
}
36 changes: 36 additions & 0 deletions Elements/src/Serialization/JSON/VectorListToByteArrayConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using Elements.Geometry;
using Newtonsoft.Json;

namespace Elements.Serialization.JSON
{
internal class VectorListToByteArrayConverter : JsonConverter
{
public override bool CanRead => false;

public override bool CanConvert(Type objectType)
{
return objectType == typeof(List<Vector3>);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();

}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var points = value as List<Vector3>;
var valueAsArray = new double[points.Count * 3];
for (int i = 0; i < points.Count; i++)
{
valueAsArray[i * 3] = points[i].X;
valueAsArray[i * 3 + 1] = points[i].Y;
valueAsArray[i * 3 + 2] = points[i].Z;
}
serializer.Serialize(writer, valueAsArray);
}
}
}
18 changes: 18 additions & 0 deletions Elements/src/Serialization/glTF/GltfExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,19 @@ private static void AddExtension(Gltf gltf, glTFLoader.Schema.Node gltfNode, str
gltfNode.Extensions.Add(extensionName, extensionAttributes);
}

/// <summary>
/// Add a custom Mesh extension.
/// </summary>
private static void AddExtension(Gltf gltf, glTFLoader.Schema.Mesh gltfMesh, string extensionName, Dictionary<string, object> extensionAttributes)
{
if (gltfMesh.Extensions == null)
{
gltfMesh.Extensions = new Dictionary<string, object>();
}
AddExtension(gltf, extensionName, extensionAttributes);
gltfMesh.Extensions.Add(extensionName, extensionAttributes);
}

/// <summary>
/// Add a generic custom extension.
/// </summary>
Expand Down Expand Up @@ -1328,6 +1341,11 @@ private static void GetRenderDataForElement(Element e,
var meshIdList = new List<int> { meshId };
representationsMap.Add(combinedId, meshIdList);
addedNodes.AddRange(NodeUtilities.AddNodes(nodes, meshIdList, elementNodeId));
var snappingPoints = representation.Representation.CreateSnappingPoints(element);
if (snappingPoints.Any())
{
AddExtension(gltf, meshes[meshId], "HYPAR_snapping_points", new Dictionary<string, object>() { { "points", snappingPoints } });
}
}
}
else
Expand Down
11 changes: 8 additions & 3 deletions Elements/src/Serialization/glTF/NodeUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ internal static Node AddInstanceAsCopyOfNode(
// Two new nodes are created: a top-level node, which has the
// element's Transform, and one just below that, which handles
// flipping the orientation of the glb to have Z up. That node has
// the node to copy as its only child.
// the node to copy as its only child.
// We use the node to copy exactly as is, with an unmodified
// transform.
// We need the outermost node to be "purely" the element's
Expand All @@ -109,7 +109,7 @@ internal static Node AddInstanceAsCopyOfNode(
var rootTransform = new Transform();
// glb has Y up. transform it to have Z up so we
// can create instances of it in a Z up world. It will get switched
// back to Y up further up in the node hierarchy.
// back to Y up further up in the node hierarchy.
rootTransform.Rotate(new Vector3(1, 0, 0), 90.0);
float[] glbOrientationTransform = TransformToMatrix(rootTransform);
var elementOrientationNode = new glTFLoader.Schema.Node();
Expand Down Expand Up @@ -237,9 +237,14 @@ public static void SetRepresentationInfo(this Node node, RepresentationInstance
var extensionDict = new Dictionary<string, object>
{
{"isDefault", representationInstance.IsDefault},
{"representationType", representationInstance.RepresentationTypes}
{"representationType", representationInstance.RepresentationTypes},
};

if (node.Mesh.HasValue)
{
extensionDict.Add("mesh", node.Mesh.Value);
}

node.Extensions["HYPAR_representation_info"] = extensionDict;
}
}
Expand Down
25 changes: 25 additions & 0 deletions Elements/src/Snapping/SnappingEdgeMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Elements
{
/// <summary>
/// Enumerates the modes for creating snap edges.
/// </summary>
public enum SnappingEdgeMode
{
/// <summary>
/// No edges are created; only individual point snaps.
/// </summary>
Points,
/// <summary>
/// A snap edge is drawn between every pair of points, creating a network of edges.
/// </summary>
Lines,
/// <summary>
/// Snap edges connect each subsequent point and also close the shape by connecting the last to the first point.
/// </summary>
LineLoop,
/// <summary>
/// Snap edges connect each subsequent point, without closing the shape.
/// </summary>
LineStrip
}
}
37 changes: 37 additions & 0 deletions Elements/src/Snapping/SnappingPoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Collections.Generic;
using Elements.Geometry;
using Elements.Serialization.JSON;
using Newtonsoft.Json;

namespace Elements
{
/// <summary>
/// Provides information about snapping points.
/// </summary>
public class SnappingPoints
{
/// <summary>
/// Initializes a new instance of SnappingPoints class.
/// </summary>
/// <param name="points">The set of points.</param>
/// <param name="edgeMode">The mode for creating snap edges.</param>
public SnappingPoints(IEnumerable<Vector3> points, SnappingEdgeMode edgeMode = SnappingEdgeMode.LineStrip)
{
Points.AddRange(points);
EdgeMode = edgeMode;
}

/// <summary>
/// Snapping points.
/// </summary>
[JsonProperty("points")]
[JsonConverter(typeof(VectorListToByteArrayConverter))]
public List<Vector3> Points { get; } = new List<Vector3>();

/// <summary>
/// The modes for creating snap edges.
/// </summary>
[JsonProperty("edgeMode")]
public SnappingEdgeMode EdgeMode { get; set; }
}
}

0 comments on commit e49f5be

Please sign in to comment.