Ejemplo n.º 1
0
        [Route("/[controller]/AreaPlaceData/{code}/{styleSet}/{dataKey}")] //Draw an area using place data.
        public ActionResult DrawPlusCodeCustomElements(string code, string styleSet, string dataKey)
        {
            try
            {
                PerformanceTracker pt = new PerformanceTracker("DrawTilePlace");
                MapTileSupport.GetPlusCodeImagePixelSize(code, out var imgX, out var imgY);
                var info = new ImageStats(OpenLocationCode.DecodeValid(code), imgX, imgY);

                if (!DataCheck.IsInBounds(cache.Get <IPreparedGeometry>("serverBounds"), info.area))
                {
                    pt.Stop("OOB");
                    return(StatusCode(500));
                }

                byte[] tileData = getExistingSlippyTile(code, styleSet);
                if (tileData != null)
                {
                    pt.Stop(code + "|" + styleSet);
                    return(File(tileData, "image/png"));
                }

                //Make tile
                var places   = GetPlacesForTile(info, null, styleSet, false);
                var paintOps = MapTileSupport.GetPaintOpsForCustomDataElements(dataKey, styleSet, info);
                tileData = FinishMapTile(info, paintOps, code, styleSet);

                pt.Stop(code + "|" + styleSet + "|" + Configuration.GetValue <string>("MapTilesEngine"));
                return(File(tileData, "image/png"));
            }
            catch (Exception ex)
            {
                ErrorLogger.LogError(ex);
                return(StatusCode(500));
            }
        }
Ejemplo n.º 2
0
        [Route("/[controller]/SlippyAreaData/{styleSet}/{dataKey}/{zoom}/{x}/{y}.png")]                //slippy map conventions.
        public ActionResult DrawSlippyTileCustomPlusCodes(int x, int y, int zoom, string styleSet, string dataKey)
        {
            try
            {
                PerformanceTracker pt      = new PerformanceTracker("DrawSlippyTileCustomPlusCodes");
                string             tileKey = x.ToString() + "|" + y.ToString() + "|" + zoom.ToString();
                var info = new ImageStats(zoom, x, y, IMapTiles.SlippyTileSizeSquare);

                if (!DataCheck.IsInBounds(cache.Get <IPreparedGeometry>("serverBounds"), info.area))
                {
                    pt.Stop("OOB");
                    return(StatusCode(500));
                }

                byte[] tileData = getExistingSlippyTile(tileKey, styleSet);
                if (tileData != null)
                {
                    pt.Stop(tileKey + "|" + styleSet);
                    return(File(tileData, "image/png"));
                }

                //Make tile
                var places   = GetPlacesForTile(info, null, styleSet);
                var paintOps = MapTileSupport.GetPaintOpsForCustomDataPlusCodes(dataKey, styleSet, info);
                tileData = FinishSlippyMapTile(info, paintOps, tileKey, styleSet);

                pt.Stop(tileKey + "|" + styleSet + "|" + Configuration.GetValue <string>("MapTilesEngine"));
                return(File(tileData, "image/png"));
            }
            catch (Exception ex)
            {
                ErrorLogger.LogError(ex);
                return(StatusCode(500));
            }
        }
Ejemplo n.º 3
0
        private static void DrawOneImage(string code)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            TagParser.ApplyTags(memorySource, "mapTiles");
            ImageStats istats   = new ImageStats(OpenLocationCode.DecodeValid(code), 1024, 1024);
            var        paintOps = MapTileSupport.GetPaintOpsForStoredElements(memorySource, "mapTiles", istats);

            File.WriteAllBytes(config["OutputDataFolder"] + code + ".png", MapTileSupport.DrawPlusCode(code, paintOps, "mapTiles"));
            sw.Stop();
            Log.WriteLog("image drawn from memory in " + sw.Elapsed);
        }
Ejemplo n.º 4
0
        private static void DrawPosterOfServer()
        {
            var db     = new PraxisContext();
            var bounds = db.ServerSettings.First();

            var geoArea = new GeoArea(bounds.SouthBound, bounds.WestBound, bounds.NorthBound, bounds.EastBound);
            //do the math to scale image.
            //the smaller side is set to 24", the larger size scales up proportionally up to a max of 36"
            //if the longer side is > 36", scale both down by the difference?

            //36x24 is target poster size, at 300 dpi, our image size will allow for a half-inch of margin on both axes.
            var dpi      = 300;
            var maxXSide = 35 * dpi;
            var maxYSide = 23 * dpi;
            var xSize    = 0;
            var ySize    = 0;

            var heightScale = geoArea.LatitudeHeight / geoArea.LongitudeWidth; //Y pixels per X pixel

            if (heightScale > 1)                                               // Y axis is longer than X axis
            {
                heightScale = geoArea.LongitudeWidth / geoArea.LatitudeHeight;
                maxXSide    = 23 * dpi;
                maxYSide    = 35 * dpi;
                ySize       = maxYSide;
                xSize       = (int)(maxXSide * heightScale);
            }
            else
            {
                xSize = maxXSide;
                ySize = (int)(maxYSide * heightScale);
            }

            Log.WriteLog("Loading all places from DB");
            var places = GetPlaces(geoArea);
            var iStats = new ImageStats(geoArea, xSize, ySize);

            Log.WriteLog("Generating paint operations");
            var paintOps = MapTileSupport.GetPaintOpsForStoredElements(places, "mapTiles", iStats);

            Log.WriteLog("Drawing image");
            var image = MapTiles.DrawAreaAtSize(iStats, paintOps);

            File.WriteAllBytes("ServerPoster.png", image);
            Log.WriteLog("Image saved to disk");
        }
Ejemplo n.º 5
0
        static void Main(string[] args)
        {
            var builder = new ConfigurationBuilder()
                          .AddJsonFile("Larry.config.json");

            config = builder.Build();

            ApplyConfigValues();
            //If multiple args are supplied, run them in the order that make sense, not the order the args are supplied.
            if (args.Any(a => a == "-createDB")) //setup the destination database
            {
                createDb();
            }

            if (!args.Any(a => a == "-makeServerDb"))                                   //This will not be available until after creating the DB slightly later.
            {
                TagParser.Initialize(config["ForceStyleDefaults"] == "True", MapTiles); //This last bit of config must be done after DB creation check
            }
            Log.WriteLog("Larry started at " + DateTime.Now);

            if (args.Count() == 0)
            {
                Log.WriteLog("You must pass an arguement to this application", Log.VerbosityLevels.High);
                //TODO: list valid commands or point at the docs file
                return;
            }

            //if (args.Any(a => a.StartsWith("-getPbf:")))
            //{
            //    //Wants 3 pieces. Drops in placeholders if some are missing. Giving no parameters downloads Ohio.
            //    string arg = args.First(a => a.StartsWith("-getPbf:")).Replace("-getPbf:", "");
            //    var splitData = arg.Split('|'); //remember the first one will be empty.
            //    string level1 = splitData.Count() >= 4 ? splitData[3] : "north-america";
            //    string level2 = splitData.Count() >= 3 ? splitData[2] : "us";
            //    string level3 = splitData.Count() >= 2 ? splitData[1] : "ohio";

            //    DownloadPbfFile(level1, level2, level3, config["PbfFolder"]);
            //}

            if (args.Any(a => a == "-resetPbf"))
            {
                ResetFiles(config["PbfFolder"]);
            }

            if (args.Any(a => a == "-resetGeomData"))
            {
                ResetFiles(config["OutputDataFolder"]);
            }

            if (args.Any(a => a == "-resetStyles"))
            {
                var db = new PraxisContext();
                db.ResetStyles();
            }

            if (args.Any(a => a == "-processPbfs"))
            {
                processPbfs();
            }

            if (args.Any(a => a == "-loadProcessedData"))
            {
                loadProcessedData();
            }

            //This is the single command to get a server going, assuming you have done all the setup steps yourself beforehand and your config is correct.
            if (args.Any(a => a == "-makeServerDb"))
            {
                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                sw.Start();
                SetEnvValues();
                var db = new PraxisContext();
                createDb();
                db.DropIndexes();
                processPbfs();
                loadProcessedData();
                db.SetServerBounds(long.Parse(config["UseOneRelationID"]));
                Log.WriteLog("Server setup complete in " + sw.Elapsed);
            }

            if (args.Any(a => a == "-makeWholeServer")) //Not a release 1 feature, but taking notes now.
            {
                SetEnvValues();
                //This is the wizard command, try to check and do everything at once.
                Log.WriteLog("Checking for installed DB per config (" + config["DbMode"] + ")");
                PraxisContext db;
                try
                {
                    db = new PraxisContext();
                }
                //Specific exceptions should hint at what to do, a general one covers ones I dont know how to handle.
                catch (Exception ex)
                {
                    Log.WriteLog("Hit an error checking for the existing database that I'm not sure how to handle:" + ex.Message);
                    return;
                }

                Log.WriteLog("Creating the Praxis DB per the connection string...");
                try
                {
                    createDb();
                }
                catch (Exception ex)
                {
                    //figure out why i can't create. Probably account settings?
                }

                PwdSpeedTest();


                //Check for MariaDB and install/configure if missing (including service account)
                //check for a PBF file and prompt to download one if none found
                //if data files are present, use them. otherwise process the PBF file per settings
                //Pre-generate gameplay map tiles, but present it as an option. It's faster to do it ahead of time but uses up more DB space if you aren't gonna need them all immediately.
                //Possible: Grab the Solar2D example app, adjust it to work with the server running on this machine.
                //--check external IP, update .lua source file to point to this pc.
                //Fire up the Kestral exe to get the server working
                //Open up a browser to the adminview slippytile page.
                //}
            }

            if (args.Any(a => a == "-updateDatabase"))
            {
                UpdateExistingEntries(config["OutputDataFolder"]);
            }

            if (args.Any(a => a.StartsWith("-createStandaloneRelation")))
            {
                //This makes a standalone DB for a specific relation passed in as a paramter.
                int relationId = Int32.Parse(config["UseOneRelationID"]);
                StandaloneCreation.CreateStandaloneDB(relationId, null, false, true); //How map tiles are handled is determined by the optional parameters
            }

            if (args.Any(a => a.StartsWith("-createStandaloneBox")))
            {
                //This makes a standalone DB for a specific area passed in as a paramter.
                //If you want to cover a region in a less-specific way, or the best available relation is much larger than you thought, this might be better.
                string[] bounds     = args.First(a => a.StartsWith("-createStandaloneBox")).Split('|');
                GeoArea  boundsArea = new GeoArea(bounds[1].ToDouble(), bounds[2].ToDouble(), bounds[3].ToDouble(), bounds[4].ToDouble());

                //in order, these go south/west/north/east.
                StandaloneCreation.CreateStandaloneDB(0, boundsArea, false, true); //How map tiles are handled is determined by the optional parameters
            }

            if (args.Any(a => a.StartsWith("-createStandalonePoint")))
            {
                //This makes a standalone DB centered on a specific point, it will grab a Cell6's area around that point.
                string[] bounds = args.First(a => a.StartsWith("-createStandalonePoint")).Split('|');

                var     resSplit   = resolutionCell6 / 2;
                GeoArea boundsArea = new GeoArea(bounds[1].ToDouble() - resSplit, bounds[2].ToDouble() - resSplit, bounds[1].ToDouble() + resSplit, bounds[2].ToDouble() + resSplit);

                //in order, these go south/west/north/east.
                StandaloneCreation.CreateStandaloneDB(0, boundsArea, false, true); //How map tiles are handled is determined by the optional parameters
            }

            if (args.Any(a => a == "-autoCreateMapTiles"))
            {
                var db     = new PraxisContext();
                var bounds = db.SetServerBounds(long.Parse(config["UseOneRelationID"]));
                MapTileSupport.PregenMapTilesForArea(bounds);
            }

            if (args.Any(a => a == "-findServerBounds"))
            {
                var db = new PraxisContext();
                db.SetServerBounds(long.Parse(config["UseOneRelationID"]));
            }

            if (args.Any(a => a.StartsWith("-drawOneImage:")))
            {
                DrawOneImage(args.First(a => a.StartsWith("-drawOneImage:")).Split(":")[1]);
            }

            if (args.Any(a => a.StartsWith("-processCoastlines:")))
            {
                string filename = args.First(a => a.StartsWith("-processCoastlines:")).Split(":")[1];
                ReadCoastlineShapefile(filename);
            }

            if (args.Any(a => a == "-makePosterImage"))
            {
                DrawPosterOfServer();
            }

            if (args.Any(a => a == "-pwdSpeedTest"))
            {
                PwdSpeedTest();
            }

            if (args.Any(a => a == "-setEnvValues"))
            {
                SetEnvValues();
            }

            //This is not currently finished or testing in the current setup. Will return in a future release.
            //if (args.Any(a => a.StartsWith("-populateEmptyArea:")))
            //{
            //    populateEmptyAreas(args.First(a => a.StartsWith("-populateEmptyArea:")).Split(":")[1]);
            //}
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Create the map tiles for an offline game, to be stored on the device alongside the database.
        /// </summary>
        /// <param name="relationID">the OSM relation the game will be built around</param>
        /// <param name="buffered">the GeoArea to use as the gameplay area</param>
        /// <param name="allPlaces">List of OSM Elements to use while drawing tiles</param>
        /// <param name="saveToFolder">If true, save images to a named folder. Does not currently save any output if this is false.</param>
        public static void DrawMapTilesStandalone(long relationID, GeoArea buffered, List <DbTables.Place> allPlaces, bool saveToFolder)
        {
            var intersectCheck = Converters.GeoAreaToPolygon(buffered);
            //start drawing maptiles and sorting out data.
            var swCorner = new OpenLocationCode(intersectCheck.EnvelopeInternal.MinY, intersectCheck.EnvelopeInternal.MinX);
            var neCorner = new OpenLocationCode(intersectCheck.EnvelopeInternal.MaxY, intersectCheck.EnvelopeInternal.MaxX);

            //declare how many map tiles will be drawn
            var xTiles     = buffered.LongitudeWidth / resolutionCell8;
            var yTiles     = buffered.LatitudeHeight / resolutionCell8;
            var totalTiles = Math.Truncate(xTiles * yTiles);

            Log.WriteLog("Starting processing maptiles for " + totalTiles + " Cell8 areas.");
            long mapTileCounter = 0;

            System.Diagnostics.Stopwatch progressTimer = new System.Diagnostics.Stopwatch();
            progressTimer.Start();

            //now, for every Cell8 involved, draw and name it.
            //This is tricky to run in parallel because it's not smooth increments
            var yCoords = new List <double>();
            var yVal    = swCorner.Decode().SouthLatitude;

            while (yVal <= neCorner.Decode().NorthLatitude)
            {
                yCoords.Add(yVal);
                yVal += resolutionCell8;
            }

            var xCoords = new List <double>();
            var xVal    = swCorner.Decode().WestLongitude;

            while (xVal <= neCorner.Decode().EastLongitude)
            {
                xCoords.Add(xVal);
                xVal += resolutionCell8;
            }
            System.Threading.ReaderWriterLockSlim dbLock = new System.Threading.ReaderWriterLockSlim();


            foreach (var y in yCoords)
            {
                //Make a collision box for just this row of Cell8s, and send the loop below just the list of things that might be relevant.
                //Add a Cell8 buffer space so all elements are loaded and drawn without needing to loop through the entire area.
                GeoArea thisRow = new GeoArea(y - ConstantValues.resolutionCell8, xCoords.First() - ConstantValues.resolutionCell8, y + ConstantValues.resolutionCell8 + ConstantValues.resolutionCell8, xCoords.Last() + resolutionCell8);
                var     row     = Converters.GeoAreaToPolygon(thisRow);
                var     rowList = allPlaces.Where(a => row.Intersects(a.ElementGeometry)).ToList();

                Parallel.ForEach(xCoords, x =>
                                 //foreach (var x in xCoords)
                {
                    //make map tile.
                    var plusCode     = new OpenLocationCode(y, x, 10);
                    var plusCode8    = plusCode.CodeDigits.Substring(0, 8);
                    var plusCodeArea = OpenLocationCode.DecodeValid(plusCode8);

                    var areaForTile = new GeoArea(new GeoPoint(plusCodeArea.SouthLatitude, plusCodeArea.WestLongitude), new GeoPoint(plusCodeArea.NorthLatitude, plusCodeArea.EastLongitude));
                    var acheck      = Converters.GeoAreaToPolygon(areaForTile);                          //this is faster than using a PreparedPolygon in testing, which was unexpected.
                    var areaList    = rowList.Where(a => acheck.Intersects(a.ElementGeometry)).ToList(); //This one is for the maptile

                    //Create the maptile first, so if we save it to the DB/a file we can call the lock once per loop.
                    int imgX = 0, imgY = 0;
                    MapTileSupport.GetPlusCodeImagePixelSize(plusCode8, out imgX, out imgY);
                    var info    = new ImageStats(areaForTile, imgX, imgY); //Each pixel is a Cell11, we're drawing a Cell8. For Cell6 testing this is 1600x2000, just barely within android limits
                    byte[] tile = null;                                    // MapTiles.DrawAreaAtSize(info, areaList);
                    if (tile == null)
                    {
                        Log.WriteLog("Tile at " + x + "," + y + "Failed to draw!");
                        return;
                    }
                    if (saveToFolder) //some apps, like my Solar2D apps, can't use the byte[] in a DB row and need files.
                    {
                        //This split helps (but does not alleviate) Solar2D performance.
                        //A county-sized app will function this way, though sometimes when zoomed out it will not load all map tiles on an android device.
                        Directory.CreateDirectory(relationID + "Tiles\\" + plusCode8.Substring(0, 6));
                        System.IO.File.WriteAllBytes(relationID + "Tiles\\" + plusCode8.Substring(0, 6) + "\\" + plusCode8.Substring(6, 2) + ".pngTile", tile); //Solar2d also can't load pngs directly from an apk file in android, but the rule is extension based.
                    }

                    mapTileCounter++;
                    //if (progressTimer.ElapsedMilliseconds > 15000)
                    //{

                    //    progressTimer.Restart();
                    //}
                });
                Log.WriteLog(mapTileCounter + " tiles processed, " + Math.Round((mapTileCounter / totalTiles) * 100, 2) + "% complete");
            }//);
        }