import os import string import re import urllib.parse # from pathlib import Path from django.http import HttpResponse from django.shortcuts import render # from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned import troggle.settings as settings from troggle.core.models.caves import Entrance, Area, SurvexStation, Cave from troggle.core.views.caves import caveKey from troggle.parsers.survex import MapLocations ''' Generates the prospecting guide document. Also produces the overlay of points on top of a prospecting_image map - to be deleted. Not working with recent PIL aka Pillow image package - removed. ''' AREANAMES = [ #('', 'Location unclear'), ('1a', '1a – Plateau: around Top Camp'), ('1b', '1b – Western plateau near 182'), ('1c', '1c – Eastern plateau near 204 walk-in path'), ('1d', '1d – Further plateau around 76'), ('2a', '2a – Southern Schwarzmooskogel near 201 path and the Nipple'), ('2b', '2b – Eishöhle area'), ('2b or 4 (unclear)', '2b or 4 (unclear)'), ('2c', '2c – Kaninchenhöhle area'), ('2d', '2d – Steinbrückenhöhle area'), ('3', '3 – Bräuning Alm'), ('4', '4 – Kratzer valley'), ('5', '5 – Schwarzmoos-Wildensee'), ('6', '6 – Far plateau'), ('1626 or 6 (borderline)', '1626 or 6 (borderline)'), ('7', '7 – Egglgrube'), ('8a', '8a – Loser south face'), ('8b', '8b – Loser below Dimmelwand'), ('8c', '8c – Augst See'), ('8d', '8d – Loser-Hochganger ridge'), ('9', '9 – Gschwandt Alm'), ('10', '10 – Altaussee'), ('11', '11 – Augstbach') ] def prospecting(request): '''This produces the multipage 'prospecting guide' document, intended to be printed and carried into the field - in 1999. All the formatting and selection cleverness is in the template file. This produces a vast number of bad 404 URLs as many URLs in the cave_data XML files refer to other caves, assuming that they are in the same directory as the prospecting guide. But since the introduction of the 1623/ level, this is not true. e.g. 163 refers to 162 as href="../162.htm" which is valid in the cave description page but not when navigating from the prospecting guide page. Since this vast number of broken links is getting in the way of finding real errors, the guide has been disabled. ''' message = f'This prospecting guide text report contains many broken URLs because of a major redesign\n' +\ ' to put caves into 1623/ and 1624/ folders in 2017. It was mostly useless because recent QM info was not in it anyway.\n\n' +\ 'It is disabled in the python code in "prospecting(request):" in troggle/core/views/prospect.py' return render(request,'errors/disabled.html', {'message': message}) areas = [] for key, name in AREANAMES: a = Area.objects.get(short_name = key) # assumes unique caves = list(a.cave_set.all()) caves.sort(key=caveKey) areas.append((name, a, caves)) return render(request, 'prospecting.html', {"areas": areas}) # Parameters for big map and zoomed subarea maps: # big map first (zoom factor ignored) # These are the values for the url /prospecting/[mapcode].png maps = { # id left top right bottom zoom # G&K G&K G&K G&K factor "all": [33810.4, 85436.5, 38192.0, 81048.2, 0.35, "All"], "40": [36275.6, 82392.5, 36780.3, 81800.0, 3.0, "Eishöhle"], "76": [35440.0, 83220.0, 36090.0, 82670.0, 1.3, "Eislufthöhle"], "204": [36354.1, 84154.5, 37047.4, 83300, 3.0, "Steinbrückenhöhle"], "tc": [35230.0, 82690.0, 36110.0, 82100.0, 3.0, "Near Top Camp"], "grieß": [36000.0, 86300.0, 38320.0, 84400.0, 4.0, "Grießkogel Area"], } for n in list(maps.keys()): L, T, R, B, S, name = maps[n] W = (R-L)/2 H = (T-B)/2 for i in range(2): for j in range(2): maps["%s%i%i" % (n, i, j)] = [L + i * W, T - j * H, L + (i + 1) * W, T - (j + 1) * H, S, name] # Keys in the order in which we want the maps output mapcodes = ["all", "grieß","40", "76", "204", "tc"] # Field codes L = 0 T = 1 R = 2 B = 3 ZOOM = 4 DESC = 5 SIZE = 5 areacolours = { '1a' : '#00ffff', '1b' : '#ff00ff', '1c' : '#ffff00', '1d' : '#ffffff', '2a' : '#ff0000', '2b' : '#00ff00', '2c' : '#008800', '2d' : '#ff9900', '3' : '#880000', '4' : '#0000ff', '6' : '#000000', # doubles for surface fixed pts, and anything else '7' : '#808080' } for FONT in [ "/usr/share/fonts/truetype/freefont/FreeSans.ttf", "/usr/X11R6/lib/X11/fonts/truetype/arial.ttf", "/mnt/c/windows/fonts/arial.ttf", "C:\WINNT\Fonts\ARIAL.TTF" ]: if os.path.isfile(FONT): break TEXTSIZE = 16 CIRCLESIZE =8 LINEWIDTH = 2 #myFont = ImageFont.truetype(FONT, TEXTSIZE) # disabled as not importing PIL #print(f' - myFont {myFont} {FONT} {TEXTSIZE}') def mungecoord(x, y, mapcode, img): # Top of Zinken is 73 1201 = dataset 34542 81967 # Top of Hinter is 1073 562 = dataset 36670 83317 # image is 1417 by 2201 # FACTOR1 = 1000.0 / (36670.0-34542.0) # FACTOR2 = (1201.0-562.0) / (83317 - 81967) # FACTOR = (FACTOR1 + FACTOR2)/2 # The factors aren't the same as the scanned map's at a slight angle. I # can't be bothered to fix this. Since we zero on the Hinter it makes # very little difference for caves in the areas round 76 or 204. # xoffset = (x - 36670)*FACTOR # yoffset = (y - 83317)*FACTOR # return (1073 + xoffset, 562 - yoffset) m = maps[mapcode] factorX, factorY = img.size[0] / (m[R] - m[L]), img.size[1] / (m[T] - m[B]) return ((x - m[L]) * factorX, (m[T] - y) * factorY) COL_TYPES = {True: "red", False: "#dddddd", "Reference": "#dddddd"} def prospecting_image(request, name): '''This draws map outlines on an existing map image. But getting the entrances plotted is broken by later changes elsewhere in the system since this code was written. SurvexStations are in x=latitude, y=longitude - these are what appear in essentials.gpx Entrances are in northing, easting which is why we can't simply plot all the Entrances... We should replace all this with something that exports an overlay for Google Maps and OpenStreetView ''' mainImage = Image.open(os.path.join(settings.EXPOFILES, "location_maps", "pguidemap.jpg")) # if settings.PUBLIC_SITE and not request.user.is_authenticated: # mainImage = Image.new("RGB", mainImage.size, '#ffffff') m = maps[name] imgmaps = [] if name == "all": img = mainImage else: M = maps['all'] W, H = mainImage.size l = int((m[L] - M[L]) / (M[R] - M[L]) * W) t = int((m[T] - M[T]) / (M[B] - M[T]) * H) r = int((m[R] - M[L]) / (M[R] - M[L]) * W) b = int((m[B] - M[T]) / (M[B] - M[T]) * H) img = mainImage.crop((l, t, r, b)) w = int(round(m[ZOOM] * (m[R] - m[L]) / (M[R] - M[L]) * W)) h = int(round(m[ZOOM] * (m[B] - m[T]) / (M[B] - M[T]) * H)) img = img.resize((w, h), Image.BICUBIC) draw = ImageDraw.Draw(img) #draw.setfont(myFont) if name == "all": for maparea in list(maps.keys()): if maparea == "all": continue localm = maps[maparea] l,t = mungecoord(localm[L], localm[T], "all", img) r,b = mungecoord(localm[R], localm[B], "all", img) text = maparea + " map" textlen = draw.textsize(text)[0] + 3 draw.rectangle([l, t, l+textlen, t+TEXTSIZE+2], fill='#ffffff') draw.text((l+2, t+1), text, fill="#000000", font=myFont) imgmaps.append( [l, t, l+textlen, t+SIZE+2, "submap" + maparea, maparea + " subarea map"] ) draw.line([l, t, r, t], fill='#777777', width=LINEWIDTH) draw.line([l, b, r, b], fill='#777777', width=LINEWIDTH) draw.line([l, t, l, b], fill='#777777', width=LINEWIDTH) draw.line([r, t, r, b], fill='#777777', width=LINEWIDTH) draw.line([l, t, l+textlen, t], fill='#777777', width=LINEWIDTH) draw.line([l, t+TEXTSIZE+2, l+textlen, t+TEXTSIZE+2], fill='#777777', width=LINEWIDTH) draw.line([l, t, l, t+TEXTSIZE+2], fill='#777777', width=LINEWIDTH) draw.line([l+textlen, t, l+textlen, t+TEXTSIZE+2], fill='#777777', width=LINEWIDTH) #imgmaps[maparea] = [] # Draw scale bar m100 = int(100 / (m[R] - m[L]) * img.size[0]) draw.line([10, TEXTSIZE*3, 10, TEXTSIZE*2], fill='#000000', width=LINEWIDTH) draw.line([10, TEXTSIZE*2, 10+m100, TEXTSIZE*2], fill='#000000', width=LINEWIDTH) draw.line([10+m100, TEXTSIZE * 3, 10+m100, TEXTSIZE*2], fill='#000000', width=LINEWIDTH) label = "100m" draw.text([10 + (m100 - draw.textsize(label)[0]) / 2, TEXTSIZE/2], label, fill='#000000', font=myFont) # Draw the circles for known points # Northing, Easting, Diameter - but N&E are swapped re database for (N, E, D, num) in [(35975.37, 83018.21, 100, "177"), # Calculated from bearings (35350.00, 81630.00, 50, "71"), # From Auer map (36025.00, 82475.00, 50, "146"), # From mystery map (35600.00, 82050.00, 50, "35"), # From Auer map (35650.00, 82025.00, 50, "44"), # From Auer map (36200.00, 82925.00, 50, "178"), # Calculated from bearings (35232.64, 82910.37, 25, "181"), # Calculated from bearings (35323.60, 81357.83, 50, "74") # From Auer map ]: (N,E,D) = list(map(float, (N, E, D))) maparea = Cave.objects.get(kataster_number = num).getArea().short_name lo = mungecoord(N-D, E+D, name, img) hi = mungecoord(N+D, E-D, name, img) lpos = mungecoord(N-D, E, name, img) draw.ellipse([lo,hi], outline="#000000") draw.ellipse([lo[0]+1, lo[1]+1, hi[0]-1, hi[1]-1], outline=areacolours[maparea]) draw.ellipse([lo[0]+2, lo[1]+2, hi[0]-2, hi[1]-2], outline=areacolours[maparea]) draw.rectangle([lpos[0],lpos[1]-TEXTSIZE/2, lpos[0] + draw.textsize(name)[0], lpos[1]+TEXTSIZE/2], fill="#ffffff") draw.text((lpos[0], lpos[1]-TEXTSIZE/2), num, fill="#000000") #print(f' CIRCLES - {num} {(N,E,D)}') # ml = MapLocations() # for p in ml.points(): # surveypoint, number, point_type, label = p # print(f'{surveypoint}, {number}, {point_type}, {label}') # plot(surveypoint, number, True, label, name, draw, img) # print(f'{name},\n{draw},\n{img}') ents = Entrance.objects.all() # only has entrances and fixed points in it these days, # but there are only 11 Entrances with northing, easting and a useable tag! D = 50 for e in ents: try: E, N = e.easting, e.northing if e.tag_station: st = e.tag_station elif e.exact_station: st = e.exact_station elif e.exact_station: st = e.exact_station else: # print(f' No tag - {e.name} ') continue if not e.northing: continue lo = mungecoord(N-D, E+D, st, img) hi = mungecoord(N+D, E-D, st, img) lpos = mungecoord(N-D, E, st, img) draw.ellipse([lo,hi], outline="#000000") draw.ellipse([lo[0]+1, lo[1]+1, hi[0]-1, hi[1]-1], outline="#ffffff") draw.ellipse([lo[0]+2, lo[1]+2, hi[0]-2, hi[1]-2], outline="#ffffff") draw.rectangle([lpos[0],lpos[1]-TEXTSIZE/2, lpos[0] + draw.textsize(st)[0], lpos[1]+TEXTSIZE/2], fill="#ffffff") draw.text((lpos[0], lpos[1]-TEXTSIZE/2), num, fill="#000000") # draw.ellipse([(x-CIRCLESIZE,y-CIRCLESIZE),(x+CIRCLESIZE,y+CIRCLESIZE)], fill="red", outline="blue") # draw.rectangle([(x+CIRCLESIZE, y-TEXTSIZE/2), (x+CIRCLESIZE*2+draw.textsize(shortnumber)[0], y+TEXTSIZE/2)], fill="#ffffff") # draw.text((x+CIRCLESIZE * 1.5,y-TEXTSIZE/2), shortnumber, fill="#000000") #print(f' SUCCESS - {st} {(E, N)} ') except: #print(f' FAIL - {st} {(E, N)} ') pass response = HttpResponse(content_type = "image/png") del draw img.save(response, "PNG") return response # def plot(surveypoint, number, point_type, label, mapcode, draw, img): # try: # ss = SurvexStation.objects.lookup(surveypoint) # E, N = ss.x, ss.y # shortnumber = number.replace("—","") # (x,y) = list(map(int, mungecoord(E, N, mapcode, img))) # imgmaps[maparea].append( [x-4, y-SIZE/2, x+4+draw.textsize(shortnumber)[0], y+SIZE/2, shortnumber, label] ) # draw.rectangle([(x+CIRCLESIZE, y-TEXTSIZE/2), (x+CIRCLESIZE*2+draw.textsize(shortnumber)[0], y+TEXTSIZE/2)], fill="#ffffff") # draw.text((x+CIRCLESIZE * 1.5,y-TEXTSIZE/2), shortnumber, fill="#000000") # draw.ellipse([(x-CIRCLESIZE,y-CIRCLESIZE),(x+CIRCLESIZE,y+CIRCLESIZE)], fill=COL_TYPES[point_type], outline="#000000") # print(f' SUCCESS - YES {surveypoint}, {number}, {point_type}, {label}') # except: # print(f' - NO {surveypoint}, {number}, {point_type}, {label}') # pass