public GraphData(string name, List <Point> inputPoints, List <Segment> segments) { if (String.IsNullOrEmpty(name) || inputPoints == null || segments == null) { throw new ArgumentNullException(); } Name = name; //InputPoints = new List<Point>(); //InputSegments = new List<Segment>(); VoronoiSolution = new BoostVoronoi(); //Populate the input foreach (var point in inputPoints) { //InputPoints.Add(point); VoronoiSolution.AddPoint(point.X, point.Y); } foreach (var segment in segments) { //InputSegments.Add(segment); VoronoiSolution.AddSegment(segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y); } //Construct VoronoiSolution.Construct(); //Populate the output //OutputVertices = VoronoiSolution.Vertices; //OutputEdges = VoronoiSolution.Edges; //OutputCells = VoronoiSolution.Cells; }
static void ConstructAndMeasure(ref List <Point> inputPoints, ref List <Segment> inputSegments) { Console.WriteLine(String.Format("Testing with {0} points and {1} segments", inputPoints.Count, inputSegments.Count)); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); using (BoostVoronoi bv = new BoostVoronoi()) { foreach (var point in inputPoints) { bv.AddPoint(point.X, point.Y); } foreach (var segment in inputSegments) { bv.AddSegment(segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y); } bv.Construct(); // Stop timing. stopwatch.Stop(); Console.WriteLine(String.Format("Vertices: {0}, Edges: {1}, Cells: {2}", bv.CountVertices, bv.CountEdges, bv.CountCells)); Console.WriteLine("Time elapsed: {0:hh\\:mm\\:ss\\:ff}.", stopwatch.Elapsed); //bv.Clear(); } inputPoints.Clear(); inputSegments.Clear(); }
public void TestInvalidCellIndexException() { List <Point> inputPoint = new List <Point>() { new Point(5, 5) }; List <Segment> inputSegment = new List <Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the C# Voronoi using (BoostVoronoi bv = new BoostVoronoi()) { foreach (var p in inputPoint) { bv.AddPoint(p.X, p.Y); } foreach (var s in inputSegment) { bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); } bv.Construct(); bv.GetCell(bv.CountCells); } }
public void TestPrimaryEdges() { List <Point> inputPoint = new List <Point>() { new Point(5, 5) }; List <Segment> inputSegment = new List <Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the C# Voronoi using (BoostVoronoi bv = new BoostVoronoi()) { foreach (var p in inputPoint) { bv.AddPoint(p.X, p.Y); } foreach (var s in inputSegment) { bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); } bv.Construct(); int countPrimary = 0; int countSecondary = 0; int countFinite = 0; for (long i = 0; i < bv.CountEdges; i++) { Edge edge = bv.GetEdge(i); if (edge.IsPrimary) { countPrimary++; } if (edge.IsFinite) { countFinite++; } if (!edge.IsPrimary && edge.IsFinite) { countSecondary++; } } //8 finites from the center of the square corner + 8 edges arount the center point. Assert.AreEqual(countFinite, 16); //Check the number of secondary edge. Because this input is a square with a point in the center, the expected count is 0. Assert.AreEqual(countSecondary, 0); Assert.AreEqual(countPrimary, countFinite - countSecondary); } }
static void Main(string[] args) { //Define a set of segments and pass them to the voronoi wrapper List <Segment> input = new List <Segment>(); input.Add(new Segment(0, 0, 0, 10)); input.Add(new Segment(0, 10, 10, 10)); input.Add(new Segment(10, 10, 10, 0)); input.Add(new Segment(10, 0, 0, 0)); //Instanciate the voronoi wrapper using (BoostVoronoi bv = new BoostVoronoi()) { //Add a point bv.AddPoint(5, 5); //Add the segments foreach (var s in input) { bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); } //Build the C# Voronoi bv.Construct(); //Get the voronoi output for (long i = 0; i < bv.CountCells; i++) { Cell cell = bv.GetCell(i); Console.Out.WriteLine(String.Format("Cell Identifier {0}. Is open = {1}", cell.Index, cell.IsOpen)); foreach (var edgeIndex in cell.EdgesIndex) { Edge edge = bv.GetEdge(edgeIndex); Console.Out.WriteLine( String.Format(" Edge Index: {0}. Start vertex index: {1}, End vertex index: {2}", edgeIndex, edge.Start, edge.End)); //If the vertex index equals -1, it means the edge is infinite. It is impossible to print the coordinates. if (edge.IsLinear) { Vertex start = bv.GetVertex(edge.Start); Vertex end = bv.GetVertex(edge.End); Console.Out.WriteLine( String.Format(" From:{0}, To: {1}", start.ToString(), end.ToString())); } } } } Console.In.ReadLine(); }
public void TestFindInputPointSiteException() { List <Point> inputPoint = new List <Point>() { new Point(5, 5) }; List <Segment> inputSegment = new List <Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the C# Voronoi using (BoostVoronoi bv = new BoostVoronoi()) { foreach (var p in inputPoint) { bv.AddPoint(p.X, p.Y); } foreach (var s in inputSegment) { bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); } bv.Construct(); for (long i = 0; i < bv.CountCells; i++) { Cell cell = bv.GetCell(i); if (cell.SourceCategory != CellSourceCatory.SegmentStartPoint && cell.SourceCategory != CellSourceCatory.SegmentEndPoint && cell.SourceCategory != CellSourceCatory.SinglePoint) { bv.RetrieveInputPoint(cell); } } } }
public void TestGetCellVertices() { List <Point> inputPoint = new List <Point>() { new Point(5, 5) }; List <Segment> inputSegment = new List <Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the C# Voronoi using (BoostVoronoi bv = new BoostVoronoi()) { foreach (var p in inputPoint) { bv.AddPoint(p.X, p.Y); } foreach (var s in inputSegment) { bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); } bv.Construct(); for (long i = 0; i < bv.CountCells; i++) { Cell cell = bv.GetCell(i); if (!cell.IsOpen) { List <long> vertexIndexes = cell.VerticesIndex; Assert.AreEqual(vertexIndexes.Count, 5); Assert.AreEqual(vertexIndexes[0], vertexIndexes[vertexIndexes.Count - 1]); } } } }
public void TestSegmentTwin() { List <Point> inputPoint = new List <Point>() { new Point(5, 5) }; List <Segment> inputSegment = new List <Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 10, 10, 0)); inputSegment.Add(new Segment(10, 0, 0, 0)); //Build the C# Voronoi using (BoostVoronoi bv = new BoostVoronoi()) { foreach (var p in inputPoint) { bv.AddPoint(p.X, p.Y); } foreach (var s in inputSegment) { bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); } bv.Construct(); //Test twin reciprocity for (long i = 0; i < bv.CountEdges; i++) { Edge edge = bv.GetEdge(i); Edge twin = bv.GetEdge(edge.Twin); Assert.AreEqual(i, twin.Twin); } } }
public static IReadOnlyList <TerrainNode> Analyze <TNode>(Map2D <TNode> map, Func <TNode, bool> isBlocking, int pruneDistanceToObstacleSquared, int maxDistanceToMergeSquared) { var tracingResult = ComponentLabeling.Trace(map, node => isBlocking(node) ? 1 : 0); var contours = new List <List <Point2D> >(); foreach (var blob in tracingResult.Blobs) { contours.AddRange( new[] { blob.ExternalContour }.Concat(blob.InternalContours).Select( points => DouglasPeucker.Simplify(points.ToList(), 2 * 2, DistanceSquared))); } var edges = new List <Edge>(); var leftBorder = new List <int>(); var rightBorder = new List <int>(); var topBorder = new List <int>(); var bottomBorder = new List <int>(); var wallsTree = new RTree <Edge>(5, 9); using (var voronoi = new BoostVoronoi()) { foreach (var contour in contours) { var startPoint = contour.First(); foreach (var point in contour.Skip(1)) { voronoi.AddSegment((int)startPoint.X, (int)startPoint.Y, (int)point.X, (int)point.Y); wallsTree.Insert(new Edge { Start = startPoint, End = point }, new RTree <Edge> .Envelope(startPoint, point)); if ((int)startPoint.X == 0 && (int)point.X == 0) { leftBorder.Add((int)startPoint.Y); leftBorder.Add((int)point.Y); } if ((int)startPoint.X == map.Width - 1 && (int)point.X == map.Width - 1) { rightBorder.Add((int)startPoint.Y); rightBorder.Add((int)point.Y); } if ((int)startPoint.Y == 0 && (int)point.Y == 0) { topBorder.Add((int)startPoint.X); topBorder.Add((int)point.X); } if ((int)startPoint.Y == map.Height - 1 && (int)point.Y == map.Height - 1) { bottomBorder.Add((int)startPoint.X); bottomBorder.Add((int)point.X); } startPoint = point; } } AddVerticalBorder(voronoi, wallsTree, leftBorder.OrderBy(x => x).ToList(), 0, map.Height - 1); AddVerticalBorder(voronoi, wallsTree, rightBorder.OrderBy(x => x).ToList(), map.Width - 1, map.Height - 1); AddHorizontalBorder(voronoi, wallsTree, topBorder.OrderBy(x => x).ToList(), 0, map.Width - 1); AddHorizontalBorder(voronoi, wallsTree, bottomBorder.OrderBy(x => x).ToList(), map.Height - 1, map.Width - 1); var visitedTwins = new List <long>(); voronoi.Construct(); for (long i = 0; i < voronoi.CountEdges; i++) { var edge = voronoi.GetEdge(i); if (!edge.IsPrimary || !edge.IsFinite || visitedTwins.Contains(edge.Twin)) { continue; } visitedTwins.Add(edge.Twin); var start = voronoi.GetVertex(edge.Start); var end = voronoi.GetVertex(edge.End); if (double.IsNaN(start.X) || double.IsNaN(start.Y) || double.IsNaN(end.X) || double.IsNaN(end.Y)) { continue; } if (edges.Any( e => (int)e.Start.X == (int)start.X && (int)e.Start.Y == (int)start.Y && (int)e.End.X == (int)end.X && (int)e.End.Y == (int)end.Y || (int)e.Start.X == (int)end.X && (int)e.Start.Y == (int)end.Y && (int)e.End.X == (int)start.X && (int)e.End.Y == (int)start.Y)) { continue; } edges.Add(new Edge { Start = new Point2D((int)start.X, (int)start.Y), End = new Point2D((int)end.X, (int)end.Y) }); } } var walkableEdges = edges.Where(edge => IsOnNonBlocking(edge, map, isBlocking)).ToList(); var nodes = new List <InternalNode>(); foreach (var node in walkableEdges) { if (node.Start == node.End) { continue; } var startNode = nodes.Find(x => x.Point == node.Start); if (startNode == null) { startNode = CreateNode(wallsTree, node.Start); nodes.Add(startNode); } var endNode = nodes.Find(x => x.Point == node.End); if (endNode == null) { endNode = CreateNode(wallsTree, node.End); nodes.Add(endNode); } startNode.Neighbors.Add(endNode); endNode.Neighbors.Add(startNode); } PruneNodes(nodes, pruneDistanceToObstacleSquared); GetPointsOfInterest(nodes, pruneDistanceToObstacleSquared, maxDistanceToMergeSquared); var mergedNodes = MergeNodes(nodes, maxDistanceToMergeSquared); return(MapToTerrainNodes(mergedNodes, wallsTree)); }
// Execute: Execute the function given the array of the parameters public void Execute(IArray paramvalues, ITrackCancel trackcancel, IGPEnvironmentManager envMgr, IGPMessages message) { IFeatureClass outputFeatureClass = null; try { // get the input feature class IGPMultiValue inputFeatureClasses_Parameter = (IGPMultiValue)m_GPUtilities.UnpackGPValue(paramvalues.get_Element(0)); layer[] input_featureClasses = new layer[inputFeatureClasses_Parameter.Count]; for (int i = 0; i < inputFeatureClasses_Parameter.Count; i++) { IGPValue inputFeatureClass_Parameter = inputFeatureClasses_Parameter.get_Value(i); IFeatureClass inputFeatureClass; IQueryFilter inputQF; m_GPUtilities.DecodeFeatureLayer(inputFeatureClass_Parameter, out inputFeatureClass, out inputQF); input_featureClasses[i] = new layer() { featureclass = inputFeatureClass, qFilter = inputQF }; } if (input_featureClasses.Length == 0 || input_featureClasses.Any(w => w.featureclass == null)) { message.AddError(2, "Could not open one or more input dataset."); return; } //IFields additionalFields = new FieldsClass(); //additionalFields.AddField(FEATURE_SOURCE_FIELD_NAME, esriFieldType.esriFieldTypeString); //additionalFields.AddField(FEATURE_ID_FIELD_NAME, esriFieldType.esriFieldTypeInteger); //additionalFields.AddField( // input_featureClasses[0].featureclass.Fields.get_Field( // input_featureClasses[0].featureclass.Fields.FindField( // input_featureClasses[0].featureclass.ShapeFieldName))); // create the output feature class IGPValue outputFeatureClass_Parameter = m_GPUtilities.UnpackGPValue(paramvalues.get_Element(1)); outputFeatureClass = GPHelperFunctions.CreateFeatureClass(outputFeatureClass_Parameter, envMgr); if (outputFeatureClass == null) { message.AddError(2, "Could not create output dataset."); return; } IGPString curveTypeParameter = (IGPString)m_GPUtilities.UnpackGPValue(paramvalues.get_Element(2)); ArcConstructionMethods method; if (!Enum.TryParse <ArcConstructionMethods>(curveTypeParameter.Value, true, out method)) { message.AddError(2, string.Format("The value {0} is not expected. Expected values are: {1}.", curveTypeParameter.Value, string.Join(",", Enum.GetNames(typeof(ArcConstructionMethods))))); return; } IStepProgressor stepPro = (IStepProgressor)trackcancel; GPHelperFunctions.dropSpatialIndex(outputFeatureClass); BoostVoronoi bv = new BoostVoronoi(100); double minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; List <site_key> point_sites = new List <site_key>(); List <site_key> segment_sites = new List <site_key>(); for (short i = 0; i < input_featureClasses.Length; i++) { layer l = input_featureClasses[i]; int featcount = l.featureclass.FeatureCount(l.qFilter); stepPro.MinRange = 0; stepPro.MaxRange = featcount; stepPro.StepValue = (1); stepPro.Message = "Reading features"; stepPro.Position = 0; stepPro.Show(); IFeatureCursor cursor = null; IFeature row = null; try { cursor = l.featureclass.Search(l.qFilter, false); while ((row = cursor.NextFeature()) != null) { stepPro.Step(); IPoint point = row.Shape as IPoint; if (point != null) { double X = point.X; double Y = point.Y; minX = Math.Min(minX, X); maxX = Math.Max(maxX, X); minY = Math.Min(minY, Y); maxY = Math.Max(maxY, Y); bv.AddPoint(point.X, point.Y); point_sites.Add(new site_key(i, row.OID)); } IMultipoint multipoint = row.Shape as IMultipoint; if (multipoint != null) { IPointCollection pointCollection = (IPointCollection)multipoint; IEnumVertex vertices = pointCollection.EnumVertices; IPoint vertex = null; int part, index; vertices.Next(out vertex, out part, out index); minX = Math.Min(minX, multipoint.Envelope.XMin); maxX = Math.Max(maxX, multipoint.Envelope.XMax); minY = Math.Min(minY, multipoint.Envelope.YMin); maxY = Math.Max(maxY, multipoint.Envelope.YMax); while (vertex != null) { bv.AddPoint(vertex.X, vertex.Y); point_sites.Add(new site_key(i, row.OID)); vertices.Next(out vertex, out part, out index); } } IPolyline polyline = row.Shape as IPolyline; if (polyline != null) { double fromX = polyline.FromPoint.X; double fromY = polyline.FromPoint.Y; double toX = polyline.ToPoint.X; double toY = polyline.ToPoint.Y; if (toX < fromX) { minX = Math.Min(minX, toX); maxX = Math.Max(maxX, fromX); } else { minX = Math.Min(minX, fromX); maxX = Math.Max(maxX, toX); } if (toY < fromY) { minY = Math.Min(minY, toY); maxY = Math.Max(maxY, fromY); } else { minY = Math.Min(minY, fromY); maxY = Math.Max(maxY, toY); } bv.AddSegment( polyline.FromPoint.X, polyline.FromPoint.Y, polyline.ToPoint.X, polyline.ToPoint.Y ); segment_sites.Add(new site_key(i, row.OID)); } Marshal.ReleaseComObject(row); } } finally { if (row != null) { Marshal.ReleaseComObject(row); } if (cursor != null) { Marshal.ReleaseComObject(cursor); } stepPro.Hide(); } } message.AddMessage(String.Format("{0}, {1} -> {2}, {3}", minX, minY, maxX, maxY)); int width = Math.Max((int)((maxX - minX) * 0.1), 1); int height = Math.Max((int)((maxY - minY) * 0.1), 1); maxX = maxX + width; minX = minX - width; maxY = maxY + height; minY = minY - height; message.AddMessage(String.Format("{0}, {1} -> {2}, {3}", minX, minY, maxX, maxY)); bv.AddSegment(minX, minY, maxX, minY); segment_sites.Add(new site_key(-1, -1)); bv.AddSegment(maxX, minY, maxX, maxY); segment_sites.Add(new site_key(-1, -1)); bv.AddSegment(maxX, maxY, minX, maxY); segment_sites.Add(new site_key(-1, -1)); bv.AddSegment(minX, maxY, minX, minY); segment_sites.Add(new site_key(-1, -1)); stepPro.Message = "Solve Voronoi"; stepPro.MaxRange = 0; stepPro.MaxRange = 0; stepPro.Show(); bv.Construct(); stepPro.Hide(); int featureSourceIndx = outputFeatureClass.Fields.FindField(FEATURE_SOURCE_FIELD_NAME); int featureIDIndx = outputFeatureClass.Fields.FindField(FEATURE_ID_FIELD_NAME); IFeatureCursor inserts = null; IFeatureBuffer buffer = null; try { object missing = Type.Missing; ISpatialReference spatialReference = ((IGeoDataset)outputFeatureClass).SpatialReference; inserts = outputFeatureClass.Insert(false); buffer = outputFeatureClass.CreateFeatureBuffer(); List <Cell> cells = bv.Cells; message.AddMessage(string.Format("{0} cells calculated", cells.Count)); List <Edge> edges = bv.Edges; message.AddMessage(string.Format("{0} edges calculated", edges.Count)); List <Vertex> vertices = bv.Vertices; message.AddMessage(string.Format("{0} vertexes calculated", vertices.Count)); stepPro.Message = "Write cells"; stepPro.MaxRange = 0; stepPro.MaxRange = cells.Count; stepPro.Show(); for (int cellIndex = 0; cellIndex < cells.Count; cellIndex++) { try { if (cellIndex % 5000 == 0) { message.AddMessage(String.Format("{0}. {1} cells processed.", DateTime.Now, cellIndex)); } Cell cell = cells[cellIndex]; int currentSite = cell.Site; IGeometryCollection geometryCollection = new GeometryBagClass() { SpatialReference = spatialReference }; //ignores any sliver cells if (cell.IsOpen || cell.EdgesIndex.Count < 3) { continue; } ISegmentCollection segmentCollection = createSegments(cell, bv, method, spatialReference); if (((IArea)segmentCollection).Area <= 0) { message.AddMessage("A invalid geometry has been detected, try reversing the orientation."); ISegmentCollection reversed_segmentCollection = new PolygonClass() { SpatialReference = spatialReference }; for (int i = segmentCollection.SegmentCount - 1; i >= 0; i--) { ISegment segment = (ISegment)segmentCollection.get_Segment(i); segment.ReverseOrientation(); reversed_segmentCollection.AddSegment(segment); } segmentCollection = reversed_segmentCollection; } ((IPolygon)segmentCollection).SpatialReference = spatialReference; if (((IArea)segmentCollection).Area <= 0) { message.AddWarning("An empty shell has been created"); for (int i = 0; i < segmentCollection.SegmentCount; i++) { ISegment segment = (ISegment)segmentCollection.get_Segment(i); message.AddMessage(String.Format("From {0}, {1} To {2},{3}", segment.FromPoint.X, segment.FromPoint.Y, segment.ToPoint.X, segment.ToPoint.Y)); } } //set attributes site_key sk = (currentSite >= point_sites.Count) ? segment_sites[currentSite - point_sites.Count] : point_sites[currentSite]; if (!sk.isEmpty) { buffer.set_Value(featureSourceIndx, input_featureClasses[sk.featureClassIndex].featureclass.AliasName); buffer.set_Value(featureIDIndx, sk.objectID); } else { buffer.set_Value(featureSourceIndx, DBNull.Value); buffer.set_Value(featureIDIndx, DBNull.Value); } IPolygon voronoiPolygon = (IPolygon)segmentCollection; buffer.Shape = (IPolygon)voronoiPolygon; inserts.InsertFeature(buffer); } catch (Exception e) { message.AddWarning("Failed to create a cell"); } } } finally { if (buffer != null) { Marshal.ReleaseComObject(buffer); } if (inserts != null) { Marshal.ReleaseComObject(inserts); } } GPHelperFunctions.createSpatialIndex(outputFeatureClass); } catch (Exception exx) { message.AddError(2, exx.Message); message.AddMessage(exx.ToString()); } finally { if (outputFeatureClass != null) { Marshal.ReleaseComObject(outputFeatureClass); } ((IProgressor)trackcancel).Hide(); } }
public void TestSegmentDicretization() { List <Point> inputPoint = new List <Point>() { new Point(5, 5) }; List <Segment> inputSegment = new List <Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the C# Voronoi using (BoostVoronoi bv = new BoostVoronoi()) { foreach (var p in inputPoint) { bv.AddPoint(p.X, p.Y); } foreach (var s in inputSegment) { bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); } bv.Construct(); long testEdgeIndex = 2; for (long i = 0; i < bv.CountEdges; i++) { Edge edge = bv.GetEdge(i); Edge twin = bv.GetEdge(edge.Twin); Cell edgeCell = bv.GetCell(edge.Cell); Cell twinCell = bv.GetCell(twin.Cell); if (twinCell.SourceCategory == CellSourceCatory.SinglePoint && edgeCell.Site == 1) { testEdgeIndex = i; } } Edge testEdge = bv.GetEdge(testEdgeIndex); Vertex startVertex = bv.GetVertex(testEdge.Start); Vertex endVertex = bv.GetVertex(testEdge.End); List <Vertex> dvertices = bv.SampleCurvedEdge(testEdge, Distance.ComputeDistanceBetweenPoints(startVertex, endVertex) / 2); int lastDicretizedVertexIndex = dvertices.Count - 1; //Make sure that the end points are consistents Assert.AreEqual(dvertices[0].X, startVertex.X); Assert.AreEqual(dvertices[0].Y, startVertex.Y); Assert.AreEqual(dvertices[lastDicretizedVertexIndex].X, endVertex.X); Assert.AreEqual(dvertices[lastDicretizedVertexIndex].Y, endVertex.Y); Assert.AreEqual(dvertices[2].X, 2.5); Assert.AreEqual(dvertices[2].Y, 5); } }