# ------------------------------------------------------------------- # 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 # ------------------------------------------------------------------- # maskgen.py # The class that generates a mask of the layer it was asked to do. # This mask will then be used to generate a photo layer, which in # turn is then used to construct the final photo. It can be argued # that this part of the code is the most crucial one, as the other # classes involved rely on what this code is doing, and by extension, # generating. # # The PNG generated will be used in this progression: # - Generate mask from OSM (here) # - Generate colored photo layer from this mask, for example for # landuse: forest # - Compile actual satellite aerial # ------------------------------------------------------------------- import math from osmxml import * from defines import * from log import * from PIL import Image, ImageFilter, ImageDraw, ImagePath from random import randrange import random class mstr_maskgen: # Initializes the class with some required variables # Much of this code is adjusted to work within a class. def __init__(self, box, vstep, tag, value, isline, subtag=None, subvalue=None): self._box = box self._tag = tag self._subtag = subtag self._subvalue = subvalue self._value = value self._vstep = vstep self._scale = 1 / math.cos(math.radians(self._box[0])) self._isline = isline #mstr_msg("mstr_maskgen", "Intialized mask gen.") # Projects a point into the canvas of the mask. # Final projection depends on positive or negative latitude or longitude. def project_pixel(self, pnt, edge): pdiff = edge - pnt byT = pdiff * 1000 divisor = byT / 16 return divisor # Extract lat/lng from custom extracted nodes block def latlong_from_id(self, id, nds): latlng = [] for i in nds: if i[0] == id: #latlng.append((float(i[1]), float(i[2]))) latlng.append(float(i[1])) latlng.append(float(i[2])) break return latlng # Builds the required mask def _build_mask(self): # Generate empty image imgsize = 0 if mstr_photores == 2048: imgsize=3000 if mstr_photores == 4096: imgsize=6000 mask_img = Image.new("RGBA", (imgsize, imgsize)) tilexml = mstr_datafolder + "_cache\\tile.xml" xml = mstr_osmxml(0,0) fstr = str(self._box[0]) + "-" + str(self._box[1]) + "_" + str(self._box[2]) + "-" + str(self._box[3]) nds = xml.acquire_nodes(tilexml) way = xml.acquire_waypoint_data(tilexml) rls = xml.acquire_relations(tilexml) mstr_msg("mstr_maskgen", "Building mask for " + str(self._box[0]) + "-" + str(self._box[1]) + ", " + str(self._box[2]) + "-" + str(self._box[3]) + ", for " + self._tag + ": " + self._value ) frs = [] # Calculate actual bounding box bbox = [] # Latitude bbox.append(self._box[0] + ((self._box[1]-1) * self._vstep)) bbox.append(self._box[0] + ((self._box[1]-1) * self._vstep) + self._vstep) # Longitude bbox.append(self._box[2] + ((self._box[3]-1) * mstr_zl_18)) bbox.append(self._box[2] + ((self._box[3]-1) * mstr_zl_18) + mstr_zl_18) # Generate mask for ONE tag only if self._subtag == None: for w in way: if w[2] == self._tag and w[3] == self._value: nd = [] for d in way: if d[0] == w[0]: nd.append(d[1]) frs.append(nd) # Scout through relations as these also make up map data for r in rls: if self._tag in r[1] and self._value in r[1]: nd = [] for w in way: if int(w[0]) == int(r[0]): nd.append(w[1]) frs.append(nd) # Generate mask for one tag, PLUS a subtag. This is mostly used for admin areas if self._subtag != None: nd = [] wids = [] for w in way: if w[2] == self._tag and w[3] == self._value: wids.append(w[0]) for w in wids: for wp in way: if wp[0] == w and wp[2] == self._subtag and wp[3] in self._subvalue: for d in way: if d[0] == wp[0] and d[1] != "NULL": nd.append(d[1]) frs.append(nd) # Project all pixels for f in frs: pts = [] for a in f: latlng = self.latlong_from_id(a, nds) if len(latlng) == 2: # For some reason, sometimes the array is empty. Make sure we have two data points. if len(latlng) == 2: # Project the pixel, and add to the polygon shape. p_lat = self.project_pixel(latlng[0], bbox[1]) p_lng = self.project_pixel(latlng[1], bbox[3]) pixlat = 0 pixlng = 0 pr = 0 if mstr_photores == 2048: pr = 3000 if mstr_photores == 4096: pr = 6000 # Draw pixels in direction according to latitude and longitude positions - # Latitude: if self._box[0] > 0: pixlat = int((imgsize*self._scale)*p_lat) if self._box[0] < 0: pixlat = pr - (int((imgsize*self._scale)*p_lat)) # Longitude: if self._box[2] > 0: pixlng = int(imgsize - (imgsize*p_lng)) if self._box[2] < 0: pixlng = pr - (int(imgsize - (imgsize*p_lng))) pts.append((pixlng, pixlat)) # Corel Draw! imgd = ImageDraw.Draw(mask_img) # Draw polygons for everything except those three tags if self._isline == False: if len(pts) >= 3: imgd.polygon(pts, fill="#000000") # For road specific items, draw lines instead if self._isline == True: if len(pts) >= 2: # Only need two points to form a line idx = 0 for i in range(len(mstr_ortho_layers)): if mstr_ortho_layers[i][0] == self._tag and mstr_ortho_layers[i][1] == self._value: idx = i break imgd.line(pts, fill="#000000", width=mstr_ortho_layers[idx][2], joint="curve") # Save image mask_img.save(mstr_datafolder + "_cache\\" + fstr + "_" + self._tag + "-" + self._value + ".png") # Inform mstr_msg("mstr_maskgen", "Mask built.") #mg = mstr_maskgen([51, 1, 7, 1], 0.0100691262567974, "natural", "bare_rock") #mg = mstr_maskgen([51, 1, 7, 1], 0.0100691262567974, "highway", "track") #mg = mstr_maskgen([51, 1, 7, 1], 0.0100691262567974, "landuse", "forest", False) #mg = mstr_maskgen([51, 1, 7, 1], 0.0100691262567974, "natural", "water") #mg = mstr_maskgen([51, 1, 7, 1], 0.0100691262567974, "leisure", "golf_course") #mg = mstr_maskgen([51, 2, 7, 5], 0.0100691262567974, "boundary", "administrative", "admin_level", ["6"]) #mg._build_mask()