From d1631b6cd7748d1a300b53d2a3c6147ef66c4f24 Mon Sep 17 00:00:00 2001 From: Dmytro Muravskyi Date: Fri, 21 Jul 2023 16:40:25 +0300 Subject: [PATCH] Doors: add 2D visualization by using TryToGraphicsBuffers override --- LayoutFunctions/Doors/dependencies/Door.cs | 96 ++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/LayoutFunctions/Doors/dependencies/Door.cs b/LayoutFunctions/Doors/dependencies/Door.cs index 09cf1c42..dcb11727 100644 --- a/LayoutFunctions/Doors/dependencies/Door.cs +++ b/LayoutFunctions/Doors/dependencies/Door.cs @@ -29,6 +29,102 @@ public static bool CanFit(Line wallLine, DoorType type, double width) return wallLine.Length() - doorWidth > DOOR_FRAME_WIDTH * 2; } + public override bool TryToGraphicsBuffers(out List graphicsBuffers, out string id, out glTFLoader.Schema.MeshPrimitive.ModeEnum? mode) + { + List points = new List(); + points.AddRange(DoorSchema(true, false, 90)); + if( Type == DoorType.Double) + { + points.AddRange(DoorSchema(false, false, 90)); + } + + 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 = $"{this.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; + } + + private List DoorSchema(bool leftSide, bool inside, double angle) + { + var doorWidth = Type == DoorType.Double ? ClearWidth / 2 : ClearWidth; + + // Depending on which side door in there are different offsets. + var doorOffset = leftSide ? ClearWidth / 2 : -ClearWidth / 2; + var horizontalOffset = leftSide ? DOOR_THICKNESS : -DOOR_THICKNESS; + var verticalOffset = inside ? DOOR_THICKNESS : -DOOR_THICKNESS; + var widthOffset = inside ? doorWidth : -doorWidth; + + // 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)) + { + Transform t = new Transform(); + double rotation = 90 - angle; + if (!leftSide) + { + rotation = -rotation; + } + + if (!inside) + { + rotation = -rotation; + } + + 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, doorWidth, 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 override void UpdateRepresentations() { Vector3 left = Vector3.XAxis * ClearWidth / 2;