Пример #1
0
        /// <summary>
        /// Computes the distance from the point to the segment. The return
        /// value is in units of sqrt(lat^2 + long^2) in WGS84 coordinates.
        /// </summary>
        /// <returns>The distance to the point in units of sqrt(lat^2 + long^2).</returns>
        /// <param name="point">Point on Earth.</param>
        public double DistanceToPoint(GeoCoordinates point)
        {
            Vector2 p1 = Endpoint1.ToVector2();
            Vector2 p2 = Endpoint2.ToVector2();

            if (CrossesMeridianRightOfP1)
            {
                p2 += new Vector2(360, 0);

                Vector2 pointRepr1 = point.ToVector2();
                Vector2 pointRepr2 = pointRepr1 + new Vector2(360, 0);

                double dist1 = Geometry2d.PointToSegmentDistance(p1, p2, pointRepr1);
                double dist2 = Geometry2d.PointToSegmentDistance(p1, p2, pointRepr2);

                return(Math.Min(dist1, dist2));
            }
            else if (CrossesMeridianLeftOfP1)
            {
                p2 -= new Vector2(360, 0);

                Vector2 pointRepr1 = point.ToVector2();
                Vector2 pointRepr2 = pointRepr1 - new Vector2(360, 0);

                double dist1 = Geometry2d.PointToSegmentDistance(p1, p2, pointRepr1);
                double dist2 = Geometry2d.PointToSegmentDistance(p1, p2, pointRepr2);

                return(Math.Min(dist1, dist2));
            }
            else
            {
                return(Geometry2d.PointToSegmentDistance(p1, p2, point.ToVector2()));
            }
        }
Пример #2
0
        /// <summary>
        /// Tests whether the geo rectangle is within the given distance of the
        /// geo segment.
        /// </summary>
        /// <returns><c>true</c>, if the rectangle contains the segment or one
        /// of the rectangle's edges is near the segment, <c>false</c> otherwise.</returns>
        /// <param name="segment">A reasonably short segment on the Earth.</param>
        /// <param name="rect">A valid geo rectangle to test.</param>
        /// <param name="maxDist">Maximum distance from segment.</param>
        public static bool RectNearSegment(GeoSegment segment, Rect rect, double maxDist)
        {
            // (Positive) cases:
            // - Segment fully contained within rect
            // - At least one edge of rect is within maxDist of segment

            if (GeoContains(rect, segment.Endpoint1) && GeoContains(rect, segment.Endpoint2))
            {
                return(true);
            }

            Vector2[] corners =
            {
                new Vector2(rect.xMin, rect.yMin),
                new Vector2(rect.xMin, rect.yMax),
                new Vector2(rect.xMax, rect.yMax),
                new Vector2(rect.xMax, rect.yMin)
            };

            var rectEdges = corners.ConsecutivePairs();

            Vector2 segA = segment.Endpoint1.ToVector2();
            Vector2 segB = segment.Endpoint2.ToVector2();;

            if (segment.CrossesMeridianLeftOfP1)
            {
                segB -= new Vector2(360, 0);

                if (rect.xMax > 180)
                {
                    // Since this is a valid geo rect, xMin is < 180, so this
                    // rect crosses the opposite side of the map that the
                    // segment crosses.
                    segA += new Vector2(360, 0);
                    segB += new Vector2(360, 0);
                }
            }
            else if (segment.CrossesMeridianRightOfP1)
            {
                segB += new Vector2(360, 0);

                if (rect.xMin < -180)
                {
                    // Since this is a valid geo rect, xMax is > -180, so this
                    // rect crosses the opposite side of the map that the
                    // segment crosses.
                    segA -= new Vector2(360, 0);
                    segB -= new Vector2(360, 0);
                }
            }

            return(rectEdges.Any(edge =>
                                 Geometry2d.SegmentsWithinDistance(
                                     segA,
                                     segB,
                                     edge.Item1,
                                     edge.Item2,
                                     maxDist)));
        }
Пример #3
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);
        }
Пример #4
0
        private BuildingsGenerationParameters MakeGenerationParameters(IViewModel viewModelParameters)
        {
            var vm   = viewModelParameters as BuildingsViewModel;
            var seed = vm.SeedString.GetHashCode();
            var rng  = new Random(seed);

            int    p1, p2;
            double baseSideLength;

            if (vm.SelectedSideEndpoint1 < 0 ||
                vm.SelectedSideEndpoint2 < 0 ||
                vm.SelectedSideEndpoint1 >= vm.PolygonPoints.Count ||
                vm.SelectedSideEndpoint2 >= vm.PolygonPoints.Count)
            {
                p1             = 0;
                p2             = vm.PolygonPoints.Count - 1;
                baseSideLength = vm.PolygonPoints[p1]
                                 .DistanceTo(vm.PolygonPoints[p2]);
                // no specific base side specified, so just take the longest
                for (int p = 0; p < vm.PolygonPoints.Count - 1; ++p)
                {
                    var candidateDistance = vm.PolygonPoints[p]
                                            .DistanceTo(vm.PolygonPoints[p + 1]);
                    if (candidateDistance > baseSideLength)
                    {
                        p1             = p;
                        p2             = p + 1;
                        baseSideLength = candidateDistance;
                    }
                }
            }
            else
            {
                p1             = vm.SelectedSideEndpoint1;
                p2             = vm.SelectedSideEndpoint2;
                baseSideLength = vm.PolygonPoints[p1]
                                 .DistanceTo(vm.PolygonPoints[p2]);
            }

            double basementLengthPerUnit = vm.SelectedSideMeters / baseSideLength;

            var facadeHeight           = Lerp(vm.BuildingMinHeight, vm.BuildingMaxHeight, rng.NextDouble());
            var floors                 = rng.Next(vm.MinNumberOfFloors, vm.MaxNumberOfFloors + 1);
            var segmentsOnSelectedWall = rng.Next(vm.MinSelectedWallHorizontalSegments, vm.MaxSelectedWallHorizontalSegments);
            var windowsOnSelectedWall  = rng.Next(vm.MinWindowsOnSelectedWall, vm.MaxWindowsOnSelectedWall);

            windowsOnSelectedWall = (int)Math.Min(windowsOnSelectedWall, segmentsOnSelectedWall);
            var roofHeight = Lerp(vm.RoofMinHeight, vm.RoofMaxHeight, rng.NextDouble());
            //var roofEdgeOffsetPct = rng.Next(vm.RoofEdgeMinOffsetPct, vm.RoofEdgeMaxOffsetPct);
            //for

            var assetsViewModel = vm.AssetsViewModel as AssetsViewModel;

            IList <Asset> doorsAsset = new List <Asset> {
                assetsViewModel.DoorsAssets[vm.SelectedDoorStyleIdx]
            };
            IList <Asset> windowsAssets;

            if (vm.IsSingleStyleWindow)
            {
                windowsAssets = new List <Asset> {
                    assetsViewModel.WindowsAssets[vm.SelectedWindowStyleIdx]
                }
            }
            ;
            else
            {
                windowsAssets = assetsViewModel.WindowsAssets;
            }

            var windowAssetTriangleLimit = assetsViewModel.WindowAssetTrianglesLimit;

            if (windowAssetTriangleLimit <= 0)
            {
                windowAssetTriangleLimit = int.MaxValue;
            }
            var doorAssetTriangleLimit = assetsViewModel.DoorAssetTrianglesLimit;

            if (doorAssetTriangleLimit <= 0)
            {
                doorAssetTriangleLimit = int.MaxValue;
            }


            IList <Point2d> basementPoints = vm.PolygonPoints.Select(p => new Point2d {
                X = p.X, Y = p.Y
            }).ToList();

            // is given basement counter clockwise
            if (Geometry2d.CalcSignedPolygonArea(basementPoints) < 0.0)
            {
                basementPoints = basementPoints.Reverse().ToList();
                var tmp = p1;
                p1 = basementPoints.Count - 1 - p2;
                p2 = basementPoints.Count - 1 - tmp;
            }

            basementPoints = Geometry2d.ScaleCenteredPolygon(
                Geometry2d.CenterPolygon(basementPoints, out var basementCentroid),
                basementLengthPerUnit
                );

            if (!vm.IsDoorOnSelectedWall)
            {
                var rndPolygonPoint = rng.Next(vm.PolygonPoints.Count);
                p1 = rndPolygonPoint;
                p2 = (rndPolygonPoint + 1) % vm.PolygonPoints.Count;
            }

            // is single style window
            return(new BuildingsGenerationParameters
            {
                // assets groups
                BasementExtrudeHeight = facadeHeight,
                BasementLengthPerUnit = basementLengthPerUnit,
                BasementPoints = basementPoints,
                Seed = seed,
                RoofStyle = (ProceduralBuildingsGeneration.RoofStyle)vm.RoofStyle,
                RoofHeight = roofHeight,
                //RoofEdgeOffsetPct = roofEdgeOffsetPct,
                FloorsNumber = floors,
                IsVerticalWindowSymmetryPreserved = vm.IsVerticalSymmetryPreserved,
                AssetsScaleModifier = 10.0,
                SelectedWallSegments = segmentsOnSelectedWall,
                WindowsToSegmentsFraction = (float)windowsOnSelectedWall / segmentsOnSelectedWall,
                WindowsAssets = windowsAssets,
                DoorsAssets = doorsAsset,
                WindowAssetTrianglesLimit = windowAssetTriangleLimit,
                DoorAssetTrianglesLimit = doorAssetTriangleLimit,
                DoorWall = new WallIndices(p1, p2),
                RandomGenerator = rng,
            });
        }