]> marstr Code Repo - orthographic/commitdiff
Normal map moved to end of ortho pipeline. Water is no longer rendered underneath...
authorMarcus Str. <marcus@marstr.online>
Sat, 30 Nov 2024 21:12:36 +0000 (22:12 +0100)
committerMarcus Str. <marcus@marstr.online>
Sat, 30 Nov 2024 21:13:58 +0000 (22:13 +0100)
layergen.py
photogen.py
xp_normalmap.py
xp_scenery.py

index cb7259556bac07abbdc9427b81fa1afd216cc6e1..98d326719b020a810b69ad2fa110a702364a34a4 100644 (file)
@@ -22,7 +22,6 @@ from log import *
 from tileinfo import *\r
 from osmxml import *\r
 from functions import *\r
-from xp_normalmap import *\r
 \r
 class mstr_layergen:\r
 \r
@@ -409,6 +408,7 @@ class mstr_layergen:
 \r
             # Depending on if scenery for XP should be made, AND if normal maps should be made, we would\r
             # need to make them at this exact point\r
+            """\r
             if mstr_xp_genscenery == True:\r
                 if mstr_xp_scn_normalmaps == True and self._is_completion == False:\r
                     nm = False\r
@@ -419,6 +419,7 @@ class mstr_layergen:
                     if nm == True:\r
                         nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld)\r
                         nrm.build_normalmap(layer_comp)\r
+            """\r
 \r
 \r
             # Let's try our hand at pseudo shadows\r
@@ -886,6 +887,7 @@ class mstr_layergen:
 \r
             # Depending on if scenery for XP should be made, AND if normal maps should be made, we would\r
             # need to make them at this exact point\r
+            """\r
             if mstr_xp_genscenery == True:\r
                 if mstr_xp_scn_normalmaps == True and self._is_completion == False:\r
                     nm = False\r
@@ -896,6 +898,7 @@ class mstr_layergen:
                     if nm == True:\r
                         nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld)\r
                         nrm.build_normalmap(layer_comp)\r
+            """\r
 \r
 \r
             # Return image\r
index 54b016bb5cc5f52d511a5347152a6604882a7d0d..c50bb866f07ce21339d2f914762db7ae1b5ed8cc 100644 (file)
@@ -5,6 +5,7 @@ from defines import *
 from layergen import *\r
 from log import *\r
 from functions import *\r
+from xp_normalmap import *\r
 \r
 # -------------------------------------------------------------------\r
 # ORTHOGRAPHIC\r
@@ -29,9 +30,7 @@ class mstr_photogen:
         self._tx = tx\r
         self._maxlatlng = [ maxlat, maxlng ]\r
         # Define layer size depending on what is wanted\r
-        self._imgsize = 0\r
-        if mstr_photores == 2048: self._imgsize = 2048\r
-        if mstr_photores == 4096: self._imgsize = 6000\r
+        self._imgsize = mstr_photores\r
         # Empty image where everything goes into\r
         self._tile = Image.new("RGBA", (self._imgsize, self._imgsize))\r
         self._latlngfld = self.latlng_folder([lat,lng])\r
@@ -148,29 +147,6 @@ class mstr_photogen:
                     corrpix[x,y] = nc\r
                 if c[3] == 0:\r
                     corrpix[x,y] = (0,0,0,0)\r
-\r
-        # Now cut out inland water\r
-        for w in waterlayers:\r
-            wtr_pix = w.load()\r
-            for y in range(w.height):\r
-                for x in range(w.width):\r
-                    v = wtr_pix[x,y]\r
-                    if v[3] >= 50:\r
-                        c = (0,0,0,0)\r
-                        corrpix[x,y] = c\r
-\r
-        """\r
-        ddsf_water = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(self._ty) + "_" + str(self._tx) + "_water.png"\r
-        if os.path.isfile(ddsf_water) == True:\r
-            wtr = Image.open(ddsf_water)\r
-            wtr_pix = wtr.load()\r
-            for y in range(wtr.height):\r
-                for x in range(wtr.width):\r
-                    v = wtr_pix[x,y]\r
-                    if v <= 50:\r
-                        c = (0,0,0,0)\r
-                        corrpix[x,y] = c\r
-        """\r
         \r
         # We are now in posession of the final image.\r
         \r
@@ -187,6 +163,29 @@ class mstr_photogen:
         os.remove(mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(self._ty) + "_" + str(self._tx) + ".png")\r
 \r
 \r
+        # Now generate the normal map for this ortho.\r
+        # But only if this is enabled.\r
+        if mstr_xp_genscenery and mstr_xp_scn_normalmaps:\r
+            # Generate the normal normal map first (hah)\r
+            nrm = mstr_xp_normalmap()\r
+            nrmimg = nrm.generate_normal_map_for_layer(self._tile, False)\r
+\r
+            # Now we need to walk through the water layers and generate a combined normal map\r
+            wtrlyr = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+            for w in waterlayers:\r
+                wtrlyr.alpha_composite(w)\r
+            wtrlyr = wtrlyr.resize((int(mstr_photores/4), int(mstr_photores/4)), Image.Resampling.BILINEAR)\r
+            wtrimg = nrm.generate_normal_map_for_layer(wtrlyr, True)\r
+\r
+            # Blend\r
+            nrmimg.alpha_composite(wtrimg)\r
+\r
+            # Save\r
+            nrmfln = mstr_datafolder + "z_orthographic/normals/" + self._latlngfld + "/" + str(self._ty) + "_" + str(\r
+                self._tx) + ".png"\r
+            nrmimg.save(nrmfln)\r
+\r
+\r
 \r
 \r
     # This checks the final image for empty patches. Should one be\r
index 9590c557bd40696352883a0b0c4244e53eb8623b..fcefc90708f89038e27d02ccc5dd61ca4f25afd3 100644 (file)
@@ -27,14 +27,7 @@ from log import *
 class mstr_xp_normalmap:\r
 \r
     # Only a few params\r
-    def __init__(self, lat, lng, tag, value, tv, th, latlngfld):\r
-        self._lat = lat\r
-        self._lng = lng\r
-        self._tag = tag\r
-        self._value = value\r
-        self._latlngfld = latlngfld\r
-        self._tv = tv\r
-        self._th = th\r
+    def __init__(self):\r
         mstr_msg("xp_normalmap", "[X-Plane] Normal Map generator initialized")\r
 \r
 \r
@@ -46,7 +39,7 @@ class mstr_xp_normalmap:
             pavg = 255.0 / avg\r
         else:\r
             pavg = 0\r
-        return pavg\r
+        return pavg * 3\r
 \r
 \r
     def clamp(self, px, mpx):\r
@@ -72,7 +65,7 @@ class mstr_xp_normalmap:
 \r
 \r
     # The Big Mac. Generate the normal map\r
-    def generate_normal_map_for_layer(self, image):\r
+    def generate_normal_map_for_layer(self, image, water=False):\r
         mstr_msg("xp_normalmap", "[X-Plane] Beginning normal map generation")\r
         # No specularity, no reflectivity - but standard color\r
         # Blue (reflectivity) and alpha (specularity) need to be 1 - but can be adjusted as needed\r
@@ -81,6 +74,9 @@ class mstr_xp_normalmap:
         image = image.resize((int(mstr_photores/4), int(mstr_photores/4)), Image.Resampling.BILINEAR)\r
 \r
         nmp = Image.new("RGBA", (image.width, image.height), (128,128,1,1))\r
+\r
+        if water: nmp = Image.new("RGBA", (image.width, image.height), (128, 128, 255, 0))\r
+\r
         org = image.load()\r
         nmp_pix = nmp.load()\r
 \r
@@ -124,7 +120,10 @@ class mstr_xp_normalmap:
                         nrm[1] = abs(nrm[1])\r
 \r
                     # Set pixel\r
-                    nmp_pix[x,y] = (int(self.map_component(nrm[0])), int(self.map_component(nrm[1])), 255 - int(self.map_component(nrm[2])), 1)\r
+                    if water:\r
+                        nmp_pix[x,y] = (int(self.map_component(nrm[0])), int(self.map_component(nrm[1])), int(self.map_component(nrm[2])), int(self.map_component(nrm[2])))\r
+                    if not water:\r
+                        nmp_pix[x,y] = (int(self.map_component(nrm[0])), int(self.map_component(nrm[1])), 255 - int(self.map_component(nrm[2])), 1)\r
 \r
         mstr_msg("xp_normalmap", "[X-Plane] Normal map generated")\r
         return nmp\r
@@ -138,26 +137,8 @@ class mstr_xp_normalmap:
         nrm = self.generate_normal_map_for_layer(layer)\r
 \r
         # Normal map final file name\r
-        nrmfln = mstr_datafolder + "z_orthographic/normals/" + self._latlngfld + "/" + str(self._tv) + "_" + str(self._th) + ".png"\r
-\r
-        # Check for existence of normal map file\r
-        ex = os.path.isfile(nrmfln)\r
-\r
-        # Does not exist? Just save\r
-        if ex == False:\r
-            nrm.save(nrmfln)\r
-\r
-        # Exists? Open it, composite both, save\r
-        if ex == True:\r
-            nrmmap = Image.open(nrmfln)\r
-            nrmmap.alpha_composite(nrm)\r
-\r
-            # Specularity blending correction\r
-            nrmmap_pix = nrmmap.load()\r
-            for y in range(nrmmap.height):\r
-                for x in range(nrmmap.width):\r
-                    c = nrmmap_pix[x,y]\r
-                    nrmmap_pix[x,y] = (c[0], c[1], c[2], 1)\r
-            nrmmap.save(nrmfln)\r
+        #nrmfln = mstr_datafolder + "z_orthographic/normals/" + self._latlngfld + "/" + str(self._tv) + "_" + str(self._th) + ".png"\r
             \r
-        mstr_msg("xp_normalmap", "[X-Plane] Normal map saved")\r
+        mstr_msg("xp_normalmap", "[X-Plane] Normal map generated")\r
+\r
+        return nrm\r
index ca07034f711b0da7d22ede567fd14d319545ccf8..2bfeee15be30dfd64fd26505752f72aada4481f8 100644 (file)
@@ -34,6 +34,8 @@ class mstr_xp_scenery:
         self._dsfstring = ""
         self._demdata = None  # To be populated when the mesh is built
         self._demcoord = None # Also to be populated when mesh is built
+        self._waterdata = []  # So that we know where to implement water
+        #self.load_water_data()
 
 
     # Build the correct file name for the elevation model
@@ -66,12 +68,30 @@ class mstr_xp_scenery:
         return fn
 
 
+    # Load the water data before we generate the mesh
+    def load_water_data(self):
+        fn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/wtrfile"
+        with open(fn) as file:
+            for line in file:
+                ln = line.replace(" ", "_")
+                ln = ln.replace("\n", "")
+                ln = ln.replace("\r", "")
+                self._waterdata.append(ln)
+
+
+    # Check if ortho has water
+    def does_ortho_have_water(self, ortho):
+        wtr = False
+        if ortho in self._waterdata: wtr = True
+        return wtr
+                
+
+
     # Build the DSF for the ortho photo overlay
     def build_and_convert_dsf(self):
         end = self.find_earthnavdata_number()
         llf = self.xplane_latlng_folder(end)
         meshtxt = mstr_datafolder + "_cache/mesh_"+self._latlngfld+".txt"
-        scr = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/meshscript.txt"
         cmd = mstr_xp_dsftool + " --text2dsf " + meshtxt + " '" + mstr_datafolder + "z_orthographic/Earth nav data/" + llf + "/" + self._latlngfld + ".dsf'"
         os.system(cmd)
 
@@ -160,9 +180,8 @@ class mstr_xp_scenery:
                 terstr = terstr + "TERRAIN\r\n"
                 terstr = terstr + "\r\n"
                 terstr = terstr + "LOAD_CENTER " + str(cnt_x) + " " + str(cnt_y) + " " + str(dmt) + " 2048\r\n"
-                #terstr = terstr + "BASE_TEX_NOWRAP ../../orthos/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".dds\r\n"
-                terstr = terstr + "TEXTURE_NOWRAP ../../orthos/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".dds\r\n"
-                if mstr_xp_scn_normalmaps == True:
+                terstr = terstr + "BASE_TEX_NOWRAP ../../orthos/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".dds\r\n"
+                if mstr_xp_scn_normalmaps:
                     terstr = terstr + "NORMAL_TEX 1.0 ../../normals/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".png\r\n"
 
                 terfln = mstr_datafolder + "z_orthographic/terrain/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".ter"
@@ -223,103 +242,34 @@ class mstr_xp_scenery:
         with open(meshtxt, 'w') as textfile:
             textfile.write(dsf_str)
 
+        dsf_str = ""
+
+        # Orthos
         for lat in range(1, self._mlat+1):
             for lng in range(1, self._mlng+1):
                 # Write the line only if an ortho exists of course.
                 ddsf = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".dds"
-                ddsf_water = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + "_water.png"
-                if os.path.isfile(ddsf) == True:
-                    dsfstr = "TERRAIN_DEF terrain/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".ter\r\n"
-                    
-                    # Let's check if this tile needs water beneath
-                    if os.path.isfile(ddsf_water) == True:
-                        dsfstr = dsfstr + "TERRAIN_DEF terrain_Water\r\n"
+                if os.path.isfile(ddsf):
+                    dsf_str = dsf_str + "TERRAIN_DEF terrain/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".ter\r\n"
 
-                    with open(meshtxt, 'a') as textfile:
-                        textfile.write(dsfstr)
+        with open(meshtxt, 'a') as textfile:
+            textfile.write(dsf_str)
         
 
         # OK. So. Let's build the mesh.
-
-        """
-        # First, the ground water mesh
-        with open(meshtxt, 'a') as textfile:
-            textfile.write("BEGIN_PATCH 0 0.000000 -1.000000 1 5\r\n")
-
-        # Vertical row (Latitude Row)
-        for lat_r in range(0, len(self._demcoord)-2):
-
-            # Horizontal row (Longitude Column)
-            for lng_c in range(0, len(self._demcoord)-2):
-
-                # Lat/lng coordinate
-                lat_crd   = self._demcoord[lat_r][lng_c][0]
-                lat_crd_t = self._demcoord[lat_r+1][lng_c][0]
-                lng_crd   = self._demcoord[lat_r][lng_c][1]
-                lng_crd_r = self._demcoord[lat_r][lng_c+1][1]
-
-                # Coords of triangle vertices
-                # 0 - Longitude
-                # 1 - Latitude
-                # 2 - Height in m
-                t1_v1 = [ lng_crd_r, lat_crd, 0 ]
-                t1_v2 = [ lng_crd, lat_crd_t, 0 ]
-                t1_v3 = [ lng_crd_r, lat_crd_t, 0 ]
-                t2_v1 = [ lng_crd, lat_crd_t, 0 ]
-                t2_v2 = [ lng_crd_r, lat_crd, 0 ]
-                t2_v3 = [ lng_crd, lat_crd, 0 ]
-
-
-                t1_v1 = [ lng_crd_r, lat_crd, self._demcoord[lat_r][lng_c+1][2] ]
-                t1_v2 = [ lng_crd, lat_crd_t, self._demcoord[lat_r+1][lng_c][2] ]
-                t1_v3 = [ lng_crd_r, lat_crd_t, self._demcoord[lat_r+1][lng_c+1][2] ]
-                t2_v1 = [ lng_crd, lat_crd_t, self._demcoord[lat_r+1][lng_c][2] ]
-                t2_v2 = [ lng_crd_r, lat_crd, self._demcoord[lat_r][lng_c+1][2] ]
-                t2_v3 = [ lng_crd, lat_crd, self._demcoord[lat_r][lng_c][2] ]
-
-
-                # Write down the two triangles
-                t_str = ""
-                t_str = t_str + "BEGIN_PRIMITIVE 0\r\n"
-                t_str = t_str + "PATCH_VERTEX " + str(t1_v1[0]) + " " + str(t1_v1[1]) + " " + str(t1_v1[2]) + " 0.000015 0.000015\r\n"
-                t_str = t_str + "PATCH_VERTEX " + str(t1_v2[0]) + " " + str(t1_v2[1]) + " " + str(t1_v2[2]) + " 0.000015 0.000015\r\n"
-                t_str = t_str + "PATCH_VERTEX " + str(t1_v3[0]) + " " + str(t1_v3[1]) + " " + str(t1_v3[2]) + " 0.000015 0.000015\r\n"
-                t_str = t_str + "END_PRIMITIVE 0\r\n"
-                t_str = t_str + "BEGIN_PRIMITIVE 0\r\n"
-                t_str = t_str + "PATCH_VERTEX " + str(t2_v1[0]) + " " + str(t2_v1[1]) + " " + str(t2_v1[2]) + " 0.000015 0.000015\r\n"
-                t_str = t_str + "PATCH_VERTEX " + str(t2_v2[0]) + " " + str(t2_v2[1]) + " " + str(t2_v2[2]) + " 0.000015 0.000015\r\n"
-                t_str = t_str + "PATCH_VERTEX " + str(t2_v3[0]) + " " + str(t2_v3[1]) + " " + str(t2_v3[2]) + " 0.000015 0.000015\r\n"
-                t_str = t_str + "END_PRIMITIVE 0\r\n"
-
-                # Send to the file
-                with open(meshtxt, 'a') as textfile:
-                    textfile.write(t_str)
-
-                t_str = ""
-
-        # Water mesh ends
-        with open(meshtxt, 'a') as textfile:
-            textfile.write("END PATCH\r\n")
-        """
         
         # Current patch
         curpatch = 0
 
         for lat in range(1, self._mlat+1):
             for lng in range(1, self._mlng+1):
-                
 
                 # Create the patch only if the matching ortho exists.
                 # This way we make sure that we hit the same order as the .ter files.
                 # We can also detect which lat and lng coord we are on.
 
-                #ddsf = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/1_1.dds"
-                ddsf = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".dds"
-                ddsf_water = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + "_water.png"
-                if os.path.isfile(ddsf) == True:
-                
-                    scangrid = self.find_height_scan_start_end_points([ self._lat+((lat-1)*self._vstep), self._lng+((lng-1)*mstr_zl_18) ])
-                    #sloped   = self.build_sloped_scangrid(scangrid)
+                ddsf  = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".dds"
+                if os.path.isfile(ddsf):
 
                     # Base coords for this ortho
                     base_lat = self._lat + ((lat-1) * self._vstep)
@@ -335,12 +285,6 @@ class mstr_xp_scenery:
                     latstep = self._vstep/odiv
                     lngstep = mstr_zl_18 /odiv
                     uv_step = 1 / odiv
-                    
-                    # Height values
-                    hgt_bl = 0
-                    hgt_br = 0
-                    hgt_tr = 0
-                    hgt_tl = 0
 
                     # Generate the ortho tile
                     for y in range(0,odiv):
@@ -408,11 +352,6 @@ class mstr_xp_scenery:
                             t_str = ""
 
                     
-                    # Height value:
-                    # hgtindex = self.find_height_for_coord([lat, lng])
-                    # height = self._demcoord[hgtindex[0]][hgtindex[1]][2]
-
-                    
                     # End this patch
                     with open(meshtxt, 'a') as textfile:
                         textfile.write("END PATCH\r\n")
@@ -422,15 +361,12 @@ class mstr_xp_scenery:
 
 
                     # Let's check if this tile needs water beneath
-                    needs_water = False
-                    if os.path.isfile(ddsf_water) == True: needs_water = True
-
-
-                    if needs_water == True:
+                    """
+                    if self.does_ortho_have_water(str(lat) + "_" + str(lng)):
 
                         # Begin a new patch
                         with open(meshtxt, 'a') as textfile:
-                            textfile.write("BEGIN_PATCH " + str(curpatch) + " 0.000000 -1.000000 1 5\r\n")
+                            textfile.write("BEGIN_PATCH " + str(curpatch) + " 0.000000 -1.000000 2 5\r\n")
 
                         # Generate the ortho tile
                         for y in range(0,odiv):
@@ -461,10 +397,10 @@ class mstr_xp_scenery:
                                 hgt_br_idx = self.find_height_for_coord([lat_b, lng_r])
                                 hgt_tr_idx = self.find_height_for_coord([lat_t, lng_r])
                                 hgt_tl_idx = self.find_height_for_coord([lat_t, lng_l])
-                                hgt_bl = round(self._demcoord[ hgt_bl_idx[0] ][ hgt_bl_idx[1] ][2] - .1, 6)
-                                hgt_br = round(self._demcoord[ hgt_br_idx[0] ][ hgt_br_idx[1] ][2] - .1, 6)
-                                hgt_tr = round(self._demcoord[ hgt_tr_idx[0] ][ hgt_tr_idx[1] ][2] - .1, 6)
-                                hgt_tl = round(self._demcoord[ hgt_tl_idx[0] ][ hgt_tl_idx[1] ][2] - .1, 6)
+                                hgt_bl = round(self._demcoord[ hgt_bl_idx[0] ][ hgt_bl_idx[1] ][2] - .01, 6)
+                                hgt_br = round(self._demcoord[ hgt_br_idx[0] ][ hgt_br_idx[1] ][2] - .01, 6)
+                                hgt_tr = round(self._demcoord[ hgt_tr_idx[0] ][ hgt_tr_idx[1] ][2] - .01, 6)
+                                hgt_tl = round(self._demcoord[ hgt_tl_idx[0] ][ hgt_tl_idx[1] ][2] - .01, 6)
 
                                 # Coords of triangle vertices
                                 # 0 - Longitude
@@ -500,6 +436,7 @@ class mstr_xp_scenery:
 
                         # Increase patch number
                         curpatch = curpatch + 1
+                    """
 
 
 
@@ -561,76 +498,5 @@ class mstr_xp_scenery:
         if startend[2] < 0: startend[2] = 0
         if startend[3] > len(self._demdata)-1: startend[3] = startend[3] = len(self._demdata)-1
 
-
-        """
-        t = self._lat
-        while t < startcoord[0]:
-            t = t + self._vstep
-            startend[0] = startend[0]+1
-
-        t = self._lat
-        while t < startcoord[0]+self._vstep:
-            t = t + self._vstep
-            startend[1] = startend[1]+1
-
-        t = self._lng
-        while t < startcoord[1]:
-            t = t + mstr_zl_18
-            startend[2] = startend[2]+1
-
-        t = self._lng
-        while t < startcoord[1]+mstr_zl_18:
-            t = t + mstr_zl_18
-            startend[3] = startend[3]+1
-
-        # Some corrections
-        startend[0] = startend[0]-1
-        if startend[0] < 0: startend[0] = 0
-
-        startend[1] = startend[1]+1
-        if startend[1] > len(self._demdata)-1: startend[1] = startend[1] = len(self._demdata)-1
-
-        startend[2] = startend[2]-1
-        if startend[2] < 0: startend[2] = 0
-        
-        startend[3] = startend[3]+1
-        if startend[3] > len(self._demdata)-1: startend[3] = startend[3] = len(self._demdata)-1
-        """
-
         return startend
 
-
-    # Function to subdivide between two vectors
-    def subdivide_vectors(self, v1, v2, subdivisions):
-        #return np.linspace(v1, v2, subdivisions + 2, axis=0)  # +2 to include endpoints
-        return numpy.linspace(v1, v2, subdivisions + 2, axis=0)  # +2 to include endpoints
-
-
-    # This build a scangrid with increased resolution, extrapolated from existing points.
-    # With this we can accurately depict the height of a point a long the slope of the ground mesh.
-    def build_sloped_scangrid(self, grid):
-        
-        # Contains the data as defined by the grid passed in
-        tmp_dem = []
-
-        # Acquire original grid data
-        for l in range(grid[2], grid[3]+1):
-            row = []
-            for c in range(grid[0], grid[1]+1):
-                row.append(self._demcoord[l][c])
-            tmp_dem.append(row)
-        
-        # Subdivide the array
-        subdivisions = 10
-        result = []
-        for i in range(len(tmp_dem) - 1):
-            for j in range(len(tmp_dem[i]) - 1):
-                subdivided = self.subdivide_vectors(tmp_dem[i][j], tmp_dem[i][j + 1], subdivisions)
-                if i > 0:  # Avoid duplicating start point
-                    subdivided = subdivided[1:]
-                result.append(subdivided)
-
-        # Combine all subdivisions into one array
-        result = numpy.vstack(result)
-
-        return result
\ No newline at end of file