From ba9ff745d7ad96bae06aa31a71625b347404d738 Mon Sep 17 00:00:00 2001 From: Julien Date: Sun, 24 Sep 2023 23:41:03 +0200 Subject: [PATCH 1/3] Keep orientation of watercourse --- GameRealisticMap/Geometries/TerrainPath.cs | 29 +++++++++++++++++-- .../Watercourses/WatercoursesBuilder.cs | 4 +-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/GameRealisticMap/Geometries/TerrainPath.cs b/GameRealisticMap/Geometries/TerrainPath.cs index b4a7f505..7b55bddb 100644 --- a/GameRealisticMap/Geometries/TerrainPath.cs +++ b/GameRealisticMap/Geometries/TerrainPath.cs @@ -130,6 +130,7 @@ public List Substract(TerrainPolygon polygon) return result.Childs.Select(c => new TerrainPath(c.Contour.Select(p => new TerrainPoint(p)).ToList())).ToList(); } + public IEnumerable SubstractAll(IEnumerable others) { var result = new List() { this }; @@ -145,6 +146,26 @@ public IEnumerable SubstractAll(IEnumerable others) return result; } + public List SubstractKeepOrientation(TerrainPolygon polygon) + { + return KeepOrientation(Substract(polygon)); + } + + public IEnumerable SubstractAllKeepOrientation(IEnumerable others) + { + var result = new List() { this }; + foreach (var other in others.Where(o => GeometryHelper.EnveloppeIntersects(this, o))) + { + var previousResult = result.ToList(); + result.Clear(); + foreach (var subjet in previousResult) + { + result.AddRange(subjet.SubstractKeepOrientation(other)); + } + } + return result; + } + public IEnumerable ClippedByEnveloppe(ITerrainEnvelope other) { if (!EnveloppeIntersects(other)) @@ -272,14 +293,16 @@ public IEnumerable ClippedKeepOrientation(TerrainPolygon polygon) { return Enumerable.Empty(); } + return KeepOrientation(Intersection(polygon)); + } + private List KeepOrientation(List clipped) + { var initialPoints = Points.Select(p => p.ToIntPointPrecision()).ToList(); - - var clipped = Intersection(polygon); foreach (var result in clipped) { var indices = result.Points.Select(np => initialPoints.FindIndex(p => TerrainPoint.Equals(np, p))).Where(i => i != -1).Take(2).ToList(); - if (indices.Count > 1) + if (indices.Count > 1) { if (indices[0] > indices[1]) { diff --git a/GameRealisticMap/Nature/Watercourses/WatercoursesBuilder.cs b/GameRealisticMap/Nature/Watercourses/WatercoursesBuilder.cs index afac412e..2cd0c54a 100644 --- a/GameRealisticMap/Nature/Watercourses/WatercoursesBuilder.cs +++ b/GameRealisticMap/Nature/Watercourses/WatercoursesBuilder.cs @@ -104,8 +104,8 @@ private List GetPaths(IBuildContext context, List l .OfType() .Where(l => !l.IsClosed) .SelectMany(geometry => TerrainPath.FromGeometry(geometry, context.Area.LatLngToTerrainPoint)) - .SelectMany(path => path.ClippedBy(context.Area.TerrainBounds)) - .SelectMany(p => p.SubstractAll(lakesPolygons))) + .SelectMany(path => path.ClippedKeepOrientation(context.Area.TerrainBounds)) + .SelectMany(p => p.SubstractAllKeepOrientation(lakesPolygons))) { waterwaysPaths.Add(new Watercourse(segment, kind.Value)); } From c1c87d25a2fbc59a8dd012ff717120c68bcf93ac Mon Sep 17 00:00:00 2001 From: Julien Date: Fri, 29 Sep 2023 22:22:01 +0200 Subject: [PATCH 2/3] Additional edge case support --- .../Geometries/TerrainPathTest.cs | 26 ++++++++++ GameRealisticMap/Geometries/TerrainPath.cs | 47 ++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/GameRealisticMap.Test/Geometries/TerrainPathTest.cs b/GameRealisticMap.Test/Geometries/TerrainPathTest.cs index 7b99ab1b..2f3b7aee 100644 --- a/GameRealisticMap.Test/Geometries/TerrainPathTest.cs +++ b/GameRealisticMap.Test/Geometries/TerrainPathTest.cs @@ -167,6 +167,32 @@ public void TerrainPath_ClippedKeepOrientation() Assert.Equal(new TerrainPoint[] { new(12019.221f, 0), new(11699.635f, 1066.635f), new(10796.125f, 4111.285f) }, clipPath.Points); } + [Fact] + public void TerrainPath_ClippedKeepOrientation_OneReferencePoint() + { + var path = new TerrainPath(new(5, 0), new(5, 4.5f), new(5, 5), new(5, 10), new(5, 15), new(5, 20)); + var clip = path.ClippedKeepOrientation(TerrainPolygon.FromRectangle(new(2.5f, 0f), new(7.5f, 4f))).ToList(); + var clipPath = Assert.Single(clip); + Assert.Equal(new TerrainPoint[] { new(5, 0), new(5, 4) }, clipPath.Points); + + clip = path.ClippedKeepOrientation(TerrainPolygon.FromRectangle(new(2.5f, 5f), new(7.5f, 6f))).ToList(); + clipPath = Assert.Single(clip); + Assert.Equal(new TerrainPoint[] { new(5, 5), new(5, 6) }, clipPath.Points); + + clip = path.ClippedKeepOrientation(TerrainPolygon.FromRectangle(new(2.5f, 19f), new(7.5f, 20f))).ToList(); + clipPath = Assert.Single(clip); + Assert.Equal(new TerrainPoint[] { new(5, 19), new(5, 20) }, clipPath.Points); + + path = new TerrainPath(new(17109.277f, -14502.888f), new(16591.264f, -12701.211f), new(16163.766f, -11304.716f), new(15508.252f, -9480.714f), new(14873.61f, -7825.331f), new(13395f, -4382.8315f), new(13258.774f, -4007.939f), new(13170.557f, -3792.907f), new(13141.093f, -3670.9758f), new(13054.459f, -3426.7131f), new(12794.966f, -2589.082f), new(11699.636f, 1066.6356f), new(10796.126f, 4111.285f)); + clip = path.ClippedKeepOrientation(TerrainPolygon.FromRectangle(new(0, 2000), new(26000, 26000))).ToList(); + clipPath = Assert.Single(clip); + Assert.Equal(new TerrainPoint[] { new(11422.656f, 2000f), new(10796.125f, 4111.285f) }, clipPath.Points); + + clip = path.ClippedKeepOrientation(TerrainPolygon.FromRectangle(new(0, 0), new(26000, 1066.6356f))).ToList(); + clipPath = Assert.Single(clip); + Assert.Equal(new TerrainPoint[] { new(12019.221f, 0), new(11699.635f, 1066.635f) }, clipPath.Points); + } + [Fact] public void TerrainPath_Substract() { diff --git a/GameRealisticMap/Geometries/TerrainPath.cs b/GameRealisticMap/Geometries/TerrainPath.cs index 7b55bddb..30cdc336 100644 --- a/GameRealisticMap/Geometries/TerrainPath.cs +++ b/GameRealisticMap/Geometries/TerrainPath.cs @@ -301,6 +301,10 @@ private List KeepOrientation(List clipped) var initialPoints = Points.Select(p => p.ToIntPointPrecision()).ToList(); foreach (var result in clipped) { + if (result.Points.Count < 2) + { + continue; + } var indices = result.Points.Select(np => initialPoints.FindIndex(p => TerrainPoint.Equals(np, p))).Where(i => i != -1).Take(2).ToList(); if (indices.Count > 1) { @@ -309,9 +313,38 @@ private List KeepOrientation(List clipped) result.Points.Reverse(); } } - else + else if (indices.Count == 1) { + var initialReferenceIndex = indices[0]; + var sharedReferencePoint = initialPoints[initialReferenceIndex]; + var resultReferenceIndex = result.Points.FindIndex(p => TerrainPoint.Equals(sharedReferencePoint, p)); + + if (resultReferenceIndex == result.Points.Count - 1) + { + if (initialReferenceIndex == 0) + { + result.Points.Reverse(); + } + else + { + CheckVector(result, sharedReferencePoint, result.Points[resultReferenceIndex - 1], initialPoints[initialReferenceIndex - 1]); + } + } + else + { + if (initialReferenceIndex == initialPoints.Count - 1) + { + result.Points.Reverse(); + } + else + { + CheckVector(result, sharedReferencePoint, result.Points[resultReferenceIndex + 1], initialPoints[initialReferenceIndex + 1]); + } + } + } + else #if DEBUG + { throw new InvalidOperationException("Unsupported edge case"); #endif } @@ -319,6 +352,18 @@ private List KeepOrientation(List clipped) return clipped; } + private static void CheckVector(TerrainPath result, TerrainPoint sharedReferencePoint, TerrainPoint resultComparePoint, TerrainPoint initialComparePoint) + { + var initialVect = Vector2.Normalize(initialComparePoint.Vector - sharedReferencePoint.Vector); + var resultVect = Vector2.Normalize(resultComparePoint.Vector - sharedReferencePoint.Vector); + if (Vector2.Dot(initialVect, resultVect) < 0) + { + result.Points.Reverse(); + } + } + + + public bool IsClosed => FirstPoint.Equals(LastPoint); public bool IsCounterClockWise => Points.IsCounterClockWise(); From 9f71abb2e0f50816ac9a111b53e5350bc5738529 Mon Sep 17 00:00:00 2001 From: Julien Date: Fri, 29 Sep 2023 22:24:09 +0200 Subject: [PATCH 3/3] Bad precompiler directive --- GameRealisticMap/Geometries/TerrainPath.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GameRealisticMap/Geometries/TerrainPath.cs b/GameRealisticMap/Geometries/TerrainPath.cs index 30cdc336..4810c247 100644 --- a/GameRealisticMap/Geometries/TerrainPath.cs +++ b/GameRealisticMap/Geometries/TerrainPath.cs @@ -342,12 +342,12 @@ private List KeepOrientation(List clipped) } } } - else #if DEBUG + else { throw new InvalidOperationException("Unsupported edge case"); -#endif } +#endif } return clipped; }