]> marstr Code Repo - marstr/orthographic.git/commitdiff
Change to ZL16, initial Perlin noise class and first steps to have Perlins generated...
authorMarcus Str. <marcus@marstr.online>
Mon, 20 Jan 2025 20:59:27 +0000 (21:59 +0100)
committerMarcus Str. <marcus@marstr.online>
Mon, 20 Jan 2025 20:59:27 +0000 (21:59 +0100)
defines.py
maskgen.py
orthographic.py
osmxml.py
perlin.py [new file with mode: 0644]

index 0e5e024c546013598794163d61829b1c690366a0..7e411beadca5d678c6196a9def6207742d779b3a 100644 (file)
@@ -46,7 +46,7 @@ mstr_clear_cache = True
 \r
 # Whether or not you want to see progress of the tool as it walks on.\r
 # High recommendation to leave this on.\r
-mstr_show_log = False\r
+mstr_show_log = True\r
 \r
 \r
 # Should a pseudo shadow be rendered on certain elements?\r
index 12f1061b715338594e9e6311dd55b25a9bb05c6a..43c91173ef1056feade010252c57da1b979033eb 100644 (file)
@@ -47,7 +47,10 @@ class mstr_maskgen:
     def project_pixel(self, pnt, edge):\r
         pdiff = edge - pnt\r
         byT = pdiff * 1000\r
-        divisor = byT / 16\r
+        divisor = 1.0\r
+        # Divisor depending on zoom level\r
+        if self._zoomlevel == mstr_zl_16: divisor = byT / 64\r
+        if self._zoomlevel == mstr_zl_18: divisor = byT / 16\r
         return divisor\r
     \r
 \r
index 929bf95432720559da811983dc9e748855c53abc..5c29ebd5fa986972badbc2e0a97d96fca6e06574 100644 (file)
@@ -22,6 +22,7 @@ from maskgen import *
 from layergen import *\r
 from photogen import *\r
 from tileprep import *\r
+from perlin import *\r
 from xp_scenery import *\r
 \r
 \r
@@ -373,9 +374,15 @@ class mstr_orthographic:
         mlng = 1\r
         while bb_lat < self._lat + 1:\r
             bb_lat = bb_lat + self._vstep\r
+            if bb_lat >= self._lat + 1:\r
+                bb_lat = bb_lat - self._zoomlevel\r
+                break\r
             mlat = mlat+1\r
         while bb_lng < self._long + 1:\r
             bb_lng = bb_lng + self._zoomlevel\r
+            if bb_lng >= self._long + 1:\r
+                bb_lng = bb_lng - self._zoomlevel\r
+                break\r
             mlng = mlng+1\r
         mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))\r
         maxlatlng = [ mlat, mlng ]\r
@@ -411,6 +418,7 @@ class mstr_orthographic:
             for lng_grid in range(1, maxlatlng[1]+1):\r
                 # Adjust bounding box\r
                 osmxml = mstr_osmxml()\r
+                osmxml.setLatLngFld(self._latlngfld)\r
                 osmxml.adjust_bbox(bb_lat, bb_lng, bb_lat_edge, bb_lng_edge)\r
                 osmxml.acquire_osm(lat_grid, lng_grid)\r
                 mstr_msg("orthographic", "Adjusted bounding box for XML object")\r
@@ -421,27 +429,30 @@ class mstr_orthographic:
                 curlyr = 1\r
                 for layer in layers:\r
                     if layer[2] == False and layer[0] != "building":\r
-                        # Let the user know\r
-                        mstr_msg("orthographic", "Processing layer " + str(curlyr) + " of " + str(len(layers)))\r
-\r
-                        # Generate the mask\r
-                        mg = mstr_maskgen( [self._lat, cur_tile_y, self._long, cur_tile_x], self._vstep, layer[0], layer[1], layer[2])\r
-                        mask = mg._build_mask(osmxml, is_prep=True) # We need an object here\r
-\r
-                        mask = mask.resize((80,80), Image.Resampling.BILINEAR)\r
-                        idx = 0\r
-                        for c in contours:\r
-                            if c[0] == layer[0] and c[1] == layer[1]:\r
-                                break\r
-                            else:\r
-                                idx=idx+1\r
-                        \r
-                        cnx = (lng_grid-1) * 80\r
-                        cny = cnt_h - (lat_grid * 80)\r
-                        contours[idx][2].alpha_composite(mask, dest=(cnx,cny))\r
-\r
-                        #tp = mstr_tileprep(self._lat, self._long, lat_grid, lng_grid, layer[0], layer[1], mask, False)\r
-                        #tp._determineEdges()\r
+                        fn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/contour/contour_" + layer[0] + "_" + layer[1] + ".png"\r
+                        if os.path.isfile(fn) == False:\r
+                            # Let the user know\r
+                            mstr_msg("orthographic", "Processing layer " + str(curlyr) + " of " + str(len(layers)))\r
+\r
+                            # Generate the mask\r
+                            mg = mstr_maskgen( [self._lat, cur_tile_y, self._long, cur_tile_x], self._vstep, layer[0], layer[1], layer[2])\r
+                            mask = mg._build_mask(osmxml, is_prep=True) # We need an object here\r
+\r
+                            mask = mask.resize((80,80), Image.Resampling.BILINEAR)\r
+                            idx = 0\r
+                            for c in contours:\r
+                                if c[0] == layer[0] and c[1] == layer[1]:\r
+                                    break\r
+                                else:\r
+                                    idx=idx+1\r
+                            \r
+                            cnx = (lng_grid-1) * 80\r
+                            cny = cnt_h - (lat_grid * 80)\r
+                            contours[idx][2].alpha_composite(mask, dest=(cnx,cny))\r
+                            contours[idx][2].save(fn)\r
+\r
+                            #tp = mstr_tileprep(self._lat, self._long, lat_grid, lng_grid, layer[0], layer[1], mask, False)\r
+                            #tp._determineEdges()\r
 \r
                     curlyr = curlyr+1\r
 \r
@@ -454,7 +465,8 @@ class mstr_orthographic:
                 if cur_tile_x > top_lng:\r
                     top_lng = cur_tile_x\r
 \r
-                totaldata = glob.glob("D:/Developer/webserver/htdocs/server/osm/*.xml")\r
+                \r
+                totaldata = glob.glob(mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/osm/*.xml")\r
                 progress = int( (len(totaldata) / total_tiles) * 100 )\r
 \r
                 if progress >= nextstep:\r
@@ -475,13 +487,20 @@ class mstr_orthographic:
 \r
 \r
         # Store all contour images\r
-        for c in contours:\r
-            c[2].save(mstr_datafolder + "_cache/contour_" + c[0] + "_" + c[1] + ".png")\r
-        mstr_msg("orthographic", "Saved contour images for each OSM tag")\r
+        #for c in contours:\r
+        #    c[2].save(mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/contour/contour_" + c[0] + "_" + c[1] + ".png")\r
+        #mstr_msg("orthographic", "Saved contour images for each OSM tag")\r
+\r
 \r
+        # Genertate all perlin noise maps\r
+        for l in mstr_ortho_layers:\r
+            mstr_important_msg("orthographic", "Generating Perlin map for " + l[0] + ":" + l[1])\r
+            prln = mstr_perlin(l[0], l[1], mlat, mlng, 16)\r
+            pmap = prln._generatePerlinMap()\r
+            fn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/perlin/perlin_" + l[0] + "_" + l[1] + ".png"\r
+            pmap.save(fn)\r
 \r
-        # We now need to "raytrace" the resources for correct placement\r
-        mstr_msg("orthographic", "Performing resource plamement tracing for tile")\r
+        \r
 \r
         # Let's set up an array which keeps track of all used tiles, per resource\r
         """\r
index 7c4c1504bee1f14f20466d2ccd3c275482d9dc9d..c5359f49dd00320aa5880e371b77ba7344180088 100644 (file)
--- a/osmxml.py
+++ b/osmxml.py
@@ -30,6 +30,12 @@ class mstr_osmxml:
         self._lng = 0\r
         self._curB_lat = 0\r
         self._curB_lng = 0\r
+        self._latlngfld = ""\r
+\r
+\r
+    # Set LatLngFolder\r
+    def setLatLngFld(self, latlngfld):\r
+        self._latlngfld = latlngfld\r
 \r
     \r
     # Adjust bbox for when this class should persost, but acquire data for a different bbox\r
@@ -66,7 +72,7 @@ class mstr_osmxml:
 \r
         # We switched to a local storage model to ease load on the server. We will check if we already have the data we need.\r
         # If not, go an acquire it.\r
-        fn = mstr_datafolder + "z_orthographic/data/+++++/osm/" + str(self._lat) + "-" + str(v) + "_"  + str(self._lng) + "-" + str(h) + ".xml"\r
+        fn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/osm/" + str(int(self._lat)) + "-" + str(v) + "_"  + str(int(self._lng)) + "-" + str(h) + ".xml"\r
         if os.path.isfile(fn) == False:\r
             # We will use our self-hosted API for this.\r
             parse = False\r
@@ -110,7 +116,9 @@ class mstr_osmxml:
             # Check if the DOM object has a document element\r
             if dom.documentElement:\r
                 # Store the content in memory\r
-                self._xmlcontent = r.content\r
+                with open(fn, encoding="utf8") as f:\r
+                    contents = f.read()\r
+                self._xmlcontent = contents\r
                 self._xmldata = xml.dom.minidom.parseString(self._xmlcontent)\r
                 self._xmlcontent = ""  # Clear\r
 \r
diff --git a/perlin.py b/perlin.py
new file mode 100644 (file)
index 0000000..a141f88
--- /dev/null
+++ b/perlin.py
@@ -0,0 +1,144 @@
+
+# -------------------------------------------------------------------
+# ORTHOGRAPHIC
+# Your personal aerial satellite. Always on. At any altitude.*
+# Developed by MarStrMind
+# License: Open Software License 3.0
+# Up to date version always on marstr.online
+# -------------------------------------------------------------------
+# perlin.py
+# Generates a perlin noise image which is used to determine how which
+# resource looks.
+# -------------------------------------------------------------------
+
+from PIL import Image # Depends on the Pillow lib
+from random import randrange
+import random
+import numpy as np
+from perlin_numpy import (
+    generate_perlin_noise_2d, generate_fractal_noise_2d
+)
+
+class mstr_perlin:
+
+    def __init__(self, tag, value, mlat, mlng, zl):
+        self._tag = tag
+        self._value = value
+        self._mlat = mlat
+        self._mlng = mlng
+
+        self._zl = zl
+        self._mapscale = 0
+        if zl == 16: self._mapscale = 80
+        if zl == 18: self._mapscale = 20
+
+        # Define some base colors
+        # tag, value, base color, perlin noise color palette
+        self._bc = [
+            # Amenity
+            ["amenity", "parking",              (31,32,34,255), [ (31,32,34), (74,74,73), (56,55,55), (34,40,44) ]],
+            ["amenity", "school",               (26,26,26,255), [ (26,26,26), (78,78,78), (28,29,25), (86,74,64) ]],
+            # Barrier
+            ["barrier", "hedge",                (27,37,25,255), [ (27,37,25),  (8,14,13), (15,20,23), (40,40,38) ]],
+            # Boundary
+            ["boundary", "administrative",      (50,49,46,255), [ (50,49,46), (32,38,34),  (9,14,18), (82,80,76) ]],
+            # Landuse
+            ["landuse", "cemetery",             (22,22,20,255), [ (22,22,20), (44,43,40), (31,33,29), (39,37,34) ]],
+            ["landuse", "construction",         (65,51,32,255), [ (65,51,32), (77,73,67), (45,49,43), (74,63,48) ]],
+            ["landuse", "farmland",             (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
+            ["landuse", "farmyard",             (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
+            ["landuse", "forest",               (0,30,10,255),  [  (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
+            ["landuse", "grass",                (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
+            ["landuse", "greenfield",           (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
+            ["landuse", "meadow",               (28,29,27,255), [ (28,29,27), (36,42,40), (45,44,41), (21,22,20) ]],
+            ["landuse", "military",             (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
+            ["landuse", "orchard",              (27,38,27,255), [ (27,38,27), (19,22,16), (40,42,33), (40,50,45) ]],
+            ["landuse", "recreation_ground",    (27,38,27,255), [ (27,38,27), (19,22,16), (40,42,33), (40,50,45) ]],
+            ["landuse", "residential",          (50,49,46,255), [ (50,49,46), (32,38,34),  (9,14,18), (82,80,76) ]],
+            ["landuse", "residential-boundary", (50,49,46,255), [ (50,49,46), (32,38,34),  (9,14,18), (82,80,76) ]],
+            ["landuse", "vineyard",             (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
+            # Leisure
+            ["leisure", "dog_park",             (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
+            ["leisure", "garden",               (39,39,32,255), [ (39,39,32), (38,47,43), (35,41,31), (21,25,18) ]],
+            ["leisure", "golf_course",          (29,39,28,255), [ (29,39,28), (86,81,76), (60,55,45), (13,18,14) ]],
+            ["leisure", "green",                (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
+            ["leisure", "nature_reserve",       (0,30,10,255),  [  (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
+            ["leisure", "park",                 (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
+            ["leisure", "pitch",                (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
+            ["leisure", "playground",           (65,51,32,255), [ (65,51,32), (77,73,67), (45,49,43), (74,63,48) ]],
+            ["leisure", "sports_centre",        (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
+            ["leisure", "swimming_pool",        (9,13,18,255),  [  (9,13,18),  (9,15,21), (11,12,12), (22,28,31) ]],
+            # Natural
+            ["natural", "bare_rock",            (47,54,56,255), [ (47,54,56), (79,75,71), (84,51,43), (26,33,45) ]],
+            ["natural", "beach",                (79,76,69,255), [ (79,76,69), (82,83,80), (71,61,48), (69,68,66) ]],
+            ["natural", "desert",               (79,64,42,255), [ (79,64,42), (79,47,24), (37,41,27), (51,39,23) ]],
+            ["natural", "grassland",            (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
+            ["natural", "heath",                (26,28,23,255), [ (26,28,23), (45,44,42), (30,34,29), (45,45,42) ]],
+            ["natural", "sand",                 (79,76,69,255), [ (79,76,69), (82,83,80), (71,61,48), (69,68,66) ]],
+            ["natural", "scree",                (38,36,33,255), [ (38,36,33), (81,80,76), (43,42,31), (37,34,27) ]],
+            ["natural", "scrub",                (41,39,35,255), [ (41,39,35), (44,38,34), (30,32,39), (20,27,22) ]],
+            ["natural", "water",                (9,13,18,255),  [  (9,13,18),  (9,15,21), (11,12,12), (22,28,31) ]],
+            ["natural", "wetland",              (32,34,33,255), [ (32,34,33),  (5, 8, 8), (35,36,35), (17,19,17) ]],
+            ["natural", "wood",                 (0,30,10,255),  [  (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
+            # Water
+            ["water", "lake",                   (9,13,18,255),  [  (9,13,18),  (9,15,21), (11,12,12), (22,28,31) ]],
+            ["water", "pond",                   (9,13,18,255),  [  (9,13,18),  (9,15,21), (11,12,12), (22,28,31) ]],
+            ["water", "river",                  (9,13,18,255),  [  (9,13,18),  (9,15,21), (11,12,12), (22,28,31) ]]
+        ]
+
+
+    # Find base color depending on tag/value
+    def _findBaseColor(self):
+        idx = -1
+        for b in range(len(self._basecolors)):
+            if self._bc[b][0] == self._tag and self._bc[b][1] == self._value:
+                idx = b
+                break
+        return idx
+
+
+    # Generates a Perlin map depending on what we need
+    def _generatePerlinMap(self):
+        idx = self._findBaseColor()
+
+        bw = self._mlng * self._mapscale
+        bh = self._mlat * self._mapscale
+        wh = 2048
+        base = Image.new("RGBA", (bw,bh), self._bc[idx][2])
+
+        for c in range(len(self._bc[idx][3])):
+            np.random.seed(randrange(10000000, 100000000))
+            noise1 = generate_fractal_noise_2d((wh,wh), (16,16), 5)
+            np.random.seed(randrange(10000000, 100000000))
+            noise2 = generate_fractal_noise_2d((wh,wh), (8,8), 4)
+
+            im1 = Image.new("RGBA", (wh,wh))
+            im2 = Image.new("RGBA", (wh,wh))
+            
+            for y in range(0, wh):
+                for x in range(0, wh):
+                    n = (noise1[y][x] + 1) / 2
+                    v = (
+                        self._bc[idx][3][c][0],
+                        self._bc[idx][3][c][1],
+                        self._bc[idx][3][c][2],
+                        int(n*255)
+                        )
+                    im1.putpixel((x,y), v)
+                    
+            for y in range(0, wh):
+                for x in range(0, wh):
+                    n = (noise2[y][x] + 1) / 2
+                    v = (
+                        self._bc[idx][3][c][0],
+                        self._bc[idx][3][c][1],
+                        self._bc[idx][3][c][2],
+                        int(n*255)
+                        )
+                    im2.putpixel((x,y), v)
+                    
+            im = Image.blend(im1,im2, alpha=0.5)
+            base.alpha_composite(im)
+
+        # Provide the perlin map
+        return base
\ No newline at end of file