//Check if the lines are interescting in 2d space //Alternative version from http://thirdpartyninjas.com/blog/2008/10/07/line-segment-intersection/ public static bool LineLineIntersection(out GeoPoint intersection, GeoSegment line1, GeoSegment line2) { bool isIntersecting = false; intersection = GeoPoint.Zero; //3d -> 2d double p1_x = line1.Start.Longitude; double p1_y = line1.Start.Latitude; double p2_x = line1.End.Longitude; double p2_y = line1.End.Latitude; double p3_x = line2.Start.Longitude; double p3_y = line2.Start.Latitude; double p4_x = line2.End.Longitude; double p4_y = line2.End.Latitude; double denominator = (p4_y - p3_y) * (p2_x - p1_x) - (p4_x - p3_x) * (p2_y - p1_y); //Make sure the denominator is > 0, if so the lines are parallel if (denominator != 0) { double u_a = ((p4_x - p3_x) * (p1_y - p3_y) - (p4_y - p3_y) * (p1_x - p3_x)) / denominator; double u_b = ((p2_x - p1_x) * (p1_y - p3_y) - (p2_y - p1_y) * (p1_x - p3_x)) / denominator; //Is intersecting if u_a and u_b are between 0 and 1 if (u_a >= 0 && u_a <= 1 && u_b >= 0 && u_b <= 1) { intersection = new GeoPoint(p1_y + u_a * (p2_y - p1_y), p1_x + u_a * (p2_x - p1_x)); isIntersecting = true; } } return(isIntersecting); }
public IEnumerable <GeoSegment> GetDEMNorthSouthLines(List <FileMetadata> segTiles, GeoPoint westernSegPoint, GeoPoint easternSegPoint) { // Get the first north west tile and last south east tile. // The lines are bounded by those tiles foreach (var tilesByX in segTiles.GroupBy(t => t.StartLon).OrderBy(g => g.Key)) { List <FileMetadata> NSTilesOrdered = tilesByX.OrderByDescending(t => t.StartLat).ToList(); FileMetadata top = NSTilesOrdered.First(); FileMetadata bottom = NSTilesOrdered.Last(); // TIP: can optimize here starting with min(westernSegPoint, startlon) but careful ! GeoPoint curPoint = new GeoPoint(top.StartLat, top.StartLon); // X Index in tile coords int curIndex = (int)Math.Ceiling((curPoint.Longitude - top.StartLon) / top.PixelScaleX); while (IsPointInTile(top, curPoint)) { if (curIndex >= top.Width) { break; } curPoint.Longitude = top.StartLon + (top.pixelSizeX * curIndex); if (curPoint.Longitude > easternSegPoint.Longitude) { break; } GeoSegment line = new GeoSegment(new GeoPoint(top.OriginLatitude, curPoint.Longitude), new GeoPoint(bottom.EndLatitude, curPoint.Longitude)); curIndex++; yield return(line); } } }
public IEnumerable <GeoSegment> GetDEMWestEastLines(List <FileMetadata> segTiles, GeoPoint northernSegPoint, GeoPoint southernSegPoint) { // Get the first north west tile and last south east tile. // The lines are bounded by those tiles foreach (var tilesByY in segTiles.GroupBy(t => t.StartLat).OrderByDescending(g => g.Key)) { List <FileMetadata> WETilesOrdered = tilesByY.OrderBy(t => t.StartLon).ToList(); FileMetadata left = WETilesOrdered.First(); FileMetadata right = WETilesOrdered.Last(); GeoPoint curPoint = new GeoPoint(left.StartLat, left.StartLon); // Y Index in tile coords int curIndex = (int)Math.Ceiling((left.StartLat - curPoint.Latitude) / left.PixelScaleY); while (IsPointInTile(left, curPoint)) { if (curIndex >= left.Height) { break; } curPoint.Latitude = left.StartLat + (left.pixelSizeY * curIndex); if (curPoint.Latitude < southernSegPoint.Latitude) { break; } GeoSegment line = new GeoSegment(new GeoPoint(curPoint.Latitude, left.OriginLongitude), new GeoPoint(curPoint.Latitude, right.EndLongitude)); curIndex++; yield return(line); } } }
/// <summary> /// Finds all intersections between given segment and DEM grid /// </summary> /// <param name="startLon">Segment start longitude</param> /// <param name="startLat">Segment start latitude</param> /// <param name="endLon">Segment end longitude</param> /// <param name="endLat">Segment end latitude</param> /// <param name="segTiles">Metadata files <see cref="GeoTiffService.GetCoveringFiles"/> to see how to get them relative to segment geometry</param> /// <param name="returnStartPoint">If true, the segment starting point will be returned. Useful when processing a line segment by segment.</param> /// <param name="returnEndPoind">If true, the segment end point will be returned. Useful when processing a line segment by segment.</param> /// <returns></returns> public List <GeoPoint> FindSegmentIntersections(double startLon, double startLat, double endLon, double endLat, List <FileMetadata> segTiles, bool returnStartPoint, bool returnEndPoind) { List <GeoPoint> segmentPointsWithDEMPoints; // Find intersections with north/south lines, // starting form segment western point to easternmost point GeoPoint westernSegPoint = startLon < endLon ? new GeoPoint(startLat, startLon) : new GeoPoint(endLat, endLon); GeoPoint easternSegPoint = startLon > endLon ? new GeoPoint(startLat, startLon) : new GeoPoint(endLat, endLon); GeoSegment inputSegment = new GeoSegment(westernSegPoint, easternSegPoint); if (segTiles.Any()) { int estimatedCapacity = (segTiles.Select(t => t.OriginLongitude).Distinct().Count() // num horizontal tiles * width * segTiles.First().Width) + (segTiles.Select(t => t.OriginLatitude).Distinct().Count() // num vertical tiles * height * segTiles.First().Height); segmentPointsWithDEMPoints = new List <GeoPoint>(estimatedCapacity); bool yAxisDown = segTiles.First().pixelSizeY < 0; if (yAxisDown == false) { throw new NotImplementedException("DEM with y axis upwards not supported."); } foreach (GeoSegment demSegment in this.GetDEMNorthSouthLines(segTiles, westernSegPoint, easternSegPoint)) { GeoPoint intersectionPoint = null; if (GeometryService.LineLineIntersection(out intersectionPoint, inputSegment, demSegment)) { segmentPointsWithDEMPoints.Add(intersectionPoint); } } // Find intersections with west/east lines, // starting form segment northernmost point to southernmost point GeoPoint northernSegPoint = startLat > endLat ? new GeoPoint(startLat, startLon) : new GeoPoint(endLat, endLon); GeoPoint southernSegPoint = startLat < endLat ? new GeoPoint(startLat, startLon) : new GeoPoint(endLat, endLon); inputSegment = new GeoSegment(northernSegPoint, southernSegPoint); foreach (GeoSegment demSegment in this.GetDEMWestEastLines(segTiles, northernSegPoint, southernSegPoint)) { GeoPoint intersectionPoint = null; if (GeometryService.LineLineIntersection(out intersectionPoint, inputSegment, demSegment)) { segmentPointsWithDEMPoints.Add(intersectionPoint); } } } else { // No DEM coverage segmentPointsWithDEMPoints = new List <GeoPoint>(2); } // add start and/or end point if (returnStartPoint) { segmentPointsWithDEMPoints.Add(inputSegment.Start); } if (returnEndPoind) { segmentPointsWithDEMPoints.Add(inputSegment.End); } // sort points in segment order // segmentPointsWithDEMPoints.Sort(new DistanceFromPointComparer(new GeoPoint(startLat, startLon))); return(segmentPointsWithDEMPoints); }