public GridCluster(IPoints dataset, JsonGetMarkersReceive jsonReceive) : base(dataset) { // Important, set _delta and _grid values in constructor as first step var deltas = GetDelta(jsonReceive); DeltaX = deltas[0]; DeltaY = deltas[1]; Grid = GetBoundaryExtended(jsonReceive); Lines = new List<Line>(); if (AlgoConfig.DoShowGridLinesInGoogleMap) MakeLines(jsonReceive); }
public static Boundary GetBoundaryExtended(JsonGetMarkersReceive jsonReceive) { var deltas = GetDelta(jsonReceive); var deltaX = deltas[0]; var deltaY = deltas[1]; // Grid with extended outer grid-area non-visible var a = MathTool.FloorLatLon(jsonReceive.Viewport.Minx, deltaX) - deltaX * AlgoConfig.OuterGridExtend; var b = MathTool.FloorLatLon(jsonReceive.Viewport.Miny, deltaY) - deltaY * AlgoConfig.OuterGridExtend; var a2 = MathTool.FloorLatLon(jsonReceive.Viewport.Maxx, deltaX) + deltaX * (1 + AlgoConfig.OuterGridExtend); var b2 = MathTool.FloorLatLon(jsonReceive.Viewport.Maxy, deltaY) + deltaY * (1 + AlgoConfig.OuterGridExtend); // Latitude is special with Google Maps, they don't wrap around, then do constrain b = MathTool.ConstrainLatitude(b); b2 = MathTool.ConstrainLatitude(b2); var grid = new Boundary { Minx = a, Miny = b, Maxx = a2, Maxy = b2 }; grid.Normalize(); return grid; }
public static double[] GetDelta(JsonGetMarkersReceive jsonReceive) { // Heuristic specific values and grid size dependent. // used in combination with zoom level. // xZoomLevel1 and yZoomLevel1 is used to define the size of one grid-cell // Absolute base value of longitude distance const int xZoomLevel1 = 480; // Absolute base value of latitude distance const int yZoomLevel1 = 240; // Relative values, used for adjusting grid size var gridScaleX = AlgoConfig.Gridx; var gridScaleY = AlgoConfig.Gridy; var x = MathTool.Half(xZoomLevel1, jsonReceive.Zoomlevel - 1) / gridScaleX; var y = MathTool.Half(yZoomLevel1, jsonReceive.Zoomlevel - 1) / gridScaleY; return new double[] { x, y }; }
void MakeLines(JsonGetMarkersReceive jsonReceive) { if(!jsonReceive.IsDebugLinesEnabled) return; // client disabled it // Make the red lines data to be drawn in Google map var temp = new List<Rectangle>(); const int borderLinesAdding = 1; var linesStepsX = (int)(Math.Round(Grid.AbsX / DeltaX) + borderLinesAdding); var linesStepsY = (int)(Math.Round(Grid.AbsY / DeltaY) + borderLinesAdding); var b = new Boundary(Grid); const double restrictLat = 5.5; b.Miny = MathTool.ConstrainLatitude(b.Miny, restrictLat); // Make sure it is visible on screen, restrict by some value b.Maxy = MathTool.ConstrainLatitude(b.Maxy, restrictLat); // Vertical lines for (var i = 0; i < linesStepsX; i++) { var xx = b.Minx + i * DeltaX; // Draw region if (jsonReceive.Zoomlevel > 3) { temp.Add(new Rectangle { Minx = xx, Miny = b.Miny, Maxx = xx, Maxy = b.Maxy }); } // World wrap issue when same latlon area visible multiple times // Make sure line is drawn from left to right on screen else { temp.Add(new Rectangle { Minx = xx, Miny = LatLonInfo.MinLatValue + restrictLat, Maxx = xx, Maxy = 0 }); temp.Add(new Rectangle { Minx = xx, Miny = 0, Maxx = xx, Maxy = LatLonInfo.MaxLatValue-restrictLat }); } } // Horizontal lines for (var i = 0; i < linesStepsY; i++) { var yy = b.Miny + i * DeltaY; // Draw region if (jsonReceive.Zoomlevel > 3) { // Don't draw lines outsize the world if (MathTool.IsLowerThanLatMin(yy) || MathTool.IsGreaterThanLatMax(yy)) continue; temp.Add(new Rectangle { Minx = b.Minx, Miny = yy, Maxx = b.Maxx, Maxy = yy }); } // World wrap issue when same latlon area visible multiple times // Make sure line is drawn from left to right on screen else { temp.Add(new Rectangle { Minx = LatLonInfo.MinLonValue, Miny = yy, Maxx = 0, Maxy = yy }); temp.Add(new Rectangle { Minx = 0, Miny = yy, Maxx = LatLonInfo.MaxLonValue, Maxy = yy }); } } // Normalize the lines and add as string foreach (var line in temp) { var x = (line.Minx).NormalizeLongitude().DoubleToString(); var x2 = (line.Maxx).NormalizeLongitude().DoubleToString(); var y = (line.Miny).NormalizeLatitude().DoubleToString(); var y2 = (line.Maxy).NormalizeLatitude().DoubleToString(); Lines.Add(new Line { X = x, Y = y, X2 = x2, Y2 = y2 }); } }
// Post public JsonMarkersReply Markers( double nelat, double nelon, double swlat, double swlon, int zoomlevel, string filter, int sendid ) { var sw = new Stopwatch(); sw.Start(); var jsonReceive = new JsonGetMarkersReceive(nelat, nelon, swlat, swlon, zoomlevel, filter, sendid); var clusteringEnabled = jsonReceive.IsClusteringEnabled || AlgoConfig.AlwaysClusteringEnabledWhenZoomLevelLess > jsonReceive.Zoomlevel; JsonMarkersReply reply; jsonReceive.Viewport.ValidateLatLon(); // Validate google map viewport input (is always valid) jsonReceive.Viewport.Normalize(); // Get all points from memory IPoints points = MemoryDatabase.GetPoints(); if (jsonReceive.TypeFilterExclude.Count == AlgoConfig.MarkerTypes.Count) { // Filter all points = new Points(); // empty } else if (jsonReceive.TypeFilterExclude.Count > 0) { // Filter data by typeFilter value // Make new obj, don't overwrite obj data points = new Points { Data = points.Data .Where(p => jsonReceive.TypeFilterExclude.Contains(p.T) == false) .ToList() }; } // Create new instance for every ajax request with input all points and json data var clusterAlgo = new GridCluster(points, jsonReceive); // create polylines // Clustering if (clusteringEnabled && jsonReceive.Zoomlevel < AlgoConfig.ZoomlevelClusterStop) { // Calculate data to be displayed var clusterPoints = clusterAlgo.GetCluster(new ClusterInfo { ZoomLevel = jsonReceive.Zoomlevel, }); var converted = DataConvert(clusterPoints); // Prepare data to the client reply = new JsonMarkersReply { Markers = converted, Rid = sendid, Polylines = clusterAlgo.Lines, Msec = Sw(sw), }; // Return client data return reply; } // If we are here then there are no clustering // The number of items returned is restricted to avoid json data overflow IPoints filteredDataset = ClusterAlgorithmBase.FilterDataset(points, jsonReceive.Viewport); IPoints filteredDatasetMaxPoints = new Points { Data = filteredDataset.Data .Take(AlgoConfig.MaxMarkersReturned) .ToList() }; reply = new JsonMarkersReply { Markers = DataConvert(filteredDatasetMaxPoints), Rid = sendid, Polylines = clusterAlgo.Lines, Mia = filteredDataset.Count - filteredDatasetMaxPoints.Count, Msec = Sw(sw), }; return reply; }