public void Isoplete(IRasterDigitalElevationModel dem, double elevationStep, NewIsohypseCallback callback) { DigitalElevationModelStatistics statistics = dem.CalculateStatistics(); double minElevation = Math.Floor(statistics.MinElevation / elevationStep) * elevationStep; double maxElevation = Math.Floor(statistics.MaxElevation / elevationStep) * elevationStep; //if (visualizer != null) //{ // GeoPosition geoPosMin = dem.GetGeoPosition (0, 0, false); // GeoPosition geoPosMax = dem.GetGeoPosition (dem.LonLength, dem.LatLength, false); // visualizer.Initialize (geoPosMin.Longitude, geoPosMin.Latitude, // geoPosMax.Longitude, geoPosMax.Latitude); //} Array2 <byte> flags = new Array2 <byte> (dem.LonLength - 1, dem.LatLength - 1); Array2 <IsohypseMovement> movements = new Array2 <IsohypseMovement> (dem.LonLength - 1, dem.LatLength - 1); int[,] adjacentCells = new int[, ] { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } }; // foreach elevation step for (double isoElev = minElevation; isoElev <= maxElevation; isoElev += elevationStep) { activityLogger.Log(ActivityLogLevel.Normal, String.Format(System.Globalization.CultureInfo.InvariantCulture, "Analyzing elevation {0}", isoElev)); //if (visualizer != null) //{ // GeoPosition geoPosMin = dem.GetGeoPosition (0, 0, false); // GeoPosition geoPosMax = dem.GetGeoPosition (dem.LongLength, dem.LatLength, false); // visualizer.Initialize (geoPosMin.Longitude, geoPosMin.Latitude, // geoPosMax.Longitude, geoPosMax.Latitude); // for (int x = 0; x < dem.LongLength; x++) // { // for (int y = 0; y < dem.LatLength; y++) // { // int elevation = dem.GetElevation (x, y); // GeoPosition geoPos = dem.GetGeoPosition (x, y); // string color = elevation >= isoElev ? "orange" : "yellow"; // visualizer.DrawPoint (color, geoPos.Longitude, geoPos.Latitude); // visualizer.DrawText ("pink", geoPos.Longitude, geoPos.Latitude, elevation.ToString ()); // } // } //} Isohypse isohypse = new Isohypse(isoElev); flags.Initialize(0); movements.Initialize(0); for (int x = 0; x < dem.LonLength - 1; x++) { for (int y = 0; y < dem.LatLength - 1; y++) { byte cellCharacteristic = 0; for (int i = 0; i < adjacentCells.GetLength(0); i++) { double adjacentCellElev = dem.GetElevationForDataPoint(x + adjacentCells[i, 0], y + adjacentCells[i, 1]); if (adjacentCellElev >= isoElev) { cellCharacteristic++; flags.SetValue((byte)(flags.GetValue(x, y) | (byte)(1 << i)), x, y); } } // skip cells which are definitively not along the isohypse if (cellCharacteristic == 0 || cellCharacteristic == 4) { continue; } if (cellCharacteristic == 2) { int maskedFlags = flags.GetValue(x, y) & 0x9; if (maskedFlags == 0 || maskedFlags == 0x9) { movements.SetValue(IsohypseMovement.North | IsohypseMovement.South, x, y); } else { maskedFlags = flags.GetValue(x, y) & 0x3; if (maskedFlags == 0 || maskedFlags == 0x3) { movements.SetValue(IsohypseMovement.West | IsohypseMovement.East, x, y); } else { movements.SetValue( IsohypseMovement.West | IsohypseMovement.East | IsohypseMovement.North | IsohypseMovement.South, x, y); } } } else { int maskedFlags = flags.GetValue(x, y) & 0x3; if (maskedFlags != 0 && maskedFlags != 0x3) { movements.SetValue(movements.GetValue(x, y) | IsohypseMovement.North, x, y); } maskedFlags = flags.GetValue(x, y) & 0x6; if (maskedFlags != 0 && maskedFlags != 0x6) { movements.SetValue(movements.GetValue(x, y) | IsohypseMovement.East, x, y); } maskedFlags = flags.GetValue(x, y) & 0xc; if (maskedFlags != 0 && maskedFlags != 0xc) { movements.SetValue(movements.GetValue(x, y) | IsohypseMovement.South, x, y); } maskedFlags = flags.GetValue(x, y) & 0x9; if (maskedFlags != 0 && maskedFlags != 0x9) { movements.SetValue(movements.GetValue(x, y) | IsohypseMovement.West, x, y); } } //if (visualizer != null) //{ // if (cellCharacteristic > 0 && cellCharacteristic < 4) // { // GeoPosition geoPos = dem.GetGeoPosition (x + 0.5, y + 0.5); // if (movements.GetValue (x, y) // == (IsohypseMovement.West | IsohypseMovement.East | IsohypseMovement.North | IsohypseMovement.South)) // visualizer.DrawText ("blue", geoPos.Longitude, geoPos.Latitude, // "X"); // //visualizer.DrawText ("blue", geoPos.Longitude, geoPos.Latitude, // // cellCharacteristic == 2 ? "K" : "T"); // //List<Point2> points = new List<Point2> (); // //if ((movements[x, y] & IsohypseMovement.North) != 0) // // points.Add (new Point2 (0.5, 0)); // //if ((movements[x, y] & IsohypseMovement.East) != 0) // // points.Add (new Point2 (1, 0.5)); // //if ((movements[x, y] & IsohypseMovement.South) != 0) // // points.Add (new Point2 (0.5, 1)); // //if ((movements[x, y] & IsohypseMovement.West) != 0) // // points.Add (new Point2 (0, 0.5)); // //List<GeoPosition> geoPoints = new List<GeoPosition> (); // //foreach (Point2 point in points) // // geoPoints.Add (dem.GetGeoPosition (x + point.X, y + point.Y)); // //visualizer.DrawLine ("black", geoPoints[0].Longitude, geoPoints[0].Latitude, // // geoPoints[1].Longitude, geoPoints[1].Latitude); // //if (geoPoints.Count > 2) // // visualizer.DrawLine ("black", geoPoints[2].Longitude, geoPoints[2].Latitude, // // geoPoints[3].Longitude, geoPoints[3].Latitude); // } //} } } for (int x = 0; x < dem.LonLength - 1; x++) { for (int y = 0; y < dem.LatLength - 1; y++) { if (movements.GetValue(x, y) != IsohypseMovement.None) { IsohypseMovements isohypseMovements = ExtractIsohypseMovements(dem, isoElev, movements, flags, x, y); Polyline isohypseSegment = ConstructIsohypseSegment(dem, isohypseMovements); isohypseSegment.RemoveDuplicateVertices(); isohypse.AddSegment(isohypseSegment); activityLogger.Log(ActivityLogLevel.Verbose, String.Format(System.Globalization.CultureInfo.InvariantCulture, "Found segment with {0} vertices", isohypseSegment.VerticesCount)); } } } if (isohypse.Segments.Count > 0) { callback(isohypse); } //isoColl.AddIsohypse (isohypse); } }
private IsohypseMovements ExtractIsohypseMovements( IRasterDigitalElevationModel dem, double isohypseElevation, Array2 <IsohypseMovement> movements, Array2 <byte> flags, int startingX, int startingY) { IsohypseMovements isohypseMovements = new IsohypseMovements(isohypseElevation); isohypseMovements.StartingX = startingX; isohypseMovements.StartingY = startingY; int x = isohypseMovements.StartingX; int y = isohypseMovements.StartingY; int lastX = 0, lastY = 0; IsohypseMovement lastMovement = IsohypseMovement.None; bool foundOneEnd = false; while (true) { // if we reached the end of the grid if (x < 0 || y < 0 || x >= dem.LonLength - 1 || y >= dem.LatLength - 1) { // have we already found one end of the segment? if (false == foundOneEnd) { // we haven't... foundOneEnd = true; // ... so reverse the segment and start moving from the other end int oldStartingX = isohypseMovements.StartingX; int oldStartingY = isohypseMovements.StartingY; isohypseMovements.ReverseIsohypseMovements(x, y); x = oldStartingX; y = oldStartingY; } else { // we have, so we can exit break; } } if (x == isohypseMovements.StartingX && y == isohypseMovements.StartingY && isohypseMovements.Movements.Count > 0) { // we found the starting point, this is a closed polygon isohypseMovements.IsClosed = true; break; } IsohypseMovement currentCellMovement = movements.GetValue(x, y); bool movementFound = false; for (int i = 0; i < 4; i++) { IsohypseMovement movementConsidered = (IsohypseMovement)(1 << i); if (0 != (currentCellMovement & movementConsidered)) { int nextX = x, nextY = y; switch (movementConsidered) { case IsohypseMovement.East: nextX++; break; case IsohypseMovement.North: nextY--; break; case IsohypseMovement.South: nextY++; break; case IsohypseMovement.West: nextX--; break; default: throw new NotImplementedException(); } // find the opposite movement of the last movement IsohypseMovement oppositeMovement = IsohypseMovements.GetOppositeMovement(lastMovement); if (lastMovement != IsohypseMovement.None) { // check that we haven't moved back if (nextX == lastX && nextY == lastY) { continue; } // special case when all movements are possible if ((((int)currentCellMovement) & 0xf) == 0xf) { IsohypseMovement movementCombination = movementConsidered | oppositeMovement; // check that we haven't moved in such a way as to make the polygon cross itself if ((movementCombination & (IsohypseMovement.North | IsohypseMovement.South)) == (IsohypseMovement.North | IsohypseMovement.South)) { continue; } // check that we haven't moved in such a way as to make the polygon cross itself if ((movementCombination & (IsohypseMovement.West | IsohypseMovement.East)) == (IsohypseMovement.West | IsohypseMovement.East)) { continue; } // check that the movement is the right one in regards to cells elevations if (flags.GetValue(x, y) == 5) { if (movementCombination == (IsohypseMovement.South | IsohypseMovement.East) || movementCombination == (IsohypseMovement.North | IsohypseMovement.West)) { continue; } } else if (flags.GetValue(x, y) == 10) { if (movementCombination == (IsohypseMovement.South | IsohypseMovement.West) || movementCombination == (IsohypseMovement.North | IsohypseMovement.East)) { continue; } } else { throw new NotImplementedException(); } } } isohypseMovements.Movements.Add(movementConsidered); // remove the used movement from the array movements.SetValue(movements.GetValue(x, y) & ~movementConsidered, x, y); // remove this opposite movement from the array movements.SetValue(movements.GetValue(x, y) & ~oppositeMovement, x, y); lastX = x; lastY = y; lastMovement = movementConsidered; x = nextX; y = nextY; movementFound = true; break; } } if (movementFound == false) { throw new NotImplementedException(); } } return(isohypseMovements); }