// Copyright (C) Stichting Deltares 2018. All rights reserved.
//
// This file is part of the application DAM - UI.
//
// DAM - UI is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.IO;
using Deltares.Dam.Data.DataPlugins.Configuration;
using Deltares.Geotechnics;
using DotSpatial.Data;
using DotSpatial.Topology;
using NetTopologySuite.IO;
using NUnit.Framework;
namespace Deltares.Dam.Tests
{
[TestFixture]
public class IntersectionOnShapesTest
{
[Test]
[Category("Slow")]
public void AllIntersectionsWithTrafficLoad()
{
const string crossSectionFile = @"..\..\..\data\Dam\Waterboards\HHNK\ShapeFiles\Crosssection.shp";
const string trafficFile = @"..\..\..\data\Dam\Waterboards\HHNK\ShapeFiles\TrafficLoad.shp";
FindAllIntersectionsDotSpatial(crossSectionFile, trafficFile);
}
[Test]
[Category("Slow")]
[Ignore("Takes 25 minutes on buildserver")]
public void AllIntersectionsWithPolderLevel()
{
const string crossSectionFile = @"..\..\..\data\Dam\Waterboards\HHNK\ShapeFiles\Crosssection.shp";
const string polderLevelFile = @"..\..\..\data\Dam\Waterboards\HHNK\ShapeFiles\PolderLevel.shp";
FindAllIntersectionsDotSpatial(crossSectionFile, polderLevelFile);
}
[Test]
public void OneIntersectionWithTrafficLoad()
{
const string crossSectionFile = @"..\..\..\data\Dam\Waterboards\HHNK\ShapeFiles\Crosssection.shp";
const string trafficFile = @"..\..\..\data\Dam\Waterboards\HHNK\ShapeFiles\TrafficLoad.shp";
FindFirstIntersectionDotSpatial(crossSectionFile, trafficFile);
}
[Test]
public void OneIntersectionWithPolderLevel()
{
const string crossSectionFile = @"..\..\..\data\Dam\Waterboards\HHNK\shapefiles\Crosssection.shp";
const string polderLevelFile = @"..\..\..\data\Dam\Waterboards\HHNK\ShapeFiles\PolderLevel.shp";
Debug.WriteLine("--- DotSpatial ---");
FindFirstIntersectionDotSpatial(crossSectionFile, polderLevelFile);
Debug.WriteLine("--- NetTopologySuite ---");
FindFirstIntersectionNetTopology(crossSectionFile, polderLevelFile);
}
private void FindAllIntersectionsDotSpatial(string sourceFile, string targetFile)
{
IFeatureSet crossSectionFeatureSet = FeatureSet.Open(sourceFile);
IFeatureSet trafficLoadFeatureSet = FeatureSet.Open(targetFile);
DateTime start = DateTime.Now;
int intersections = 0;
foreach (Feature crossSectionFeature in crossSectionFeatureSet.Features)
{
foreach (Feature trafficLoadFeature in trafficLoadFeatureSet.Features)
{
if (crossSectionFeature.Intersects(trafficLoadFeature))
{
intersections++;
}
}
}
DateTime finish = DateTime.Now;
TimeSpan duration = finish - start;
Debug.WriteLine("Number of source sections: " + crossSectionFeatureSet.Features.Count);
Debug.WriteLine("Number of targets: " + trafficLoadFeatureSet.Features.Count);
Debug.WriteLine("Number of intersections: " + intersections);
Debug.WriteLine("Seconds: " + duration.TotalSeconds);
Debug.WriteLine("Seconds per intersection: " + duration.TotalSeconds / (trafficLoadFeatureSet.Features.Count * crossSectionFeatureSet.Features.Count));
}
private void FindFirstIntersectionDotSpatial(string sourceFile, string targetFile)
{
IFeatureSet crossSectionFeatureSet = FeatureSet.Open(sourceFile);
IFeatureSet trafficLoadFeatureSet = FeatureSet.Open(targetFile);
DateTime start = DateTime.Now;
int intersections = 0;
IFeature crossSectionFeature = crossSectionFeatureSet.Features[0];
foreach (Feature trafficLoadFeature in trafficLoadFeatureSet.Features)
{
if (crossSectionFeature.Intersects(trafficLoadFeature))
{
intersections++;
}
}
DateTime finish = DateTime.Now;
TimeSpan duration = finish - start;
Debug.WriteLine("Number of source sections: 1");
Debug.WriteLine("Number of targets: " + trafficLoadFeatureSet.Features.Count);
Debug.WriteLine("Number of intersections: " + intersections);
Debug.WriteLine("Seconds: " + duration.TotalSeconds);
Debug.WriteLine("Seconds per intersection: " + duration.TotalSeconds / trafficLoadFeatureSet.Features.Count);
}
private void FindFirstIntersectionNetTopology(string sourceFile, string targetFile)
{
var crossSectionFeatures = NtsFeature.Read(sourceFile);
var trafficLoadFeatures = NtsFeature.Read(targetFile);
DateTime start = DateTime.Now;
int intersections = 0;
//if (featureToTest.IsWithin(feature) || featureToTest.IsTouching(feature)) line-polygon
//if (feature.IsIntersecting(featureToTest)) line-line
NtsFeature crossSectionFeature = crossSectionFeatures.First();
foreach (NtsFeature trafficLoadFeature in trafficLoadFeatures)
{
if (crossSectionFeature.IsIntersecting(trafficLoadFeature))
{
intersections++;
}
}
DateTime finish = DateTime.Now;
TimeSpan duration = finish - start;
Debug.WriteLine("Number of source sections: 1");
Debug.WriteLine("Number of targets: " + trafficLoadFeatures.Count());
Debug.WriteLine("Number of intersections: " + intersections);
Debug.WriteLine("Seconds: " + duration.TotalSeconds);
Debug.WriteLine("Seconds per intersection: " + duration.TotalSeconds / trafficLoadFeatures.Count());
}
}
abstract class AbstractFeature
{
protected AbstractFeature()
{
this.Attributes = new Dictionary();
}
public T Geometry { get; set; }
public IDictionary Attributes { get; set; }
public abstract bool IsIntersecting(AbstractFeature otherFeature);
public abstract bool IsWithin(AbstractFeature otherFeature);
public abstract bool IsTouching(AbstractFeature otherFeature);
}
class NtsFeature : AbstractFeature
{
public static IEnumerable Read(string fileName)
{
using (var reader = new ShapefileDataReader(fileName, NetTopologySuite.Geometries.GeometryFactory.Default))
{
while (reader.Read())
{
// force the reader to read with the US culture
var feature = new NtsFeature()
{
Geometry = reader.Geometry
};
for (int i = 0; i < reader.DbaseHeader.NumFields; i++)
{
string colName = reader.DbaseHeader.Fields[i].Name;
object rowValue = reader.GetValue(i);
if (!feature.Attributes.ContainsKey(colName))
feature.Attributes.Add(colName, rowValue);
}
yield return feature;
}
}
}
public override bool IsIntersecting(AbstractFeature otherFeature)
{
return this.Geometry.Intersects(otherFeature.Geometry);
}
public override bool IsWithin(AbstractFeature otherFeature)
{
return this.Geometry.Within(otherFeature.Geometry);
}
public override bool IsTouching(AbstractFeature otherFeature)
{
return this.Geometry.Touches(otherFeature.Geometry);
}
}
}