From fa81fc23ff41d651f97827b82c3df4dbc5371079 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Thu, 26 Oct 2023 17:57:39 +0300 Subject: [PATCH 01/31] Added summaries and improved Door constructors --- Elements/src/Door.cs | 120 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 13 deletions(-) diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index 964371101..eaa365bff 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -9,8 +9,19 @@ namespace Elements /// Definition of a door public class Door : GeometricElement { + private readonly Material DEFAULT_MATERIAL = new Material("Door material", Colors.White); + + /// + /// Default thickness of a door. + /// public const double DOOR_THICKNESS = 0.125; + /// + /// Default thickness of a door frame. + /// public const double DOOR_FRAME_THICKNESS = 0.15; + /// + /// Default width of a door frame. + /// public const double DOOR_FRAME_WIDTH = 2 * 0.0254; //2 inches /// Door width without a frame @@ -28,6 +39,24 @@ public class Door : GeometricElement /// Opening for a door. public Opening Opening { get; private set; } + /// + /// Create a door that attaches to the closest point on a certain wall. + /// + /// The wall the door is attached to. + /// A center line of a wall that door is attached to. + /// The position where the door was plased originally. + /// The current door's position. + /// The with of a single door. + /// The door's height. + /// The side where the door opens. + /// The way the door opens. + /// The door's material. + /// The door's representation. + /// The door's id. + /// The door's name. + /// The door's opening depth front. + /// The door's opening depth back. + /// Is the door flipped? public Door(Wall wall, Line wallLine, Vector3 originalPosition, @@ -36,6 +65,10 @@ public Door(Wall wall, double height, DoorOpeningSide openingSide, DoorOpeningType openingType, + Material material = null, + Representation representation = null, + Guid id = default, + string name = "Door", double depthFront = 1, double depthBack = 1, bool flip = false) @@ -46,33 +79,72 @@ public Door(Wall wall, OriginalPosition = originalPosition; ClearWidth = WidthWithoutFrame(width, openingSide); ClearHeight = height; - Material = new Material("Door material", Colors.White); + Material = material ?? DEFAULT_MATERIAL; Transform = GetDoorTransform(currentPosition, wallLine, flip); - Representation = new Representation(new List() { }); + Representation = representation ?? new Representation(new List() { }); Opening = new Opening(Polygon.Rectangle(width, height), depthFront, depthBack, GetOpeningTransform()); + Id = id; + Name = name; } - public Door(Wall wall, - Transform transform, - double width, + /// + /// Create a door that is not attached to a wall. + /// + /// The with of a single door. + /// The door's height. + /// The side where the door opens. + /// The way the door opens. + /// The door's transform. X-direction is aligned with the door, Y-direction is the opening direction. + /// The door's material. + /// The door's representation. + /// The door's id. + /// The door's name. + /// The door's opening depth front. + /// The door's opening depth back. + public Door(double width, double height, DoorOpeningSide openingSide, DoorOpeningType openingType, + Transform transform = null, + Material material = null, + Representation representation = null, + Guid id = default, + string name = "Door", double depthFront = 1, - double depthBack = 1) + double depthBack = 1 + ) { - Wall = wall; + Wall = null; Transform = transform; OpeningSide = openingSide; OpeningType = openingType; ClearHeight = height; ClearWidth = WidthWithoutFrame(width, openingSide); - Material = new Material("Door material", Colors.White); - Representation = new Representation(new List() { }); + Material = material ?? DEFAULT_MATERIAL; + Representation = representation ?? new Representation(new List() { }); Opening = new Opening(Polygon.Rectangle(width, height), depthFront, depthBack, GetOpeningTransform()); OriginalPosition = Transform.Origin; + Id = id; + Name = name; } + /// + /// Create a door at the certain point of a wall. + /// + /// The wall the door is attached to. + /// A center line of a wall that door is attached to. + /// Relative position on the wall where door is placed. Should be in [0; 1]. + /// The with of a single door. + /// The door's height. + /// The side where the door opens. + /// The way the door opens. + /// The door's material. + /// The door's representation. + /// The door's id. + /// The door's name. + /// The door's opening depth front. + /// The door's opening depth back. + /// Is the door flipped? public Door(Wall wall, Line wallLine, double tPos, @@ -80,6 +152,10 @@ public Door(Wall wall, double height, DoorOpeningSide openingSide, DoorOpeningType openingType, + Material material = null, + Representation representation = null, + Guid id = default, + string name = "Door", double depthFront = 1, double depthBack = 1, bool flip = false) @@ -91,6 +167,10 @@ public Door(Wall wall, height, openingSide, openingType, + material, + representation, + id, + name, depthFront, depthBack, flip) @@ -104,19 +184,29 @@ private Transform GetOpeningTransform() return openingTransform; } - private Transform GetDoorTransform(Vector3 currentPosition, Line centerLine, bool flip) + private Transform GetDoorTransform(Vector3 currentPosition, Line wallLine, bool flip) { - var adjustedPosition = GetClosestValidDoorPos(centerLine, currentPosition); - var xDoorAxis = flip ? centerLine.Direction().Negate() : centerLine.Direction(); + var adjustedPosition = GetClosestValidDoorPos(wallLine, currentPosition); + var xDoorAxis = flip ? wallLine.Direction().Negate() : wallLine.Direction(); return new Transform(adjustedPosition, xDoorAxis, Vector3.ZAxis); } + /// + /// Checks if the door can fit into the wall with the center line @. + /// public static bool CanFit(Line wallLine, DoorOpeningSide openingSide, double width) { var doorWidth = WidthWithoutFrame(width, openingSide) + DOOR_FRAME_WIDTH * 2; return wallLine.Length() - doorWidth > DOOR_FRAME_WIDTH * 2; } + /// + /// Get graphics buffers and other metadata required to modify a GLB. + /// + /// + /// True if there is graphicsbuffers data applicable to add, false otherwise. + /// Out variables should be ignored if the return value is false. + /// public override bool TryToGraphicsBuffers(out List graphicsBuffers, out string id, out glTFLoader.Schema.MeshPrimitive.ModeEnum? mode) { var points = CollectPointsForSchematicVisualization(); @@ -128,7 +218,7 @@ public override bool TryToGraphicsBuffers(out List graphicsBuff buffer.AddIndex((ushort)i); } - id = $"{this.Id}_door"; + id = $"{Id}_door"; // Only one type is allowed, since line are not linked into one loop, LINES is used. // This mean that each line segment need both endpoints stored, often duplicated. mode = glTFLoader.Schema.MeshPrimitive.ModeEnum.LINES; @@ -245,6 +335,9 @@ private List CollectSchematicVisualizationLines(bool leftSide, bool ins return points; } + /// + /// Update the representations. + /// public override void UpdateRepresentations() { Vector3 left = Vector3.XAxis * ClearWidth / 2; @@ -289,6 +382,7 @@ public override void UpdateRepresentations() right + Vector3.ZAxis * ClearHeight - frameOffset }); var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); + Representation.SolidOperations.Clear(); Representation.SolidOperations.Add(doorFrameExtrude); foreach (var extrusion in doorExtrusions) { From 5bddae2591976918be3e742747439dc830627fa7 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Fri, 27 Oct 2023 11:35:03 +0300 Subject: [PATCH 02/31] Removed OriginalPosition property --- Elements/src/Door.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index eaa365bff..daccc3caa 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -34,8 +34,6 @@ public class Door : GeometricElement public Wall Wall { get; private set; } /// Height of a door without a frame. public double ClearHeight { get; private set; } - /// Position where door was placed originally. - public Vector3 OriginalPosition { get; private set; } /// Opening for a door. public Opening Opening { get; private set; } @@ -44,7 +42,6 @@ public class Door : GeometricElement /// /// The wall the door is attached to. /// A center line of a wall that door is attached to. - /// The position where the door was plased originally. /// The current door's position. /// The with of a single door. /// The door's height. @@ -59,7 +56,6 @@ public class Door : GeometricElement /// Is the door flipped? public Door(Wall wall, Line wallLine, - Vector3 originalPosition, Vector3 currentPosition, double width, double height, @@ -76,7 +72,6 @@ public Door(Wall wall, Wall = wall; OpeningType = openingType; OpeningSide = openingSide; - OriginalPosition = originalPosition; ClearWidth = WidthWithoutFrame(width, openingSide); ClearHeight = height; Material = material ?? DEFAULT_MATERIAL; @@ -123,7 +118,6 @@ public Door(double width, Material = material ?? DEFAULT_MATERIAL; Representation = representation ?? new Representation(new List() { }); Opening = new Opening(Polygon.Rectangle(width, height), depthFront, depthBack, GetOpeningTransform()); - OriginalPosition = Transform.Origin; Id = id; Name = name; } @@ -162,7 +156,6 @@ public Door(Wall wall, : this(wall, wallLine, wallLine.PointAtNormalized(tPos), - wallLine.PointAtNormalized(tPos), width, height, openingSide, From 419f7c04a4d49eb8c6157f71fe6a824360fd86a8 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Fri, 27 Oct 2023 14:53:08 +0300 Subject: [PATCH 03/31] Removed redundant constructor --- Elements/src/Door.cs | 70 +++++++------------------------------------- 1 file changed, 11 insertions(+), 59 deletions(-) diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index daccc3caa..e1fc25c55 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -37,51 +37,6 @@ public class Door : GeometricElement /// Opening for a door. public Opening Opening { get; private set; } - /// - /// Create a door that attaches to the closest point on a certain wall. - /// - /// The wall the door is attached to. - /// A center line of a wall that door is attached to. - /// The current door's position. - /// The with of a single door. - /// The door's height. - /// The side where the door opens. - /// The way the door opens. - /// The door's material. - /// The door's representation. - /// The door's id. - /// The door's name. - /// The door's opening depth front. - /// The door's opening depth back. - /// Is the door flipped? - public Door(Wall wall, - Line wallLine, - Vector3 currentPosition, - double width, - double height, - DoorOpeningSide openingSide, - DoorOpeningType openingType, - Material material = null, - Representation representation = null, - Guid id = default, - string name = "Door", - double depthFront = 1, - double depthBack = 1, - bool flip = false) - { - Wall = wall; - OpeningType = openingType; - OpeningSide = openingSide; - ClearWidth = WidthWithoutFrame(width, openingSide); - ClearHeight = height; - Material = material ?? DEFAULT_MATERIAL; - Transform = GetDoorTransform(currentPosition, wallLine, flip); - Representation = representation ?? new Representation(new List() { }); - Opening = new Opening(Polygon.Rectangle(width, height), depthFront, depthBack, GetOpeningTransform()); - Id = id; - Name = name; - } - /// /// Create a door that is not attached to a wall. /// @@ -153,21 +108,18 @@ public Door(Wall wall, double depthFront = 1, double depthBack = 1, bool flip = false) - : this(wall, - wallLine, - wallLine.PointAtNormalized(tPos), - width, - height, - openingSide, - openingType, - material, - representation, - id, - name, - depthFront, - depthBack, - flip) { + Wall = wall; + OpeningType = openingType; + OpeningSide = openingSide; + ClearWidth = WidthWithoutFrame(width, openingSide); + ClearHeight = height; + Material = material ?? DEFAULT_MATERIAL; + Transform = GetDoorTransform(wallLine.PointAtNormalized(tPos), wallLine, flip); + Representation = representation ?? new Representation(new List() { }); + Opening = new Opening(Polygon.Rectangle(width, height), depthFront, depthBack, GetOpeningTransform()); + Id = id; + Name = name; } private Transform GetOpeningTransform() From 7196aa2a8fbf226a6a262fa1db9c31e743a43f3a Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Tue, 31 Oct 2023 17:41:20 +0200 Subject: [PATCH 04/31] Fixed Door deserialization issue - Fixed Door deserialization issue - Door can be deserialized now; - Removed 'Wall' property; - Added 'isElementDefinition' property to constructors; - Added DoorTest. --- .../src/Serialization/IFC/IFCExtensions.cs | 6 +- Elements.Serialization.IFC/test/IFCTests.cs | 4 +- Elements/src/Door.cs | 103 ++++++++++-------- Elements/test/DoorTest.cs | 27 +++++ 4 files changed, 87 insertions(+), 53 deletions(-) create mode 100644 Elements/test/DoorTest.cs diff --git a/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs b/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs index 3a022c728..28ba01df4 100644 --- a/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs +++ b/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs @@ -182,11 +182,11 @@ internal static Door ToDoor(this IfcDoor ifcDoor, List allWalls) throw new Exception("This DoorOperationType is not supported yet."); } - var transform = GetTransformFromIfcElement(ifcDoor); - var wall = GetWallFromDoor(ifcDoor, allWalls); + var transform = GetTransformFromIfcElement(ifcDoor); - var result = new Door(wall, transform, (IfcLengthMeasure)ifcDoor.OverallWidth, (IfcLengthMeasure)ifcDoor.OverallHeight, openingSide, openingType); + var result = new Door((IfcLengthMeasure)ifcDoor.OverallWidth, (IfcLengthMeasure)ifcDoor.OverallHeight, openingSide, openingType, transform); + result.AdditionalProperties["Wall"] = wall; return result; } diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index dbd912197..30e9fd370 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -91,8 +91,8 @@ public void Doors() model.AddElement(wall1); model.AddElement(wall2); - var door1 = new Door(wall1, wallLine1, 0.5, 1.5, 2.0, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); - var door2 = new Door(wall2, wallLine2, 0.5, 1.5, 1.8, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door1 = new Door(wallLine1, 0.5, 1.5, 2.0, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); model.AddElement(door1); model.AddElement(door2); diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index e1fc25c55..19ebb2f2a 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Text; +using Newtonsoft.Json; namespace Elements { @@ -30,96 +31,104 @@ public class Door : GeometricElement public DoorOpeningType OpeningType { get; private set; } /// The opening side of the door that should be placed public DoorOpeningSide OpeningSide { get; private set; } - /// The wall on which a door is placed. - public Wall Wall { get; private set; } /// Height of a door without a frame. public double ClearHeight { get; private set; } /// Opening for a door. public Opening Opening { get; private set; } + private readonly double _fullDoorWidthWithoutFrame; + /// - /// Create a door that is not attached to a wall. + /// Create a door. /// - /// The with of a single door. - /// The door's height. + /// The width of a single door. + /// The door's height. /// The side where the door opens. /// The way the door opens. /// The door's transform. X-direction is aligned with the door, Y-direction is the opening direction. /// The door's material. /// The door's representation. + /// Is this an element definition? /// The door's id. /// The door's name. /// The door's opening depth front. /// The door's opening depth back. - public Door(double width, - double height, + [JsonConstructor] + public Door(double clearWidth, + double clearHeight, DoorOpeningSide openingSide, DoorOpeningType openingType, Transform transform = null, Material material = null, Representation representation = null, + bool isElementDefinition = false, Guid id = default, string name = "Door", double depthFront = 1, double depthBack = 1 - ) + ) : base ( + transform: transform, + representation: representation, + isElementDefinition: isElementDefinition, + id: id, + name: name + ) { - Wall = null; - Transform = transform; OpeningSide = openingSide; OpeningType = openingType; - ClearHeight = height; - ClearWidth = WidthWithoutFrame(width, openingSide); + ClearHeight = clearHeight; + ClearWidth = clearWidth; Material = material ?? DEFAULT_MATERIAL; - Representation = representation ?? new Representation(new List() { }); - Opening = new Opening(Polygon.Rectangle(width, height), depthFront, depthBack, GetOpeningTransform()); - Id = id; - Name = name; + _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(clearWidth, openingSide); + Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); } /// - /// Create a door at the certain point of a wall. + /// Create a door at the certain point of a line. /// - /// The wall the door is attached to. - /// A center line of a wall that door is attached to. - /// Relative position on the wall where door is placed. Should be in [0; 1]. - /// The with of a single door. - /// The door's height. + /// The line where the door is placed. + /// Relative position on the line where door is placed. Should be in [0; 1]. + /// The width of a single door. + /// The door's height. /// The side where the door opens. /// The way the door opens. /// The door's material. /// The door's representation. + /// Is this an element definition? /// The door's id. /// The door's name. /// The door's opening depth front. /// The door's opening depth back. /// Is the door flipped? - public Door(Wall wall, - Line wallLine, + public Door(Line line, double tPos, - double width, - double height, + double clearWidth, + double clearHeight, DoorOpeningSide openingSide, DoorOpeningType openingType, Material material = null, Representation representation = null, + bool isElementDefinition = false, Guid id = default, string name = "Door", double depthFront = 1, double depthBack = 1, - bool flip = false) + bool flip = false + ) : base ( + representation: representation, + isElementDefinition: isElementDefinition, + id: id, + name: name + ) { - Wall = wall; OpeningType = openingType; OpeningSide = openingSide; - ClearWidth = WidthWithoutFrame(width, openingSide); - ClearHeight = height; + ClearWidth = clearWidth; + ClearHeight = clearHeight; Material = material ?? DEFAULT_MATERIAL; - Transform = GetDoorTransform(wallLine.PointAtNormalized(tPos), wallLine, flip); - Representation = representation ?? new Representation(new List() { }); - Opening = new Opening(Polygon.Rectangle(width, height), depthFront, depthBack, GetOpeningTransform()); - Id = id; - Name = name; + _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(ClearWidth, openingSide); + Transform = GetDoorTransform(line.PointAtNormalized(tPos), line, flip); + Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); } private Transform GetOpeningTransform() @@ -141,7 +150,7 @@ private Transform GetDoorTransform(Vector3 currentPosition, Line wallLine, bool /// public static bool CanFit(Line wallLine, DoorOpeningSide openingSide, double width) { - var doorWidth = WidthWithoutFrame(width, openingSide) + DOOR_FRAME_WIDTH * 2; + var doorWidth = GetDoorFullWidthWithoutFrame(width, openingSide) + DOOR_FRAME_WIDTH * 2; return wallLine.Length() - doorWidth > DOOR_FRAME_WIDTH * 2; } @@ -211,13 +220,11 @@ private List CollectPointsForSchematicVisualization() private List CollectSchematicVisualizationLines(bool leftSide, bool inside, double angle) { - var doorWidth = OpeningSide == DoorOpeningSide.DoubleDoor ? ClearWidth / 2 : ClearWidth; - // Depending on which side door in there are different offsets. - var doorOffset = leftSide ? ClearWidth / 2 : -ClearWidth / 2; + var doorOffset = leftSide ? _fullDoorWidthWithoutFrame / 2 : -_fullDoorWidthWithoutFrame / 2; var horizontalOffset = leftSide ? DOOR_THICKNESS : -DOOR_THICKNESS; var verticalOffset = inside ? DOOR_THICKNESS : -DOOR_THICKNESS; - var widthOffset = inside ? doorWidth : -doorWidth; + var widthOffset = inside ? ClearWidth : -ClearWidth; // Draw open door silhouette rectangle. Vector3 corner = Vector3.XAxis * doorOffset; @@ -269,7 +276,7 @@ private List CollectSchematicVisualizationLines(bool leftSide, bool ins } // Draw the arc from closed door to opened door. - Arc arc = new Arc(c0, doorWidth, anchorAngle, endAngle); + Arc arc = new Arc(c0, ClearWidth, anchorAngle, endAngle); var tessalatedArc = arc.ToPolyline((int)(Math.Abs(angle) / 2)); for (int i = 0; i < tessalatedArc.Vertices.Count - 1; i++) { @@ -285,8 +292,8 @@ private List CollectSchematicVisualizationLines(bool leftSide, bool ins /// public override void UpdateRepresentations() { - Vector3 left = Vector3.XAxis * ClearWidth / 2; - Vector3 right = Vector3.XAxis.Negate() * ClearWidth / 2; + Vector3 left = Vector3.XAxis * _fullDoorWidthWithoutFrame / 2; + Vector3 right = Vector3.XAxis.Negate() * _fullDoorWidthWithoutFrame / 2; var doorPolygon = new Polygon(new List() { left + Vector3.YAxis * DOOR_THICKNESS, @@ -337,7 +344,7 @@ public override void UpdateRepresentations() private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) { - var fullWidth = ClearWidth + DOOR_FRAME_WIDTH * 2; + var fullWidth = _fullDoorWidthWithoutFrame + (DOOR_FRAME_WIDTH * 2); double wallWidth = wallLine.Length(); Vector3 p1 = wallLine.PointAt(0.5 * fullWidth); Vector3 p2 = wallLine.PointAt(wallWidth - 0.5 * fullWidth); @@ -345,15 +352,15 @@ private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) return currentPosition.ClosestPointOn(reducedWallLine); } - private static double WidthWithoutFrame(double internalWidth, DoorOpeningSide openingSide) + private static double GetDoorFullWidthWithoutFrame(double doorClearWidth, DoorOpeningSide doorOpeningSide) { - switch (openingSide) + switch (doorOpeningSide) { case DoorOpeningSide.LeftHand: case DoorOpeningSide.RightHand: - return internalWidth; + return doorClearWidth; case DoorOpeningSide.DoubleDoor: - return internalWidth * 2; + return doorClearWidth * 2; } return 0; } diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs new file mode 100644 index 000000000..7e66239cd --- /dev/null +++ b/Elements/test/DoorTest.cs @@ -0,0 +1,27 @@ +using Elements.Geometry; +using Elements.Tests; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Elements +{ + public class DoorTest : ModelTest + { + [Fact, Trait("Category", "Examples")] + public void Example() + { + this.Name = "Elements_Door"; + + var line = new Line(new Vector3(0, 0, 0), new Vector3(10, 10, 0)); + var wall = new StandardWall(line, 0.1, 3.0); + var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); + + this.Model.AddElement(wall); + Model.AddElement(door); + } + } +} From 8dc16fbaafbb46d2a10054378df5ad0b7ad62a9b Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Tue, 31 Oct 2023 18:37:38 +0200 Subject: [PATCH 05/31] Move Door related staff to separate folder --- .../src/Serialization/IFC/IFCElementExtensions.cs | 1 + .../src/Serialization/IFC/IFCExtensions.cs | 2 +- .../src/Serialization/IFC/IFCModelExtensions.cs | 1 + Elements.Serialization.IFC/test/IFCTests.cs | 1 + Elements/src/{ => BuildingElements/Door}/Door.cs | 8 ++++---- .../src/{ => BuildingElements/Door}/DoorOpeningSide.cs | 2 +- .../src/{ => BuildingElements/Door}/DoorOpeningType.cs | 2 +- Elements/test/DoorTest.cs | 3 ++- 8 files changed, 12 insertions(+), 8 deletions(-) rename Elements/src/{ => BuildingElements/Door}/Door.cs (98%) rename Elements/src/{ => BuildingElements/Door}/DoorOpeningSide.cs (92%) rename Elements/src/{ => BuildingElements/Door}/DoorOpeningType.cs (90%) diff --git a/Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs b/Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs index 78d06159d..90d8991a8 100644 --- a/Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs +++ b/Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Elements.BuildingElements.Door; using Elements.Geometry; using Elements.Geometry.Interfaces; using Elements.Geometry.Solids; diff --git a/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs b/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs index 28ba01df4..6b824b3ce 100644 --- a/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs +++ b/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Elements; +using Elements.BuildingElements.Door; using Elements.Geometry; using Elements.Geometry.Interfaces; using Elements.Geometry.Solids; diff --git a/Elements.Serialization.IFC/src/Serialization/IFC/IFCModelExtensions.cs b/Elements.Serialization.IFC/src/Serialization/IFC/IFCModelExtensions.cs index c74b3e8e1..48df5e1b2 100644 --- a/Elements.Serialization.IFC/src/Serialization/IFC/IFCModelExtensions.cs +++ b/Elements.Serialization.IFC/src/Serialization/IFC/IFCModelExtensions.cs @@ -1,4 +1,5 @@ using Elements.Analysis; +using Elements.BuildingElements.Door; using Elements.Geometry; using IFC; using STEP; diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index 30e9fd370..7231fe2e9 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using Elements.Geometry.Profiles; using System.Linq; +using Elements.BuildingElements.Door; namespace Elements.IFC.Tests { diff --git a/Elements/src/Door.cs b/Elements/src/BuildingElements/Door/Door.cs similarity index 98% rename from Elements/src/Door.cs rename to Elements/src/BuildingElements/Door/Door.cs index 19ebb2f2a..16c301b51 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/BuildingElements/Door/Door.cs @@ -5,7 +5,7 @@ using System.Text; using Newtonsoft.Json; -namespace Elements +namespace Elements.BuildingElements.Door { /// Definition of a door public class Door : GeometricElement @@ -66,7 +66,7 @@ public Door(double clearWidth, string name = "Door", double depthFront = 1, double depthBack = 1 - ) : base ( + ) : base( transform: transform, representation: representation, isElementDefinition: isElementDefinition, @@ -114,7 +114,7 @@ public Door(Line line, double depthFront = 1, double depthBack = 1, bool flip = false - ) : base ( + ) : base( representation: representation, isElementDefinition: isElementDefinition, id: id, @@ -344,7 +344,7 @@ public override void UpdateRepresentations() private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) { - var fullWidth = _fullDoorWidthWithoutFrame + (DOOR_FRAME_WIDTH * 2); + var fullWidth = _fullDoorWidthWithoutFrame + DOOR_FRAME_WIDTH * 2; double wallWidth = wallLine.Length(); Vector3 p1 = wallLine.PointAt(0.5 * fullWidth); Vector3 p2 = wallLine.PointAt(wallWidth - 0.5 * fullWidth); diff --git a/Elements/src/DoorOpeningSide.cs b/Elements/src/BuildingElements/Door/DoorOpeningSide.cs similarity index 92% rename from Elements/src/DoorOpeningSide.cs rename to Elements/src/BuildingElements/Door/DoorOpeningSide.cs index 0acfcbc57..5a821385c 100644 --- a/Elements/src/DoorOpeningSide.cs +++ b/Elements/src/BuildingElements/Door/DoorOpeningSide.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Elements +namespace Elements.BuildingElements.Door { public enum DoorOpeningSide { diff --git a/Elements/src/DoorOpeningType.cs b/Elements/src/BuildingElements/Door/DoorOpeningType.cs similarity index 90% rename from Elements/src/DoorOpeningType.cs rename to Elements/src/BuildingElements/Door/DoorOpeningType.cs index 19c17e2f5..c0e10289c 100644 --- a/Elements/src/DoorOpeningType.cs +++ b/Elements/src/BuildingElements/Door/DoorOpeningType.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Elements +namespace Elements.BuildingElements.Door { public enum DoorOpeningType { diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index 7e66239cd..76f4853bb 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -1,4 +1,5 @@ -using Elements.Geometry; +using Elements.BuildingElements.Door; +using Elements.Geometry; using Elements.Tests; using System; using System.Collections.Generic; From 438932f4c67a4403cdd29d31774f01be6778fef2 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Tue, 31 Oct 2023 19:12:34 +0200 Subject: [PATCH 06/31] Moved solid representation creation logic to a separate class The representation is a RepresentationInstance now instead of Representation. --- Elements/src/BuildingElements/Door/Door.cs | 59 +++------------- .../Door/DoorRepresentationFactory.cs | 69 +++++++++++++++++++ 2 files changed, 78 insertions(+), 50 deletions(-) create mode 100644 Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs diff --git a/Elements/src/BuildingElements/Door/Door.cs b/Elements/src/BuildingElements/Door/Door.cs index 16c301b51..69acb348c 100644 --- a/Elements/src/BuildingElements/Door/Door.cs +++ b/Elements/src/BuildingElements/Door/Door.cs @@ -1,5 +1,4 @@ -using Elements.Geometry.Solids; -using Elements.Geometry; +using Elements.Geometry; using System; using System.Collections.Generic; using System.Text; @@ -292,54 +291,9 @@ private List CollectSchematicVisualizationLines(bool leftSide, bool ins /// public override void UpdateRepresentations() { - Vector3 left = Vector3.XAxis * _fullDoorWidthWithoutFrame / 2; - Vector3 right = Vector3.XAxis.Negate() * _fullDoorWidthWithoutFrame / 2; - - var doorPolygon = new Polygon(new List() { - left + Vector3.YAxis * DOOR_THICKNESS, - left - Vector3.YAxis * DOOR_THICKNESS, - right - Vector3.YAxis * DOOR_THICKNESS, - right + Vector3.YAxis * DOOR_THICKNESS}); - - var doorPolygons = new List(); - - if (OpeningSide == DoorOpeningSide.DoubleDoor) - { - doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, DOOR_THICKNESS, 0), new Vector3(0, -DOOR_THICKNESS, 0))); - } - else - { - doorPolygons.Add(doorPolygon); - } - - var doorExtrusions = new List(); - - foreach (var polygon in doorPolygons) - { - var doorExtrude = new Extrude(new Profile(polygon.Offset(-0.005)[0]), ClearHeight, Vector3.ZAxis); - doorExtrusions.Add(doorExtrude); - } - - var frameLeft = left + Vector3.XAxis * DOOR_FRAME_WIDTH; - var frameRight = right - Vector3.XAxis * DOOR_FRAME_WIDTH; - var frameOffset = Vector3.YAxis * DOOR_FRAME_THICKNESS; - var doorFramePolygon = new Polygon(new List() { - left + Vector3.ZAxis * ClearHeight - frameOffset, - left - frameOffset, - frameLeft - frameOffset, - frameLeft + Vector3.ZAxis * (ClearHeight + DOOR_FRAME_WIDTH) - frameOffset, - frameRight + Vector3.ZAxis * (ClearHeight + DOOR_FRAME_WIDTH) - frameOffset, - frameRight - frameOffset, - right - frameOffset, - right + Vector3.ZAxis * ClearHeight - frameOffset }); - var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); - - Representation.SolidOperations.Clear(); - Representation.SolidOperations.Add(doorFrameExtrude); - foreach (var extrusion in doorExtrusions) - { - Representation.SolidOperations.Add(extrusion); - } + RepresentationInstances.Clear(); + var solidRepInstance = DoorRepresentationFactory.CreateSolidDoorRepresentation(this); + RepresentationInstances.Add(solidRepInstance); } private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) @@ -352,6 +306,11 @@ private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) return currentPosition.ClosestPointOn(reducedWallLine); } + internal double GetFullDoorWidthWithoutFrame() + { + return _fullDoorWidthWithoutFrame; + } + private static double GetDoorFullWidthWithoutFrame(double doorClearWidth, DoorOpeningSide doorOpeningSide) { switch (doorOpeningSide) diff --git a/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs b/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs new file mode 100644 index 000000000..f21f90d28 --- /dev/null +++ b/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs @@ -0,0 +1,69 @@ +using Elements.Geometry.Solids; +using Elements.Geometry; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Elements.BuildingElements.Door +{ + internal static class DoorRepresentationFactory + { + /// + /// Create a solid representation of a . + /// + /// Parameters of + /// will be used for the representation creation. + /// A solid representation, created from properties of . + public static RepresentationInstance CreateSolidDoorRepresentation(Door door) + { + double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); + + Vector3 left = Vector3.XAxis * fullDoorWidthWithoutFrame / 2; + Vector3 right = Vector3.XAxis.Negate() * fullDoorWidthWithoutFrame / 2; + + var doorPolygon = new Polygon(new List() { + left + Vector3.YAxis * Door.DOOR_THICKNESS, + left - Vector3.YAxis * Door.DOOR_THICKNESS, + right - Vector3.YAxis * Door.DOOR_THICKNESS, + right + Vector3.YAxis * Door.DOOR_THICKNESS}); + + var doorPolygons = new List(); + + if (door.OpeningSide == DoorOpeningSide.DoubleDoor) + { + doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, Door.DOOR_THICKNESS, 0), new Vector3(0, -Door.DOOR_THICKNESS, 0))); + } + else + { + doorPolygons.Add(doorPolygon); + } + + var doorExtrusions = new List(); + + foreach (var polygon in doorPolygons) + { + var doorExtrude = new Extrude(new Profile(polygon.Offset(-0.005)[0]), door.ClearHeight, Vector3.ZAxis); + doorExtrusions.Add(doorExtrude); + } + + var frameLeft = left + Vector3.XAxis * Door.DOOR_FRAME_WIDTH; + var frameRight = right - Vector3.XAxis * Door.DOOR_FRAME_WIDTH; + var frameOffset = Vector3.YAxis * Door.DOOR_FRAME_THICKNESS; + var doorFramePolygon = new Polygon(new List() { + left + Vector3.ZAxis * door.ClearHeight - frameOffset, + left - frameOffset, + frameLeft - frameOffset, + frameLeft + Vector3.ZAxis * (door.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, + frameRight + Vector3.ZAxis * (door.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, + frameRight - frameOffset, + right - frameOffset, + right + Vector3.ZAxis * door.ClearHeight - frameOffset }); + var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), Door.DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); + doorExtrusions.Add(doorFrameExtrude); + + var solidRep = new SolidRepresentation(doorExtrusions); + var repInstance = new RepresentationInstance(solidRep, door.Material, true); + return repInstance; + } + } +} From 1295d257024afc0c8819b285fd9c011f6e24216e Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Tue, 31 Oct 2023 19:41:06 +0200 Subject: [PATCH 07/31] Moved curve representation to DoorRepresentationFactory - Moved curve representation to DoorRepresentationFactory; - Added curve representation to UpdateRepresentations. --- Elements/src/BuildingElements/Door/Door.cs | 141 +----------------- .../Door/DoorRepresentationFactory.cs | 123 +++++++++++++++ 2 files changed, 128 insertions(+), 136 deletions(-) diff --git a/Elements/src/BuildingElements/Door/Door.cs b/Elements/src/BuildingElements/Door/Door.cs index 69acb348c..f992a53df 100644 --- a/Elements/src/BuildingElements/Door/Door.cs +++ b/Elements/src/BuildingElements/Door/Door.cs @@ -153,147 +153,16 @@ public static bool CanFit(Line wallLine, DoorOpeningSide openingSide, double wid return wallLine.Length() - doorWidth > DOOR_FRAME_WIDTH * 2; } - /// - /// Get graphics buffers and other metadata required to modify a GLB. - /// - /// - /// True if there is graphicsbuffers data applicable to add, false otherwise. - /// Out variables should be ignored if the return value is false. - /// - public override bool TryToGraphicsBuffers(out List graphicsBuffers, out string id, out glTFLoader.Schema.MeshPrimitive.ModeEnum? mode) - { - var points = CollectPointsForSchematicVisualization(); - GraphicsBuffers buffer = new GraphicsBuffers(); - Color color = Colors.Black; - for (int i = 0; i < points.Count; i++) - { - buffer.AddVertex(points[i], default, default, color); - buffer.AddIndex((ushort)i); - } - - id = $"{Id}_door"; - // Only one type is allowed, since line are not linked into one loop, LINES is used. - // This mean that each line segment need both endpoints stored, often duplicated. - mode = glTFLoader.Schema.MeshPrimitive.ModeEnum.LINES; - graphicsBuffers = new List { buffer }; - return true; - } - - // TODO: Move visualization logic out of the class in case of DoorOpeningType enum extension. - private List CollectPointsForSchematicVisualization() - { - var points = new List(); - - if (OpeningSide == DoorOpeningSide.Undefined || OpeningType == DoorOpeningType.Undefined) - { - return points; - } - - if (OpeningSide != DoorOpeningSide.LeftHand) - { - points.AddRange(CollectSchematicVisualizationLines(false, false, 90)); - } - - if (OpeningSide != DoorOpeningSide.RightHand) - { - points.AddRange(CollectSchematicVisualizationLines(true, false, 90)); - } - - if (OpeningType == DoorOpeningType.SingleSwing) - { - return points; - } - - if (OpeningSide != DoorOpeningSide.LeftHand) - { - points.AddRange(CollectSchematicVisualizationLines(false, true, 90)); - } - - if (OpeningSide != DoorOpeningSide.RightHand) - { - points.AddRange(CollectSchematicVisualizationLines(true, true, 90)); - } - - return points; - } - - private List CollectSchematicVisualizationLines(bool leftSide, bool inside, double angle) - { - // Depending on which side door in there are different offsets. - var doorOffset = leftSide ? _fullDoorWidthWithoutFrame / 2 : -_fullDoorWidthWithoutFrame / 2; - var horizontalOffset = leftSide ? DOOR_THICKNESS : -DOOR_THICKNESS; - var verticalOffset = inside ? DOOR_THICKNESS : -DOOR_THICKNESS; - var widthOffset = inside ? ClearWidth : -ClearWidth; - - // Draw open door silhouette rectangle. - Vector3 corner = Vector3.XAxis * doorOffset; - var c0 = corner + Vector3.YAxis * verticalOffset; - var c1 = c0 + Vector3.YAxis * widthOffset; - var c2 = c1 - Vector3.XAxis * horizontalOffset; - var c3 = c0 - Vector3.XAxis * horizontalOffset; - - // Rotate silhouette is it's need to be drawn as partially open. - if (!angle.ApproximatelyEquals(90)) - { - double rotation = 90 - angle; - if (!leftSide) - { - rotation = -rotation; - } - - if (!inside) - { - rotation = -rotation; - } - - Transform t = new Transform(); - t.RotateAboutPoint(c0, Vector3.ZAxis, rotation); - c1 = t.OfPoint(c1); - c2 = t.OfPoint(c2); - c3 = t.OfPoint(c3); - } - List points = new List() { c0, c1, c1, c2, c2, c3, c3, c0 }; - - // Calculated correct arc angles based on door orientation. - double adjustedAngle = inside ? angle : -angle; - double anchorAngle = leftSide ? 180 : 0; - double endAngle = leftSide ? 180 - adjustedAngle : adjustedAngle; - if (endAngle < 0) - { - endAngle = 360 + endAngle; - anchorAngle = 360; - } - - // If arc is constructed from bigger angle to smaller is will have incorrect domain - // with max being smaller than min and negative length. - // ToPolyline will return 0 points for it. - // Until it's fixed angles should be aligned manually. - bool flipEnds = endAngle < anchorAngle; - if (flipEnds) - { - (anchorAngle, endAngle) = (endAngle, anchorAngle); - } - - // Draw the arc from closed door to opened door. - Arc arc = new Arc(c0, ClearWidth, anchorAngle, endAngle); - var tessalatedArc = arc.ToPolyline((int)(Math.Abs(angle) / 2)); - for (int i = 0; i < tessalatedArc.Vertices.Count - 1; i++) - { - points.Add(tessalatedArc.Vertices[i]); - points.Add(tessalatedArc.Vertices[i + 1]); - } - - return points; - } - /// /// Update the representations. /// public override void UpdateRepresentations() { - RepresentationInstances.Clear(); - var solidRepInstance = DoorRepresentationFactory.CreateSolidDoorRepresentation(this); - RepresentationInstances.Add(solidRepInstance); + RepresentationInstances = new List() + { + DoorRepresentationFactory.CreateSolidDoorRepresentation(this), + DoorRepresentationFactory.CreateCurveDoorRepresentation(this) + }; } private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) diff --git a/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs b/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs index f21f90d28..8ad760ed8 100644 --- a/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs +++ b/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs @@ -65,5 +65,128 @@ public static RepresentationInstance CreateSolidDoorRepresentation(Door door) var repInstance = new RepresentationInstance(solidRep, door.Material, true); return repInstance; } + + /// + /// Create a curve 2D representation of a . + /// + /// Parameters of + /// will be used for the representation creation. + /// A curve 2D representation, created from properties of . + public static RepresentationInstance CreateCurveDoorRepresentation(Door door) + { + var points = CollectPointsForSchematicVisualization(door); + var curve = new IndexedPolycurve(points); + var curveRep = new CurveRepresentation(curve, false); + var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + return repInstance; + } + + private static List CollectPointsForSchematicVisualization(Door door) + { + var points = new List(); + + if (door.OpeningSide == DoorOpeningSide.Undefined || door.OpeningType == DoorOpeningType.Undefined) + { + return points; + } + + if (door.OpeningSide != DoorOpeningSide.LeftHand) + { + points.AddRange(CollectSchematicVisualizationLines(door, false, false, 90)); + } + + if (door.OpeningSide != DoorOpeningSide.RightHand) + { + points.AddRange(CollectSchematicVisualizationLines(door, true, false, 90)); + } + + if (door.OpeningType == DoorOpeningType.SingleSwing) + { + return points; + } + + if (door.OpeningSide != DoorOpeningSide.LeftHand) + { + points.AddRange(CollectSchematicVisualizationLines(door, false, true, 90)); + } + + if (door.OpeningSide != DoorOpeningSide.RightHand) + { + points.AddRange(CollectSchematicVisualizationLines(door, true, true, 90)); + } + + return points; + } + + private static List CollectSchematicVisualizationLines(Door door, bool leftSide, bool inside, double angle) + { + var fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); + + // Depending on which side door in there are different offsets. + var doorOffset = leftSide ? fullDoorWidthWithoutFrame / 2 : -fullDoorWidthWithoutFrame / 2; + var horizontalOffset = leftSide ? Door.DOOR_THICKNESS : -Door.DOOR_THICKNESS; + var verticalOffset = inside ? Door.DOOR_THICKNESS : -Door.DOOR_THICKNESS; + var widthOffset = inside ? door.ClearWidth : -door.ClearWidth; + + // Draw open door silhouette rectangle. + Vector3 corner = Vector3.XAxis * doorOffset; + var c0 = corner + Vector3.YAxis * verticalOffset; + var c1 = c0 + Vector3.YAxis * widthOffset; + var c2 = c1 - Vector3.XAxis * horizontalOffset; + var c3 = c0 - Vector3.XAxis * horizontalOffset; + + // Rotate silhouette is it's need to be drawn as partially open. + if (!angle.ApproximatelyEquals(90)) + { + double rotation = 90 - angle; + if (!leftSide) + { + rotation = -rotation; + } + + if (!inside) + { + rotation = -rotation; + } + + Transform t = new Transform(); + t.RotateAboutPoint(c0, Vector3.ZAxis, rotation); + c1 = t.OfPoint(c1); + c2 = t.OfPoint(c2); + c3 = t.OfPoint(c3); + } + List points = new List() { c0, c1, c1, c2, c2, c3, c3, c0 }; + + // Calculated correct arc angles based on door orientation. + double adjustedAngle = inside ? angle : -angle; + double anchorAngle = leftSide ? 180 : 0; + double endAngle = leftSide ? 180 - adjustedAngle : adjustedAngle; + if (endAngle < 0) + { + endAngle = 360 + endAngle; + anchorAngle = 360; + } + + // If arc is constructed from bigger angle to smaller is will have incorrect domain + // with max being smaller than min and negative length. + // ToPolyline will return 0 points for it. + // Until it's fixed angles should be aligned manually. + bool flipEnds = endAngle < anchorAngle; + if (flipEnds) + { + (anchorAngle, endAngle) = (endAngle, anchorAngle); + } + + // Draw the arc from closed door to opened door. + Arc arc = new Arc(c0, door.ClearWidth, anchorAngle, endAngle); + var tessalatedArc = arc.ToPolyline((int)(Math.Abs(angle) / 2)); + for (int i = 0; i < tessalatedArc.Vertices.Count - 1; i++) + { + points.Add(tessalatedArc.Vertices[i]); + points.Add(tessalatedArc.Vertices[i + 1]); + } + + return points; + } } } From ebd35b5b052df68bbd9e2a7b6362bc52da324937 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Mon, 6 Nov 2023 17:15:07 +0200 Subject: [PATCH 08/31] Use DoorRepresentationProvider instead of static DoorRepresentationFactory --- Elements/src/BuildingElements/Door/Door.cs | 11 +++++----- ...ctory.cs => DoorRepresentationProvider.cs} | 22 ++++++++++++++----- .../src/CoreModels/RepresentationProvider.cs | 11 ++++++++++ 3 files changed, 34 insertions(+), 10 deletions(-) rename Elements/src/BuildingElements/Door/{DoorRepresentationFactory.cs => DoorRepresentationProvider.cs} (90%) create mode 100644 Elements/src/CoreModels/RepresentationProvider.cs diff --git a/Elements/src/BuildingElements/Door/Door.cs b/Elements/src/BuildingElements/Door/Door.cs index f992a53df..16c6dd3dd 100644 --- a/Elements/src/BuildingElements/Door/Door.cs +++ b/Elements/src/BuildingElements/Door/Door.cs @@ -36,6 +36,7 @@ public class Door : GeometricElement public Opening Opening { get; private set; } private readonly double _fullDoorWidthWithoutFrame; + private readonly DoorRepresentationProvider _representationProvider; /// /// Create a door. @@ -80,6 +81,8 @@ public Door(double clearWidth, Material = material ?? DEFAULT_MATERIAL; _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(clearWidth, openingSide); Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); + + _representationProvider = new DoorRepresentationProvider(); } /// @@ -128,6 +131,8 @@ public Door(Line line, _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(ClearWidth, openingSide); Transform = GetDoorTransform(line.PointAtNormalized(tPos), line, flip); Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); + + _representationProvider = new DoorRepresentationProvider(); } private Transform GetOpeningTransform() @@ -158,11 +163,7 @@ public static bool CanFit(Line wallLine, DoorOpeningSide openingSide, double wid /// public override void UpdateRepresentations() { - RepresentationInstances = new List() - { - DoorRepresentationFactory.CreateSolidDoorRepresentation(this), - DoorRepresentationFactory.CreateCurveDoorRepresentation(this) - }; + RepresentationInstances = _representationProvider.GetInstances(this); } private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) diff --git a/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs b/Elements/src/BuildingElements/Door/DoorRepresentationProvider.cs similarity index 90% rename from Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs rename to Elements/src/BuildingElements/Door/DoorRepresentationProvider.cs index 8ad760ed8..ec5007a25 100644 --- a/Elements/src/BuildingElements/Door/DoorRepresentationFactory.cs +++ b/Elements/src/BuildingElements/Door/DoorRepresentationProvider.cs @@ -3,23 +3,35 @@ using System; using System.Collections.Generic; using System.Text; +using Elements.CoreModels; namespace Elements.BuildingElements.Door { - internal static class DoorRepresentationFactory + internal class DoorRepresentationProvider : RepresentationProvider { + public override List GetInstances(Door element) + { + var representationInstances = new List() + { + CreateSolidDoorRepresentation(element), + CreateCurveDoorRepresentation(element) + }; + + return representationInstances; + } + /// /// Create a solid representation of a . /// /// Parameters of /// will be used for the representation creation. /// A solid representation, created from properties of . - public static RepresentationInstance CreateSolidDoorRepresentation(Door door) + private static RepresentationInstance CreateSolidDoorRepresentation(Door door) { double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); - Vector3 left = Vector3.XAxis * fullDoorWidthWithoutFrame / 2; - Vector3 right = Vector3.XAxis.Negate() * fullDoorWidthWithoutFrame / 2; + Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); + Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); var doorPolygon = new Polygon(new List() { left + Vector3.YAxis * Door.DOOR_THICKNESS, @@ -72,7 +84,7 @@ public static RepresentationInstance CreateSolidDoorRepresentation(Door door) /// Parameters of /// will be used for the representation creation. /// A curve 2D representation, created from properties of . - public static RepresentationInstance CreateCurveDoorRepresentation(Door door) + private static RepresentationInstance CreateCurveDoorRepresentation(Door door) { var points = CollectPointsForSchematicVisualization(door); var curve = new IndexedPolycurve(points); diff --git a/Elements/src/CoreModels/RepresentationProvider.cs b/Elements/src/CoreModels/RepresentationProvider.cs new file mode 100644 index 000000000..713bae53c --- /dev/null +++ b/Elements/src/CoreModels/RepresentationProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Elements.CoreModels +{ + internal abstract class RepresentationProvider where E : Element + { + public abstract List GetInstances(E element); + } +} From 20c134f3188745a48c454e34958262ef9dc2e89a Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 8 Nov 2023 13:41:49 +0200 Subject: [PATCH 09/31] Moved Door related classes back to Elements --- .../src/Serialization/IFC/IFCElementExtensions.cs | 1 - .../src/Serialization/IFC/IFCExtensions.cs | 1 - .../src/Serialization/IFC/IFCModelExtensions.cs | 1 - Elements.Serialization.IFC/test/IFCTests.cs | 1 - Elements/src/{BuildingElements/Door => }/Door.cs | 2 +- Elements/src/{BuildingElements/Door => }/DoorOpeningSide.cs | 2 +- Elements/src/{BuildingElements/Door => }/DoorOpeningType.cs | 2 +- .../{BuildingElements/Door => }/DoorRepresentationProvider.cs | 2 +- Elements/test/DoorTest.cs | 3 +-- 9 files changed, 5 insertions(+), 10 deletions(-) rename Elements/src/{BuildingElements/Door => }/Door.cs (99%) rename Elements/src/{BuildingElements/Door => }/DoorOpeningSide.cs (92%) rename Elements/src/{BuildingElements/Door => }/DoorOpeningType.cs (90%) rename Elements/src/{BuildingElements/Door => }/DoorRepresentationProvider.cs (99%) diff --git a/Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs b/Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs index 90d8991a8..78d06159d 100644 --- a/Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs +++ b/Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Elements.BuildingElements.Door; using Elements.Geometry; using Elements.Geometry.Interfaces; using Elements.Geometry.Solids; diff --git a/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs b/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs index 6b824b3ce..c99aebfba 100644 --- a/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs +++ b/Elements.Serialization.IFC/src/Serialization/IFC/IFCExtensions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Elements.BuildingElements.Door; using Elements.Geometry; using Elements.Geometry.Interfaces; using Elements.Geometry.Solids; diff --git a/Elements.Serialization.IFC/src/Serialization/IFC/IFCModelExtensions.cs b/Elements.Serialization.IFC/src/Serialization/IFC/IFCModelExtensions.cs index 48df5e1b2..c74b3e8e1 100644 --- a/Elements.Serialization.IFC/src/Serialization/IFC/IFCModelExtensions.cs +++ b/Elements.Serialization.IFC/src/Serialization/IFC/IFCModelExtensions.cs @@ -1,5 +1,4 @@ using Elements.Analysis; -using Elements.BuildingElements.Door; using Elements.Geometry; using IFC; using STEP; diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index 7231fe2e9..30e9fd370 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using Elements.Geometry.Profiles; using System.Linq; -using Elements.BuildingElements.Door; namespace Elements.IFC.Tests { diff --git a/Elements/src/BuildingElements/Door/Door.cs b/Elements/src/Door.cs similarity index 99% rename from Elements/src/BuildingElements/Door/Door.cs rename to Elements/src/Door.cs index 16c6dd3dd..96163ced6 100644 --- a/Elements/src/BuildingElements/Door/Door.cs +++ b/Elements/src/Door.cs @@ -4,7 +4,7 @@ using System.Text; using Newtonsoft.Json; -namespace Elements.BuildingElements.Door +namespace Elements { /// Definition of a door public class Door : GeometricElement diff --git a/Elements/src/BuildingElements/Door/DoorOpeningSide.cs b/Elements/src/DoorOpeningSide.cs similarity index 92% rename from Elements/src/BuildingElements/Door/DoorOpeningSide.cs rename to Elements/src/DoorOpeningSide.cs index 5a821385c..0acfcbc57 100644 --- a/Elements/src/BuildingElements/Door/DoorOpeningSide.cs +++ b/Elements/src/DoorOpeningSide.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Elements.BuildingElements.Door +namespace Elements { public enum DoorOpeningSide { diff --git a/Elements/src/BuildingElements/Door/DoorOpeningType.cs b/Elements/src/DoorOpeningType.cs similarity index 90% rename from Elements/src/BuildingElements/Door/DoorOpeningType.cs rename to Elements/src/DoorOpeningType.cs index c0e10289c..19c17e2f5 100644 --- a/Elements/src/BuildingElements/Door/DoorOpeningType.cs +++ b/Elements/src/DoorOpeningType.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Elements.BuildingElements.Door +namespace Elements { public enum DoorOpeningType { diff --git a/Elements/src/BuildingElements/Door/DoorRepresentationProvider.cs b/Elements/src/DoorRepresentationProvider.cs similarity index 99% rename from Elements/src/BuildingElements/Door/DoorRepresentationProvider.cs rename to Elements/src/DoorRepresentationProvider.cs index ec5007a25..4e2de8b7c 100644 --- a/Elements/src/BuildingElements/Door/DoorRepresentationProvider.cs +++ b/Elements/src/DoorRepresentationProvider.cs @@ -5,7 +5,7 @@ using System.Text; using Elements.CoreModels; -namespace Elements.BuildingElements.Door +namespace Elements { internal class DoorRepresentationProvider : RepresentationProvider { diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index 76f4853bb..7e66239cd 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -1,5 +1,4 @@ -using Elements.BuildingElements.Door; -using Elements.Geometry; +using Elements.Geometry; using Elements.Tests; using System; using System.Collections.Generic; From 43a96025a62279f38b651b73e100903e48ec820a Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 8 Nov 2023 17:18:40 +0200 Subject: [PATCH 10/31] Added dictionary that stores created representations --- Elements/src/DoorProperties.cs | 70 ++++++++++++++++++++++ Elements/src/DoorRepresentationProvider.cs | 21 ++++++- 2 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 Elements/src/DoorProperties.cs diff --git a/Elements/src/DoorProperties.cs b/Elements/src/DoorProperties.cs new file mode 100644 index 000000000..11003f2b4 --- /dev/null +++ b/Elements/src/DoorProperties.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Elements +{ + internal class DoorProperties + { + private readonly double _width; + private readonly double _height; + private readonly Material _material; + private readonly DoorOpeningSide _openingSide; + private readonly DoorOpeningType _openingType; + + public DoorProperties(Door door) + { + _width = door.ClearWidth; + _height = door.ClearHeight; + _material = door.Material; + _openingSide = door.OpeningSide; + _openingType = door.OpeningType; + } + + public override bool Equals(object obj) + { + if (!(obj is DoorProperties doorProps)) + { + return false; + } + + if (!_width.ApproximatelyEquals(doorProps._width)) + { + return false; + } + + if (!_height.ApproximatelyEquals(doorProps._height)) + { + return false; + } + + if (!_material.Id.Equals(doorProps._material.Id)) + { + return false; + } + + if (!_openingSide.Equals(doorProps._openingSide)) + { + return false; + } + + if (!_openingType.Equals(doorProps._openingType)) + { + return false; + } + + return true; + } + + public override int GetHashCode() + { + int hash = 17; + hash = hash * 31 + _width.GetHashCode(); + hash = hash * 31 + _height.GetHashCode(); + hash = hash * 31 + _material.Id.GetHashCode(); + hash = hash * 31 + _openingSide.GetHashCode(); + hash = hash * 31 + _openingType.GetHashCode(); + return hash; + } + } +} diff --git a/Elements/src/DoorRepresentationProvider.cs b/Elements/src/DoorRepresentationProvider.cs index 4e2de8b7c..d1b6fc511 100644 --- a/Elements/src/DoorRepresentationProvider.cs +++ b/Elements/src/DoorRepresentationProvider.cs @@ -9,14 +9,29 @@ namespace Elements { internal class DoorRepresentationProvider : RepresentationProvider { - public override List GetInstances(Door element) + private readonly Dictionary> _doorTypeToRepresentations; + + public DoorRepresentationProvider() + { + _doorTypeToRepresentations = new Dictionary>(); + } + + public override List GetInstances(Door door) { + var doorProps = new DoorProperties(door); + + if (_doorTypeToRepresentations.TryGetValue(doorProps, out var representations)) + { + return representations; + } + var representationInstances = new List() { - CreateSolidDoorRepresentation(element), - CreateCurveDoorRepresentation(element) + CreateSolidDoorRepresentation(door), + CreateCurveDoorRepresentation(door) }; + _doorTypeToRepresentations[doorProps] = representationInstances; return representationInstances; } From 2ca2fb4acda2517e9bff9ecc0151b3a479ad351e Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 8 Nov 2023 17:25:58 +0200 Subject: [PATCH 11/31] Reverted adding of RepresentationProvider class --- Elements/src/CoreModels/RepresentationProvider.cs | 11 ----------- Elements/src/DoorRepresentationProvider.cs | 5 ++--- 2 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 Elements/src/CoreModels/RepresentationProvider.cs diff --git a/Elements/src/CoreModels/RepresentationProvider.cs b/Elements/src/CoreModels/RepresentationProvider.cs deleted file mode 100644 index 713bae53c..000000000 --- a/Elements/src/CoreModels/RepresentationProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Elements.CoreModels -{ - internal abstract class RepresentationProvider where E : Element - { - public abstract List GetInstances(E element); - } -} diff --git a/Elements/src/DoorRepresentationProvider.cs b/Elements/src/DoorRepresentationProvider.cs index d1b6fc511..d59dc1335 100644 --- a/Elements/src/DoorRepresentationProvider.cs +++ b/Elements/src/DoorRepresentationProvider.cs @@ -3,11 +3,10 @@ using System; using System.Collections.Generic; using System.Text; -using Elements.CoreModels; namespace Elements { - internal class DoorRepresentationProvider : RepresentationProvider + internal class DoorRepresentationProvider { private readonly Dictionary> _doorTypeToRepresentations; @@ -16,7 +15,7 @@ public DoorRepresentationProvider() _doorTypeToRepresentations = new Dictionary>(); } - public override List GetInstances(Door door) + public List GetInstances(Door door) { var doorProps = new DoorProperties(door); From 93d5af25edda732510db52833dfb162d61106482 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Wed, 8 Nov 2023 16:37:23 -0800 Subject: [PATCH 12/31] updates for frame and opening --- .../Converters/FromIfcDoorConverter.cs | 5 ++- Elements/Elements.sln | 31 +++++++++++++++ Elements/src/Door.cs | 7 +++- Elements/src/DoorRepresentationProvider.cs | 38 ++++++++++++++++--- .../JSON/JsonInheritanceConverter.cs | 1 + Elements/src/StandardWall.cs | 5 ++- 6 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 Elements/Elements.sln diff --git a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs index d59234f57..30b2fee06 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs @@ -34,8 +34,8 @@ public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationDa // TODO: Implement during the connections establishment. //var wall = GetWallFromDoor(ifcDoor, allWalls); - var doorWidth = (IfcLengthMeasure) ifcDoor.OverallWidth; - var doorHeight = (IfcLengthMeasure) ifcDoor.OverallHeight; + var doorWidth = (IfcLengthMeasure)ifcDoor.OverallWidth; + var doorHeight = (IfcLengthMeasure)ifcDoor.OverallHeight; var result = new Door(doorWidth, doorHeight, @@ -44,6 +44,7 @@ public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationDa repData.Transform, repData.Material, new Representation(repData.SolidOperations), + false, IfcGuid.FromIfcGUID(ifcDoor.GlobalId), ifcDoor.Name ); diff --git a/Elements/Elements.sln b/Elements/Elements.sln new file mode 100644 index 000000000..606452f02 --- /dev/null +++ b/Elements/Elements.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elements", "src\Elements.csproj", "{29FD57A4-88A8-4600-900E-839FDDDC2A28}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elements.Tests", "test\Elements.Tests.csproj", "{ECCEFB6A-DF33-429B-950D-8082EA731320}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {29FD57A4-88A8-4600-900E-839FDDDC2A28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29FD57A4-88A8-4600-900E-839FDDDC2A28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29FD57A4-88A8-4600-900E-839FDDDC2A28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29FD57A4-88A8-4600-900E-839FDDDC2A28}.Release|Any CPU.Build.0 = Release|Any CPU + {ECCEFB6A-DF33-429B-950D-8082EA731320}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECCEFB6A-DF33-429B-950D-8082EA731320}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECCEFB6A-DF33-429B-950D-8082EA731320}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECCEFB6A-DF33-429B-950D-8082EA731320}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5B1BA77B-C0FC-4EBD-B7B9-61E5C244207E} + EndGlobalSection +EndGlobal diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index 96163ced6..87e370406 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -6,6 +6,7 @@ namespace Elements { + /// Definition of a door public class Door : GeometricElement { @@ -14,11 +15,11 @@ public class Door : GeometricElement /// /// Default thickness of a door. /// - public const double DOOR_THICKNESS = 0.125; + public const double DOOR_THICKNESS = 1.375 * 0.0254; /// /// Default thickness of a door frame. /// - public const double DOOR_FRAME_THICKNESS = 0.15; + public const double DOOR_FRAME_THICKNESS = 4 * 0.0254; /// /// Default width of a door frame. /// @@ -35,6 +36,8 @@ public class Door : GeometricElement /// Opening for a door. public Opening Opening { get; private set; } + public Vector3 OriginalPosition { get; set; } + private readonly double _fullDoorWidthWithoutFrame; private readonly DoorRepresentationProvider _representationProvider; diff --git a/Elements/src/DoorRepresentationProvider.cs b/Elements/src/DoorRepresentationProvider.cs index d59dc1335..4e9e2a99a 100644 --- a/Elements/src/DoorRepresentationProvider.cs +++ b/Elements/src/DoorRepresentationProvider.cs @@ -10,6 +10,8 @@ internal class DoorRepresentationProvider { private readonly Dictionary> _doorTypeToRepresentations; + private static readonly Material frameMaterial = new Material(Colors.Gray, 0.5, 0.25, false, null, false, false, null, false, null, 0, false, default, "Silver Frame"); + public DoorRepresentationProvider() { _doorTypeToRepresentations = new Dictionary>(); @@ -27,6 +29,7 @@ public List GetInstances(Door door) var representationInstances = new List() { CreateSolidDoorRepresentation(door), + CreateSolidFrameRepresentation(door), CreateCurveDoorRepresentation(door) }; @@ -37,12 +40,13 @@ public List GetInstances(Door door) /// /// Create a solid representation of a . /// - /// Parameters of + /// Parameters of /// will be used for the representation creation. /// A solid representation, created from properties of . private static RepresentationInstance CreateSolidDoorRepresentation(Door door) { - double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); + //subtracting a bit for Z fighting + double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame() - 0.001; Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); @@ -72,6 +76,28 @@ private static RepresentationInstance CreateSolidDoorRepresentation(Door door) doorExtrusions.Add(doorExtrude); } + var solidRep = new SolidRepresentation(doorExtrusions); + var repInstance = new RepresentationInstance(solidRep, BuiltInMaterials.Wood, true); + return repInstance; + } + + + /// + /// Create a solid frame representation of a . + /// + /// Parameters of + /// will be used for the representation creation. + /// A solid representation, created from properties of . + private static RepresentationInstance CreateSolidFrameRepresentation(Door door) + { + //subtracting a bit for Z fighting + double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame() - 0.001; + + Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); + Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); + + var doorExtrusions = new List(); + var frameLeft = left + Vector3.XAxis * Door.DOOR_FRAME_WIDTH; var frameRight = right - Vector3.XAxis * Door.DOOR_FRAME_WIDTH; var frameOffset = Vector3.YAxis * Door.DOOR_FRAME_THICKNESS; @@ -88,14 +114,16 @@ private static RepresentationInstance CreateSolidDoorRepresentation(Door door) doorExtrusions.Add(doorFrameExtrude); var solidRep = new SolidRepresentation(doorExtrusions); - var repInstance = new RepresentationInstance(solidRep, door.Material, true); + + + var repInstance = new RepresentationInstance(solidRep, frameMaterial, true); return repInstance; } /// /// Create a curve 2D representation of a . /// - /// Parameters of + /// Parameters of /// will be used for the representation creation. /// A curve 2D representation, created from properties of . private static RepresentationInstance CreateCurveDoorRepresentation(Door door) @@ -193,7 +221,7 @@ private static List CollectSchematicVisualizationLines(Door door, bool anchorAngle = 360; } - // If arc is constructed from bigger angle to smaller is will have incorrect domain + // If arc is constructed from bigger angle to smaller is will have incorrect domain // with max being smaller than min and negative length. // ToPolyline will return 0 points for it. // Until it's fixed angles should be aligned manually. diff --git a/Elements/src/Serialization/JSON/JsonInheritanceConverter.cs b/Elements/src/Serialization/JSON/JsonInheritanceConverter.cs index 366201115..7604f8bb5 100644 --- a/Elements/src/Serialization/JSON/JsonInheritanceConverter.cs +++ b/Elements/src/Serialization/JSON/JsonInheritanceConverter.cs @@ -295,6 +295,7 @@ public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type o if (discriminator != null) { + return null; throw new Exception($"An object with the discriminator, {discriminator}, could not be deserialized. {baseMessage} {moreInfoMessage}", ex); } else diff --git a/Elements/src/StandardWall.cs b/Elements/src/StandardWall.cs index 40b75851d..b8dc7c13e 100644 --- a/Elements/src/StandardWall.cs +++ b/Elements/src/StandardWall.cs @@ -117,7 +117,10 @@ public Opening AddOpening(Polygon perimeter, double x, double y, double depthFro private Transform GetOpeningTransform(double x, double y) { var xAxis = this.CenterLine.Direction(); - var openingTransform = new Transform(this.CenterLine.Start + xAxis * x + Vector3.ZAxis * y, xAxis, xAxis.Cross(Vector3.ZAxis)); + // Opening transform is still off... `outOfPlane` added because transform is not working correctly + var outOfPlane = xAxis.Cross(Vector3.ZAxis); + // Opening transform is still off? + var openingTransform = new Transform(this.CenterLine.Start + xAxis * x + Vector3.ZAxis * y - outOfPlane, xAxis, xAxis.Cross(Vector3.ZAxis)); return openingTransform; } From 5b8de0916c1e609efbaea181e7d459d821648e8d Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Thu, 9 Nov 2023 15:54:58 +0200 Subject: [PATCH 13/31] Update IFCTests.cs --- Elements.Serialization.IFC/test/IFCTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index c9d56bd15..372ae9e22 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -38,7 +38,7 @@ public IfcTests(ITestOutputHelper output) // TODO: The entrance door has an incorrect representation. It happens because during // the UpdateRepresentation the default representation of a door is created instead of // the extracted one. - [InlineData("AC20-Institute-Var-2", "../../../models/IFC4/AC20-Institute-Var-2.ifc", 1517, 5, 577, 121, 7, 82, 0, 21)] + [InlineData("AC20-Institute-Var-2", "../../../models/IFC4/AC20-Institute-Var-2.ifc", 1513, 5, 577, 121, 7, 82, 0, 21)] // [InlineData("20160125WestRiverSide Hospital - IFC4-Autodesk_Hospital_Sprinkle", "../../../models/IFC4/20160125WestRiverSide Hospital - IFC4-Autodesk_Hospital_Sprinkle.ifc")] public void FromIFC4(string name, string ifcPath, From d7a673fb3ca4be53ed47108a3f4343f9cb0e12ec Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Tue, 14 Nov 2023 14:35:31 +0200 Subject: [PATCH 14/31] Move Door schematic visualization to a separate class --- Elements/src/DoorRepresentationProvider.cs | 111 +--------------- .../DoorSchematicVisualizationHelper.cs | 118 ++++++++++++++++++ 2 files changed, 120 insertions(+), 109 deletions(-) create mode 100644 Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs diff --git a/Elements/src/DoorRepresentationProvider.cs b/Elements/src/DoorRepresentationProvider.cs index d59dc1335..697c7bb30 100644 --- a/Elements/src/DoorRepresentationProvider.cs +++ b/Elements/src/DoorRepresentationProvider.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Text; +using Elements.Representations.DoorRepresentations; namespace Elements { @@ -100,119 +101,11 @@ private static RepresentationInstance CreateSolidDoorRepresentation(Door door) /// A curve 2D representation, created from properties of . private static RepresentationInstance CreateCurveDoorRepresentation(Door door) { - var points = CollectPointsForSchematicVisualization(door); + var points = DoorSchematicVisualizationHelper.CollectPointsForSchematicVisualization(door); var curve = new IndexedPolycurve(points); var curveRep = new CurveRepresentation(curve, false); var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); return repInstance; } - - private static List CollectPointsForSchematicVisualization(Door door) - { - var points = new List(); - - if (door.OpeningSide == DoorOpeningSide.Undefined || door.OpeningType == DoorOpeningType.Undefined) - { - return points; - } - - if (door.OpeningSide != DoorOpeningSide.LeftHand) - { - points.AddRange(CollectSchematicVisualizationLines(door, false, false, 90)); - } - - if (door.OpeningSide != DoorOpeningSide.RightHand) - { - points.AddRange(CollectSchematicVisualizationLines(door, true, false, 90)); - } - - if (door.OpeningType == DoorOpeningType.SingleSwing) - { - return points; - } - - if (door.OpeningSide != DoorOpeningSide.LeftHand) - { - points.AddRange(CollectSchematicVisualizationLines(door, false, true, 90)); - } - - if (door.OpeningSide != DoorOpeningSide.RightHand) - { - points.AddRange(CollectSchematicVisualizationLines(door, true, true, 90)); - } - - return points; - } - - private static List CollectSchematicVisualizationLines(Door door, bool leftSide, bool inside, double angle) - { - var fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); - - // Depending on which side door in there are different offsets. - var doorOffset = leftSide ? fullDoorWidthWithoutFrame / 2 : -fullDoorWidthWithoutFrame / 2; - var horizontalOffset = leftSide ? Door.DOOR_THICKNESS : -Door.DOOR_THICKNESS; - var verticalOffset = inside ? Door.DOOR_THICKNESS : -Door.DOOR_THICKNESS; - var widthOffset = inside ? door.ClearWidth : -door.ClearWidth; - - // Draw open door silhouette rectangle. - Vector3 corner = Vector3.XAxis * doorOffset; - var c0 = corner + Vector3.YAxis * verticalOffset; - var c1 = c0 + Vector3.YAxis * widthOffset; - var c2 = c1 - Vector3.XAxis * horizontalOffset; - var c3 = c0 - Vector3.XAxis * horizontalOffset; - - // Rotate silhouette is it's need to be drawn as partially open. - if (!angle.ApproximatelyEquals(90)) - { - double rotation = 90 - angle; - if (!leftSide) - { - rotation = -rotation; - } - - if (!inside) - { - rotation = -rotation; - } - - Transform t = new Transform(); - t.RotateAboutPoint(c0, Vector3.ZAxis, rotation); - c1 = t.OfPoint(c1); - c2 = t.OfPoint(c2); - c3 = t.OfPoint(c3); - } - List points = new List() { c0, c1, c1, c2, c2, c3, c3, c0 }; - - // Calculated correct arc angles based on door orientation. - double adjustedAngle = inside ? angle : -angle; - double anchorAngle = leftSide ? 180 : 0; - double endAngle = leftSide ? 180 - adjustedAngle : adjustedAngle; - if (endAngle < 0) - { - endAngle = 360 + endAngle; - anchorAngle = 360; - } - - // If arc is constructed from bigger angle to smaller is will have incorrect domain - // with max being smaller than min and negative length. - // ToPolyline will return 0 points for it. - // Until it's fixed angles should be aligned manually. - bool flipEnds = endAngle < anchorAngle; - if (flipEnds) - { - (anchorAngle, endAngle) = (endAngle, anchorAngle); - } - - // Draw the arc from closed door to opened door. - Arc arc = new Arc(c0, door.ClearWidth, anchorAngle, endAngle); - var tessalatedArc = arc.ToPolyline((int)(Math.Abs(angle) / 2)); - for (int i = 0; i < tessalatedArc.Vertices.Count - 1; i++) - { - points.Add(tessalatedArc.Vertices[i]); - points.Add(tessalatedArc.Vertices[i + 1]); - } - - return points; - } } } diff --git a/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs b/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs new file mode 100644 index 000000000..51ebfec8e --- /dev/null +++ b/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs @@ -0,0 +1,118 @@ +using Elements.Geometry; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Elements.Representations.DoorRepresentations +{ + internal static class DoorSchematicVisualizationHelper + { + public static List CollectPointsForSchematicVisualization(Door door) + { + var points = new List(); + + if (door.OpeningSide == DoorOpeningSide.Undefined || door.OpeningType == DoorOpeningType.Undefined) + { + return points; + } + + if (door.OpeningSide != DoorOpeningSide.LeftHand) + { + points.AddRange(CollectSchematicVisualizationLines(door, false, false, 90)); + } + + if (door.OpeningSide != DoorOpeningSide.RightHand) + { + points.AddRange(CollectSchematicVisualizationLines(door, true, false, 90)); + } + + if (door.OpeningType == DoorOpeningType.SingleSwing) + { + return points; + } + + if (door.OpeningSide != DoorOpeningSide.LeftHand) + { + points.AddRange(CollectSchematicVisualizationLines(door, false, true, 90)); + } + + if (door.OpeningSide != DoorOpeningSide.RightHand) + { + points.AddRange(CollectSchematicVisualizationLines(door, true, true, 90)); + } + + return points; + } + + private static List CollectSchematicVisualizationLines(Door door, bool leftSide, bool inside, double angle) + { + var fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); + + // Depending on which side door in there are different offsets. + var doorOffset = leftSide ? fullDoorWidthWithoutFrame / 2 : -fullDoorWidthWithoutFrame / 2; + var horizontalOffset = leftSide ? Door.DOOR_THICKNESS : -Door.DOOR_THICKNESS; + var verticalOffset = inside ? Door.DOOR_THICKNESS : -Door.DOOR_THICKNESS; + var widthOffset = inside ? door.ClearWidth : -door.ClearWidth; + + // Draw open door silhouette rectangle. + Vector3 corner = Vector3.XAxis * doorOffset; + var c0 = corner + Vector3.YAxis * verticalOffset; + var c1 = c0 + Vector3.YAxis * widthOffset; + var c2 = c1 - Vector3.XAxis * horizontalOffset; + var c3 = c0 - Vector3.XAxis * horizontalOffset; + + // Rotate silhouette is it's need to be drawn as partially open. + if (!angle.ApproximatelyEquals(90)) + { + double rotation = 90 - angle; + if (!leftSide) + { + rotation = -rotation; + } + + if (!inside) + { + rotation = -rotation; + } + + Transform t = new Transform(); + t.RotateAboutPoint(c0, Vector3.ZAxis, rotation); + c1 = t.OfPoint(c1); + c2 = t.OfPoint(c2); + c3 = t.OfPoint(c3); + } + List points = new List() { c0, c1, c1, c2, c2, c3, c3, c0 }; + + // Calculated correct arc angles based on door orientation. + double adjustedAngle = inside ? angle : -angle; + double anchorAngle = leftSide ? 180 : 0; + double endAngle = leftSide ? 180 - adjustedAngle : adjustedAngle; + if (endAngle < 0) + { + endAngle = 360 + endAngle; + anchorAngle = 360; + } + + // If arc is constructed from bigger angle to smaller is will have incorrect domain + // with max being smaller than min and negative length. + // ToPolyline will return 0 points for it. + // Until it's fixed angles should be aligned manually. + bool flipEnds = endAngle < anchorAngle; + if (flipEnds) + { + (anchorAngle, endAngle) = (endAngle, anchorAngle); + } + + // Draw the arc from closed door to opened door. + Arc arc = new Arc(c0, door.ClearWidth, anchorAngle, endAngle); + var tessalatedArc = arc.ToPolyline((int)(Math.Abs(angle) / 2)); + for (int i = 0; i < tessalatedArc.Vertices.Count - 1; i++) + { + points.Add(tessalatedArc.Vertices[i]); + points.Add(tessalatedArc.Vertices[i + 1]); + } + + return points; + } + } +} From 671e4e421cf94b2694940d213b95630a6949b101 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Tue, 14 Nov 2023 17:17:00 +0200 Subject: [PATCH 15/31] Split frame representation from solid representation --- Elements/src/Door.cs | 5 +- Elements/src/DoorRepresentationProvider.cs | 83 +------------------ .../DefaultDoorRepresentationFactory.cs | 82 ++++++++++++++++++ .../DoorRepresentationFactory.cs | 43 ++++++++++ 4 files changed, 132 insertions(+), 81 deletions(-) create mode 100644 Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs create mode 100644 Elements/src/Representations/DoorRepresentations/DoorRepresentationFactory.cs diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index 96163ced6..bf4f6d811 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Text; using Newtonsoft.Json; +using Elements.Representations.DoorRepresentations; namespace Elements { @@ -82,7 +83,7 @@ public Door(double clearWidth, _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(clearWidth, openingSide); Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); - _representationProvider = new DoorRepresentationProvider(); + _representationProvider = new DoorRepresentationProvider(new DefaultDoorRepresentationFactory()); } /// @@ -132,7 +133,7 @@ public Door(Line line, Transform = GetDoorTransform(line.PointAtNormalized(tPos), line, flip); Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); - _representationProvider = new DoorRepresentationProvider(); + _representationProvider = new DoorRepresentationProvider(new DefaultDoorRepresentationFactory()); } private Transform GetOpeningTransform() diff --git a/Elements/src/DoorRepresentationProvider.cs b/Elements/src/DoorRepresentationProvider.cs index 697c7bb30..3998e66dc 100644 --- a/Elements/src/DoorRepresentationProvider.cs +++ b/Elements/src/DoorRepresentationProvider.cs @@ -10,10 +10,12 @@ namespace Elements internal class DoorRepresentationProvider { private readonly Dictionary> _doorTypeToRepresentations; + private readonly DoorRepresentationFactory _doorRepresentationFactory; - public DoorRepresentationProvider() + public DoorRepresentationProvider(DoorRepresentationFactory doorRepresentationFactory) { _doorTypeToRepresentations = new Dictionary>(); + _doorRepresentationFactory = doorRepresentationFactory; } public List GetInstances(Door door) @@ -25,87 +27,10 @@ public List GetInstances(Door door) return representations; } - var representationInstances = new List() - { - CreateSolidDoorRepresentation(door), - CreateCurveDoorRepresentation(door) - }; + var representationInstances = _doorRepresentationFactory.CreateAllRepresentationInstances(door); _doorTypeToRepresentations[doorProps] = representationInstances; return representationInstances; } - - /// - /// Create a solid representation of a . - /// - /// Parameters of - /// will be used for the representation creation. - /// A solid representation, created from properties of . - private static RepresentationInstance CreateSolidDoorRepresentation(Door door) - { - double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); - - Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); - Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); - - var doorPolygon = new Polygon(new List() { - left + Vector3.YAxis * Door.DOOR_THICKNESS, - left - Vector3.YAxis * Door.DOOR_THICKNESS, - right - Vector3.YAxis * Door.DOOR_THICKNESS, - right + Vector3.YAxis * Door.DOOR_THICKNESS}); - - var doorPolygons = new List(); - - if (door.OpeningSide == DoorOpeningSide.DoubleDoor) - { - doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, Door.DOOR_THICKNESS, 0), new Vector3(0, -Door.DOOR_THICKNESS, 0))); - } - else - { - doorPolygons.Add(doorPolygon); - } - - var doorExtrusions = new List(); - - foreach (var polygon in doorPolygons) - { - var doorExtrude = new Extrude(new Profile(polygon.Offset(-0.005)[0]), door.ClearHeight, Vector3.ZAxis); - doorExtrusions.Add(doorExtrude); - } - - var frameLeft = left + Vector3.XAxis * Door.DOOR_FRAME_WIDTH; - var frameRight = right - Vector3.XAxis * Door.DOOR_FRAME_WIDTH; - var frameOffset = Vector3.YAxis * Door.DOOR_FRAME_THICKNESS; - var doorFramePolygon = new Polygon(new List() { - left + Vector3.ZAxis * door.ClearHeight - frameOffset, - left - frameOffset, - frameLeft - frameOffset, - frameLeft + Vector3.ZAxis * (door.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, - frameRight + Vector3.ZAxis * (door.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, - frameRight - frameOffset, - right - frameOffset, - right + Vector3.ZAxis * door.ClearHeight - frameOffset }); - var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), Door.DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); - doorExtrusions.Add(doorFrameExtrude); - - var solidRep = new SolidRepresentation(doorExtrusions); - var repInstance = new RepresentationInstance(solidRep, door.Material, true); - return repInstance; - } - - /// - /// Create a curve 2D representation of a . - /// - /// Parameters of - /// will be used for the representation creation. - /// A curve 2D representation, created from properties of . - private static RepresentationInstance CreateCurveDoorRepresentation(Door door) - { - var points = DoorSchematicVisualizationHelper.CollectPointsForSchematicVisualization(door); - var curve = new IndexedPolycurve(points); - var curveRep = new CurveRepresentation(curve, false); - var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); - return repInstance; - } } } diff --git a/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs b/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs new file mode 100644 index 000000000..cb112d294 --- /dev/null +++ b/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs @@ -0,0 +1,82 @@ +using Elements.Geometry; +using Elements.Geometry.Solids; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Elements.Representations.DoorRepresentations +{ + internal class DefaultDoorRepresentationFactory : DoorRepresentationFactory + { + public override RepresentationInstance CreateDoorCurveRepresentation(Door door) + { + var points = DoorSchematicVisualizationHelper.CollectPointsForSchematicVisualization(door); + var curve = new IndexedPolycurve(points); + var curveRep = new CurveRepresentation(curve, false); + var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + return repInstance; + } + + public override RepresentationInstance CreateDoorFrameRepresentation(Door door) + { + double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); + Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); + Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); + + var frameLeft = left + Vector3.XAxis * Door.DOOR_FRAME_WIDTH; + var frameRight = right - Vector3.XAxis * Door.DOOR_FRAME_WIDTH; + var frameOffset = Vector3.YAxis * Door.DOOR_FRAME_THICKNESS; + var doorFramePolygon = new Polygon(new List() { + left + Vector3.ZAxis * door.ClearHeight - frameOffset, + left - frameOffset, + frameLeft - frameOffset, + frameLeft + Vector3.ZAxis * (door.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, + frameRight + Vector3.ZAxis * (door.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, + frameRight - frameOffset, + right - frameOffset, + right + Vector3.ZAxis * door.ClearHeight - frameOffset }); + var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), Door.DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); + + var solidRep = new SolidRepresentation(doorFrameExtrude); + var repInstance = new RepresentationInstance(solidRep, door.Material, true); + return repInstance; + } + + public override RepresentationInstance CreateDoorSolidRepresentation(Door door) + { + double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); + + Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); + Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); + + var doorPolygon = new Polygon(new List() { + left + Vector3.YAxis * Door.DOOR_THICKNESS, + left - Vector3.YAxis * Door.DOOR_THICKNESS, + right - Vector3.YAxis * Door.DOOR_THICKNESS, + right + Vector3.YAxis * Door.DOOR_THICKNESS}); + + var doorPolygons = new List(); + + if (door.OpeningSide == DoorOpeningSide.DoubleDoor) + { + doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, Door.DOOR_THICKNESS, 0), new Vector3(0, -Door.DOOR_THICKNESS, 0))); + } + else + { + doorPolygons.Add(doorPolygon); + } + + var doorExtrusions = new List(); + + foreach (var polygon in doorPolygons) + { + var doorExtrude = new Extrude(new Profile(polygon.Offset(-0.005)[0]), door.ClearHeight, Vector3.ZAxis); + doorExtrusions.Add(doorExtrude); + } + + var solidRep = new SolidRepresentation(doorExtrusions); + var repInstance = new RepresentationInstance(solidRep, door.Material, true); + return repInstance; + } + } +} diff --git a/Elements/src/Representations/DoorRepresentations/DoorRepresentationFactory.cs b/Elements/src/Representations/DoorRepresentations/DoorRepresentationFactory.cs new file mode 100644 index 000000000..c59295c18 --- /dev/null +++ b/Elements/src/Representations/DoorRepresentations/DoorRepresentationFactory.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Elements.Representations.DoorRepresentations +{ + internal abstract class DoorRepresentationFactory + { + /// + /// Create curve 2D representation of a . + /// + /// Parameters of + /// will be used for the representation creation. + /// A curve 2D representation, created from properties of . + public abstract RepresentationInstance CreateDoorCurveRepresentation(Door door); + + /// + /// Create solid representation of a . + /// + /// Parameters of + /// will be used for the representation creation. + /// A solid representation, created from properties of . + public abstract RepresentationInstance CreateDoorSolidRepresentation(Door door); + + /// + /// Create solid representation of a frame. + /// + /// Parameters of + /// will be used for the representation creation. + /// A solid frame representation, created from properties of . + public abstract RepresentationInstance CreateDoorFrameRepresentation(Door door); + + public List CreateAllRepresentationInstances(Door door) + { + return new List() + { + CreateDoorCurveRepresentation(door), + CreateDoorSolidRepresentation(door), + CreateDoorFrameRepresentation(door) + }; + } + } +} From c2a26109e18746732e7b142cd5a05dd48838d776 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 15 Nov 2023 13:13:23 +0200 Subject: [PATCH 16/31] Added Thickness property to Door class --- .../IFCToHypar/Converters/FromIfcDoorConverter.cs | 1 + Elements.Serialization.IFC/test/IFCTests.cs | 4 ++-- Elements/src/Door.cs | 14 +++++++++++--- .../DefaultDoorRepresentationFactory.cs | 10 +++++----- .../DoorSchematicVisualizationHelper.cs | 4 ++-- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs index 27b0bc982..dbf037e09 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs @@ -39,6 +39,7 @@ public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationDa var result = new Door(doorWidth, doorHeight, + Door.DOOR_DEFAULT_THICKNESS, openingSide, openingType, repData.Transform, diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index 372ae9e22..3bb467085 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -140,8 +140,8 @@ public void Doors() model.AddElement(wall1); model.AddElement(wall2); - var door1 = new Door(wallLine1, 0.5, 1.5, 2.0, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); - var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door1 = new Door(wallLine1, 0.5, 1.5, Door.DOOR_DEFAULT_THICKNESS, 2.0, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door2 = new Door(wallLine2, 0.5, 1.5, Door.DOOR_DEFAULT_THICKNESS, 1.8, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); model.AddElement(door1); model.AddElement(door2); diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index bf4f6d811..0b1f3f352 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -15,7 +15,7 @@ public class Door : GeometricElement /// /// Default thickness of a door. /// - public const double DOOR_THICKNESS = 0.125; + public const double DOOR_DEFAULT_THICKNESS = 0.125; /// /// Default thickness of a door frame. /// @@ -33,6 +33,8 @@ public class Door : GeometricElement public DoorOpeningSide OpeningSide { get; private set; } /// Height of a door without a frame. public double ClearHeight { get; private set; } + /// Door thickness. + public double Thickness { get; private set; } /// Opening for a door. public Opening Opening { get; private set; } @@ -43,7 +45,8 @@ public class Door : GeometricElement /// Create a door. /// /// The width of a single door. - /// The door's height. + /// Height of the door without frame. + /// Door thickness. /// The side where the door opens. /// The way the door opens. /// The door's transform. X-direction is aligned with the door, Y-direction is the opening direction. @@ -57,6 +60,7 @@ public class Door : GeometricElement [JsonConstructor] public Door(double clearWidth, double clearHeight, + double thickness, DoorOpeningSide openingSide, DoorOpeningType openingType, Transform transform = null, @@ -79,6 +83,7 @@ public Door(double clearWidth, OpeningType = openingType; ClearHeight = clearHeight; ClearWidth = clearWidth; + Thickness = thickness; Material = material ?? DEFAULT_MATERIAL; _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(clearWidth, openingSide); Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); @@ -92,7 +97,8 @@ public Door(double clearWidth, /// The line where the door is placed. /// Relative position on the line where door is placed. Should be in [0; 1]. /// The width of a single door. - /// The door's height. + /// Height of the door without frame. + /// Door thickness. /// The side where the door opens. /// The way the door opens. /// The door's material. @@ -107,6 +113,7 @@ public Door(Line line, double tPos, double clearWidth, double clearHeight, + double thickness, DoorOpeningSide openingSide, DoorOpeningType openingType, Material material = null, @@ -128,6 +135,7 @@ public Door(Line line, OpeningSide = openingSide; ClearWidth = clearWidth; ClearHeight = clearHeight; + Thickness = thickness; Material = material ?? DEFAULT_MATERIAL; _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(ClearWidth, openingSide); Transform = GetDoorTransform(line.PointAtNormalized(tPos), line, flip); diff --git a/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs b/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs index cb112d294..a4f74e117 100644 --- a/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs +++ b/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs @@ -50,16 +50,16 @@ public override RepresentationInstance CreateDoorSolidRepresentation(Door door) Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); var doorPolygon = new Polygon(new List() { - left + Vector3.YAxis * Door.DOOR_THICKNESS, - left - Vector3.YAxis * Door.DOOR_THICKNESS, - right - Vector3.YAxis * Door.DOOR_THICKNESS, - right + Vector3.YAxis * Door.DOOR_THICKNESS}); + left + Vector3.YAxis * door.Thickness, + left - Vector3.YAxis * door.Thickness, + right - Vector3.YAxis * door.Thickness, + right + Vector3.YAxis * door.Thickness}); var doorPolygons = new List(); if (door.OpeningSide == DoorOpeningSide.DoubleDoor) { - doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, Door.DOOR_THICKNESS, 0), new Vector3(0, -Door.DOOR_THICKNESS, 0))); + doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, door.Thickness, 0), new Vector3(0, -door.Thickness, 0))); } else { diff --git a/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs b/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs index 51ebfec8e..c3e943d41 100644 --- a/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs +++ b/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs @@ -50,8 +50,8 @@ private static List CollectSchematicVisualizationLines(Door door, bool // Depending on which side door in there are different offsets. var doorOffset = leftSide ? fullDoorWidthWithoutFrame / 2 : -fullDoorWidthWithoutFrame / 2; - var horizontalOffset = leftSide ? Door.DOOR_THICKNESS : -Door.DOOR_THICKNESS; - var verticalOffset = inside ? Door.DOOR_THICKNESS : -Door.DOOR_THICKNESS; + var horizontalOffset = leftSide ? door.Thickness : -door.Thickness; + var verticalOffset = inside ? door.Thickness : -door.Thickness; var widthOffset = inside ? door.ClearWidth : -door.ClearWidth; // Draw open door silhouette rectangle. From 599889ec1c4d5651a3548f9eed3d588c44c4c6ee Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 15 Nov 2023 15:18:15 +0200 Subject: [PATCH 17/31] Fixed an issue with Opening - Method CreateDoorOpening is used now instead of Opening property; - Removed opening properties from constructor; - Fixed issue in Opening class; - Fixed several small issues in door opening size computation. --- Elements/src/Door.cs | 47 +++++++++++++++++++++-------------------- Elements/src/Opening.cs | 3 ++- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index 0b1f3f352..61b613362 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -35,8 +35,6 @@ public class Door : GeometricElement public double ClearHeight { get; private set; } /// Door thickness. public double Thickness { get; private set; } - /// Opening for a door. - public Opening Opening { get; private set; } private readonly double _fullDoorWidthWithoutFrame; private readonly DoorRepresentationProvider _representationProvider; @@ -55,8 +53,6 @@ public class Door : GeometricElement /// Is this an element definition? /// The door's id. /// The door's name. - /// The door's opening depth front. - /// The door's opening depth back. [JsonConstructor] public Door(double clearWidth, double clearHeight, @@ -68,9 +64,7 @@ public Door(double clearWidth, Representation representation = null, bool isElementDefinition = false, Guid id = default, - string name = "Door", - double depthFront = 1, - double depthBack = 1 + string name = "Door" ) : base( transform: transform, representation: representation, @@ -86,7 +80,6 @@ public Door(double clearWidth, Thickness = thickness; Material = material ?? DEFAULT_MATERIAL; _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(clearWidth, openingSide); - Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); _representationProvider = new DoorRepresentationProvider(new DefaultDoorRepresentationFactory()); } @@ -106,9 +99,6 @@ public Door(double clearWidth, /// Is this an element definition? /// The door's id. /// The door's name. - /// The door's opening depth front. - /// The door's opening depth back. - /// Is the door flipped? public Door(Line line, double tPos, double clearWidth, @@ -120,10 +110,7 @@ public Door(Line line, Representation representation = null, bool isElementDefinition = false, Guid id = default, - string name = "Door", - double depthFront = 1, - double depthBack = 1, - bool flip = false + string name = "Door" ) : base( representation: representation, isElementDefinition: isElementDefinition, @@ -138,23 +125,37 @@ public Door(Line line, Thickness = thickness; Material = material ?? DEFAULT_MATERIAL; _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(ClearWidth, openingSide); - Transform = GetDoorTransform(line.PointAtNormalized(tPos), line, flip); - Opening = new Opening(Polygon.Rectangle(_fullDoorWidthWithoutFrame, clearHeight), depthFront, depthBack, GetOpeningTransform()); + Transform = GetDoorTransform(line.PointAtNormalized(tPos), line); _representationProvider = new DoorRepresentationProvider(new DefaultDoorRepresentationFactory()); } - private Transform GetOpeningTransform() + /// + /// Create an opening for the door. + /// + /// The door's opening depth front. + /// The door's opening depth back. + /// Is the opening flipped? + /// An opening where the door can be inserted. + public Opening CreateDoorOpening(double depthFront, double depthBack, bool flip) { - var halfHeightDir = 0.5 * (ClearHeight + DOOR_FRAME_THICKNESS) * Vector3.ZAxis; - var openingTransform = new Transform(Transform.Origin + halfHeightDir, Transform.XAxis, Transform.XAxis.Cross(Vector3.ZAxis)); - return openingTransform; + var openingWidth = _fullDoorWidthWithoutFrame + 2 * DOOR_FRAME_WIDTH; + var openingHeight = ClearHeight + DOOR_FRAME_WIDTH; + + var openingDir = flip ? Vector3.YAxis.Negate() : Vector3.YAxis; + var widthDir = flip ? Vector3.XAxis.Negate() : Vector3.XAxis; + var openingTransform = new Transform(0.5 * openingHeight * Vector3.ZAxis, widthDir, openingDir); + + var openingPolygon = Polygon.Rectangle(openingWidth, openingHeight).TransformedPolygon(openingTransform); + + var opening = new Opening(openingPolygon, openingDir, depthFront, depthBack, Transform); + return opening; } - private Transform GetDoorTransform(Vector3 currentPosition, Line wallLine, bool flip) + private Transform GetDoorTransform(Vector3 currentPosition, Line wallLine) { var adjustedPosition = GetClosestValidDoorPos(wallLine, currentPosition); - var xDoorAxis = flip ? wallLine.Direction().Negate() : wallLine.Direction(); + var xDoorAxis = wallLine.Direction(); return new Transform(adjustedPosition, xDoorAxis, Vector3.ZAxis); } diff --git a/Elements/src/Opening.cs b/Elements/src/Opening.cs index a14069e16..80be2d6e6 100644 --- a/Elements/src/Opening.cs +++ b/Elements/src/Opening.cs @@ -90,7 +90,8 @@ public override void UpdateRepresentations() { this.Representation.SolidOperations.Clear(); var depth = this.DepthFront + this.DepthBack; - var op = new Extrude(this.Perimeter, depth, Normal, true); + var depthBackTransform = new Transform(-DepthBack * Normal); + var op = new Extrude(this.Perimeter.TransformedPolygon(depthBackTransform), depth, Normal, true); this.Representation.SolidOperations.Add(op); } } From 9e004b50f4de63ab7fda1a4c2cb25c7dd3946ee0 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 15 Nov 2023 15:20:12 +0200 Subject: [PATCH 18/31] Update DoorTest.cs --- Elements/test/DoorTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index 7e66239cd..f4255fee0 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -18,7 +18,7 @@ public void Example() var line = new Line(new Vector3(0, 0, 0), new Vector3(10, 10, 0)); var wall = new StandardWall(line, 0.1, 3.0); - var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); + var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); this.Model.AddElement(wall); Model.AddElement(door); From 6410b9db2a840e3366b702bf784792c3e7f425ef Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 15 Nov 2023 15:41:30 +0200 Subject: [PATCH 19/31] Fixed door ifc test --- Elements.Serialization.IFC/test/IFCTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index 3bb467085..668aaee0d 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -140,8 +140,8 @@ public void Doors() model.AddElement(wall1); model.AddElement(wall2); - var door1 = new Door(wallLine1, 0.5, 1.5, Door.DOOR_DEFAULT_THICKNESS, 2.0, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); - var door2 = new Door(wallLine2, 0.5, 1.5, Door.DOOR_DEFAULT_THICKNESS, 1.8, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door1 = new Door(wallLine1, 0.5, 1.5, 2.0, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); model.AddElement(door1); model.AddElement(door2); From 5fa8f819d43ed63209e05d6a08791300d0d641fe Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 15 Nov 2023 16:41:35 +0200 Subject: [PATCH 20/31] Fixed IFCTests The tests failed because doors don't have Opening members anymore. --- Elements.Serialization.IFC/test/IFCTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index 668aaee0d..1e363ed9a 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -28,7 +28,7 @@ public IfcTests(ITestOutputHelper output) // [InlineData("rac_sample", "../../../models/IFC4/rac_advanced_sample_project.ifc")] // [InlineData("rme_sample", "../../../models/IFC4/rme_advanced_sample_project.ifc")] // [InlineData("rst_sample", "../../../models/IFC4/rst_advanced_sample_project.ifc")] - [InlineData("AC-20-Smiley-West-10-Bldg", "../../../models/IFC4/AC-20-Smiley-West-10-Bldg.ifc", 1972, 120, 539, 270, 9, 140, 10, 2)] + [InlineData("AC-20-Smiley-West-10-Bldg", "../../../models/IFC4/AC-20-Smiley-West-10-Bldg.ifc", 1963, 120, 530, 270, 9, 140, 10, 2)] // TODO: Some walls are extracted incorrectly and intersecting the roof. It happens because // IfcBooleanClippingResultParser doesn't handle the boolean clipping operation. // In order to fix it surface support is required. @@ -38,7 +38,7 @@ public IfcTests(ITestOutputHelper output) // TODO: The entrance door has an incorrect representation. It happens because during // the UpdateRepresentation the default representation of a door is created instead of // the extracted one. - [InlineData("AC20-Institute-Var-2", "../../../models/IFC4/AC20-Institute-Var-2.ifc", 1513, 5, 577, 121, 7, 82, 0, 21)] + [InlineData("AC20-Institute-Var-2", "../../../models/IFC4/AC20-Institute-Var-2.ifc", 1506, 5, 570, 121, 7, 82, 0, 21)] // [InlineData("20160125WestRiverSide Hospital - IFC4-Autodesk_Hospital_Sprinkle", "../../../models/IFC4/20160125WestRiverSide Hospital - IFC4-Autodesk_Hospital_Sprinkle.ifc")] public void FromIFC4(string name, string ifcPath, From f3ebe0ac8a039d6b9b39af9aa2f6b91198a5ef16 Mon Sep 17 00:00:00 2001 From: srudenkoamc Date: Wed, 15 Nov 2023 16:42:34 +0200 Subject: [PATCH 21/31] Added AddDoorOpening method to StandardWall class --- Elements.Serialization.IFC/test/IFCTests.cs | 10 +++++++--- Elements/src/StandardWall.cs | 11 +++++++++++ Elements/test/DoorTest.cs | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index 1e363ed9a..65ee50106 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using Elements.Geometry.Profiles; using System.Linq; +using System.Xml.Linq; namespace Elements.IFC.Tests { @@ -137,15 +138,18 @@ public void Doors() var wall1 = new StandardWall(wallLine1, 0.2, 3, name: "Wall1"); var wall2 = new StandardWall(wallLine2, 0.2, 2, name: "Wall2"); - model.AddElement(wall1); - model.AddElement(wall2); - var door1 = new Door(wallLine1, 0.5, 1.5, 2.0, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + wall1.AddDoorOpening(door1); + wall2.AddDoorOpening(door2); + + model.AddElement(wall1); + model.AddElement(wall2); model.AddElement(door1); model.AddElement(door2); + model.ToJson(ConstructJsonPath("IfcDoor")); model.ToIFC(ConstructIfcPath("IfcDoor")); } diff --git a/Elements/src/StandardWall.cs b/Elements/src/StandardWall.cs index 40b75851d..8938cdcbc 100644 --- a/Elements/src/StandardWall.cs +++ b/Elements/src/StandardWall.cs @@ -132,5 +132,16 @@ public override void UpdateRepresentations() var profile = new Polygon(new[] { e1.Start, e1.End, e2.End, e2.Start }); this.Representation.SolidOperations.Add(new Extrude(profile, this.Height, Vector3.ZAxis, false)); } + + /// + /// Creates an opening that suits . + /// + /// Properties of will be used to create an opening. + public void AddDoorOpening(Door door) + { + var halfThickness = 0.5 * Thickness; + var opening = door.CreateDoorOpening(halfThickness, halfThickness, false); + Openings.Add(opening); + } } } \ No newline at end of file diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index f4255fee0..572696f60 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -19,6 +19,7 @@ public void Example() var line = new Line(new Vector3(0, 0, 0), new Vector3(10, 10, 0)); var wall = new StandardWall(line, 0.1, 3.0); var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); + wall.AddDoorOpening(door); this.Model.AddElement(wall); Model.AddElement(door); From 282075f1d106ebe7484732f8015bf9ec8d47011c Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Wed, 15 Nov 2023 10:14:28 -0800 Subject: [PATCH 22/31] removals --- .../Converters/FromIfcDoorConverter.cs | 2 +- Elements/src/Door.cs | 227 +++++++++++++++++- Elements/src/DoorOpeningSide.cs | 18 -- Elements/src/DoorOpeningType.cs | 16 -- Elements/src/DoorProperties.cs | 70 ------ Elements/src/DoorRepresentationProvider.cs | 38 --- .../DefaultDoorRepresentationFactory.cs | 82 ------- .../DoorRepresentationFactory.cs | 43 ---- .../DoorSchematicVisualizationHelper.cs | 118 --------- Elements/test/DoorTest.cs | 2 +- 10 files changed, 221 insertions(+), 395 deletions(-) delete mode 100644 Elements/src/DoorOpeningSide.cs delete mode 100644 Elements/src/DoorOpeningType.cs delete mode 100644 Elements/src/DoorProperties.cs delete mode 100644 Elements/src/DoorRepresentationProvider.cs delete mode 100644 Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs delete mode 100644 Elements/src/Representations/DoorRepresentations/DoorRepresentationFactory.cs delete mode 100644 Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs diff --git a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs index 9a7e1a569..27a0bb539 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs @@ -39,7 +39,7 @@ public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationDa var result = new Door(doorWidth, doorHeight, - Door.DOOR_DEFAULT_THICKNESS, + Door.DOOR_THICKNESS, openingSide, openingType, repData.Transform, diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index a579e6d5d..43122c3c4 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.Text; using Newtonsoft.Json; -using Elements.Representations.DoorRepresentations; +using Elements.Geometry.Solids; namespace Elements { - /// Definition of a door public class Door : GeometricElement { @@ -40,7 +39,6 @@ public class Door : GeometricElement public Vector3 OriginalPosition { get; set; } private readonly double _fullDoorWidthWithoutFrame; - private readonly DoorRepresentationProvider _representationProvider; /// /// Create a door. @@ -83,8 +81,6 @@ public Door(double clearWidth, Thickness = thickness; Material = material ?? DEFAULT_MATERIAL; _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(clearWidth, openingSide); - - _representationProvider = new DoorRepresentationProvider(new DefaultDoorRepresentationFactory()); } /// @@ -129,8 +125,6 @@ public Door(Line line, Material = material ?? DEFAULT_MATERIAL; _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(ClearWidth, openingSide); Transform = GetDoorTransform(line.PointAtNormalized(tPos), line); - - _representationProvider = new DoorRepresentationProvider(new DefaultDoorRepresentationFactory()); } /// @@ -176,7 +170,20 @@ public static bool CanFit(Line wallLine, DoorOpeningSide openingSide, double wid /// public override void UpdateRepresentations() { - RepresentationInstances = _representationProvider.GetInstances(this); + RepresentationInstances = this.GetInstances(this); + } + + + public List GetInstances(Door door) + { + var representationInstances = new List() + { + this.CreateDoorSolidRepresentation(), + this.CreateDoorFrameRepresentation(), + this.CreateDoorCurveRepresentation() + }; + + return representationInstances; } private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) @@ -206,5 +213,209 @@ private static double GetDoorFullWidthWithoutFrame(double doorClearWidth, DoorOp } return 0; } + + + public RepresentationInstance CreateDoorCurveRepresentation() + { + var points = CollectPointsForSchematicVisualization(); + var curve = new IndexedPolycurve(points); + var curveRep = new CurveRepresentation(curve, false); + var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + return repInstance; + } + + public RepresentationInstance CreateDoorFrameRepresentation() + { + double fullDoorWidthWithoutFrame = this.GetFullDoorWidthWithoutFrame(); + Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); + Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); + + var frameLeft = left + Vector3.XAxis * Door.DOOR_FRAME_WIDTH; + var frameRight = right - Vector3.XAxis * Door.DOOR_FRAME_WIDTH; + var frameOffset = Vector3.YAxis * Door.DOOR_FRAME_THICKNESS; + var doorFramePolygon = new Polygon(new List() { + left + Vector3.ZAxis * this.ClearHeight - frameOffset, + left - frameOffset, + frameLeft - frameOffset, + frameLeft + Vector3.ZAxis * (this.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, + frameRight + Vector3.ZAxis * (this.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, + frameRight - frameOffset, + right - frameOffset, + right + Vector3.ZAxis * this.ClearHeight - frameOffset }); + var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), Door.DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); + + var solidRep = new SolidRepresentation(doorFrameExtrude); + var repInstance = new RepresentationInstance(solidRep, this.Material, true); + return repInstance; + } + + public RepresentationInstance CreateDoorSolidRepresentation() + { + double fullDoorWidthWithoutFrame = this.GetFullDoorWidthWithoutFrame(); + + Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); + Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); + + var doorPolygon = new Polygon(new List() { + left + Vector3.YAxis * this.Thickness, + left - Vector3.YAxis * this.Thickness, + right - Vector3.YAxis * this.Thickness, + right + Vector3.YAxis * this.Thickness}); + + var doorPolygons = new List(); + + if (this.OpeningSide == DoorOpeningSide.DoubleDoor) + { + doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, this.Thickness, 0), new Vector3(0, -this.Thickness, 0))); + } + else + { + doorPolygons.Add(doorPolygon); + } + + var doorExtrusions = new List(); + + foreach (var polygon in doorPolygons) + { + var doorExtrude = new Extrude(new Profile(polygon.Offset(-0.005)[0]), this.ClearHeight, Vector3.ZAxis); + doorExtrusions.Add(doorExtrude); + } + + var solidRep = new SolidRepresentation(doorExtrusions); + var repInstance = new RepresentationInstance(solidRep, this.Material, true); + return repInstance; + } + + public List CollectPointsForSchematicVisualization() + { + var points = new List(); + + if (this.OpeningSide == DoorOpeningSide.Undefined || this.OpeningType == DoorOpeningType.Undefined) + { + return points; + } + + if (this.OpeningSide != DoorOpeningSide.LeftHand) + { + points.AddRange(CollectSchematicVisualizationLines(this, false, false, 90)); + } + + if (this.OpeningSide != DoorOpeningSide.RightHand) + { + points.AddRange(CollectSchematicVisualizationLines(this, true, false, 90)); + } + + if (this.OpeningType == DoorOpeningType.SingleSwing) + { + return points; + } + + if (this.OpeningSide != DoorOpeningSide.LeftHand) + { + points.AddRange(CollectSchematicVisualizationLines(this, false, true, 90)); + } + + if (this.OpeningSide != DoorOpeningSide.RightHand) + { + points.AddRange(CollectSchematicVisualizationLines(this, true, true, 90)); + } + + return points; + } + + private static List CollectSchematicVisualizationLines(Door door, bool leftSide, bool inside, double angle) + { + var fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); + + // Depending on which side door in there are different offsets. + var doorOffset = leftSide ? fullDoorWidthWithoutFrame / 2 : -fullDoorWidthWithoutFrame / 2; + var horizontalOffset = leftSide ? door.Thickness : -door.Thickness; + var verticalOffset = inside ? door.Thickness : -door.Thickness; + var widthOffset = inside ? door.ClearWidth : -door.ClearWidth; + + // Draw open door silhouette rectangle. + Vector3 corner = Vector3.XAxis * doorOffset; + var c0 = corner + Vector3.YAxis * verticalOffset; + var c1 = c0 + Vector3.YAxis * widthOffset; + var c2 = c1 - Vector3.XAxis * horizontalOffset; + var c3 = c0 - Vector3.XAxis * horizontalOffset; + + // Rotate silhouette is it's need to be drawn as partially open. + if (!angle.ApproximatelyEquals(90)) + { + double rotation = 90 - angle; + if (!leftSide) + { + rotation = -rotation; + } + + if (!inside) + { + rotation = -rotation; + } + + Transform t = new Transform(); + t.RotateAboutPoint(c0, Vector3.ZAxis, rotation); + c1 = t.OfPoint(c1); + c2 = t.OfPoint(c2); + c3 = t.OfPoint(c3); + } + List points = new List() { c0, c1, c1, c2, c2, c3, c3, c0 }; + + // Calculated correct arc angles based on door orientation. + double adjustedAngle = inside ? angle : -angle; + double anchorAngle = leftSide ? 180 : 0; + double endAngle = leftSide ? 180 - adjustedAngle : adjustedAngle; + if (endAngle < 0) + { + endAngle = 360 + endAngle; + anchorAngle = 360; + } + + // If arc is constructed from bigger angle to smaller is will have incorrect domain + // with max being smaller than min and negative length. + // ToPolyline will return 0 points for it. + // Until it's fixed angles should be aligned manually. + bool flipEnds = endAngle < anchorAngle; + if (flipEnds) + { + (anchorAngle, endAngle) = (endAngle, anchorAngle); + } + + // Draw the arc from closed door to opened door. + Arc arc = new Arc(c0, door.ClearWidth, anchorAngle, endAngle); + var tessalatedArc = arc.ToPolyline((int)(Math.Abs(angle) / 2)); + for (int i = 0; i < tessalatedArc.Vertices.Count - 1; i++) + { + points.Add(tessalatedArc.Vertices[i]); + points.Add(tessalatedArc.Vertices[i + 1]); + } + + return points; + } + } + + public enum DoorOpeningSide + { + [System.Runtime.Serialization.EnumMember(Value = @"Undefined")] + Undefined, + [System.Runtime.Serialization.EnumMember(Value = @"Left Hand")] + LeftHand, + [System.Runtime.Serialization.EnumMember(Value = @"Right Hand")] + RightHand, + [System.Runtime.Serialization.EnumMember(Value = @"Double Door")] + DoubleDoor } + + public enum DoorOpeningType + { + [System.Runtime.Serialization.EnumMember(Value = @"Undefined")] + Undefined, + [System.Runtime.Serialization.EnumMember(Value = @"Single Swing")] + SingleSwing, + [System.Runtime.Serialization.EnumMember(Value = @"Double Swing")] + DoubleSwing + } + + } diff --git a/Elements/src/DoorOpeningSide.cs b/Elements/src/DoorOpeningSide.cs deleted file mode 100644 index 0acfcbc57..000000000 --- a/Elements/src/DoorOpeningSide.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Elements -{ - public enum DoorOpeningSide - { - [System.Runtime.Serialization.EnumMember(Value = @"Undefined")] - Undefined, - [System.Runtime.Serialization.EnumMember(Value = @"Left Hand")] - LeftHand, - [System.Runtime.Serialization.EnumMember(Value = @"Right Hand")] - RightHand, - [System.Runtime.Serialization.EnumMember(Value = @"Double Door")] - DoubleDoor - } -} diff --git a/Elements/src/DoorOpeningType.cs b/Elements/src/DoorOpeningType.cs deleted file mode 100644 index 19c17e2f5..000000000 --- a/Elements/src/DoorOpeningType.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Elements -{ - public enum DoorOpeningType - { - [System.Runtime.Serialization.EnumMember(Value = @"Undefined")] - Undefined, - [System.Runtime.Serialization.EnumMember(Value = @"Single Swing")] - SingleSwing, - [System.Runtime.Serialization.EnumMember(Value = @"Double Swing")] - DoubleSwing - } -} diff --git a/Elements/src/DoorProperties.cs b/Elements/src/DoorProperties.cs deleted file mode 100644 index 11003f2b4..000000000 --- a/Elements/src/DoorProperties.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Elements -{ - internal class DoorProperties - { - private readonly double _width; - private readonly double _height; - private readonly Material _material; - private readonly DoorOpeningSide _openingSide; - private readonly DoorOpeningType _openingType; - - public DoorProperties(Door door) - { - _width = door.ClearWidth; - _height = door.ClearHeight; - _material = door.Material; - _openingSide = door.OpeningSide; - _openingType = door.OpeningType; - } - - public override bool Equals(object obj) - { - if (!(obj is DoorProperties doorProps)) - { - return false; - } - - if (!_width.ApproximatelyEquals(doorProps._width)) - { - return false; - } - - if (!_height.ApproximatelyEquals(doorProps._height)) - { - return false; - } - - if (!_material.Id.Equals(doorProps._material.Id)) - { - return false; - } - - if (!_openingSide.Equals(doorProps._openingSide)) - { - return false; - } - - if (!_openingType.Equals(doorProps._openingType)) - { - return false; - } - - return true; - } - - public override int GetHashCode() - { - int hash = 17; - hash = hash * 31 + _width.GetHashCode(); - hash = hash * 31 + _height.GetHashCode(); - hash = hash * 31 + _material.Id.GetHashCode(); - hash = hash * 31 + _openingSide.GetHashCode(); - hash = hash * 31 + _openingType.GetHashCode(); - return hash; - } - } -} diff --git a/Elements/src/DoorRepresentationProvider.cs b/Elements/src/DoorRepresentationProvider.cs deleted file mode 100644 index 2d080125c..000000000 --- a/Elements/src/DoorRepresentationProvider.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Elements.Geometry.Solids; -using Elements.Geometry; -using System; -using System.Collections.Generic; -using System.Text; -using Elements.Representations.DoorRepresentations; - -namespace Elements -{ - internal class DoorRepresentationProvider - { - private readonly Dictionary> _doorTypeToRepresentations; - private readonly DoorRepresentationFactory _doorRepresentationFactory; - - private static readonly Material frameMaterial = new Material(Colors.Gray, 0.5, 0.25, false, null, false, false, null, false, null, 0, false, default, "Silver Frame"); - - public DoorRepresentationProvider() - { - _doorTypeToRepresentations = new Dictionary>(); - _doorRepresentationFactory = doorRepresentationFactory; - } - - public List GetInstances(Door door) - { - var doorProps = new DoorProperties(door); - - if (_doorTypeToRepresentations.TryGetValue(doorProps, out var representations)) - { - return representations; - } - - var representationInstances = _doorRepresentationFactory.CreateAllRepresentationInstances(door); - - _doorTypeToRepresentations[doorProps] = representationInstances; - return representationInstances; - } - } -} diff --git a/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs b/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs deleted file mode 100644 index a4f74e117..000000000 --- a/Elements/src/Representations/DoorRepresentations/DefaultDoorRepresentationFactory.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Elements.Geometry; -using Elements.Geometry.Solids; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Elements.Representations.DoorRepresentations -{ - internal class DefaultDoorRepresentationFactory : DoorRepresentationFactory - { - public override RepresentationInstance CreateDoorCurveRepresentation(Door door) - { - var points = DoorSchematicVisualizationHelper.CollectPointsForSchematicVisualization(door); - var curve = new IndexedPolycurve(points); - var curveRep = new CurveRepresentation(curve, false); - var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); - return repInstance; - } - - public override RepresentationInstance CreateDoorFrameRepresentation(Door door) - { - double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); - Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); - Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); - - var frameLeft = left + Vector3.XAxis * Door.DOOR_FRAME_WIDTH; - var frameRight = right - Vector3.XAxis * Door.DOOR_FRAME_WIDTH; - var frameOffset = Vector3.YAxis * Door.DOOR_FRAME_THICKNESS; - var doorFramePolygon = new Polygon(new List() { - left + Vector3.ZAxis * door.ClearHeight - frameOffset, - left - frameOffset, - frameLeft - frameOffset, - frameLeft + Vector3.ZAxis * (door.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, - frameRight + Vector3.ZAxis * (door.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, - frameRight - frameOffset, - right - frameOffset, - right + Vector3.ZAxis * door.ClearHeight - frameOffset }); - var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), Door.DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); - - var solidRep = new SolidRepresentation(doorFrameExtrude); - var repInstance = new RepresentationInstance(solidRep, door.Material, true); - return repInstance; - } - - public override RepresentationInstance CreateDoorSolidRepresentation(Door door) - { - double fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); - - Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); - Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); - - var doorPolygon = new Polygon(new List() { - left + Vector3.YAxis * door.Thickness, - left - Vector3.YAxis * door.Thickness, - right - Vector3.YAxis * door.Thickness, - right + Vector3.YAxis * door.Thickness}); - - var doorPolygons = new List(); - - if (door.OpeningSide == DoorOpeningSide.DoubleDoor) - { - doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, door.Thickness, 0), new Vector3(0, -door.Thickness, 0))); - } - else - { - doorPolygons.Add(doorPolygon); - } - - var doorExtrusions = new List(); - - foreach (var polygon in doorPolygons) - { - var doorExtrude = new Extrude(new Profile(polygon.Offset(-0.005)[0]), door.ClearHeight, Vector3.ZAxis); - doorExtrusions.Add(doorExtrude); - } - - var solidRep = new SolidRepresentation(doorExtrusions); - var repInstance = new RepresentationInstance(solidRep, door.Material, true); - return repInstance; - } - } -} diff --git a/Elements/src/Representations/DoorRepresentations/DoorRepresentationFactory.cs b/Elements/src/Representations/DoorRepresentations/DoorRepresentationFactory.cs deleted file mode 100644 index c59295c18..000000000 --- a/Elements/src/Representations/DoorRepresentations/DoorRepresentationFactory.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Elements.Representations.DoorRepresentations -{ - internal abstract class DoorRepresentationFactory - { - /// - /// Create curve 2D representation of a . - /// - /// Parameters of - /// will be used for the representation creation. - /// A curve 2D representation, created from properties of . - public abstract RepresentationInstance CreateDoorCurveRepresentation(Door door); - - /// - /// Create solid representation of a . - /// - /// Parameters of - /// will be used for the representation creation. - /// A solid representation, created from properties of . - public abstract RepresentationInstance CreateDoorSolidRepresentation(Door door); - - /// - /// Create solid representation of a frame. - /// - /// Parameters of - /// will be used for the representation creation. - /// A solid frame representation, created from properties of . - public abstract RepresentationInstance CreateDoorFrameRepresentation(Door door); - - public List CreateAllRepresentationInstances(Door door) - { - return new List() - { - CreateDoorCurveRepresentation(door), - CreateDoorSolidRepresentation(door), - CreateDoorFrameRepresentation(door) - }; - } - } -} diff --git a/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs b/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs deleted file mode 100644 index c3e943d41..000000000 --- a/Elements/src/Representations/DoorRepresentations/DoorSchematicVisualizationHelper.cs +++ /dev/null @@ -1,118 +0,0 @@ -using Elements.Geometry; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Elements.Representations.DoorRepresentations -{ - internal static class DoorSchematicVisualizationHelper - { - public static List CollectPointsForSchematicVisualization(Door door) - { - var points = new List(); - - if (door.OpeningSide == DoorOpeningSide.Undefined || door.OpeningType == DoorOpeningType.Undefined) - { - return points; - } - - if (door.OpeningSide != DoorOpeningSide.LeftHand) - { - points.AddRange(CollectSchematicVisualizationLines(door, false, false, 90)); - } - - if (door.OpeningSide != DoorOpeningSide.RightHand) - { - points.AddRange(CollectSchematicVisualizationLines(door, true, false, 90)); - } - - if (door.OpeningType == DoorOpeningType.SingleSwing) - { - return points; - } - - if (door.OpeningSide != DoorOpeningSide.LeftHand) - { - points.AddRange(CollectSchematicVisualizationLines(door, false, true, 90)); - } - - if (door.OpeningSide != DoorOpeningSide.RightHand) - { - points.AddRange(CollectSchematicVisualizationLines(door, true, true, 90)); - } - - return points; - } - - private static List CollectSchematicVisualizationLines(Door door, bool leftSide, bool inside, double angle) - { - var fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); - - // Depending on which side door in there are different offsets. - var doorOffset = leftSide ? fullDoorWidthWithoutFrame / 2 : -fullDoorWidthWithoutFrame / 2; - var horizontalOffset = leftSide ? door.Thickness : -door.Thickness; - var verticalOffset = inside ? door.Thickness : -door.Thickness; - var widthOffset = inside ? door.ClearWidth : -door.ClearWidth; - - // Draw open door silhouette rectangle. - Vector3 corner = Vector3.XAxis * doorOffset; - var c0 = corner + Vector3.YAxis * verticalOffset; - var c1 = c0 + Vector3.YAxis * widthOffset; - var c2 = c1 - Vector3.XAxis * horizontalOffset; - var c3 = c0 - Vector3.XAxis * horizontalOffset; - - // Rotate silhouette is it's need to be drawn as partially open. - if (!angle.ApproximatelyEquals(90)) - { - double rotation = 90 - angle; - if (!leftSide) - { - rotation = -rotation; - } - - if (!inside) - { - rotation = -rotation; - } - - Transform t = new Transform(); - t.RotateAboutPoint(c0, Vector3.ZAxis, rotation); - c1 = t.OfPoint(c1); - c2 = t.OfPoint(c2); - c3 = t.OfPoint(c3); - } - List points = new List() { c0, c1, c1, c2, c2, c3, c3, c0 }; - - // Calculated correct arc angles based on door orientation. - double adjustedAngle = inside ? angle : -angle; - double anchorAngle = leftSide ? 180 : 0; - double endAngle = leftSide ? 180 - adjustedAngle : adjustedAngle; - if (endAngle < 0) - { - endAngle = 360 + endAngle; - anchorAngle = 360; - } - - // If arc is constructed from bigger angle to smaller is will have incorrect domain - // with max being smaller than min and negative length. - // ToPolyline will return 0 points for it. - // Until it's fixed angles should be aligned manually. - bool flipEnds = endAngle < anchorAngle; - if (flipEnds) - { - (anchorAngle, endAngle) = (endAngle, anchorAngle); - } - - // Draw the arc from closed door to opened door. - Arc arc = new Arc(c0, door.ClearWidth, anchorAngle, endAngle); - var tessalatedArc = arc.ToPolyline((int)(Math.Abs(angle) / 2)); - for (int i = 0; i < tessalatedArc.Vertices.Count - 1; i++) - { - points.Add(tessalatedArc.Vertices[i]); - points.Add(tessalatedArc.Vertices[i + 1]); - } - - return points; - } - } -} diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index 572696f60..2a643fc3e 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -18,7 +18,7 @@ public void Example() var line = new Line(new Vector3(0, 0, 0), new Vector3(10, 10, 0)); var wall = new StandardWall(line, 0.1, 3.0); - var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); + var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, Door.DOOR_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); wall.AddDoorOpening(door); this.Model.AddElement(wall); From cef84bb274a126fe291d3593797c3d3edcf7dab1 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Wed, 15 Nov 2023 13:46:49 -0800 Subject: [PATCH 23/31] door refactor --- Elements/src/Door.cs | 68 +++++++------------ .../JSON/JsonInheritanceConverter.cs | 1 - 2 files changed, 24 insertions(+), 45 deletions(-) diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index 43122c3c4..5c4545db2 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -10,21 +10,15 @@ namespace Elements /// Definition of a door public class Door : GeometricElement { - private readonly Material DEFAULT_MATERIAL = new Material("Door material", Colors.White); + private readonly Material DEFAULT_MATERIAL = BuiltInMaterials.Wood; + private readonly Material FRAME_MATERIAL = new Material(Colors.Gray, 0.5, 0.25, false, null, false, false, null, false, null, 0, false, default, "Silver Frame"); - /// - /// Default thickness of a door. - /// + /// Default thickness of a door. public const double DOOR_THICKNESS = 1.375 * 0.0254; - /// - /// Default thickness of a door frame. - /// + /// Default thickness of a door frame. public const double DOOR_FRAME_THICKNESS = 4 * 0.0254; - /// - /// Default width of a door frame. - /// + /// Default width of a door frame. public const double DOOR_FRAME_WIDTH = 2 * 0.0254; //2 inches - /// Door width without a frame public double ClearWidth { get; private set; } /// The opening type of the door that should be placed @@ -35,10 +29,11 @@ public class Door : GeometricElement public double ClearHeight { get; private set; } /// Door thickness. public double Thickness { get; private set; } - + /// Original position of the door used for override identity public Vector3 OriginalPosition { get; set; } - private readonly double _fullDoorWidthWithoutFrame; + [JsonIgnore] + private double fullDoorWidthWithoutFrame => GetDoorFullWidthWithoutFrame(ClearWidth, OpeningSide); /// /// Create a door. @@ -80,7 +75,6 @@ public Door(double clearWidth, ClearWidth = clearWidth; Thickness = thickness; Material = material ?? DEFAULT_MATERIAL; - _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(clearWidth, openingSide); } /// @@ -123,7 +117,6 @@ public Door(Line line, ClearHeight = clearHeight; Thickness = thickness; Material = material ?? DEFAULT_MATERIAL; - _fullDoorWidthWithoutFrame = GetDoorFullWidthWithoutFrame(ClearWidth, openingSide); Transform = GetDoorTransform(line.PointAtNormalized(tPos), line); } @@ -136,7 +129,7 @@ public Door(Line line, /// An opening where the door can be inserted. public Opening CreateDoorOpening(double depthFront, double depthBack, bool flip) { - var openingWidth = _fullDoorWidthWithoutFrame + 2 * DOOR_FRAME_WIDTH; + var openingWidth = fullDoorWidthWithoutFrame + 2 * DOOR_FRAME_WIDTH; var openingHeight = ClearHeight + DOOR_FRAME_WIDTH; var openingDir = flip ? Vector3.YAxis.Negate() : Vector3.YAxis; @@ -173,7 +166,6 @@ public override void UpdateRepresentations() RepresentationInstances = this.GetInstances(this); } - public List GetInstances(Door door) { var representationInstances = new List() @@ -188,7 +180,7 @@ public List GetInstances(Door door) private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) { - var fullWidth = _fullDoorWidthWithoutFrame + DOOR_FRAME_WIDTH * 2; + var fullWidth = fullDoorWidthWithoutFrame + DOOR_FRAME_WIDTH * 2; double wallWidth = wallLine.Length(); Vector3 p1 = wallLine.PointAt(0.5 * fullWidth); Vector3 p2 = wallLine.PointAt(wallWidth - 0.5 * fullWidth); @@ -196,11 +188,6 @@ private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) return currentPosition.ClosestPointOn(reducedWallLine); } - internal double GetFullDoorWidthWithoutFrame() - { - return _fullDoorWidthWithoutFrame; - } - private static double GetDoorFullWidthWithoutFrame(double doorClearWidth, DoorOpeningSide doorOpeningSide) { switch (doorOpeningSide) @@ -215,7 +202,7 @@ private static double GetDoorFullWidthWithoutFrame(double doorClearWidth, DoorOp } - public RepresentationInstance CreateDoorCurveRepresentation() + private RepresentationInstance CreateDoorCurveRepresentation() { var points = CollectPointsForSchematicVisualization(); var curve = new IndexedPolycurve(points); @@ -224,9 +211,8 @@ public RepresentationInstance CreateDoorCurveRepresentation() return repInstance; } - public RepresentationInstance CreateDoorFrameRepresentation() + private RepresentationInstance CreateDoorFrameRepresentation() { - double fullDoorWidthWithoutFrame = this.GetFullDoorWidthWithoutFrame(); Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); @@ -234,25 +220,23 @@ public RepresentationInstance CreateDoorFrameRepresentation() var frameRight = right - Vector3.XAxis * Door.DOOR_FRAME_WIDTH; var frameOffset = Vector3.YAxis * Door.DOOR_FRAME_THICKNESS; var doorFramePolygon = new Polygon(new List() { - left + Vector3.ZAxis * this.ClearHeight - frameOffset, - left - frameOffset, - frameLeft - frameOffset, - frameLeft + Vector3.ZAxis * (this.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, - frameRight + Vector3.ZAxis * (this.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, - frameRight - frameOffset, - right - frameOffset, - right + Vector3.ZAxis * this.ClearHeight - frameOffset }); + left + Vector3.ZAxis * this.ClearHeight - frameOffset, + left - frameOffset, + frameLeft - frameOffset, + frameLeft + Vector3.ZAxis * (this.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, + frameRight + Vector3.ZAxis * (this.ClearHeight + Door.DOOR_FRAME_WIDTH) - frameOffset, + frameRight - frameOffset, + right - frameOffset, + right + Vector3.ZAxis * this.ClearHeight - frameOffset }); var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), Door.DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); var solidRep = new SolidRepresentation(doorFrameExtrude); - var repInstance = new RepresentationInstance(solidRep, this.Material, true); + var repInstance = new RepresentationInstance(solidRep, FRAME_MATERIAL, true); return repInstance; } - public RepresentationInstance CreateDoorSolidRepresentation() + private RepresentationInstance CreateDoorSolidRepresentation() { - double fullDoorWidthWithoutFrame = this.GetFullDoorWidthWithoutFrame(); - Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); @@ -286,7 +270,7 @@ public RepresentationInstance CreateDoorSolidRepresentation() return repInstance; } - public List CollectPointsForSchematicVisualization() + private List CollectPointsForSchematicVisualization() { var points = new List(); @@ -323,10 +307,8 @@ public List CollectPointsForSchematicVisualization() return points; } - private static List CollectSchematicVisualizationLines(Door door, bool leftSide, bool inside, double angle) + private List CollectSchematicVisualizationLines(Door door, bool leftSide, bool inside, double angle) { - var fullDoorWidthWithoutFrame = door.GetFullDoorWidthWithoutFrame(); - // Depending on which side door in there are different offsets. var doorOffset = leftSide ? fullDoorWidthWithoutFrame / 2 : -fullDoorWidthWithoutFrame / 2; var horizontalOffset = leftSide ? door.Thickness : -door.Thickness; @@ -416,6 +398,4 @@ public enum DoorOpeningType [System.Runtime.Serialization.EnumMember(Value = @"Double Swing")] DoubleSwing } - - } diff --git a/Elements/src/Serialization/JSON/JsonInheritanceConverter.cs b/Elements/src/Serialization/JSON/JsonInheritanceConverter.cs index 7604f8bb5..366201115 100644 --- a/Elements/src/Serialization/JSON/JsonInheritanceConverter.cs +++ b/Elements/src/Serialization/JSON/JsonInheritanceConverter.cs @@ -295,7 +295,6 @@ public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type o if (discriminator != null) { - return null; throw new Exception($"An object with the discriminator, {discriminator}, could not be deserialized. {baseMessage} {moreInfoMessage}", ex); } else From a5febf9f4bf44b27d7ab9afcf0645e7ec29ba402 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Thu, 16 Nov 2023 08:09:27 -0800 Subject: [PATCH 24/31] format comments --- Elements/src/Door.cs | 10 +++++----- Elements/src/StandardWall.cs | 2 -- Elements/test/DoorTest.cs | 6 ++++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Elements/src/Door.cs b/Elements/src/Door.cs index 5c4545db2..5a06f9fa7 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/Door.cs @@ -169,11 +169,11 @@ public override void UpdateRepresentations() public List GetInstances(Door door) { var representationInstances = new List() - { - this.CreateDoorSolidRepresentation(), - this.CreateDoorFrameRepresentation(), - this.CreateDoorCurveRepresentation() - }; + { + this.CreateDoorSolidRepresentation(), + this.CreateDoorFrameRepresentation(), + this.CreateDoorCurveRepresentation() + }; return representationInstances; } diff --git a/Elements/src/StandardWall.cs b/Elements/src/StandardWall.cs index 5dd72c640..4df80717b 100644 --- a/Elements/src/StandardWall.cs +++ b/Elements/src/StandardWall.cs @@ -117,9 +117,7 @@ public Opening AddOpening(Polygon perimeter, double x, double y, double depthFro private Transform GetOpeningTransform(double x, double y) { var xAxis = this.CenterLine.Direction(); - // Opening transform is still off... `outOfPlane` added because transform is not working correctly var outOfPlane = xAxis.Cross(Vector3.ZAxis); - // Opening transform is still off? var openingTransform = new Transform(this.CenterLine.Start + xAxis * x + Vector3.ZAxis * y - outOfPlane, xAxis, xAxis.Cross(Vector3.ZAxis)); return openingTransform; } diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index 2a643fc3e..7b85b2d36 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -12,15 +12,17 @@ namespace Elements public class DoorTest : ModelTest { [Fact, Trait("Category", "Examples")] - public void Example() + public void MakeDoorElement() { - this.Name = "Elements_Door"; + this.Name = nameof(MakeDoorElement); var line = new Line(new Vector3(0, 0, 0), new Vector3(10, 10, 0)); var wall = new StandardWall(line, 0.1, 3.0); var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, Door.DOOR_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); wall.AddDoorOpening(door); + Assert.Single(wall.Openings); + this.Model.AddElement(wall); Model.AddElement(door); } From 209214be38673203722ddb2b7e762c92ce4ae9c0 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Thu, 16 Nov 2023 15:49:50 -0800 Subject: [PATCH 25/31] starting BIM folder and refactor Door namespace --- .../src/IFCElementExtensions.cs | 11 +++++---- .../Converters/FromIfcDoorConverter.cs | 1 + .../src/IFCToHypar/IFCExtensions.cs | 3 ++- Elements/src/{ => BIM/Door}/Door.cs | 24 +------------------ Elements/src/BIM/Door/DoorOpeningSide.cs | 14 +++++++++++ Elements/src/BIM/Door/DoorOpeningType.cs | 12 ++++++++++ Elements/src/StandardWall.cs | 1 + Elements/test/DoorTest.cs | 6 +---- 8 files changed, 38 insertions(+), 34 deletions(-) rename Elements/src/{ => BIM/Door}/Door.cs (95%) create mode 100644 Elements/src/BIM/Door/DoorOpeningSide.cs create mode 100644 Elements/src/BIM/Door/DoorOpeningType.cs diff --git a/Elements.Serialization.IFC/src/IFCElementExtensions.cs b/Elements.Serialization.IFC/src/IFCElementExtensions.cs index 78d06159d..4dbbc29ad 100644 --- a/Elements.Serialization.IFC/src/IFCElementExtensions.cs +++ b/Elements.Serialization.IFC/src/IFCElementExtensions.cs @@ -5,6 +5,7 @@ using Elements.Geometry.Interfaces; using Elements.Geometry.Solids; using Elements.Interfaces; +using Elements.BIM; using IFC; namespace Elements.Serialization.IFC @@ -192,17 +193,17 @@ private static List AddSolidOperationToDocument(Document var ifcRepresentations = new List(); if (op is Sweep sweep) { - // Neither of these entities, which are part of the - // IFC4 specification, and which would allow a sweep - // along a curve, are supported by many applications + // Neither of these entities, which are part of the + // IFC4 specification, and which would allow a sweep + // along a curve, are supported by many applications // which are supposedly IFC4 compliant (Revit). For // Those applications where these entities appear, - // the rotation of the profile is often wrong or + // the rotation of the profile is often wrong or // inconsistent. // geom = sweep.ToIfcSurfaceCurveSweptAreaSolid(doc); // geom = sweep.ToIfcFixedReferenceSweptAreaSolid(geoElement.Transform, doc); - // Instead, we'll divide the curve and create a set of + // Instead, we'll divide the curve and create a set of // linear extrusions instead. Polyline pline; if (sweep.Curve is Line) diff --git a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs index 27a0bb539..977725f80 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs @@ -1,5 +1,6 @@ using Elements.Geometry; using Elements.Serialization.IFC.IFCToHypar.RepresentationsExtraction; +using Elements.BIM; using IFC; using System; using System.Collections.Generic; diff --git a/Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs b/Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs index 6a9417ac6..b4b2781fc 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs @@ -4,6 +4,7 @@ using Elements.Geometry; using Elements.Geometry.Interfaces; using Elements.Geometry.Solids; +using Elements.BIM; using IFC; namespace Elements.Serialization.IFC.IFCToHypar @@ -131,7 +132,7 @@ internal static ICurve ToCurve(this IfcParameterizedProfileDef profile) } else if (profile is IfcCircleProfileDef ifcCircle) { - var circle = new Circle((IfcLengthMeasure) ifcCircle.Radius); + var circle = new Circle((IfcLengthMeasure)ifcCircle.Radius); return circle.Transformed(transform); } else diff --git a/Elements/src/Door.cs b/Elements/src/BIM/Door/Door.cs similarity index 95% rename from Elements/src/Door.cs rename to Elements/src/BIM/Door/Door.cs index 5a06f9fa7..b400e6c07 100644 --- a/Elements/src/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; using Elements.Geometry.Solids; -namespace Elements +namespace Elements.BIM { /// Definition of a door public class Door : GeometricElement @@ -376,26 +376,4 @@ private List CollectSchematicVisualizationLines(Door door, bool leftSid return points; } } - - public enum DoorOpeningSide - { - [System.Runtime.Serialization.EnumMember(Value = @"Undefined")] - Undefined, - [System.Runtime.Serialization.EnumMember(Value = @"Left Hand")] - LeftHand, - [System.Runtime.Serialization.EnumMember(Value = @"Right Hand")] - RightHand, - [System.Runtime.Serialization.EnumMember(Value = @"Double Door")] - DoubleDoor - } - - public enum DoorOpeningType - { - [System.Runtime.Serialization.EnumMember(Value = @"Undefined")] - Undefined, - [System.Runtime.Serialization.EnumMember(Value = @"Single Swing")] - SingleSwing, - [System.Runtime.Serialization.EnumMember(Value = @"Double Swing")] - DoubleSwing - } } diff --git a/Elements/src/BIM/Door/DoorOpeningSide.cs b/Elements/src/BIM/Door/DoorOpeningSide.cs new file mode 100644 index 000000000..0abaf037b --- /dev/null +++ b/Elements/src/BIM/Door/DoorOpeningSide.cs @@ -0,0 +1,14 @@ +namespace Elements.BIM +{ + public enum DoorOpeningSide + { + [System.Runtime.Serialization.EnumMember(Value = @"Undefined")] + Undefined, + [System.Runtime.Serialization.EnumMember(Value = @"Left Hand")] + LeftHand, + [System.Runtime.Serialization.EnumMember(Value = @"Right Hand")] + RightHand, + [System.Runtime.Serialization.EnumMember(Value = @"Double Door")] + DoubleDoor + } +} \ No newline at end of file diff --git a/Elements/src/BIM/Door/DoorOpeningType.cs b/Elements/src/BIM/Door/DoorOpeningType.cs new file mode 100644 index 000000000..847dc3cec --- /dev/null +++ b/Elements/src/BIM/Door/DoorOpeningType.cs @@ -0,0 +1,12 @@ +namespace Elements.BIM +{ + public enum DoorOpeningType + { + [System.Runtime.Serialization.EnumMember(Value = @"Undefined")] + Undefined, + [System.Runtime.Serialization.EnumMember(Value = @"Single Swing")] + SingleSwing, + [System.Runtime.Serialization.EnumMember(Value = @"Double Swing")] + DoubleSwing + } +} \ No newline at end of file diff --git a/Elements/src/StandardWall.cs b/Elements/src/StandardWall.cs index 4df80717b..f46bdaab3 100644 --- a/Elements/src/StandardWall.cs +++ b/Elements/src/StandardWall.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Elements.Geometry; using Elements.Geometry.Solids; +using Elements.BIM; namespace Elements { diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index 7b85b2d36..ca4a95fa4 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -1,10 +1,6 @@ using Elements.Geometry; using Elements.Tests; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Elements.BIM; using Xunit; namespace Elements From 45e7095e40421df544187692f11a103ec0bbdc91 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Fri, 17 Nov 2023 13:04:37 -0800 Subject: [PATCH 26/31] storage --- Elements/src/BIM/Door/Door.cs | 91 +++++++++++++++++-- .../src/BIM/Door/DoorRepresentationStorage.cs | 23 +++++ 2 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 Elements/src/BIM/Door/DoorRepresentationStorage.cs diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index b400e6c07..e383357c4 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -10,8 +10,13 @@ namespace Elements.BIM /// Definition of a door public class Door : GeometricElement { + private const double HANDLE_HEIGHT_POSITION = 42 * 0.0254; + private const double HANDLE_CIRCLE_RADIUS = 0.02; + private const double HANDLE_CYLINDER_RADIUS = 0.5 * HANDLE_CIRCLE_RADIUS; + private const double HANDLE_LENGTH = 6 * 0.0254; + private const double HANDLE_CYLINDER_HEIGHT = 0.05; private readonly Material DEFAULT_MATERIAL = BuiltInMaterials.Wood; - private readonly Material FRAME_MATERIAL = new Material(Colors.Gray, 0.5, 0.25, false, null, false, false, null, false, null, 0, false, default, "Silver Frame"); + private readonly Material SILVER_MATERIAL = new Material(Colors.Gray, 0.5, 0.25, false, null, false, false, null, false, null, 0, false, default, "Silver Frame"); /// Default thickness of a door. public const double DOOR_THICKNESS = 1.375 * 0.0254; @@ -34,7 +39,6 @@ public class Door : GeometricElement [JsonIgnore] private double fullDoorWidthWithoutFrame => GetDoorFullWidthWithoutFrame(ClearWidth, OpeningSide); - /// /// Create a door. /// @@ -163,16 +167,28 @@ public static bool CanFit(Line wallLine, DoorOpeningSide openingSide, double wid /// public override void UpdateRepresentations() { - RepresentationInstances = this.GetInstances(this); + if (RepresentationInstances.Count == 0) + { + DoorRepresentationStorage.SetDoorRepresentation(this); + } + } + + /// + /// Get Hash for representation storage dictionary + /// + public string GetRepresentationHash() + { + return $"{this.GetType().Name}-{this.ClearWidth}-{this.ClearHeight}-{this.Thickness}-{this.OpeningType}-{this.OpeningSide}-{this.Material.Name}"; } - public List GetInstances(Door door) + public List GetInstances() { var representationInstances = new List() { this.CreateDoorSolidRepresentation(), this.CreateDoorFrameRepresentation(), - this.CreateDoorCurveRepresentation() + this.CreateDoorCurveRepresentation(), + this.CreateDoorHandleRepresentation() }; return representationInstances; @@ -231,7 +247,7 @@ private RepresentationInstance CreateDoorFrameRepresentation() var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), Door.DOOR_FRAME_THICKNESS * 2, Vector3.YAxis); var solidRep = new SolidRepresentation(doorFrameExtrude); - var repInstance = new RepresentationInstance(solidRep, FRAME_MATERIAL, true); + var repInstance = new RepresentationInstance(solidRep, SILVER_MATERIAL, true); return repInstance; } @@ -375,5 +391,68 @@ private List CollectSchematicVisualizationLines(Door door, bool leftSid return points; } + + private RepresentationInstance CreateDoorHandleRepresentation() + { + var solidOperationsList = new List(); + + if (OpeningSide == DoorOpeningSide.DoubleDoor) + { + var handlePair1 = CreateHandlePair(-0.05, false); + solidOperationsList.AddRange(handlePair1); + + var handlePair2 = CreateHandlePair(0.05, true); + solidOperationsList.AddRange(handlePair2); + } + else if (OpeningSide != DoorOpeningSide.Undefined) + { + var xPos = OpeningSide == DoorOpeningSide.LeftHand ? -0.45 : 0.45; + var handle = CreateHandlePair(xPos, OpeningSide == DoorOpeningSide.LeftHand); + solidOperationsList.AddRange(handle); + } + + var solidRep = new SolidRepresentation(solidOperationsList); + var repInst = new RepresentationInstance(solidRep, SILVER_MATERIAL); + return repInst; + } + + private List CreateHandlePair(double xRelPos, bool isCodirectionalToX) + { + var xOffset = xRelPos * ClearWidth * Vector3.XAxis; + var yOffset = Thickness * Vector3.YAxis; + var zOffset = HANDLE_HEIGHT_POSITION * Vector3.ZAxis; + + var solidOperationsList = new List(); + var handleDir = isCodirectionalToX ? Vector3.XAxis : Vector3.XAxis.Negate(); + + var handleOrigin1 = xOffset + yOffset + zOffset; + var handle1Ops = CreateHandle(handleOrigin1, handleDir, Vector3.YAxis); + solidOperationsList.AddRange(handle1Ops); + + var handleOrigin2 = xOffset - yOffset + zOffset; + var handle2Ops = CreateHandle(handleOrigin2, handleDir, Vector3.YAxis.Negate()); + solidOperationsList.AddRange(handle2Ops); + + return solidOperationsList; + } + + private List CreateHandle(Vector3 origin, Vector3 handleDir, Vector3 yDir) + { + var circleTransform = new Transform(origin, handleDir, yDir); + var circle = new Circle(circleTransform, HANDLE_CIRCLE_RADIUS).ToPolygon(); + var circleOperation = new Extrude(circle, 0.1 * HANDLE_CYLINDER_HEIGHT, yDir); + + var cyl1Transform = new Transform(origin + 0.1 * HANDLE_CYLINDER_HEIGHT * yDir, handleDir, yDir); + var cyl1Circle = new Circle(cyl1Transform, HANDLE_CYLINDER_RADIUS).ToPolygon(); + var cyl1Operation = new Extrude(cyl1Circle, 0.9 * HANDLE_CYLINDER_HEIGHT, yDir); + + var cyl2Origin = cyl1Transform.Origin + cyl1Operation.Height * yDir + handleDir.Negate() * HANDLE_CYLINDER_RADIUS; + var cyl2Transform = new Transform(cyl2Origin, handleDir); + var cyl2Circle = new Circle(cyl2Transform, HANDLE_CYLINDER_RADIUS).ToPolygon(); + var cyl2Operation = new Extrude(cyl2Circle, HANDLE_LENGTH, handleDir); + + var handleSolids = new List() { circleOperation, cyl1Operation, cyl2Operation }; + return handleSolids; + } } } diff --git a/Elements/src/BIM/Door/DoorRepresentationStorage.cs b/Elements/src/BIM/Door/DoorRepresentationStorage.cs new file mode 100644 index 000000000..a1430751b --- /dev/null +++ b/Elements/src/BIM/Door/DoorRepresentationStorage.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using Elements.Geometry.Solids; + +namespace Elements.BIM +{ + static class DoorRepresentationStorage + { + private static readonly Dictionary> _fittings = new Dictionary>(); + public static Dictionary> Fittings => _fittings; + + public static void SetDoorRepresentation(Door door) + { + var hash = door.GetRepresentationHash(); + if (!_fittings.ContainsKey(hash)) + { + _fittings.Add(hash, door.GetInstances()); + } + door.RepresentationInstances = _fittings[hash]; + } + } + +} \ No newline at end of file From 92a342f9c38cd631c98a883a69d2ac98fe9bc9d9 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Fri, 17 Nov 2023 13:25:26 -0800 Subject: [PATCH 27/31] no bim --- Elements/src/BIM/Door/Door.cs | 11 ++++++----- Elements/src/BIM/Door/DoorOpeningSide.cs | 2 +- Elements/src/BIM/Door/DoorOpeningType.cs | 2 +- Elements/src/BIM/Door/DoorRepresentationStorage.cs | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index e383357c4..98edd0b08 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; using Elements.Geometry.Solids; -namespace Elements.BIM +namespace Elements { /// Definition of a door public class Door : GeometricElement @@ -224,6 +224,7 @@ private RepresentationInstance CreateDoorCurveRepresentation() var curve = new IndexedPolycurve(points); var curveRep = new CurveRepresentation(curve, false); var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + return repInstance; } @@ -257,10 +258,10 @@ private RepresentationInstance CreateDoorSolidRepresentation() Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); var doorPolygon = new Polygon(new List() { - left + Vector3.YAxis * this.Thickness, - left - Vector3.YAxis * this.Thickness, - right - Vector3.YAxis * this.Thickness, - right + Vector3.YAxis * this.Thickness}); + left + Vector3.YAxis * this.Thickness, + left - Vector3.YAxis * this.Thickness, + right - Vector3.YAxis * this.Thickness, + right + Vector3.YAxis * this.Thickness}); var doorPolygons = new List(); diff --git a/Elements/src/BIM/Door/DoorOpeningSide.cs b/Elements/src/BIM/Door/DoorOpeningSide.cs index 0abaf037b..b33dbe5fe 100644 --- a/Elements/src/BIM/Door/DoorOpeningSide.cs +++ b/Elements/src/BIM/Door/DoorOpeningSide.cs @@ -1,4 +1,4 @@ -namespace Elements.BIM +namespace Elements { public enum DoorOpeningSide { diff --git a/Elements/src/BIM/Door/DoorOpeningType.cs b/Elements/src/BIM/Door/DoorOpeningType.cs index 847dc3cec..85d893788 100644 --- a/Elements/src/BIM/Door/DoorOpeningType.cs +++ b/Elements/src/BIM/Door/DoorOpeningType.cs @@ -1,4 +1,4 @@ -namespace Elements.BIM +namespace Elements { public enum DoorOpeningType { diff --git a/Elements/src/BIM/Door/DoorRepresentationStorage.cs b/Elements/src/BIM/Door/DoorRepresentationStorage.cs index a1430751b..1d409dbf9 100644 --- a/Elements/src/BIM/Door/DoorRepresentationStorage.cs +++ b/Elements/src/BIM/Door/DoorRepresentationStorage.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Elements.Geometry.Solids; -namespace Elements.BIM +namespace Elements { static class DoorRepresentationStorage { From af64a8c5e31c20eaac8bc8ca8eedb506115c3029 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Fri, 17 Nov 2023 13:27:05 -0800 Subject: [PATCH 28/31] revert BIM namespace --- Elements.Serialization.IFC/src/IFCElementExtensions.cs | 2 +- .../src/IFCToHypar/Converters/FromIfcDoorConverter.cs | 2 +- Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs | 2 +- Elements/src/StandardWall.cs | 2 +- Elements/test/DoorTest.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Elements.Serialization.IFC/src/IFCElementExtensions.cs b/Elements.Serialization.IFC/src/IFCElementExtensions.cs index 4dbbc29ad..5c060a0ad 100644 --- a/Elements.Serialization.IFC/src/IFCElementExtensions.cs +++ b/Elements.Serialization.IFC/src/IFCElementExtensions.cs @@ -5,7 +5,7 @@ using Elements.Geometry.Interfaces; using Elements.Geometry.Solids; using Elements.Interfaces; -using Elements.BIM; +using Elements; using IFC; namespace Elements.Serialization.IFC diff --git a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs index 977725f80..878769aeb 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs @@ -1,6 +1,6 @@ using Elements.Geometry; using Elements.Serialization.IFC.IFCToHypar.RepresentationsExtraction; -using Elements.BIM; +using Elements; using IFC; using System; using System.Collections.Generic; diff --git a/Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs b/Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs index b4b2781fc..63e52c2f1 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/IFCExtensions.cs @@ -4,7 +4,7 @@ using Elements.Geometry; using Elements.Geometry.Interfaces; using Elements.Geometry.Solids; -using Elements.BIM; +using Elements; using IFC; namespace Elements.Serialization.IFC.IFCToHypar diff --git a/Elements/src/StandardWall.cs b/Elements/src/StandardWall.cs index f46bdaab3..bebe933e4 100644 --- a/Elements/src/StandardWall.cs +++ b/Elements/src/StandardWall.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Elements.Geometry; using Elements.Geometry.Solids; -using Elements.BIM; +using Elements; namespace Elements { diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index ca4a95fa4..a4ee8ace6 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -1,6 +1,6 @@ using Elements.Geometry; using Elements.Tests; -using Elements.BIM; +using Elements; using Xunit; namespace Elements From f3e9129e182b540739f885a867dab8f7235270ea Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Fri, 17 Nov 2023 14:51:40 -0800 Subject: [PATCH 29/31] handles n stuff --- Elements/src/BIM/Door/Door.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index 98edd0b08..b69e7f049 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -11,10 +11,10 @@ namespace Elements public class Door : GeometricElement { private const double HANDLE_HEIGHT_POSITION = 42 * 0.0254; - private const double HANDLE_CIRCLE_RADIUS = 0.02; - private const double HANDLE_CYLINDER_RADIUS = 0.5 * HANDLE_CIRCLE_RADIUS; - private const double HANDLE_LENGTH = 6 * 0.0254; - private const double HANDLE_CYLINDER_HEIGHT = 0.05; + private const double HANDLE_CIRCLE_RADIUS = 1.35 * 0.0254; + private const double HANDLE_CYLINDER_RADIUS = 0.45 * 0.0254; + private const double HANDLE_LENGTH = 5 * 0.0254; + private const double HANDLE_CYLINDER_HEIGHT = 2 * 0.0254; private readonly Material DEFAULT_MATERIAL = BuiltInMaterials.Wood; private readonly Material SILVER_MATERIAL = new Material(Colors.Gray, 0.5, 0.25, false, null, false, false, null, false, null, 0, false, default, "Silver Frame"); @@ -399,15 +399,15 @@ private RepresentationInstance CreateDoorHandleRepresentation() if (OpeningSide == DoorOpeningSide.DoubleDoor) { - var handlePair1 = CreateHandlePair(-0.05, false); + var handlePair1 = CreateHandlePair(-3 * 0.0254, false); solidOperationsList.AddRange(handlePair1); - var handlePair2 = CreateHandlePair(0.05, true); + var handlePair2 = CreateHandlePair(3 * 0.0254, true); solidOperationsList.AddRange(handlePair2); } else if (OpeningSide != DoorOpeningSide.Undefined) { - var xPos = OpeningSide == DoorOpeningSide.LeftHand ? -0.45 : 0.45; + var xPos = OpeningSide == DoorOpeningSide.LeftHand ? -(fullDoorWidthWithoutFrame / 2 - 2 * 0.0254) : (fullDoorWidthWithoutFrame / 2 - 2 * 0.0254); var handle = CreateHandlePair(xPos, OpeningSide == DoorOpeningSide.LeftHand); solidOperationsList.AddRange(handle); } From 349d09540ff022d4e56c73e56bb1a1b32fc43f2f Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Mon, 20 Nov 2023 09:37:56 -0800 Subject: [PATCH 30/31] rename --- Elements/src/BIM/Door/DoorRepresentationStorage.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Elements/src/BIM/Door/DoorRepresentationStorage.cs b/Elements/src/BIM/Door/DoorRepresentationStorage.cs index 1d409dbf9..2b01c4b56 100644 --- a/Elements/src/BIM/Door/DoorRepresentationStorage.cs +++ b/Elements/src/BIM/Door/DoorRepresentationStorage.cs @@ -6,17 +6,17 @@ namespace Elements { static class DoorRepresentationStorage { - private static readonly Dictionary> _fittings = new Dictionary>(); - public static Dictionary> Fittings => _fittings; + private static readonly Dictionary> _doors = new Dictionary>(); + public static Dictionary> Doors => _doors; public static void SetDoorRepresentation(Door door) { var hash = door.GetRepresentationHash(); - if (!_fittings.ContainsKey(hash)) + if (!_doors.ContainsKey(hash)) { - _fittings.Add(hash, door.GetInstances()); + _doors.Add(hash, door.GetInstances()); } - door.RepresentationInstances = _fittings[hash]; + door.RepresentationInstances = _doors[hash]; } } From f4e1965ebb5d6559214c1962c585f1da138a587a Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Mon, 20 Nov 2023 11:03:38 -0800 Subject: [PATCH 31/31] test update --- Elements.Serialization.IFC/test/IFCTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index 65ee50106..ad077c6db 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -138,8 +138,8 @@ public void Doors() var wall1 = new StandardWall(wallLine1, 0.2, 3, name: "Wall1"); var wall2 = new StandardWall(wallLine2, 0.2, 2, name: "Wall2"); - var door1 = new Door(wallLine1, 0.5, 1.5, 2.0, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); - var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, Door.DOOR_DEFAULT_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door1 = new Door(wallLine1, 0.5, 1.5, 2.0, Door.DOOR_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, Door.DOOR_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); wall1.AddDoorOpening(door1); wall2.AddDoorOpening(door2);