Skip to content

Commit

Permalink
Merge pull request #154 from jetelain/149-waterway-clipping-does-not-…
Browse files Browse the repository at this point in the history
…always-keep-orientation

Keep orientation of watercourse
  • Loading branch information
jetelain authored Sep 29, 2023
2 parents 09ed7a6 + 9f71abb commit 6f92797
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 7 deletions.
26 changes: 26 additions & 0 deletions GameRealisticMap.Test/Geometries/TerrainPathTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
78 changes: 73 additions & 5 deletions GameRealisticMap/Geometries/TerrainPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public List<TerrainPath> Substract(TerrainPolygon polygon)
return result.Childs.Select(c => new TerrainPath(c.Contour.Select(p => new TerrainPoint(p)).ToList())).ToList();
}


public IEnumerable<TerrainPath> SubstractAll(IEnumerable<TerrainPolygon> others)
{
var result = new List<TerrainPath>() { this };
Expand All @@ -145,6 +146,26 @@ public IEnumerable<TerrainPath> SubstractAll(IEnumerable<TerrainPolygon> others)
return result;
}

public List<TerrainPath> SubstractKeepOrientation(TerrainPolygon polygon)
{
return KeepOrientation(Substract(polygon));
}

public IEnumerable<TerrainPath> SubstractAllKeepOrientation(IEnumerable<TerrainPolygon> others)
{
var result = new List<TerrainPath>() { 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<TerrainPath> ClippedByEnveloppe(ITerrainEnvelope other)
{
if (!EnveloppeIntersects(other))
Expand Down Expand Up @@ -272,30 +293,77 @@ public IEnumerable<TerrainPath> ClippedKeepOrientation(TerrainPolygon polygon)
{
return Enumerable.Empty<TerrainPath>();
}
return KeepOrientation(Intersection(polygon));
}

private List<TerrainPath> KeepOrientation(List<TerrainPath> clipped)
{
var initialPoints = Points.Select(p => p.ToIntPointPrecision()).ToList();

var clipped = Intersection(polygon);
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)
if (indices.Count > 1)
{
if (indices[0] > indices[1])
{
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]);
}
}
}
#if DEBUG
else
{
throw new InvalidOperationException("Unsupported edge case");
#endif
}
#endif
}
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();
Expand Down
4 changes: 2 additions & 2 deletions GameRealisticMap/Nature/Watercourses/WatercoursesBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ private List<Watercourse> GetPaths(IBuildContext context, List<TerrainPolygon> l
.OfType<ILineString>()
.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));
}
Expand Down

0 comments on commit 6f92797

Please sign in to comment.