]> marstr Code Repo - orthographic/commitdiff
Last minor adjustments and a needed feature for PBF generation (needed for a later...
authorMarcus Str. <marcus@marstr.online>
Fri, 18 Oct 2024 19:48:24 +0000 (21:48 +0200)
committerMarcus Str. <marcus@marstr.online>
Fri, 18 Oct 2024 19:48:24 +0000 (21:48 +0200)
defines.py
layergen.py
maskgen.py
og.py
orthographic.py
osmxml.py

index 89ed6310c139e809888c18b1f093b43b9b0a6d0c..5dc427a3112d520dea20a16fee27a2197a91967f 100644 (file)
@@ -75,6 +75,7 @@ mstr_xp_scn_normalmaps = True
 mstr_xp_meshtool = "/home/marcus/Developer/Projects/orthographic/bin/MeshTool"\r
 mstr_xp_ddstool = "/home/marcus/Developer/Projects/orthographic/bin/DDSTool"\r
 mstr_xp_xessrc = "https://dev.x-plane.com/update/misc/MeshTool/"\r
+mstr_xp_floor_height = 2.8 # 2.5m ceiling height + 30cm concrete per floor\r
 \r
 # If you set the above to true, you can define for which features you\r
 # want to generate normal maps for. The below is my recommendation for\r
index c873a2b17bd6601875703b8d55f9d7f436c89e8c..6c02f9b1d846124703e7dfa5d36d12023e25b503 100644 (file)
@@ -1123,7 +1123,7 @@ class mstr_layergen:
                     ptc_src.append(Image.open(p))\r
 \r
                 osm_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" )\r
-                lyr_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )\r
+                #lyr_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )\r
 \r
                 for i in mstr_mask_blur:\r
                     if i[0] == self._tag and i[1] == self._value:\r
@@ -1147,12 +1147,12 @@ class mstr_layergen:
 \r
                 adj_image.alpha_composite( brd_src )\r
 \r
-                lyr_pix = lyr_mask.load()\r
+                #lyr_pix = lyr_mask.load()\r
                 for y in range(self._imgsize):\r
                     for x in range(self._imgsize):\r
-                        if lyr_pix[x, y][3] > 0:\r
+                        if mask_pix[x, y][3] > 0:\r
                             rgb=adj_pix[x,y]\r
-                            a=lyr_pix[x,y]\r
+                            a=mask_pix[x,y]\r
                             adj_pix[x, y] = ( rgb[0], rgb[1], rgb[2], a[3])\r
 \r
                 # Up until here we mimiced the exact same behavior as layergen. However, now\r
index 732d08c99b4301dae757825bd9336ae9cafe45d6..9515e333a8ba1e65dbc65d9fa1a7b9ea8faeb527 100644 (file)
 # that this part of the code is the most crucial one, as the other\r
 # classes involved rely on what this code is doing, and by extension,\r
 # generating.\r
-# \r
-# The PNG generated will be used in this progression:\r
-# - Generate mask from OSM (here)\r
-# - Generate colored photo layer from this mask, for example for\r
-#   landuse: forest\r
-# - Compile actual satellite aerial\r
 # -------------------------------------------------------------------\r
 \r
 import math\r
@@ -83,9 +77,7 @@ class mstr_maskgen:
     # Builds the required mask\r
     def _build_mask(self):\r
         # Generate empty image\r
-        imgsize = 0\r
-        if mstr_photores == 2048: imgsize=2048\r
-        if mstr_photores == 4096: imgsize=6000\r
+        imgsize = 2048\r
         mask_img = Image.new("RGBA", (imgsize, imgsize))\r
 \r
         tilexml = mstr_datafolder + "_cache/tile.xml"\r
@@ -119,7 +111,7 @@ class mstr_maskgen:
                     for d in way:\r
                         if d[0] == w[0]:\r
                             if self._tag == "building" and bld_levels == 0:\r
-                                bld_levels = xml.find_building_levels(tilexml, w[0])\r
+                                bld_levels = xml.find_building_levels(w[0])\r
                             nd.append(d[1])\r
                     frs.append(nd)\r
             # Scout through relations as these also make up map data\r
@@ -160,9 +152,7 @@ class mstr_maskgen:
                         p_lng = self.project_pixel(latlng[1], bbox[3])\r
                         pixlat = 0\r
                         pixlng = 0\r
-                        pr = 0\r
-                        if mstr_photores == 2048: pr = 2048\r
-                        if mstr_photores == 4096: pr = 6000\r
+                        pr = 2048\r
 \r
                         # Draw pixels in direction according to latitude and longitude positions -\r
 \r
diff --git a/og.py b/og.py
index 3050a040b8ba4e12059c654fa728c97dd910a041..f8f128ebde0730d224270cbff762b9e176db9306 100644 (file)
--- a/og.py
+++ b/og.py
@@ -22,7 +22,7 @@ from defines import *
 print(" ")\r
 print(" ---------------------------------------------------------------- ")\r
 print(" ORTHOGRAPHIC: An ortho-photo generator, using real world data.")\r
-print(" Developed by MarStrMind - Code available on marstr.online")\r
+print(" Developed by MarStr - Code available on marstr.online")\r
 print(" ---------------------------------------------------------------- ")\r
 print(" ")\r
 \r
@@ -30,9 +30,14 @@ print(" ")
 # Evaluate CLI arguments and process tile.\r
 \r
 cli = False\r
+pbf = False\r
+\r
 if len(sys.argv) == 3:\r
     cli = True\r
 \r
+if len(sys.argv) == 4:\r
+    pbf = True\r
+\r
 # Only if we find enough arguments, proceed.\r
 if cli == True:\r
     lat = int(sys.argv[1])\r
@@ -44,10 +49,23 @@ if cli == True:
     og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd())\r
     og._buildTile()\r
 \r
-else:\r
+\r
+# Only if we find enough arguments, proceed.\r
+if pbf == True:\r
+    lat = int(sys.argv[1])\r
+    lng = int(sys.argv[2])\r
+    pbf = sys.argv[3]\r
+\r
+    if pbf == "pbf":\r
+        # Create the class and init values\r
+        og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd())\r
+        og._generateData()\r
+\r
+\r
+if cli == False and pbf == False:\r
     mstr_msg("_main", "Please provide Latitude and Longitude. Exiting.")\r
     print ("")\r
 \r
 \r
 \r
-# * No Space Shuttle or SpaceShipOne needed to deploy.
\ No newline at end of file
+# * No Space Shuttle or SpaceShipOne needed to deploy.\r
index a279c4cfcdb500e958a3165bc7890585a7c2cc25..16eb887dd3d426bc058357b197796cec14c215c2 100644 (file)
@@ -77,6 +77,74 @@ class mstr_orthographic:
         return round(dm * 1000, 3)\r
 \r
 \r
+    # In this case we only want to acquire PBF for a latitude and longitude. Normally\r
+    # not needed for standard ortho generation.\r
+    def _generateData(self):\r
+        # The tile is constructed of many smaller parts. We walk through the\r
+        # smallest possible, from which the bigger ones are later built.\r
+        bb_lat = self._lat\r
+        bb_lng = self._long\r
+        bb_lat_edge = self._lat+self._vstep\r
+        bb_lng_edge = self._long+mstr_zl_18\r
+        cur_tile_x = 1\r
+        cur_tile_y = 1\r
+        osmxml = mstr_osmxml(0,0)\r
+        mstr_msg("orthographic", "Set initial coordinates and bounding box for OSM acquisition")\r
+\r
+        # The highest encountered tile numbers\r
+        # This is needed to produce the zoom level 16 images\r
+        top_lat = 1\r
+        top_lng = 1\r
+\r
+        # We need to know the highest possible latitude and longitude tile numbers,\r
+        # in case we render at the edge\r
+        mlat = 1\r
+        mlng = 1\r
+        while bb_lat < self._lat + 1:\r
+            bb_lat = bb_lat + self._vstep\r
+            mlat = mlat+1\r
+        while bb_lng < self._long + 1:\r
+            bb_lng = bb_lng + mstr_zl_18\r
+            mlng = mlng+1\r
+        mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))\r
+        maxlatlng = [ mlat, mlng ]\r
+\r
+        # Reset these two\r
+        bb_lat = self._lat\r
+        bb_lng = self._long\r
+\r
+        # Previously, I downloaded all XML files in one go - but to ease the\r
+        # stress on OSM servers and my server, we will do acquire the data\r
+        # only for the current processed part of the tile.\r
+        for lat_grid in range(1, maxlatlng[0]+1):\r
+            for lng_grid in range(1, maxlatlng[1]+1):\r
+                # Adjust bounding box\r
+                osmxml.adjust_bbox(bb_lat, bb_lng, bb_lat_edge, bb_lng_edge)\r
+                \r
+                osmxml.generate_osm(cur_tile_y, cur_tile_x) # <- This acquires current OSM info\r
+                \r
+                # Adjust longitude coordinates\r
+                cur_tile_x = cur_tile_x+1\r
+                bb_lng = bb_lng + mstr_zl_18\r
+                bb_lng_edge = bb_lng_edge + mstr_zl_18\r
+                mstr_msg("orthographic", "Adjustment of longitude performed")\r
+                # Adjust peak longitude tile number\r
+                if cur_tile_x > top_lng:\r
+                    top_lng = cur_tile_x\r
+            \r
+            # Adjust latitude and all other values when we get here\r
+            cur_tile_y = cur_tile_y+1\r
+            cur_tile_x = 1\r
+            bb_lng = self._long\r
+            bb_lng_edge = self._long + mstr_zl_18\r
+            bb_lat = bb_lat + self._vstep\r
+            bb_lat_edge = bb_lat_edge + self._vstep\r
+            mstr_msg("orthographic", "Adjustment of latitude performed")\r
+            # Adjust peak latitude number\r
+            if cur_tile_y > top_lat:\r
+                top_lat = cur_tile_y\r
+\r
+\r
     # Builds and processes the tile with everything required, in one call.\r
     def _buildTile(self):\r
         mstr_msg("orthographic", "Beginning construction of tile")\r
@@ -163,9 +231,6 @@ class mstr_orthographic:
         bb_lat = self._lat\r
         bb_lng = self._long\r
 \r
-        # For X-Plane scenery generation\r
-        xp_datagroup = 1\r
-\r
         # Previously, I downloaded all XML files in one go - but to ease the\r
         # stress on OSM servers and my server, we will do acquire the data\r
         # only for the current processed part of the tile.\r
@@ -363,4 +428,4 @@ class mstr_orthographic:
         lng = abs(int(self._long / 10) * 10)\r
         earthnavdata.append(lat)\r
         earthnavdata.append(lng)\r
-        return earthnavdata
\ No newline at end of file
+        return earthnavdata\r
index 3f4c93182f84ea2a6f08acc10c8bf51717bbf165..c80dc4bd86341a46888d2ae4979d69c32aadb422 100644 (file)
--- a/osmxml.py
+++ b/osmxml.py
@@ -34,7 +34,27 @@ class mstr_osmxml:
         self._lng = round(lng, 4)\r
         self._curB_lat = round(lat_e, 4)\r
         self._curB_lng = round(lng_e, 4)\r
+\r
     \r
+    def generate_osm(self, v, h, asobject=False):\r
+        mstr_msg("osmxml", "Acquiring OSM data for " + str(self._lat)+","+str(self._lng)+" - "+str(self._curB_lat)+","+str(self._curB_lng))\r
+        \r
+        # We will use our self-hosted API for this.\r
+        data = { \r
+            "bbox": { \r
+                    "lat": str(self._lat),\r
+                    "lng": str(self._lng),\r
+                    "lat_b": str(self._curB_lat),\r
+                    "lng_b": str(self._curB_lng)\r
+                },\r
+                "tile_lat": str(self._lat),\r
+                "tile_lng": str(self._lng),\r
+                "square_lat": str(v),\r
+                "square_lng": str(h),\r
+                "as_pbf": "true"\r
+                }\r
+        r = requests.post(mstr_osm_endpoint, json=data)\r
+\r
 \r
     # Acquire XMLs in chunks, then store them\r
     def acquire_osm(self, v, h, asobject=False):\r
@@ -65,7 +85,7 @@ class mstr_osmxml:
             # 1 second delay in case the request fails\r
             if os.path.isfile(mstr_datafolder + "_cache/tile.xml") == False:\r
                 sleep(1)\r
-\r
+            \r
         # Provide the object directly\r
         if asobject == True:\r
             xml_doc = xml.dom.minidom.parse("_cache/tile.xml")\r
@@ -152,9 +172,9 @@ class mstr_osmxml:
 \r
 \r
     # Find the levels of a building (for shadow rendering)\r
-    def find_building_levels(self, xmlfile, way_id):\r
-        lvl = 3 # Standard if we don't find anything else\r
-        xml_doc = xml.dom.minidom.parse(xmlfile)\r
+    def find_building_levels(self, way_id):\r
+        lvl = 2 # Standard if we don't find anything else\r
+        xml_doc = xml.dom.minidom.parse(mstr_datafolder + "_cache/tile.xml")\r
         wpdata = xml_doc.getElementsByTagName("way")\r
         for wp in wpdata:\r
             if wp.getAttribute("id") == way_id:\r
@@ -167,6 +187,54 @@ class mstr_osmxml:
                         break\r
         return lvl\r
     \r
+    # Find minimum level of a building\r
+    def find_building_minlevel(self, way_id):\r
+        lvl = 0 # Standard if we don't find anything else\r
+        xml_doc = xml.dom.minidom.parse(mstr_datafolder + "_cache/tile.xml")\r
+        wpdata = xml_doc.getElementsByTagName("way")\r
+        for wp in wpdata:\r
+            if wp.getAttribute("id") == way_id:\r
+                tags = wp.getElementsByTagName("tag")\r
+                for tag in tags:\r
+                    a = tag.getAttribute("k")\r
+                    v = tag.getAttribute("v")\r
+                    if a == "building:min_level":\r
+                        lvl = int(v)\r
+                        break\r
+        return lvl\r
+    \r
+    # Find the roof shape\r
+    def find_building_roof_shape(self, way_id):\r
+        rs = "flat" # Standard if we don't find anything else\r
+        xml_doc = xml.dom.minidom.parse(mstr_datafolder + "_cache/tile.xml")\r
+        wpdata = xml_doc.getElementsByTagName("way")\r
+        for wp in wpdata:\r
+            if wp.getAttribute("id") == way_id:\r
+                tags = wp.getElementsByTagName("tag")\r
+                for tag in tags:\r
+                    a = tag.getAttribute("k")\r
+                    v = tag.getAttribute("v")\r
+                    if a == "roof:shape":\r
+                        rs = v\r
+                        break\r
+        return rs\r
+    \r
+    # Find the roof levels\r
+    def find_building_roof_levels(self, way_id):\r
+        lvl = 0 # Standard if we don't find anything else\r
+        xml_doc = xml.dom.minidom.parse(mstr_datafolder + "_cache/tile.xml")\r
+        wpdata = xml_doc.getElementsByTagName("way")\r
+        for wp in wpdata:\r
+            if wp.getAttribute("id") == way_id:\r
+                tags = wp.getElementsByTagName("tag")\r
+                for tag in tags:\r
+                    a = tag.getAttribute("k")\r
+                    v = tag.getAttribute("v")\r
+                    if a == "roof:levels":\r
+                        lvl = int(v)\r
+                        break\r
+        return lvl\r
+    \r
 \r
     # It turns out that some features hide themselves in the relations section.\r
     # I figured this out during testing, and almost going insane over the\r
@@ -191,4 +259,4 @@ class mstr_osmxml:
                         tgd.append(i.getAttribute("v"))\r
                     rls.append((rp.getAttribute("ref"), tgd))\r
         return rls\r
-    
\ No newline at end of file
+    \r