def read_header(self): self.dheader = self.fhlay.read(0x80) [self.category] = self.unpack("i", self.dheader[4:]) [self.fileidentifier] = self.unpack("H", self.dheader[8:]) tmp = self.unpack("4f", self.dheader[0xa:]) self._bbox = Rec(N.array([tmp[0], tmp[2]]), N.array([tmp[1], tmp[3]])) [self.nlevels] = self.unpack("h", self.dheader[0x1a:]) [self.nobjects] = self.unpack("i", self.dheader[0x1c:]) [xscale] = self.unpack("d", self.dheader[0x20:]) [yscale] = self.unpack("d", self.dheader[0x28:]) self._scale = N.array([xscale, yscale]) self._refpoint = N.array(self.unpack("2f", self.dheader[0x30:])) tmp = self.unpack("4i", self.dheader[0x38:]) self._dbbox = Rec(N.array([tmp[0], tmp[1]]), N.array([tmp[2], tmp[3]])) [self.layertype] = self.unpack("b", self.dheader[0x48:]) [unknown49] = self.unpack("b", self.dheader[0x49:]) [self.largestcellsize] = self.unpack("i", self.dheader[0x4a:]) [self.firstcell] = self.unpack("i", self.dheader[0x4e:]) [self.lastcell] = self.unpack("i", self.dheader[0x52:]) assert (unknown49, 0)
def set_dbboxrec(self, drec): first_time = self._dbbox == None if not first_time and self.mode == 'r': raise ValueError( "Can't change boundary rectangle in read-only mode") self._dbbox = drec.negY() self._bbox = self._dbbox.tocontinous(self._refpoint, self._scale) if self._dbbox.width % (2**self.nlevels) != 0 or self._dbbox.height % ( 2**self.nlevels) != 0: logging.warn( "bbox should be a multiple of minimum cell size, adjusting bbox borders" ) n = 2**(self.nlevels + 1) width = self._dbbox.width height = self._dbbox.height width += -width % n height += -height % n self._dbbox = Rec(self._dbbox.c1, self._dbbox.c1 + N.array(width, height)) # If in append mode all cell elements must be re-added to fit the new # cell boundaries if not first_time and self.mode == 'a': cellelements = [e for e in self.getCellElements()] self.clearCells() for e in cellelements: self.addCellElement(e)
def calculateDBBox(self): """Calculate estimated bounding box of layer in discrete coordinates""" if N.alltrue(self.dbboxmin == self.layer.float2discrete(( N.array([180.0, 90.0]), ))): return None if N.all(self.dbboxmin != self.dbboxmax): dbbox = Rec(self.dbboxmin, self.dbboxmax) else: # Magellan Software cannot handle zero-area bounding boxes dbbox = Rec(self.dbboxmin, self.dbboxmax + N.array([1, 1])) if self.verbose: print "Estimated discretebbox", dbbox return dbbox
def calc_cell_extents(self, cellnum): """ Calculate discrete bounding box of a cell Note, the extents return is in the internal coordinates with negated Y-values """ ## Calculate cell level level = 0 while cellnum > totcells_at_level(level): level = level + 1 n = 2**level # Number of rows/cols lbb = self._dbbox layerwidth = lbb.width layerheight = lbb.height layersize = N.array([layerwidth, layerheight]) relcnum = cellnum - (totcells_at_level(level - 1) + 1) cellsize = layersize / n if relcnum < n * n: mincorner = N.array([relcnum % n, relcnum / n]) * cellsize maxcorner = mincorner + cellsize else: relcnum = relcnum - n * n mincorner = N.array([relcnum % (n + 1), relcnum / (n + 1)]) * cellsize - cellsize / 2 maxcorner = mincorner + layersize / n mincorner[N.where(mincorner < 0)] = 0 maxcorner[0] = min(maxcorner[0], layerwidth) maxcorner[1] = min(maxcorner[1], layerheight) return Rec(mincorner + lbb.c1, maxcorner + lbb.c1)
def get_best_cell(bounds, r, max_cell_level): max_cell_level += 1 # To take account of the "shifted" level i = 1 << max_cell_level # Normalise rectangle's coordinates to within 0 to i-1 v = (bounds.s - bounds.n) / i # vertical normalisation factor h = (bounds.e - bounds.w) / i # horizontal normalisation factor n = (r.n - bounds.n) / v s = (r.s - bounds.n) / v w = (r.w - bounds.w) / h e = (r.e - bounds.w) / h # Find the best "direct" cell (without half cell shifting) m = (n ^ s) | (w ^ e) # The most significant 1 (as a bit) in m indicates cell level # Now compute cell number l = 1 << (max_cell_level - 1) cell = 1 shift = max_cell_level stride = 1 i = -3 # compensation for the lack of Level 0' (shifted) while l > 1 and (l & m) == 0: cell = i + stride * stride + (stride + 1)**2 i = cell stride <<= 1 l >>= 1 shift -= 1 # Now l equals 1 << (level - 1) for unshifted cells # Compute the number of the best unshifted cell best_cell = cell + (n >> shift) * stride + (w >> shift) cell_size = 1 << shift cell_offset = 0 cell_level = max_cell_level - shift # Check if a shifted cell of the same or more detailed level # can be used if cell == 1: # Skip Level 0' l >>= 1 shift -= 1 stride <<= 1 cell = 2 while l > 0: cell += stride * stride m = ((n + l) ^ (s + l)) | ((w + l) ^ (e + l)) if m < 2 * l: # found a better cell best_cell = cell + ((n + l) >> shift) * (stride + 1) \ + ((w + l) >> shift) cell_size = 1 << shift cell_offset = l cell_level = max_cell_level - shift l >>= 1 cell += (stride + 1)**2 stride <<= 1 shift -= 1 # layer's bounding rectangle normn = ((n + cell_offset) & -cell_size) - cell_offset normw = ((w + cell_offset) & -cell_size) - cell_offset n = max(normn * v, 0) w = max(normw * h, 0) s = min((normn + cell_size) * v, bounds.s - bounds.n) - 1 e = min((normw + cell_size) * h, bounds.e - bounds.w) - 1 border = Rec((s, w), (n, e)) # Return cell number, level, and border return int(best_cell), cell_level, border
def __init__(self, mapdirobj = None, gpsimage = True, maptype = MapTypeNormal, mapnumber=0, bigendian = False, inifile = None, hasmultiplemaps=True): self.gpsimage = gpsimage self.maptype = maptype self._mapnumber = mapnumber if mapdirobj == None: self.mapdir = mapdir.MapDirectory() else: if not isinstance(mapdirobj, mapdir.MapDirectory): raise ValueError("mapdirobj should be a MapDirectory object") self.mapdir = mapdirobj self.name = "Map" self.mode = None # Open mode ['r','w','a'] self.debug=False self.has_zip = True self.has_marine = (maptype == MapTypeStreetRoute) self._inifile = inifile self.inmemory = False ## If true all processing will be done in memory if maptype == MapTypeStreetRoute: self.routingcfg = routing.RoutingConfig() else: self.routingcfg = None ## Set endian self.bigendian = bigendian # Groups self._poigroup=None self.groups=[] self._searchgroups = [] ## Searchable group indices # Tables if maptype == MapTypeStreetRoute: self._ziptables = (0,1,0,0) else: self._ziptables = (0,0) self._marinetables = (0,1,0,1) ## Bounding box and bounding rect self._bboxrec = None self._boundrec = Rec((-198.316818, -99.475197), (198.316818, 99.475197)) ## Resolution and reference point self._scale = self.defaultscale self._refpoint = N.array([0.0, 0.0]) ## Config file self._cfg = ConfigParserUpper() self._initcfg() ## Layer and POI config self._laycfg = LayerConfig() self._poiconfig = POILayerConfig() ## Database self._db = None ## Other parameters otherparameters = ( ## Name, default value, description ('startscale', 4500.0, 'Start scale'), ('laycolor', 0, 'Unknown'), ('copyrightholders', ['Unknown'], 'Copyright holders'), ) ## Create properties for these parameters for param in otherparameters: setattr(self, '_' + param[0], param[1]) getfunc = lambda self, val: self.set_parameter('_'+param[0]) setfunc = lambda self, val: self.set_parameter('_'+param[0], val) setattr(self.__class__, param[0], property(getfunc, setfunc, doc=param[2])) ## Update config self._updatecfg() ## hasmultiplemaps is True if mapdir can have multiple maps with prefixes before their files self.hasmultiplemaps = hasmultiplemaps
def open(self, mode='r'): if self.mode != None: return None self.mode = mode if mode == 'w': if self.gpsimage: if self._inifile == None: self._inifile = self.mapnumstr + 'map.ini' ## Create database self._db = Database(self.mapdir, 'db' + self.mapnumstr, mode, self.bigendian) ## Create zip table if self.has_zip: buildziprecord(self._db, zipfilename = self.mapnumstr + 'z.dat', auxfilename = self.mapnumstr + 'cn.dat', extended = self.maptype == MapTypeStreetRoute) ## Create marine table if self.has_marine: buildmarinerecord(self._db, filenameprefix = self.mapnumstr) ## Create basic groups if self.maptype == MapTypeStreetRoute: roads = GroupStreet(self, name=self.mapnumstr + "_Roads") else: roads = GroupNormal(self, name=self.mapnumstr + "_Roads") roads.searchable = True self.addGroup(roads) self.addGroup(GroupNormal(self, name=self.mapnumstr + "_Railroads")) self.addGroup(GroupNormal(self, name=self.mapnumstr + "_Hydrography")) self.addGroup(GroupNormal(self, name=self.mapnumstr + "_Parks")) else: if self._inifile == None: self._inifile = 'map.ini' elif mode in ('r','a'): ## Find ini file if self._inifile == None: filelist = self.mapdir.listdir() possibleinifiles = ('map.ini', self.mapnumstr + 'map.ini', 'lay_info.ini') found = False for filename in possibleinifiles: if filename in filelist: self._inifile = filename found = True break if not found: raise ValueError('Could not find ini-file') self._cfg.readfp(IniFileFilter(self.mapdir.open(self._inifile))) # Get map type if self._cfg.has_option('MAP_INFO', 'MAPTYPE'): self.maptype = self._cfg.get("MAP_INFO", "MAPTYPE") # Get bounding box if self._cfg.has_option('MAP_INFO', 'BND_BOX'): bbox = map(float, self._cfg.get("MAP_INFO", "BND_BOX").split(" ")) self._bboxrec = Rec([bbox[0],bbox[2]], [bbox[1], bbox[3]]) # Get map name self.name = self._cfg.get('MAP_INFO', 'MAP_NAME') # self.date = self._cfg.get('MAP_INFO', 'MAP_DATE') self._laycfg.setupfromcfg(self._cfg, self) # Find database path dbname = self._cfg.get("LAYERS","DB_NAME") dbname = re.sub('\\\\', os.sep, dbname) # Since Windows is case insensitive, try to match the path case insensitive plist=dbname.split(os.sep) for i in range(0,len(plist)-2): path=os.sep.join(plist[0:i+1]) if len(path)>0: hits=[d for d in self.mapdir.listdir(path) if d.lower() == plist[i+1].lower()] if len(hits)==0: raise ValueError("Couldnt find database") plist[i+1]=hits[0] dbname = os.sep.join(plist) if dbname: self._db = Database(self.mapdir, dbname, self.mode, self.bigendian) # Read groups if self.debug: print "Groups:" for i in range(0,self._cfg.getint("GROUPS","NUMBER")): thegroup = groupFactory(self, i, self._cfg, self._db) self.groups.append(thegroup) thegroup.initFromIni(self._cfg) # Read POI file and POI layers if self._cfg.has_section("POI"): poi_ini = self._cfg.get("POI","POI_CONFIG") self.poicfg = ConfigParserUpper() if self.mapdir.isfile(poi_ini): self.poicfg.readfp(IniFileFilter(self.mapdir.open(poi_ini))) if self.poicfg.has_section("LAYERS"): self._poigroup = POIGroup(self) self._poiconfig.setupfromcfg(self.poicfg, self) # Read routing info if self.maptype == MapTypeStreetRoute: self.routingcfg = routing.RoutingConfig() self.routingcfg.setupfromcfg(self._cfg, self) # Read unpack tables if self._cfg.has_section('PACK_LAYS'): i = 0 while self._cfg.has_option('PACK_LAYS', str(i)): fields = self._cfg.get('PACK_LAYS', str(i)).split(' ') filename = fields[0] n = int(fields[1]) layernumbers = map(int, fields[2:]) assert len(layernumbers) == n for layernumber in layernumbers: self.getLayerByIndex(layernumber).setUnpackTable(filename) i += 1
def set_bbox(self, points): self.bboxrec = Rec(tuple(points[0]), tuple(points[1]))