From a89488a1b5658d228c0c7f61a9f039110663c969 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Wed, 22 Nov 2023 16:48:05 -0800 Subject: [PATCH 1/8] rename and make properties accessible --- .../src/IFCElementExtensions.cs | 4 +- .../Converters/FromIfcDoorConverter.cs | 3 +- Elements.Serialization.IFC/test/IFCTests.cs | 4 +- Elements/src/BIM/Door/Door.cs | 167 +++++++++--------- .../src/BIM/Door/DoorRepresentationStorage.cs | 2 +- Elements/test/DoorTest.cs | 2 +- 6 files changed, 92 insertions(+), 90 deletions(-) diff --git a/Elements.Serialization.IFC/src/IFCElementExtensions.cs b/Elements.Serialization.IFC/src/IFCElementExtensions.cs index 5c060a0ad..063fdcdc9 100644 --- a/Elements.Serialization.IFC/src/IFCElementExtensions.cs +++ b/Elements.Serialization.IFC/src/IFCElementExtensions.cs @@ -274,8 +274,8 @@ private static IfcDoor ToIfc(this Door door, Guid id, IfcLocalPlacement localPla localPlacement, shape, null, - new IfcPositiveLengthMeasure(new IfcLengthMeasure(door.ClearHeight)), - new IfcPositiveLengthMeasure(new IfcLengthMeasure(door.ClearWidth)), + new IfcPositiveLengthMeasure(new IfcLengthMeasure(door.DoorHeight)), + new IfcPositiveLengthMeasure(new IfcLengthMeasure(door.DoorWidth)), IfcDoorTypeEnum.DOOR, door.GetIfcDoorTypeOperation(), null diff --git a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs index 878769aeb..f038fe230 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs @@ -37,10 +37,11 @@ public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationDa //var wall = GetWallFromDoor(ifcDoor, allWalls); var doorWidth = (IfcLengthMeasure)ifcDoor.OverallWidth; var doorHeight = (IfcLengthMeasure)ifcDoor.OverallHeight; + var doorThickness = 2 * 0.0254; var result = new Door(doorWidth, doorHeight, - Door.DOOR_THICKNESS, + doorThickness, openingSide, openingType, repData.Transform, diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index ad077c6db..77ea7f01b 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_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); - var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, Door.DOOR_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door1 = new Door(wallLine1, 0.5, 1.5, 2.0, 2 * 0.0254, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, 2 * 0.0254, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); wall1.AddDoorOpening(door1); wall2.AddDoorOpening(door2); diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index b69e7f049..c1e01e828 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -4,41 +4,47 @@ using System.Text; using Newtonsoft.Json; using Elements.Geometry.Solids; +using System.Linq; namespace Elements { /// Definition of a door public class Door : GeometricElement { - private const double HANDLE_HEIGHT_POSITION = 42 * 0.0254; - 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"); - - /// Default thickness of a door. - public const double DOOR_THICKNESS = 1.375 * 0.0254; - /// Default thickness of a door frame. - public const double DOOR_FRAME_THICKNESS = 4 * 0.0254; - /// 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; } + public Material FrameMaterial { get; set; } = new Material(Colors.Gray, 0.5, 0.25, false, null, false, false, null, false, null, 0, false, default, "Silver Frame"); + /// The opening type of the door that should be placed + [JsonProperty("Door Opening Type")] public DoorOpeningType OpeningType { get; private set; } /// The opening side of the door that should be placed + [JsonProperty("Door Opening Side")] public DoorOpeningSide OpeningSide { get; private set; } + /// Width of a door without a frame. + public double DoorWidth { get; set; } /// Height of a door without a frame. - public double ClearHeight { get; private set; } + public double DoorHeight { get; set; } /// Door thickness. - public double Thickness { get; private set; } + public double DoorThickness { get; set; } + /// Default thickness of a door frame. + public double FrameDepth { get; set; } = 4 * 0.0254; + /// Default width of a door frame. + public double FrameWidth { get; set; } = 2 * 0.0254; //2 inches + + /// Height of the door handle from the ground + public double HandleHeight { get; set; } = 42 * 0.0254; + /// Radius of the fixture against the door + public double HandleBaseRadius { get; set; } = 1.35 * 0.0254; + /// Radius of the handle + public double HandleRadius { get; set; } = 0.45 * 0.0254; + /// Length of the handle + public double HandleLength { get; set; } = 5 * 0.0254; + /// Depth of the handle from the face of the door + public double HandleDepth { get; set; } = 2 * 0.0254; /// Original position of the door used for override identity public Vector3 OriginalPosition { get; set; } [JsonIgnore] - private double fullDoorWidthWithoutFrame => GetDoorFullWidthWithoutFrame(ClearWidth, OpeningSide); + private double FullDoorWidthWithoutFrame => GetDoorFullWidthWithoutFrame(); /// /// Create a door. /// @@ -75,10 +81,10 @@ public Door(double clearWidth, { OpeningSide = openingSide; OpeningType = openingType; - ClearHeight = clearHeight; - ClearWidth = clearWidth; - Thickness = thickness; - Material = material ?? DEFAULT_MATERIAL; + DoorHeight = clearHeight; + DoorWidth = clearWidth; + DoorThickness = thickness; + Material = material; } /// @@ -117,10 +123,10 @@ public Door(Line line, { OpeningType = openingType; OpeningSide = openingSide; - ClearWidth = clearWidth; - ClearHeight = clearHeight; - Thickness = thickness; - Material = material ?? DEFAULT_MATERIAL; + DoorWidth = clearWidth; + DoorHeight = clearHeight; + DoorThickness = thickness; + Material = material; Transform = GetDoorTransform(line.PointAtNormalized(tPos), line); } @@ -133,8 +139,8 @@ 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 openingHeight = ClearHeight + DOOR_FRAME_WIDTH; + var openingWidth = FullDoorWidthWithoutFrame + 2 * FrameWidth; + var openingHeight = DoorHeight + FrameWidth; var openingDir = flip ? Vector3.YAxis.Negate() : Vector3.YAxis; var widthDir = flip ? Vector3.XAxis.Negate() : Vector3.XAxis; @@ -153,15 +159,6 @@ private Transform GetDoorTransform(Vector3 currentPosition, Line wallLine) 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 = GetDoorFullWidthWithoutFrame(width, openingSide) + DOOR_FRAME_WIDTH * 2; - return wallLine.Length() - doorWidth > DOOR_FRAME_WIDTH * 2; - } - /// /// Update the representations. /// @@ -178,7 +175,7 @@ public override void UpdateRepresentations() /// public string GetRepresentationHash() { - return $"{this.GetType().Name}-{this.ClearWidth}-{this.ClearHeight}-{this.Thickness}-{this.OpeningType}-{this.OpeningSide}-{this.Material.Name}"; + return $"{this.GetType().Name}-{this.DoorWidth}-{this.DoorHeight}-{this.DoorThickness}-{this.FrameDepth}-{this.FrameWidth}{this.FrameMaterial}-{this.OpeningType}-{this.OpeningSide}-{this.Material.Name}"; } public List GetInstances() @@ -191,12 +188,12 @@ public List GetInstances() this.CreateDoorHandleRepresentation() }; - return representationInstances; + return representationInstances.Where(instance => instance != null).ToList(); } private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) { - var fullWidth = fullDoorWidthWithoutFrame + DOOR_FRAME_WIDTH * 2; + var fullWidth = FullDoorWidthWithoutFrame + FrameWidth * 2; double wallWidth = wallLine.Length(); Vector3 p1 = wallLine.PointAt(0.5 * fullWidth); Vector3 p2 = wallLine.PointAt(wallWidth - 0.5 * fullWidth); @@ -204,20 +201,19 @@ private Vector3 GetClosestValidDoorPos(Line wallLine, Vector3 currentPosition) return currentPosition.ClosestPointOn(reducedWallLine); } - private static double GetDoorFullWidthWithoutFrame(double doorClearWidth, DoorOpeningSide doorOpeningSide) + private double GetDoorFullWidthWithoutFrame() { - switch (doorOpeningSide) + switch (this.OpeningSide) { case DoorOpeningSide.LeftHand: case DoorOpeningSide.RightHand: - return doorClearWidth; + return this.DoorWidth; case DoorOpeningSide.DoubleDoor: - return doorClearWidth * 2; + return this.DoorWidth * 2; } return 0; } - private RepresentationInstance CreateDoorCurveRepresentation() { var points = CollectPointsForSchematicVisualization(); @@ -230,44 +226,49 @@ private RepresentationInstance CreateDoorCurveRepresentation() private RepresentationInstance CreateDoorFrameRepresentation() { - Vector3 left = Vector3.XAxis * (fullDoorWidthWithoutFrame / 2); - Vector3 right = Vector3.XAxis.Negate() * (fullDoorWidthWithoutFrame / 2); + if (FrameDepth == 0 || FrameWidth == 0) + { + return null; + } + + 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 frameLeft = left + Vector3.XAxis * this.FrameWidth; + var frameRight = right - Vector3.XAxis * this.FrameWidth; + var frameOffset = Vector3.YAxis * this.FrameDepth / 2; var doorFramePolygon = new Polygon(new List() { - left + Vector3.ZAxis * this.ClearHeight - frameOffset, + left + Vector3.ZAxis * this.DoorHeight - 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, + frameLeft + Vector3.ZAxis * (this.DoorHeight + this.FrameWidth) - frameOffset, + frameRight + Vector3.ZAxis * (this.DoorHeight + this.FrameWidth) - 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); + right + Vector3.ZAxis * this.DoorHeight - frameOffset }); + var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), this.FrameDepth, Vector3.YAxis); var solidRep = new SolidRepresentation(doorFrameExtrude); - var repInstance = new RepresentationInstance(solidRep, SILVER_MATERIAL, true); + var repInstance = new RepresentationInstance(solidRep, FrameMaterial, true); return repInstance; } private RepresentationInstance CreateDoorSolidRepresentation() { - 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 * this.Thickness, - left - Vector3.YAxis * this.Thickness, - right - Vector3.YAxis * this.Thickness, - right + Vector3.YAxis * this.Thickness}); + left + Vector3.YAxis * this.DoorThickness/2, + left - Vector3.YAxis * this.DoorThickness/2, + right - Vector3.YAxis * this.DoorThickness/2, + right + Vector3.YAxis * this.DoorThickness/2}); 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))); + doorPolygons = doorPolygon.Split(new Polyline(new Vector3(0, this.DoorThickness / 2, 0), new Vector3(0, -this.DoorThickness / 2, 0))); } else { @@ -278,7 +279,7 @@ private RepresentationInstance CreateDoorSolidRepresentation() foreach (var polygon in doorPolygons) { - var doorExtrude = new Extrude(new Profile(polygon.Offset(-0.005)[0]), this.ClearHeight, Vector3.ZAxis); + var doorExtrude = new Extrude(new Profile(polygon.Offset(-0.005)[0]), this.DoorHeight, Vector3.ZAxis); doorExtrusions.Add(doorExtrude); } @@ -327,10 +328,10 @@ private List CollectPointsForSchematicVisualization() private List CollectSchematicVisualizationLines(Door door, 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 ? door.ClearWidth : -door.ClearWidth; + var doorOffset = leftSide ? FullDoorWidthWithoutFrame / 2 : -FullDoorWidthWithoutFrame / 2; + var horizontalOffset = leftSide ? door.DoorThickness : -door.DoorThickness; + var verticalOffset = inside ? door.DoorThickness : -door.DoorThickness; + var widthOffset = inside ? door.DoorWidth : -door.DoorWidth; // Draw open door silhouette rectangle. Vector3 corner = Vector3.XAxis * doorOffset; @@ -382,7 +383,7 @@ private List CollectSchematicVisualizationLines(Door door, bool leftSid } // Draw the arc from closed door to opened door. - Arc arc = new Arc(c0, door.ClearWidth, anchorAngle, endAngle); + Arc arc = new Arc(c0, door.DoorWidth, anchorAngle, endAngle); var tessalatedArc = arc.ToPolyline((int)(Math.Abs(angle) / 2)); for (int i = 0; i < tessalatedArc.Vertices.Count - 1; i++) { @@ -407,21 +408,21 @@ private RepresentationInstance CreateDoorHandleRepresentation() } else if (OpeningSide != DoorOpeningSide.Undefined) { - var xPos = OpeningSide == DoorOpeningSide.LeftHand ? -(fullDoorWidthWithoutFrame / 2 - 2 * 0.0254) : (fullDoorWidthWithoutFrame / 2 - 2 * 0.0254); + 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); } var solidRep = new SolidRepresentation(solidOperationsList); - var repInst = new RepresentationInstance(solidRep, SILVER_MATERIAL); + var repInst = new RepresentationInstance(solidRep, FrameMaterial); 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 xOffset = xRelPos * DoorWidth * Vector3.XAxis; + var yOffset = DoorThickness * Vector3.YAxis; + var zOffset = HandleHeight * Vector3.ZAxis; var solidOperationsList = new List(); var handleDir = isCodirectionalToX ? Vector3.XAxis : Vector3.XAxis.Negate(); @@ -440,17 +441,17 @@ private List CreateHandlePair(double xRelPos, bool isCodirection 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 circle = new Circle(circleTransform, HandleBaseRadius).ToPolygon(); + var circleOperation = new Extrude(circle, 0.1 * HandleDepth, 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 cyl1Transform = new Transform(origin + 0.1 * HandleDepth * yDir, handleDir, yDir); + var cyl1Circle = new Circle(cyl1Transform, HandleRadius).ToPolygon(); + var cyl1Operation = new Extrude(cyl1Circle, 0.9 * HandleDepth, yDir); - var cyl2Origin = cyl1Transform.Origin + cyl1Operation.Height * yDir + handleDir.Negate() * HANDLE_CYLINDER_RADIUS; + var cyl2Origin = cyl1Transform.Origin + cyl1Operation.Height * yDir + handleDir.Negate() * HandleRadius; var cyl2Transform = new Transform(cyl2Origin, handleDir); - var cyl2Circle = new Circle(cyl2Transform, HANDLE_CYLINDER_RADIUS).ToPolygon(); - var cyl2Operation = new Extrude(cyl2Circle, HANDLE_LENGTH, handleDir); + var cyl2Circle = new Circle(cyl2Transform, HandleRadius).ToPolygon(); + var cyl2Operation = new Extrude(cyl2Circle, HandleLength, 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 index 2b01c4b56..93f39b015 100644 --- a/Elements/src/BIM/Door/DoorRepresentationStorage.cs +++ b/Elements/src/BIM/Door/DoorRepresentationStorage.cs @@ -4,7 +4,7 @@ namespace Elements { - static class DoorRepresentationStorage + public static class DoorRepresentationStorage { private static readonly Dictionary> _doors = new Dictionary>(); public static Dictionary> Doors => _doors; diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index a4ee8ace6..e241e87c2 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -14,7 +14,7 @@ public void 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); + var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, 2 * 0.0254, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); wall.AddDoorOpening(door); Assert.Single(wall.Openings); From c1399d9138e4ce905720a51971a9f02c228f58c9 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Tue, 28 Nov 2023 08:58:43 -0800 Subject: [PATCH 2/8] bring back constant --- .../src/IFCToHypar/Converters/FromIfcDoorConverter.cs | 2 +- Elements.Serialization.IFC/test/IFCTests.cs | 4 ++-- Elements/src/BIM/Door/Door.cs | 10 ++++++---- Elements/test/DoorTest.cs | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs index f038fe230..ab190b5c6 100644 --- a/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs +++ b/Elements.Serialization.IFC/src/IFCToHypar/Converters/FromIfcDoorConverter.cs @@ -37,7 +37,7 @@ public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationDa //var wall = GetWallFromDoor(ifcDoor, allWalls); var doorWidth = (IfcLengthMeasure)ifcDoor.OverallWidth; var doorHeight = (IfcLengthMeasure)ifcDoor.OverallHeight; - var doorThickness = 2 * 0.0254; + var doorThickness = Door.DEFAULT_DOOR_THICKNESS; var result = new Door(doorWidth, doorHeight, diff --git a/Elements.Serialization.IFC/test/IFCTests.cs b/Elements.Serialization.IFC/test/IFCTests.cs index 77ea7f01b..cd6a0d76f 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, 2 * 0.0254, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); - var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, 2 * 0.0254, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door1 = new Door(wallLine1, 0.5, 1.5, 2.0, Door.DEFAULT_DOOR_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); + var door2 = new Door(wallLine2, 0.5, 1.5, 1.8, Door.DEFAULT_DOOR_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.DoubleSwing); wall1.AddDoorOpening(door1); wall2.AddDoorOpening(door2); diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index c1e01e828..3ac461d7e 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -23,8 +23,10 @@ public class Door : GeometricElement public double DoorWidth { get; set; } /// Height of a door without a frame. public double DoorHeight { get; set; } + /// Default door thickness. + public static double DEFAULT_DOOR_THICKNESS = 2 * 0.0254; /// Door thickness. - public double DoorThickness { get; set; } + public double DoorThickness { get; set; } = DEFAULT_DOOR_THICKNESS; /// Default thickness of a door frame. public double FrameDepth { get; set; } = 4 * 0.0254; /// Default width of a door frame. @@ -84,7 +86,7 @@ public Door(double clearWidth, DoorHeight = clearHeight; DoorWidth = clearWidth; DoorThickness = thickness; - Material = material; + Material = material ?? BuiltInMaterials.Default; } /// @@ -126,7 +128,7 @@ public Door(Line line, DoorWidth = clearWidth; DoorHeight = clearHeight; DoorThickness = thickness; - Material = material; + Material = material ?? BuiltInMaterials.Default; Transform = GetDoorTransform(line.PointAtNormalized(tPos), line); } @@ -175,7 +177,7 @@ public override void UpdateRepresentations() /// public string GetRepresentationHash() { - return $"{this.GetType().Name}-{this.DoorWidth}-{this.DoorHeight}-{this.DoorThickness}-{this.FrameDepth}-{this.FrameWidth}{this.FrameMaterial}-{this.OpeningType}-{this.OpeningSide}-{this.Material.Name}"; + return $"{this.GetType().Name}-{this.DoorWidth}-{this.DoorHeight}-{this.DoorThickness}-{this.FrameDepth}-{this.FrameWidth}{this.FrameMaterial.Name}-{this.OpeningType}-{this.OpeningSide}-{this.Material.Name}"; } public List GetInstances() diff --git a/Elements/test/DoorTest.cs b/Elements/test/DoorTest.cs index e241e87c2..574171a85 100644 --- a/Elements/test/DoorTest.cs +++ b/Elements/test/DoorTest.cs @@ -14,7 +14,7 @@ public void 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, 2 * 0.0254, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); + var door = new Door(wall.CenterLine, 0.5, 2.0, 2.0, Door.DEFAULT_DOOR_THICKNESS, DoorOpeningSide.LeftHand, DoorOpeningType.SingleSwing); wall.AddDoorOpening(door); Assert.Single(wall.Openings); From d4dd8f290a8400201b31d47822b9261ba0962d77 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Tue, 28 Nov 2023 14:33:39 -0800 Subject: [PATCH 3/8] updating test because we added a representation to doors --- 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 cd6a0d76f..be4c104b1 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -39,7 +39,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", 1506, 5, 570, 121, 7, 82, 0, 21)] + [InlineData("AC20-Institute-Var-2", "../../../models/IFC4/AC20-Institute-Var-2.ifc", 1513, 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 17cb1d760662bd7ab0e39bf6527ff433eb96f4b2 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Tue, 28 Nov 2023 14:42:55 -0800 Subject: [PATCH 4/8] I thought this was updated... --- 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 be4c104b1..cc0900379 100644 --- a/Elements.Serialization.IFC/test/IFCTests.cs +++ b/Elements.Serialization.IFC/test/IFCTests.cs @@ -29,7 +29,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", 1963, 120, 530, 270, 9, 140, 10, 2)] + [InlineData("AC-20-Smiley-West-10-Bldg", "../../../models/IFC4/AC-20-Smiley-West-10-Bldg.ifc", 1972, 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. From 6b6cd3fb52d4f33f11917d9cf38f1f4a9036ba20 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Tue, 28 Nov 2023 16:22:48 -0800 Subject: [PATCH 5/8] Added methods to set and get snap points --- Elements/src/BIM/Door/Door.cs | 4 ++++ .../src/CoreModels/ElementRepresentation.cs | 22 ++++++++++++++++++- .../Representations/CurveRepresentation.cs | 3 ++- .../Representations/SolidRepresentation.cs | 4 ++-- .../src/Serialization/glTF/GltfExtensions.cs | 5 +++-- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index 3ac461d7e..781eac298 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -221,6 +221,7 @@ private RepresentationInstance CreateDoorCurveRepresentation() var points = CollectPointsForSchematicVisualization(); var curve = new IndexedPolycurve(points); var curveRep = new CurveRepresentation(curve, false); + curveRep.SetSnappingPoints(new List()); var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); return repInstance; @@ -251,6 +252,7 @@ private RepresentationInstance CreateDoorFrameRepresentation() var doorFrameExtrude = new Extrude(new Profile(doorFramePolygon), this.FrameDepth, Vector3.YAxis); var solidRep = new SolidRepresentation(doorFrameExtrude); + solidRep.SetSnappingPoints(new List()); var repInstance = new RepresentationInstance(solidRep, FrameMaterial, true); return repInstance; } @@ -286,6 +288,7 @@ private RepresentationInstance CreateDoorSolidRepresentation() } var solidRep = new SolidRepresentation(doorExtrusions); + solidRep.SetSnappingPoints(new List(new SnappingPoints[] { new SnappingPoints(new[] { left, Vector3.Origin, right }, SnappingEdgeMode.LineStrip) })); var repInstance = new RepresentationInstance(solidRep, this.Material, true); return repInstance; } @@ -416,6 +419,7 @@ private RepresentationInstance CreateDoorHandleRepresentation() } var solidRep = new SolidRepresentation(solidOperationsList); + solidRep.SetSnappingPoints(new List()); var repInst = new RepresentationInstance(solidRep, FrameMaterial); return repInst; } diff --git a/Elements/src/CoreModels/ElementRepresentation.cs b/Elements/src/CoreModels/ElementRepresentation.cs index 4545df75f..48748c350 100644 --- a/Elements/src/CoreModels/ElementRepresentation.cs +++ b/Elements/src/CoreModels/ElementRepresentation.cs @@ -9,6 +9,8 @@ /// public abstract class ElementRepresentation : SharedObject { + protected List _snapPoints; + /// /// Get graphics buffers and other metadata required to modify a GLB. /// @@ -28,12 +30,30 @@ internal virtual List GetNodeExtensions(GeometricElement element) return new List(); } + /// + /// Set the snapping points for this representation. + /// + public void SetSnappingPoints(List snapPoints) + { + _snapPoints = snapPoints; + } + + /// + /// Get the snapping points for this representation. Uses CreateSnappingPoints if _snapPoints is null. + /// + public List GetSnappingPoints(GeometricElement element) + { + if (_snapPoints == null) return CreateSnappingPoints(element); + return _snapPoints; + } + + /// ///Creates the set of snapping points /// /// The element with this representation. /// - public virtual List CreateSnappingPoints(GeometricElement element) + protected virtual List CreateSnappingPoints(GeometricElement element) { return new List(); } diff --git a/Elements/src/Representations/CurveRepresentation.cs b/Elements/src/Representations/CurveRepresentation.cs index aeaf61e16..3f799514a 100644 --- a/Elements/src/Representations/CurveRepresentation.cs +++ b/Elements/src/Representations/CurveRepresentation.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using Elements.Geometry; using glTFLoader.Schema; @@ -47,7 +48,7 @@ public override bool TryToGraphicsBuffers(GeometricElement element, out List - public override List CreateSnappingPoints(GeometricElement element) + protected override List CreateSnappingPoints(GeometricElement element) { var snappingPoints = new List(); var curvePoints = _curve.RenderVertices(); diff --git a/Elements/src/Representations/SolidRepresentation.cs b/Elements/src/Representations/SolidRepresentation.cs index d8521056c..f512c7155 100644 --- a/Elements/src/Representations/SolidRepresentation.cs +++ b/Elements/src/Representations/SolidRepresentation.cs @@ -12,7 +12,7 @@ namespace Elements { /// - /// + /// A solid representation of an element. /// public class SolidRepresentation : ElementRepresentation { @@ -193,7 +193,7 @@ public List> CalculateIntersectionPoints(GeometricElement element, } /// - public override List CreateSnappingPoints(GeometricElement element) + protected override List CreateSnappingPoints(GeometricElement element) { var snappingPoints = new List(); diff --git a/Elements/src/Serialization/glTF/GltfExtensions.cs b/Elements/src/Serialization/glTF/GltfExtensions.cs index 68d70c326..9937218bc 100644 --- a/Elements/src/Serialization/glTF/GltfExtensions.cs +++ b/Elements/src/Serialization/glTF/GltfExtensions.cs @@ -1341,8 +1341,9 @@ private static void GetRenderDataForElement(Element e, var meshIdList = new List { meshId }; representationsMap.Add(combinedId, meshIdList); addedNodes.AddRange(NodeUtilities.AddNodes(nodes, meshIdList, elementNodeId)); - var snappingPoints = representation.Representation.CreateSnappingPoints(element); - if (snappingPoints.Any()) + var snappingPoints = representation.Representation.GetSnappingPoints(element); + + if (snappingPoints != null) { AddExtension(gltf, meshes[meshId], "HYPAR_snapping_points", new Dictionary() { { "points", snappingPoints } }); } From c3beb99153536db1e4a41f548b193ccda5db52a1 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Wed, 29 Nov 2023 13:42:37 -0800 Subject: [PATCH 6/8] fix enums and representations --- Elements/src/BIM/Door/Door.cs | 75 +++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index 781eac298..b76c86b3c 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -11,17 +11,21 @@ namespace Elements /// Definition of a door public class Door : GeometricElement { + /// The material to be used on the door frame public Material FrameMaterial { get; set; } = new Material(Colors.Gray, 0.5, 0.25, false, null, false, false, null, false, null, 0, false, default, "Silver Frame"); - /// The opening type of the door that should be placed [JsonProperty("Door Opening Type")] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public DoorOpeningType OpeningType { get; private set; } /// The opening side of the door that should be placed [JsonProperty("Door Opening Side")] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public DoorOpeningSide OpeningSide { get; private set; } /// Width of a door without a frame. + [JsonProperty("Door Width")] public double DoorWidth { get; set; } /// Height of a door without a frame. + [JsonProperty("Door Height")] public double DoorHeight { get; set; } /// Default door thickness. public static double DEFAULT_DOOR_THICKNESS = 2 * 0.0254; @@ -31,7 +35,6 @@ public class Door : GeometricElement public double FrameDepth { get; set; } = 4 * 0.0254; /// Default width of a door frame. public double FrameWidth { get; set; } = 2 * 0.0254; //2 inches - /// Height of the door handle from the ground public double HandleHeight { get; set; } = 42 * 0.0254; /// Radius of the fixture against the door @@ -186,10 +189,11 @@ public List GetInstances() { this.CreateDoorSolidRepresentation(), this.CreateDoorFrameRepresentation(), - this.CreateDoorCurveRepresentation(), this.CreateDoorHandleRepresentation() }; + representationInstances.AddRange(this.CreateDoorCurveRepresentation()); + return representationInstances.Where(instance => instance != null).ToList(); } @@ -216,15 +220,11 @@ private double GetDoorFullWidthWithoutFrame() return 0; } - private RepresentationInstance CreateDoorCurveRepresentation() + private List CreateDoorCurveRepresentation() { - var points = CollectPointsForSchematicVisualization(); - var curve = new IndexedPolycurve(points); - var curveRep = new CurveRepresentation(curve, false); - curveRep.SetSnappingPoints(new List()); - var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + var repInstances = CollectPointsForSchematicVisualization(); - return repInstance; + return repInstances; } private RepresentationInstance CreateDoorFrameRepresentation() @@ -293,41 +293,64 @@ private RepresentationInstance CreateDoorSolidRepresentation() return repInstance; } - private List CollectPointsForSchematicVisualization() + private List CollectPointsForSchematicVisualization() { - var points = new List(); + var representationInstances = new List(); if (this.OpeningSide == DoorOpeningSide.Undefined || this.OpeningType == DoorOpeningType.Undefined) { - return points; + return representationInstances; } if (this.OpeningSide != DoorOpeningSide.LeftHand) { - points.AddRange(CollectSchematicVisualizationLines(this, false, false, 90)); + var points = CollectSchematicVisualizationLines(this, false, false, 90); + points.Add(points[0]); + var curve = new IndexedPolycurve(points); + var curveRep = new CurveRepresentation(curve, false); + curveRep.SetSnappingPoints(new List()); + var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + representationInstances.Add(repInstance); } if (this.OpeningSide != DoorOpeningSide.RightHand) { - points.AddRange(CollectSchematicVisualizationLines(this, true, false, 90)); + var points = CollectSchematicVisualizationLines(this, true, false, 90); + points.Add(points[0]); + var curve = new IndexedPolycurve(points); + var curveRep = new CurveRepresentation(curve, false); + curveRep.SetSnappingPoints(new List()); + var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + representationInstances.Add(repInstance); } - if (this.OpeningType == DoorOpeningType.SingleSwing) + if (this.OpeningType == DoorOpeningType.DoubleSwing) { - return points; - } - if (this.OpeningSide != DoorOpeningSide.LeftHand) - { - points.AddRange(CollectSchematicVisualizationLines(this, false, true, 90)); - } + if (this.OpeningSide != DoorOpeningSide.LeftHand) + { + var points = CollectSchematicVisualizationLines(this, false, true, 90); + points.Add(points[0]); + var curve = new IndexedPolycurve(points); + var curveRep = new CurveRepresentation(curve, false); + curveRep.SetSnappingPoints(new List()); + var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + representationInstances.Add(repInstance); + } - if (this.OpeningSide != DoorOpeningSide.RightHand) - { - points.AddRange(CollectSchematicVisualizationLines(this, true, true, 90)); + if (this.OpeningSide != DoorOpeningSide.RightHand) + { + var points = CollectSchematicVisualizationLines(this, true, true, 90); + points.Add(points[0]); + var curve = new IndexedPolycurve(points); + var curveRep = new CurveRepresentation(curve, false); + curveRep.SetSnappingPoints(new List()); + var repInstance = new RepresentationInstance(curveRep, BuiltInMaterials.Black); + representationInstances.Add(repInstance); + } } - return points; + return representationInstances; } private List CollectSchematicVisualizationLines(Door door, bool leftSide, bool inside, double angle) From 59f2e2044b32add2c65e4ae1c5c6581848f7c029 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Wed, 29 Nov 2023 14:10:50 -0800 Subject: [PATCH 7/8] Included door type override --- Elements/src/BIM/Door/Door.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index b76c86b3c..055e9fcf1 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -27,6 +27,8 @@ public class Door : GeometricElement /// Height of a door without a frame. [JsonProperty("Door Height")] public double DoorHeight { get; set; } + [JsonProperty("Door Type")] + public string DoorType { get; set; } /// Default door thickness. public static double DEFAULT_DOOR_THICKNESS = 2 * 0.0254; /// Door thickness. From 60b69e821eeda17b613e2a6b7aab1e12c7b40cb9 Mon Sep 17 00:00:00 2001 From: Anthonie Kramer Date: Wed, 29 Nov 2023 14:12:07 -0800 Subject: [PATCH 8/8] description --- Elements/src/BIM/Door/Door.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Elements/src/BIM/Door/Door.cs b/Elements/src/BIM/Door/Door.cs index 055e9fcf1..bba017140 100644 --- a/Elements/src/BIM/Door/Door.cs +++ b/Elements/src/BIM/Door/Door.cs @@ -27,6 +27,7 @@ public class Door : GeometricElement /// Height of a door without a frame. [JsonProperty("Door Height")] public double DoorHeight { get; set; } + /// Type of door (Glass or Solid). [JsonProperty("Door Type")] public string DoorType { get; set; } /// Default door thickness.