/// <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())); } }
/// <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))); }
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); }
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, }); }