Beispiel #1
0
        //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 BottomProfile(int numberOfPointsInTransect, GeoSegment geoSegment , Bathymetry bathymetry)
 {
     MaxDepth = double.MinValue;
     Profile = new List<BottomProfilePoint>();
     Length = Geo.RadiansToMeters(geoSegment.LengthRadians);
     //Length = transect.StartPoint.DistanceKilometers(transect.EndPoint) * 1000;
     var stepLength = Length / (numberOfPointsInTransect - 1);
     var stepFraction = 1.0 / numberOfPointsInTransect;
     //var currentPoint = transect.StartPoint;
     var currentPoint = geoSegment[0];
     var curRange = 0.0;
     for (var i = 0; i < numberOfPointsInTransect; i++)
     {
         var curDepth = Math.Round(-1.0 * TwoDBilinearApproximation(bathymetry, currentPoint), 2);
         Profile.Add(new BottomProfilePoint { Depth = curDepth, Range = (curRange / 1000.0) });
         if (MaxDepth < curDepth)
         {
             MaxDepth = curDepth;
             DeepestPoint = currentPoint;
         }
         currentPoint = geoSegment.Slerp(stepFraction * i);
         //currentPoint = currentPoint.Offset(Geo.KilometersToRadians(stepLength / 1000f), Geo.DegreesToRadians(transect.Bearing));
         curRange += stepLength;
     }
     //Profile = profile.ToList();
 }
Beispiel #3
0
        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);
                }
            }
        }
Beispiel #4
0
        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);
                }
            }
        }
 private static void ValidateGeoSegment(GeoSegment segment, SectorElementCollection sectorElements, IEventLogger events)
 {
     if (!ColourValid(segment.Colour, sectorElements))
     {
         string errorMessage =
             $"Invalid colour value {segment.Colour} in GEO segment {segment.GetCompileData(sectorElements)}";
         events.AddEvent(new ValidationRuleFailure(errorMessage, segment));
     }
 }
 private static void ValidateGeoSegment(GeoSegment segment, SectorElementCollection sectorElements, IEventLogger events)
 {
     if (!PointsValid(segment.FirstPoint, segment.SecondPoint, sectorElements))
     {
         string message = $"Invalid waypoint on GEO segment: {segment.GetCompileData(sectorElements)}";
         events.AddEvent(
             new ValidationRuleFailure(message, segment)
             );
     }
 }
Beispiel #7
0
        public void FullEarthRectContainsAverageSegment()
        {
            Rect fullEarth = GetFullEarthRect();

            GeoCoordinates segA = new GeoCoordinates(0, -10);
            GeoCoordinates segB = new GeoCoordinates(10, 10);
            GeoSegment     seg  = new GeoSegment(segA, segB);

            Assert.True(GeoRectUtils.RectNearSegment(seg, fullEarth, 0));
        }
Beispiel #8
0
        public void FullEarthRectContainsSegmentCrossingPrimeMeridian()
        {
            Rect fullEarth = GetFullEarthRect();

            GeoCoordinates segA = new GeoCoordinates(-10, 170);
            GeoCoordinates segB = new GeoCoordinates(10, 190);
            GeoSegment     seg  = new GeoSegment(segA, segB);

            Assert.True(GeoRectUtils.RectNearSegment(seg, fullEarth, 0));
        }
Beispiel #9
0
 public GeoSegmentTest()
 {
     this.segment = new GeoSegment(
         new Point(new Coordinate("abc", "def")),
         new Point(new Coordinate("ghi", "jkl")),
         "red",
         DefinitionFactory.Make(),
         DocblockFactory.Make(),
         CommentFactory.Make()
         );
 }
Beispiel #10
0
        public void DistanceToPointForSmallSegmentNotCrossingPrimeMeridian()
        {
            Vector2 point = new Vector2(1, 1);
            Vector2 segA  = new Vector2(-1, 0);
            Vector2 segB  = new Vector2(1, 0);

            GeoCoordinates geoPoint   = new GeoCoordinates(point.y, point.x);
            GeoSegment     geoSegment = new GeoSegment(
                new GeoCoordinates(segA.y, segA.x),
                new GeoCoordinates(segB.y, segB.x));

            Assert.Equal(
                Geometry2d.PointToSegmentDistance(segA, segB, point),
                geoSegment.DistanceToPoint(geoPoint),
                6);
        }
Beispiel #11
0
        public void RectIsntNearSegment()
        {
            Rect rect = new Rect
            {
                xMin = -10,
                xMax = 10,
                yMin = -10,
                yMax = 10
            };

            GeoCoordinates segA = new GeoCoordinates(11, -20);
            GeoCoordinates segB = new GeoCoordinates(11, 20);
            GeoSegment     seg  = new GeoSegment(segA, segB);

            Assert.False(GeoRectUtils.RectNearSegment(seg, rect, 0.5));
        }
Beispiel #12
0
        public void RectNearSegmentWorksWithRectCrossingPrimeMeridian2()
        {
            Rect rect = new Rect
            {
                xMin = -185,
                xMax = -175,
                yMin = -10,
                yMax = 10
            };

            GeoCoordinates segA = new GeoCoordinates(-30, -177);
            GeoCoordinates segB = new GeoCoordinates(30, -177);
            GeoSegment     seg  = new GeoSegment(segA, segB);

            Assert.True(GeoRectUtils.RectNearSegment(seg, rect, 0));
        }
Beispiel #13
0
        public void GeoRectIsNearSegmentItContains()
        {
            Rect rect = new Rect
            {
                xMin = -10,
                xMax = 10,
                yMin = -10,
                yMax = 10
            };

            GeoCoordinates segA = new GeoCoordinates(-1, 0);
            GeoCoordinates segB = new GeoCoordinates(1, 0);
            GeoSegment     seg  = new GeoSegment(segA, segB);

            Assert.True(GeoRectUtils.RectNearSegment(seg, rect, 0));
        }
Beispiel #14
0
        public void DistanceToPointForSegmentCrossingPrimeMeridian()
        {
            Vector2 point = new Vector2(-180, 0);
            Vector2 segA  = new Vector2(175, -10);
            Vector2 segB  = new Vector2(185, 10);

            GeoCoordinates geoPoint   = new GeoCoordinates(point.y, point.x);
            GeoSegment     geoSegment = new GeoSegment(
                new GeoCoordinates(segA.y, segA.x),
                new GeoCoordinates(segB.y, segB.x));

            Assert.Equal(
                0,
                geoSegment.DistanceToPoint(geoPoint),
                6);
        }
Beispiel #15
0
        public void GeoRectIsNearSegmentThatIntersectsItsEdge()
        {
            Rect rect = new Rect
            {
                xMin = -10,
                xMax = 10,
                yMin = -10,
                yMax = 10
            };

            GeoCoordinates segA = new GeoCoordinates(0, -20);
            GeoCoordinates segB = new GeoCoordinates(0, 20);
            GeoSegment     seg  = new GeoSegment(segA, segB);

            Assert.True(GeoRectUtils.RectNearSegment(seg, rect, 0));
        }
Beispiel #16
0
        public void GeoRectIsWithinDistanceOfSegment()
        {
            Rect rect = new Rect
            {
                xMin = -10,
                xMax = 10,
                yMin = -10,
                yMax = 10
            };

            GeoCoordinates segA = new GeoCoordinates(11, -20);
            GeoCoordinates segB = new GeoCoordinates(11, 20);
            GeoSegment     seg  = new GeoSegment(segA, segB);

            Assert.True(GeoRectUtils.RectNearSegment(seg, rect, 1 + 1e-10));
        }
Beispiel #17
0
        public void SmallRectContainsSegmentCrossingPrimeMeridianOnOppositeSide()
        {
            Rect rect = new Rect
            {
                xMin = -181,
                xMax = -179,
                yMin = 10,
                yMax = 13
            };

            GeoCoordinates segA = new GeoCoordinates(11, 170);
            GeoCoordinates segB = new GeoCoordinates(11, 190);
            GeoSegment     seg  = new GeoSegment(segA, segB);

            Assert.True(GeoRectUtils.RectNearSegment(seg, rect, 0));
        }
 /// <summary>
 /// Compute the result of a specular reflection between incidentSegment and edgeSegment.  
 /// If incidentSegment and edgeSegment do not intersect somewhere along both of their 
 /// lengths, null is returned.  The returned segment is one meter long, originating 
 /// at the point of reflection and terminating one meter along the reflected path.
 /// </summary>
 /// <param name="incidentSegment"></param>
 /// <param name="edgeSegment"></param>
 /// <returns>Angle of reflection, in radians</returns>
 public static GeoSegment Reflect(this GeoSegment incidentSegment, GeoSegment edgeSegment)
 {
     var intersectionPoint = incidentSegment.Intersection(edgeSegment);
     if (intersectionPoint == null) return null;
     var intersectionFraction1 = new GeoSegment(incidentSegment[0], intersectionPoint).LengthRadians / incidentSegment.LengthRadians;
     var intersectionFraction2 = new GeoSegment(edgeSegment[0], intersectionPoint).LengthRadians / edgeSegment.LengthRadians;
     var fiftyCm1 = 1 / (Geo.RadiansToKilometers(incidentSegment.LengthRadians) * 2000);
     var fiftyCm2 = 1 / (Geo.RadiansToKilometers(edgeSegment.LengthRadians) * 2000);
     // Create two one-meter-long segments, centered on the intersection point so we can pretend we're doing geometry on a plane
     var incidentUnit = incidentSegment.SubSegment(intersectionFraction1 - fiftyCm1, intersectionFraction1 + fiftyCm1);
     var edgeUnit = edgeSegment.SubSegment(intersectionFraction2 - fiftyCm2, intersectionFraction2 + fiftyCm2);
     var incidentVector = new SurfaceVector(incidentUnit);
     var edgeVector = new SurfaceVector(edgeUnit);
     var rightNormal = edgeVector.Rotate(-MoreMath.PiOverTwo);
     var isRightNormal = incidentVector.Dot(rightNormal) <= 0;
     var normal = isRightNormal ? rightNormal : edgeVector.Rotate(MoreMath.PiOverTwo);
     var reflectionVector = incidentVector - normal.Scale(2 * normal.Dot(incidentVector));
     return new GeoSegment(intersectionPoint, intersectionPoint.Offset(Geo.KilometersToRadians(0.001), reflectionVector.GeoAzimuth));
 }
 /// <summary>
 /// Bounce a platform around inside a given perimeter
 /// </summary>
 /// <param name="perimeter">A GeoArray of points in the perimeter, which must satisfy certain conditions (no segments may cross and the polygon 
 /// must be closed)</param>
 /// <param name="startPoint">A Geo containing the starting point.  If this is null, a point inside the perimeter is chosen randomly</param>
 /// <param name="initialCourse">The initial course, in radians from true north.  If startPoint is null, or if initialCourse is NaN, this is 
 /// chosen randomly</param>
 /// <param name="minimumCourseLength">The minimum length of the returned course, in meters</param>
 /// <returns>A GeoArray containing the start location and each point where the course bounces off the perimeter</returns>
 public static GeoArray PerimeterBounce(this GeoArray perimeter, Geo startPoint, double initialCourse, double minimumCourseLength)
 {
     if (!perimeter.IsClosed) throw new InvalidPerimeterException("Perimeter is not closed");
     if (perimeter.HasCrossingSegments) throw new InvalidPerimeterException("Perimeter is not a simple polygon (segments cross each other)");
     var points = new List<Geo>();
     while ((startPoint == null) || (!startPoint.IsInside(perimeter)))
     {
         var distance = Random.NextDouble() * perimeter.BoundingCircle.Radius;
         var azimuth = Random.NextDouble() * MoreMath.TwoPi;
         startPoint = perimeter.Center.Offset(distance, azimuth);
     }
     points.Add(startPoint);
     if (double.IsNaN(initialCourse)) initialCourse = Random.NextDouble()*MoreMath.TwoPi;
     var courseSegment = new GeoSegment(startPoint, startPoint.Offset(Geo.KilometersToRadians(0.001), initialCourse)).Scale(1000 * Geo.RadiansToKilometers(MoreMath.PiOverTwo));
     var bounceCount = 1;
     while (minimumCourseLength > 0)
     {
         var minIntersectionRange = double.MaxValue;
         GeoSegment firstIntersectingSegment = null;
         Geo firstIntersection = null;
         foreach (var segment in perimeter.Segments)
         {
             var intersection = courseSegment.Intersection(segment);
             if (intersection == null) continue;
             var curIntersectionRange = startPoint.DistanceRadians(intersection);
             if (curIntersectionRange < Geo.KilometersToRadians(0.001) || curIntersectionRange >= minIntersectionRange) continue;
             minIntersectionRange = curIntersectionRange;
             firstIntersectingSegment = segment;
             firstIntersection = intersection;
         }
         if (firstIntersection == null) throw new PerimeterBounceException(string.Format("Course segment failed to intersect the perimeter on bounce {0}", bounceCount));
         var actualCourseSegment = new GeoSegment(points.Last(), firstIntersection);
         minimumCourseLength -= Geo.RadiansToKilometers(actualCourseSegment.LengthRadians) * 1000;
         points.Add(firstIntersection);
         var reflectedSegment = courseSegment.Reflect(firstIntersectingSegment);
         var reflectionAzimuth = reflectedSegment[0].Azimuth(reflectedSegment[1]);
         courseSegment = new GeoSegment(reflectedSegment[1], 1000 * Geo.RadiansToKilometers(MoreMath.PiOverTwo), Geo.RadiansToDegrees(reflectionAzimuth));
         bounceCount++;
     }
     return new GeoArray(points);
 }
Beispiel #20
0
        public void LineLineIntersectionTest()
        {
            string   wkt1  = "LINESTRING(-5.888671875 47.90161354142077,3.4716796875 44.11914151643737)";
            string   wkt2  = "LINESTRING(-2.8564453125 44.30812668488613,5.625 48.166085419012525)";
            Geometry geom1 = GeometryService.ParseWKTAsGeometry(wkt1);
            Geometry geom2 = GeometryService.ParseWKTAsGeometry(wkt2);


            Geometry intersection = geom1.Intersection(geom2);

            GeoSegment seg1 = geom1.Segments().First();
            GeoSegment seg2 = geom2.Segments().First();
            GeoPoint   intersectionResult = GeoPoint.Zero;

            bool intersects = GeometryService.LineLineIntersection(out intersectionResult, seg1, seg2);


            double dist = intersection.Coordinate.ToGeoPoint().DistanceTo(intersectionResult);


            Assert.True(dist < 0.05d, "Problem in intersection calculation.");
        }
Beispiel #21
0
        public void LineLineIntersectionTest()
        {
            string      wkt1         = "LINESTRING(-5.888671875 47.90161354142077,3.4716796875 44.11914151643737)";
            string      wkt2         = "LINESTRING(-2.8564453125 44.30812668488613,5.625 48.166085419012525)";
            SqlGeometry geom1        = GeometryService.ParseWKTAsGeometry(wkt1);
            SqlGeometry geom2        = GeometryService.ParseWKTAsGeometry(wkt2);
            SqlGeometry intersection = geom1.STIntersection(geom2);

            GeoSegment seg1 = new GeoSegment(new GeoPoint(geom1.STStartPoint().STY.Value, geom1.STStartPoint().STX.Value), new GeoPoint(geom1.STEndPoint().STY.Value, geom1.STEndPoint().STX.Value));
            GeoSegment seg2 = new GeoSegment(new GeoPoint(geom2.STStartPoint().STY.Value, geom2.STStartPoint().STX.Value), new GeoPoint(geom2.STEndPoint().STY.Value, geom2.STEndPoint().STX.Value));
            GeoPoint   intersectionResult = GeoPoint.Zero;

            bool intersects = GeometryService.LineLineIntersection(out intersectionResult, seg1, seg2);


            SqlGeography geog1 = null;

            intersection.TryToGeography(out geog1);
            SqlGeography geog2 = SqlGeography.Point(intersectionResult.Latitude, intersectionResult.Longitude, 4326);
            double       dist  = geog1.STDistance(geog2).Value;

            Assert.IsTrue(dist < 0.05d, "Problem in intersection calculation.");
        }
 /// <summary>
 /// Is geo on the specified segment?
 /// </summary>
 /// <param name="segment"></param>
 /// <param name="geo"></param>
 /// <returns>true if geo is on segment, false otherwise</returns>
 public static bool IsOn(this Geo geo, GeoSegment segment)
 {
     return (MoreMath.IsApproximatelyEqual(Math.Abs(segment[0].Cross(segment[1]).Normalized.Dot(geo)), 0.0) &&
             (segment[0].DistanceRadians(geo) <= segment[0].DistanceRadians(segment[1])) &&
             (segment[1].DistanceRadians(geo) <= segment[1].DistanceRadians(segment[0])));
 }
 /// <summary>
 /// Calculates the great circle distance from geo to the great circle described by segment.
 /// </summary>
 /// <param name="geo"></param>
 /// <param name="segment"></param>
 /// <returns>distance, in radians</returns>
 public static double DistanceToGreatCircle(this Geo geo, GeoSegment segment)
 {
     var cosTheta = segment.Normal.Dot(geo.Normalized);
     var theta = Math.Acos(cosTheta);
     return Math.Abs(Math.PI / 2 - theta);
 }
        /// <summary>
        /// Recursively calculates the nearest sound speed profiles along a given radial using a binary search-like algorithm
        /// 1. If start and end points are provided, use them, otherwise find the nearest SSP to each of those points
        /// 2. If the start point was calculated, add the SSP closest to the calculated start point to the enumerable
        /// 2. If the SSPs closest to the start and end points are within 10m of each other they are considered identical and there are 
        ///    assumed to be no more intervening points
        /// 3. If the SSPs closest to the start and end points are NOT within 10m of each other, calculate the midpoint of the segment 
        ///    and find the nearest SSP to that point.
        /// 4. If the SSP nearest the midpoint is not within 10m of the SSP nearest to the start point, recursively call this function to
        ///    find the new midpoint between the start point and the current midpoint
        /// 5. Return the
        /// </summary>
        /// <param name="segment"></param>
        /// <param name="startDistance"></param>
        /// <param name="startProfile"></param>
        /// <param name="endProfile"></param>
        /// <param name="bottomProfile"></param>
        /// <param name="soundSpeedData"></param>
        /// <param name="deepestProfile"></param>
        /// <returns></returns>
        static IEnumerable<Tuple<double, SoundSpeedProfile>> ProfilesAlongRadial(GeoSegment segment, double startDistance, SoundSpeedProfile startProfile, SoundSpeedProfile endProfile, BottomProfile bottomProfile, EnvironmentData<SoundSpeedProfile> soundSpeedData, SoundSpeedProfile deepestProfile)
        {
            var returnStartProfile = false;
            var returnEndProfile = false;
            if (startProfile == null)
            {
                returnStartProfile = true;
                startProfile = soundSpeedData.IsFast2DLookupAvailable
                                   ? soundSpeedData.GetNearestPointAsync(segment[0]).Result.Extend(deepestProfile)
                                   : soundSpeedData.GetNearestPoint(segment[0]).Extend(deepestProfile);
            }
            if (endProfile == null)
            {
                returnEndProfile = true;
                endProfile = soundSpeedData.IsFast2DLookupAvailable
                                 ? soundSpeedData.GetNearestPointAsync(segment[1]).Result.Extend(deepestProfile)
                                 : soundSpeedData.GetNearestPoint(segment[1]).Extend(deepestProfile);
            }
            if (returnStartProfile) yield return Tuple.Create(NearestBottomProfileDistanceTo(bottomProfile, startDistance), startProfile);
            // If the start and end profiles are the same, we're done
            if (startProfile.DistanceKilometers(endProfile) <= 0.01) yield break;

            // If not, create a middle profile
            var middleProfile = soundSpeedData.IsFast2DLookupAvailable
                                    ? soundSpeedData.GetNearestPointAsync(segment.Center).Result.Extend(deepestProfile)
                                    : soundSpeedData.GetNearestPoint(segment.Center).Extend(deepestProfile);
            // If the center profile is different from BOTH endpoints
            if (startProfile.DistanceKilometers(middleProfile) > 0.01 && middleProfile.DistanceKilometers(endProfile) > 0.01)
            {
                // Recursively create and return any new sound speed profiles between the start and the center
                var firstHalfSegment = new GeoSegment(segment[0], segment.Center);
                foreach (var tuple in ProfilesAlongRadial(firstHalfSegment, startDistance, startProfile, middleProfile, bottomProfile, soundSpeedData, deepestProfile)) yield return tuple;

                var centerDistance = startDistance + Geo.RadiansToKilometers(segment[0].DistanceRadians(segment.Center));
                // return the center profile
                yield return Tuple.Create(NearestBottomProfileDistanceTo(bottomProfile, centerDistance), middleProfile);

                // Recursively create and return any new sound speed profiles between the center and the end
                var secondHalfSegment = new GeoSegment(segment.Center, segment[1]);
                foreach (var tuple in ProfilesAlongRadial(secondHalfSegment, centerDistance, middleProfile, endProfile, bottomProfile, soundSpeedData, deepestProfile)) yield return tuple;
            }
            var endDistance = startDistance + Geo.RadiansToKilometers(segment.LengthRadians);
            // return the end profile
            if (returnEndProfile) yield return Tuple.Create(NearestBottomProfileDistanceTo(bottomProfile, endDistance), endProfile);
        }
 public void Add(Scenarios.TransmissionLoss transmissionLoss, double bearing)
 {
     var geoRect = (GeoRect)transmissionLoss.AnalysisPoint.Scenario.Location.GeoRect;
     var segment = new GeoSegment(transmissionLoss.AnalysisPoint.Geo, transmissionLoss.Modes[0].MaxPropagationRadius, bearing);
     if (!geoRect.Contains(segment[0]) || !geoRect.Contains(segment[1]))
     {
         //radial.Errors.Add("This radial extends beyond the location boundaries");
         return;
     }
     //Debug.WriteLine("{0}: Queueing calculation of transmission loss for radial bearing {1} degrees, of mode {2} in analysis point {3}", DateTime.Now, radial.Bearing, radial.TransmissionLoss.Mode.ModeName, (Geo)radial.TransmissionLoss.AnalysisPoint.Geo); 
     Radial outRadial;
     if (WorkQueue.TryGetValue(radial.Guid, out outRadial)) return;
     WorkQueue.Add(radial.Guid, radial);
     _calculatorQueue.Post(radial);
 }
        /// <summary>
        /// Wrap a fixed-distance corridor around an (open) path, as specified by a GeoArray
        /// </summary>
        /// <param name="path">Open path, must not have repeated points or consecutive antipodes</param>
        /// <param name="radius">Distance from path to widen corridor, in angular radians.</param>
        /// <param name="err">maximum angle of rounded edges, in radians. If 0, will directly cut outside bends.</param>
        /// <param name="roundEndCaps">if true, will round end caps</param>
        /// <returns>a closed polygon representing the specified corridor around the path.</returns>
        public static GeoArray ComputeCorridor(this IGeoArray path, double radius, double err, bool roundEndCaps)
        {
            if (radius < 0) throw new ArgumentException("Must be non negative", "radius");
            if (path == null) throw new ArgumentException("Must be non null", "path");
            if (path.IsClosed) throw new ArgumentException("Must not be closed", "path");

            var pl = path.Length;
            if (pl < 2)
                return null;

            // polygon will be right[0],...,right[n],left[m],...,left[0]
            var right = new List<Geo>();
            var left = new List<Geo>();

            Geo g0 = null; // previous point
            Geo n0 = null; // previous normal vector
            Geo l0 = null;
            Geo r0 = null;

            var g1 = path[0]; // current point

            int j;
            for (var i = 1; i < pl; i++)
            {
                var g2 = path[i]; // next point
                var n1 = g1.Cross(g2).Normalized; // n is perpendicular to the vector
                // from g1 to g2
                n1 = n1.Scale(radius); // normalize to radius
                // these are the offsets on the g2 side at g1
                var r1b = g1 + n1;
                var l1b = g1 - n1;

                if (n0 == null)
                {
                    if (roundEndCaps && err > 0)
                    {
                        // start cap
                        var arc = g1.ApproximateArc(l1b, r1b, err);
                        for (j = arc.Length - 1; j >= 0; j--)
                        {
                            right.Add(arc[j]);
                        }
                    }
                    else
                    {
                        // no previous point - we'll just be square
                        right.Add(l1b);
                        left.Add(r1b);
                    }
                    // advance normals
                    l0 = l1b;
                    r0 = r1b;
                }
                else
                {
                    // otherwise, compute a more complex shape

                    // these are the right and left on the g0 side of g1
                    var r1a = g1 + n0;
                    var l1a = g1 - n0;

                    var handed = g0.Cross(g1).Dot(g2); // right or left handed
                    // divergence
                    if (handed > 0)
                    {
                        // left needs two points, right needs 1
                        if (err > 0)
                        {
                            var arc = g1.ApproximateArc(l1b, l1a, err);
                            for (j = arc.Length - 1; j >= 0; j--)
                            {
                                right.Add(arc[j]);
                            }
                        }
                        else
                        {
                            right.Add(l1a);
                            right.Add(l1b);
                        }
                        l0 = l1b;

                        var ip = new GeoSegment(r0, r1a).GreatCircleIntersection(new GeoSegment(r1b, g2 + n1));
                        // if they intersect, take the intersection, else use the
                        // points and punt
                        if (ip != null)
                        {
                            left.Add(ip);
                        }
                        else
                        {
                            left.Add(r1a);
                            left.Add(r1b);
                        }
                        r0 = ip;
                    }
                    else
                    {
                        var ip = new GeoSegment(l0, l1a).GreatCircleIntersection(new GeoSegment(l1b, g2 - n1));
                        // if they intersect, take the intersection, else use the
                        // points and punt
                        if (ip != null)
                        {
                            right.Add(ip);
                        }
                        else
                        {
                            right.Add(l1a);
                            right.Add(l1b);
                        }
                        l0 = ip;
                        if (err > 0)
                        {
                            var arc = g1.ApproximateArc(r1a, r1b, err);
                            for (j = 0; j < arc.Length; j++)
                            {
                                left.Add(arc[j]);
                            }
                        }
                        else
                        {
                            left.Add(r1a);
                            left.Add(r1b);
                        }
                        r0 = r1b;
                    }
                }

                // advance points
                g0 = g1;
                n0 = n1;
                g1 = g2;
            }

            // finish it off
            var rn = g1 - n0;
            var ln = g1 + n0;
            if (roundEndCaps && err > 0)
            {
                // end cap
                var arc = g1.ApproximateArc(ln, rn, err);
                for (j = arc.Length - 1; j >= 0; j--)
                {
                    right.Add(arc[j]);
                }
            }
            else
            {
                right.Add(rn);
                left.Add(ln);
            }

            var ll = right.Count;
            var rl = left.Count;
            var result = new List<Geo>();
            for (var i = 0; i < ll; i++)
            {
                result.Add(right[i]);
            }
            for (var i = rl - 1; i >= 0; i--)
            {
                result.Add(left[i]);
            }
            return new GeoArray(result);
        }
Beispiel #27
0
        /// <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);
        }
        public void ParseData(AbstractSectorDataFile data)
        {
            bool foundFirst = false;

            // Set up some variables for the first declaration line
            string     name = "";
            Point      initialFirstPoint  = new Point("");
            Point      initialSecondPoint = new Point("");
            string     initialColour      = "0";
            Definition initialDefinition  = new Definition("", 1);
            Comment    initialComment     = new Comment("");
            Docblock   initialDocblock    = new Docblock();

            List <GeoSegment> segments = new List <GeoSegment>();

            foreach (SectorData line in data)
            {
                // If not found the first item, we should check it's a name.
                if (!foundFirst)
                {
                    if (!this.IsNameSegment(line))
                    {
                        this.eventLogger.AddEvent(
                            new SyntaxError("Invalid start to geo segment, expected a name", line)
                            );
                        return;
                    }

                    foundFirst = true;

                    // Set up the segment
                    int nameEndIndex = this.GetEndOfNameIndex(line);
                    name = string.Join(' ', line.dataSegments.GetRange(0, nameEndIndex));
                    line.dataSegments.RemoveRange(0, nameEndIndex);

                    try
                    {
                        GeoSegment firstSegment = this.ParseGeoSegment(line);
                        initialFirstPoint  = firstSegment.FirstPoint;
                        initialSecondPoint = firstSegment.SecondPoint;
                        initialColour      = firstSegment.Colour;
                        initialDefinition  = firstSegment.GetDefinition();
                        initialDocblock    = firstSegment.Docblock;
                        initialComment     = firstSegment.InlineComment;
                    }
                    catch (ArgumentException)
                    {
                        // Syntax errors dealt with in segment parsing method
                        return;
                    }

                    continue;
                }

                // If it's a name segment, we should save our progress and start afresh
                if (this.IsNameSegment(line))
                {
                    // Add the full geo element
                    this.elements.Add(
                        new Geo(
                            name,
                            initialFirstPoint,
                            initialSecondPoint,
                            initialColour,
                            segments,
                            initialDefinition,
                            initialDocblock,
                            initialComment
                            )
                        );

                    // Reset the segments array
                    segments = new List <GeoSegment>();

                    // Set up the segment
                    int nameEndIndex = this.GetEndOfNameIndex(line);
                    name = string.Join(' ', line.dataSegments.GetRange(0, nameEndIndex));
                    line.dataSegments.RemoveRange(0, nameEndIndex);

                    try
                    {
                        GeoSegment firstSegment = this.ParseGeoSegment(line);
                        initialFirstPoint  = firstSegment.FirstPoint;
                        initialSecondPoint = firstSegment.SecondPoint;
                        initialColour      = firstSegment.Colour;
                        initialDefinition  = firstSegment.GetDefinition();
                        initialDocblock    = firstSegment.Docblock;
                        initialComment     = firstSegment.InlineComment;
                    }
                    catch (ArgumentException)
                    {
                        // Syntax errors dealt with in segment parsing method
                        return;
                    }

                    continue;
                }

                // Otherwise, process the segment
                try
                {
                    segments.Add(this.ParseGeoSegment(line));
                }
                catch
                {
                    // Syntax errors dealt with in segment parsing method
                    return;
                }
            }

            // Add final geo element
            this.elements.Add(
                new Geo(
                    name,
                    initialFirstPoint,
                    initialSecondPoint,
                    initialColour,
                    segments,
                    initialDefinition,
                    initialDocblock,
                    initialComment
                    )
                );
        }
 /// <summary>
 /// Treating the passed in GeoSegments as planar vectors, return the dot product
 /// </summary>
 /// <param name="segment1"></param>
 /// <param name="segment2"></param>
 /// <returns></returns>
 public static double Dot(this GeoSegment segment1, GeoSegment segment2)
 {
     // Using Geo only for convenience, these are NOT Geos, really!
     // X is delta longitude, Y is delta latitude, Z is always zero.
     var vec1 = new Geo(segment1[1].Longitude - segment1[0].Longitude, segment1[1].Latitude - segment1[0].Latitude, 0).Normalized;
     var vec2 = new Geo(segment2[1].Longitude - segment2[0].Longitude, segment2[1].Latitude - segment2[0].Latitude, 0).Normalized;
     return vec1.Dot(vec2);
 }
 /// <summary>
 /// Find the intersection of the great circle described by segment1 and the great circle described
 /// by segment2. We assume the segments both subtend less than 180 degrees.  If either segment 
 /// happens to subtend exactly 180 degrees, the antipode of the returned point is also a valid 
 /// intersection. Note that the returned point may not actually lie on either segment, if the 
 /// intersection point lies at a different location along their respective great circles than that 
 /// subtended by the segments themselves. To check if the returned point is actually on the segment,
 /// use the Intersection extension method for the segment.
 /// </summary>
 /// <param name="segment1"> </param>
 /// <param name="segment2"> </param>
 /// <returns></returns>
 public static Geo GreatCircleIntersection(this GeoSegment segment1, GeoSegment segment2)
 {
     return segment1[0].CrossNormalize(segment1[1]).CrossNormalize(segment2[0].CrossNormalize(segment2[1]));
 }
 /// <summary>
 /// Find the intersection of the great circle described by segment1 and the great circle described
 /// by segment2, if that intersection point is contained within segment both segments. If it is not 
 /// contained within both segments, null is returned.
 /// </summary>
 /// <param name="segment1"> </param>
 /// <param name="segment2"> </param>
 /// <returns></returns>
 public static Geo Intersection(this GeoSegment segment1, GeoSegment segment2)
 {
     var geo = segment1.GreatCircleIntersection(segment2); 
     return geo.IsOn(segment1) && geo.IsOn(segment2) ? geo : geo.Antipode.IsOn(segment1) && geo.Antipode.IsOn(segment2) ? geo.Antipode : null;
 }
 /// <summary>
 /// Is geo on the specified segment or within a specified radius of it?
 /// </summary>
 /// <param name="segment"></param>
 /// <param name="geo"></param>
 /// <param name="withinRadians">
 /// Non-negative radius (in radians) that the geo must be within in order to return true.
 /// Defaults to zero (geo must be exactly on the segment to return true)
 /// </param>
 /// <returns>true if geo is near segment, false otherwise</returns>
 public static bool IsNear(this Geo geo, GeoSegment segment, double withinRadians)
 {
     if (withinRadians < 0) throw new ArgumentException("Must be non-negative", "withinRadians");
     return ((Math.Abs(segment.Normal.Dot(geo)) <= withinRadians) &&
             (segment[0].DistanceRadians(geo) <= segment[0].DistanceRadians(segment[1])) &&
             (segment[1].DistanceRadians(geo) <= segment[1].DistanceRadians(segment[0])));
 }
 public static bool Intersects(this GeoSegment segment1, GeoSegment segment2)
 {
     return segment1.GreatCircleIntersection(segment2) != null;
 }
        /// <summary>
        /// Returns a Geo location if the great circle segments come within the range 
        /// (r, radians) of each other. The angles between the segments must be less 
        /// than PI or the results are ambiguous. 
        /// </summary>
        /// <param name="segment1"> </param>
        /// <param name="segment2"> </param>
        /// <param name="r"></param>
        /// <returns>null if the segments don't intersect within the range.</returns>
        public static Geo Intersection(this GeoSegment segment1, GeoSegment segment2, double r)
        {
            if (segment2 == null) throw new ArgumentNullException("segment2");
            if (r < 0) throw new ArgumentException("Must be non-negative", "r");

            // ac and bc are the unit vectors normal to the two great
            // circles defined by the segments
            var ac = segment1[0].Cross(segment1[1]).Normalized;
            var bc = segment2[0].Cross(segment2[1]).Normalized;

            // aL and bL are the lengths (in radians) of the segments
            var aL = segment1[0].DistanceRadians(segment1[1]) + r;
            var bL = segment2[0].DistanceRadians(segment2[1]) + r;

            // i is one of the two points where the two great circles
            // intersect. 
            var i = ac.Cross(bc).Normalized;

            // if i is not on A
            if (!(i.DistanceRadians(segment1[0]) <= aL && i.DistanceRadians(segment1[1]) <= aL))
            {
                i = i.Antipode; // switch to the antipode instead
                // check again
                if (!(i.DistanceRadians(segment1[0]) <= aL && i.DistanceRadians(segment1[1]) <= aL))
                {
                    // nope - neither i nor i' is on A, so we'll bail out
                    return null;
                }
            }
            // i is intersection or anti-intersection point now.

            // Now see if it intersects with b
            if (i.DistanceRadians(segment2[0]) <= bL && i.DistanceRadians(segment2[1]) <= bL) return i;
            return null;
        }
 /// <summary>
 /// Is Geo p inside the time bubble along the great circle segment from 
 /// this to v2 looking forward forwardRadius and backward backwardRadius.
 /// </summary>
 /// <param name="segment"> </param>
 /// <param name="forwardRadius"></param>
 /// <param name="backRadius"></param>
 /// <param name="p"></param>
 /// <returns></returns>
 public static bool IsInBubble(this Geo p, GeoSegment segment, double forwardRadius, double backRadius)
 {
     return segment[0].DistanceRadians(p) <= (((segment[1] - segment[0]).Normalized.Dot(p - segment[0]) > 0.0) ? forwardRadius : backRadius);
 }
        GetRide(UserRideOffer offer,
                ConcurrentGeoQuadtree <MatchableRideRequest> origins,
                ConcurrentGeoQuadtree <MatchableRideRequest> destinations)
        {
            RouteInfo driverRoute = await GetRoute(offer);

            var originsTask      = GetElementsInsideAsync(origins, NearRoute);
            var destinationsTask = GetElementsInsideAsync(destinations, NearRoute);

            // Only consider passengers whose origins and destinations are near
            // the driver's route.
            var potentialPassengers = new HashSet <MatchableRideRequest>(
                from element in await originsTask
                select element.Data);

            potentialPassengers.IntersectWith(
                from element in await destinationsTask
                select element.Data);

            // Find a passenger going in the same direction as the driver such that
            // picking up the passenger does not put the driver too far out of their way.
            foreach (var passenger in potentialPassengers.Where(GoingInDriversDirection))
            {
                RouteInfo routeWithPassenger = await GetRouteWithPassenger(offer, passenger);

                // Reject route if it's too far out of the way according to
                // the driver's settings.
                if (driverRoute.drivingTime.HasValue && routeWithPassenger.drivingTime.HasValue)
                {
                    TimeSpan originalTime = driverRoute.drivingTime.Value;
                    TimeSpan newTime      = routeWithPassenger.drivingTime.Value;
                    TimeSpan maxTime      = originalTime + TimeSpan.FromMinutes(offer.RideOffer.MaxTimeOutOfWay);

                    if (newTime > maxTime)
                    {
                        // Output debug info for demos.
                        Program.LogError($"Matched {offer.User.UserInfo.UserId} with {passenger.Request.User.UserInfo.UserId}" +
                                         " but resulting route was too long." +
                                         $" Original trip duration: {originalTime.Minutes} mins." +
                                         $" Matched trip duration: {newTime.Minutes} mins." +
                                         $" Driver's max time out of way: {offer.RideOffer.MaxTimeOutOfWay} mins.");
                        continue;
                    }
                }

                return(RideWithPassenger(offer, passenger));
            }

            return(EmptyRide(offer, driverRoute));


            /// <summary>
            /// Tests whether any point in the rect is close enough to <see cref="route"/>.
            /// </summary>
            bool NearRoute(Rect rect)
            {
                // Ignore passengers more than approximately 1km of the route.
                // TODO Take large max-time-out-of-way values into account when choosing max-dist-out-of-way.
                double maxDistMeters  = 1000;
                double maxDistDegrees = offer.RideOffer.Trip.Source.DegreesUpperBound(maxDistMeters);

                GeoPolyline route = driverRoute.overviewPolyline;

                return(route.RectWithinDistance(rect, maxDistDegrees));
            }

            /// <summary>
            /// Tests whether this passenger is going in the same direction as the driver.
            /// </summary>
            bool GoingInDriversDirection(MatchableRideRequest request)
            {
                var driverDest = offer.RideOffer.Trip.Destination;
                var driverOrig = offer.RideOffer.Trip.Source;
                var driverSeg  = new GeoSegment(driverOrig, driverDest);

                var passDest = request.Request.RideRequest.Trip.Destination;
                var passOrig = request.Request.RideRequest.Trip.Source;
                var passSeg  = new GeoSegment(passOrig, passDest);

                // Use GeoSegments so that this works near prime meridian.
                var passDiff   = passSeg.Point2Representative - passSeg.Point1Representative;
                var driverDiff = driverSeg.Point2Representative - driverSeg.Point1Representative;

                // Compute the dot product of the vectors. This is a pretty rough
                // estimate and doesn't take into account the Earth's curvature.
                return(passDiff.Dot(driverDiff) > 0);
            }
        }