From 818f5f2c4d6fdd17c19d9a1189ee7c371fa7400a Mon Sep 17 00:00:00 2001
From: Andrew Heumann <andrew@heumann.com>
Date: Fri, 31 Jul 2020 08:37:50 -0400
Subject: [PATCH 1/4] fix for line trim where line starts on polygon edge

---
 src/Elements/Geometry/Line.cs                 |   6 +-
 test/Elements.Tests/LineTests.cs              |  24 ++++
 .../models/Geometry/ConcavePolygon.json       | 105 ++++++++++++++++++
 .../models/Geometry/LineThatFailsTrim.json    |  13 +++
 4 files changed, 145 insertions(+), 3 deletions(-)
 create mode 100644 test/Elements.Tests/models/Geometry/ConcavePolygon.json
 create mode 100644 test/Elements.Tests/models/Geometry/LineThatFailsTrim.json

diff --git a/src/Elements/Geometry/Line.cs b/src/Elements/Geometry/Line.cs
index 2bd3cb9a1..f4d2a3e06 100644
--- a/src/Elements/Geometry/Line.cs
+++ b/src/Elements/Geometry/Line.cs
@@ -1,4 +1,3 @@
-using Elements.Geometry.Interfaces;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -470,7 +469,8 @@ public List<Line> Trim(Polygon polygon, out List<Line> outsideSegments)
 
             // Add the segment's starting point.
             intersections.Add(this.Start);
-            var StartsOutsidePolygon = !polygon.Contains(this.Start);
+            polygon.Contains(this.Start, out var containment);
+            var StartsOutsidePolygon = containment == Containment.Outside;
 
             var hasVertexIntersections = false;
 
@@ -514,7 +514,7 @@ public List<Line> Trim(Polygon polygon, out List<Line> outsideSegments)
                     continue;
                 }
                 var segment = new Line(A, B);
-                if (hasVertexIntersections) // if it passed through a vertex, we can't rely on alternating, so check each midpoint
+                if (hasVertexIntersections || containment == Containment.CoincidesAtEdge) // if it passed through a vertex, or started at an edge, we can't rely on alternating, so check each midpoint
                 {
                     currentlyIn = polygon.Contains((A + B) / 2);
                 }
diff --git a/test/Elements.Tests/LineTests.cs b/test/Elements.Tests/LineTests.cs
index 3a0cd5f54..cbf42c84d 100644
--- a/test/Elements.Tests/LineTests.cs
+++ b/test/Elements.Tests/LineTests.cs
@@ -1,5 +1,8 @@
 using System;
+using System.Collections.Generic;
+using System.IO;
 using Elements.Tests;
+using Newtonsoft.Json;
 using Xunit;
 
 namespace Elements.Geometry.Tests
@@ -174,6 +177,27 @@ public void LineTrimToInYZ()
             Assert.NotNull(l3);
         }
 
+        [Fact]
+        public void ShortLineTrim()
+        {
+            var boundary = new Polygon(new[] { new Vector3(30.0596079459439, 28.2900892254263), new Vector3(30.0596079459439, 25.2563767254263), new Vector3(30.0596079459439, 12.5928892254263), new Vector3(45.7568079459439, 12.5928892254263), new Vector3(45.7568079459439, 13.7104892254263), new Vector3(54.4436079459439, 13.7104892254263), new Vector3(54.4436079459439, 12.5928892254264), new Vector3(70.1408079459439, 12.5928892254263), new Vector3(70.1408079459439, 40.4820892254263), new Vector3(67.0928079459439, 40.4820892254263), new Vector3(67.0928079459439, 46.5780892254262), new Vector3(33.1076079459439, 46.5780892254263), new Vector3(33.1076079459439, 28.2900892254263) });
+            var line = new Line(new Vector3(67.257907945943941, 46.208201725426342), new Vector3(66.595920445943946, 46.208201725426342));
+            var segmentsIn = line.Trim(boundary, out var segmentsOut);
+            var obj = new Dictionary<string, object> { { "SegmentsIn", segmentsIn }, { "SegmentsOut", segmentsOut } };
+            var json = JsonConvert.SerializeObject(obj);
+            
+        }
+
+        [Fact]
+        public void TrimLineThatStartsAtPolygonEdge()
+        {
+            var polygon = JsonConvert.DeserializeObject<Polygon>(File.ReadAllText("../../../models/Geometry/ConcavePolygon.json"));
+            var line = JsonConvert.DeserializeObject<Line>(File.ReadAllText("../../../models/Geometry/LineThatFailsTrim.json"));
+            var lines = line.Trim(polygon, out var _);
+
+            Assert.Equal(4.186147, lines[0].Length(), 2);
+        }
+
 
         [Fact]
         public void LineTrimWithPolygon()
diff --git a/test/Elements.Tests/models/Geometry/ConcavePolygon.json b/test/Elements.Tests/models/Geometry/ConcavePolygon.json
new file mode 100644
index 000000000..d36b23703
--- /dev/null
+++ b/test/Elements.Tests/models/Geometry/ConcavePolygon.json
@@ -0,0 +1,105 @@
+{
+    "discriminator": "Elements.Geometry.Polygon",
+    "Vertices": [
+        {
+            "X": -10.276991193869598,
+            "Y": -1.1511904595984275,
+            "Z": 0.0
+        },
+        {
+            "X": -3.1186796087302824,
+            "Y": -1.1511904595984301,
+            "Z": 0.0
+        },
+        {
+            "X": -3.1186796087302824,
+            "Y": 6.007121125540885,
+            "Z": 0.0
+        },
+        {
+            "X": 6.0908440680571374,
+            "Y": 6.007121125540885,
+            "Z": 0.0
+        },
+        {
+            "X": 6.0908440680571374,
+            "Y": 0.98374457456592879,
+            "Z": 0.0
+        },
+        {
+            "X": 10.6118829639346,
+            "Y": 0.98374457456592879,
+            "Z": 0.0
+        },
+        {
+            "X": 10.6118829639346,
+            "Y": -4.5001081602483968,
+            "Z": 0.0
+        },
+        {
+            "X": 14.002662135842693,
+            "Y": -4.5001081602483968,
+            "Z": 0.0
+        },
+        {
+            "X": 14.002662135842693,
+            "Y": 5.5047834704433907,
+            "Z": 0.0
+        },
+        {
+            "X": 18.188809261655159,
+            "Y": 5.5047834704433907,
+            "Z": 0.0
+        },
+        {
+            "X": 18.188809261655159,
+            "Y": -8.5606708722864866,
+            "Z": 0.0
+        },
+        {
+            "X": 5.2954761141527626,
+            "Y": -8.5606708722864866,
+            "Z": 0.0
+        },
+        {
+            "X": 5.2954761141527626,
+            "Y": -3.1605410799884073,
+            "Z": 0.0
+        },
+        {
+            "X": 0.14651514940343802,
+            "Y": -3.1605410799884073,
+            "Z": 0.0
+        },
+        {
+            "X": 0.14651514940343691,
+            "Y": -9.1885929411583547,
+            "Z": 0.0
+        },
+        {
+            "X": -5.0861687578621426,
+            "Y": -9.1885929411583547,
+            "Z": 0.0
+        },
+        {
+            "X": -5.0861687578621426,
+            "Y": -4.9605843440877688,
+            "Z": 0.0
+        },
+        {
+            "X": -7.1792423207683749,
+            "Y": -4.9605843440877688,
+            "Z": 0.0
+        },
+        {
+            "X": -7.1792423207683749,
+            "Y": -7.3885496770589976,
+            "Z": 0.0
+        },
+        {
+            "X": -10.276991193869598,
+            "Y": -6.0908440680571321,
+            "Z": 0.0
+        }
+    ]
+}
\ No newline at end of file
diff --git a/test/Elements.Tests/models/Geometry/LineThatFailsTrim.json b/test/Elements.Tests/models/Geometry/LineThatFailsTrim.json
new file mode 100644
index 000000000..a1dbe69e0
--- /dev/null
+++ b/test/Elements.Tests/models/Geometry/LineThatFailsTrim.json
@@ -0,0 +1,13 @@
+{
+    "discriminator": "Elements.Geometry.Line",
+    "Start": {
+        "X": 18.188809261655159,
+        "Y": 1.0038380807698293,
+        "Z": 0.0
+    },
+    "End": {
+        "X": -10.276991193869598,
+        "Y": 1.0038380807698293,
+        "Z": 0.0
+    }
+}
\ No newline at end of file

From 2c86fa608847176d36fa15516d4905000fbeae3f Mon Sep 17 00:00:00 2001
From: Andrew Heumann <andrew@heumann.com>
Date: Fri, 31 Jul 2020 08:38:50 -0400
Subject: [PATCH 2/4] changelog update

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 699c8e652..8f5c378c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 ### Fixed
 - CodeGen was failing intermittently
 - Elements schemas with Dictionary types were failing to serialize
+- [#355](https://github.com/hypar-io/Elements/issues/355)
 ### Added
 - Elements supports the [Hub beta](https://hypar-io.github.io/Elements/Hub.html)
 - CodeGen supports `input_schema`

From b59cd1ccd51bb7732f32d244f78ec1bb429c3916 Mon Sep 17 00:00:00 2001
From: Andrew Heumann <andrew@heumann.com>
Date: Fri, 31 Jul 2020 09:04:05 -0400
Subject: [PATCH 3/4] use a better line

---
 test/Elements.Tests/models/Geometry/LineThatFailsTrim.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/Elements.Tests/models/Geometry/LineThatFailsTrim.json b/test/Elements.Tests/models/Geometry/LineThatFailsTrim.json
index a1dbe69e0..6acb1b32b 100644
--- a/test/Elements.Tests/models/Geometry/LineThatFailsTrim.json
+++ b/test/Elements.Tests/models/Geometry/LineThatFailsTrim.json
@@ -2,12 +2,12 @@
     "discriminator": "Elements.Geometry.Line",
     "Start": {
         "X": 18.188809261655159,
-        "Y": 1.0038380807698293,
+        "Y": 1.5664562544790255,
         "Z": 0.0
     },
     "End": {
         "X": -10.276991193869598,
-        "Y": 1.0038380807698293,
+        "Y": 1.5664562544790255,
         "Z": 0.0
     }
 }
\ No newline at end of file

From 1201a462f08b0ded12b78053b110ad3490e6e5c7 Mon Sep 17 00:00:00 2001
From: Andrew Heumann <andrew@heumann.com>
Date: Fri, 31 Jul 2020 09:09:34 -0400
Subject: [PATCH 4/4] remove old unused test

---
 test/Elements.Tests/LineTests.cs | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/test/Elements.Tests/LineTests.cs b/test/Elements.Tests/LineTests.cs
index cbf42c84d..1e82bdb6b 100644
--- a/test/Elements.Tests/LineTests.cs
+++ b/test/Elements.Tests/LineTests.cs
@@ -177,17 +177,6 @@ public void LineTrimToInYZ()
             Assert.NotNull(l3);
         }
 
-        [Fact]
-        public void ShortLineTrim()
-        {
-            var boundary = new Polygon(new[] { new Vector3(30.0596079459439, 28.2900892254263), new Vector3(30.0596079459439, 25.2563767254263), new Vector3(30.0596079459439, 12.5928892254263), new Vector3(45.7568079459439, 12.5928892254263), new Vector3(45.7568079459439, 13.7104892254263), new Vector3(54.4436079459439, 13.7104892254263), new Vector3(54.4436079459439, 12.5928892254264), new Vector3(70.1408079459439, 12.5928892254263), new Vector3(70.1408079459439, 40.4820892254263), new Vector3(67.0928079459439, 40.4820892254263), new Vector3(67.0928079459439, 46.5780892254262), new Vector3(33.1076079459439, 46.5780892254263), new Vector3(33.1076079459439, 28.2900892254263) });
-            var line = new Line(new Vector3(67.257907945943941, 46.208201725426342), new Vector3(66.595920445943946, 46.208201725426342));
-            var segmentsIn = line.Trim(boundary, out var segmentsOut);
-            var obj = new Dictionary<string, object> { { "SegmentsIn", segmentsIn }, { "SegmentsOut", segmentsOut } };
-            var json = JsonConvert.SerializeObject(obj);
-            
-        }
-
         [Fact]
         public void TrimLineThatStartsAtPolygonEdge()
         {