#!/usr/bin/python # -*- coding: utf-8 -*- from troggle.core.models import CaveSlug, Cave, CaveAndEntrance, Survey, Expedition, QM, CaveDescription, EntranceSlug, Entrance, Area, SurvexStation from troggle.core.forms import CaveForm, CaveAndEntranceFormSet, VersionControlCommentForm, EntranceForm, EntranceLetterForm import troggle.core.models as models import troggle.settings as settings from troggle.helper import login_required_if_public from django.forms.models import modelformset_factory from django import forms from django.core.urlresolvers import reverse from django.http import HttpResponse, HttpResponseRedirect from django.conf import settings import re, urlparse from django.shortcuts import get_object_or_404, render import settings from PIL import Image, ImageDraw, ImageFont import string, os, sys, subprocess def getCave(cave_id): """Returns a cave object when given a cave name or number. It is used by views including cavehref, ent, and qm.""" try: cave = Cave.objects.get(kataster_number=cave_id) except Cave.DoesNotExist: cave = Cave.objects.get(unofficial_number=cave_id) return cave def pad5(x): return "0" * (5 -len(x.group(0))) + x.group(0) def padnumber(x): return re.sub("\d+", pad5, x) def numericalcmp(x, y): return cmp(padnumber(x), padnumber(y)) def caveCmp(x, y): if x.kataster_number: if y.kataster_number: return numericalcmp(x.kataster_number, y.kataster_number) # Note that cave kataster numbers are not generally integers. else: return -1 else: if y.kataster_number: return 1 else: return numericalcmp(x.unofficial_number, y.unofficial_number) def caveindex(request): caves = Cave.objects.all() notablecavehrefs = settings.NOTABLECAVESHREFS notablecaves = [Cave.objects.get(kataster_number=kataster_number) for kataster_number in notablecavehrefs ] caves1623 = list(Cave.objects.filter(area__short_name = "1623")) caves1626 = list(Cave.objects.filter(area__short_name = "1626")) caves1623.sort(caveCmp) caves1626.sort(caveCmp) return render(request,'caveindex.html', {'caves1623': caves1623, 'caves1626': caves1626, 'notablecaves':notablecaves, 'cavepage': True}) def millenialcaves(request): #RW messing around area return HttpResponse("Test text", content_type="text/plain") def cave3d(request, cave_id=''): cave = getCave(cave_id) survexfilename = settings.SURVEX_DATA + cave.survex_file threedfilename = settings.THREEDCACHEDIR + '%s.3d' % cave_id if True or os.path.getmtime(survexfilename) > os.path.getmtime(threedfilename): subprocess.call(["cavern", "--output=%s" % threedfilename, survexfilename]) test_file = open(threedfilename, 'rb') response = HttpResponse(content=test_file, content_type='application/3d')#mimetype is replaced by content_type for django 1.7 response['Content-Disposition'] = 'attachment; filename=%s.3d' % cave_id # response['X-Sendfile'] = "%s.3d" % cave_id # It's usually a good idea to set the 'Content-Length' header too. # You can also set any other required headers: Cache-Control, etc. return response def cave(request, cave_id='', offical_name=''): cave=getCave(cave_id) if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated(): return render(request,'nonpublic.html', {'instance': cave, 'cavepage': True, 'cave_id': cave_id}) else: return render(request,'cave.html', {'settings': settings, 'cave': cave, 'cavepage': True, 'cave_id': cave_id}) def caveEntrance(request, slug): cave = Cave.objects.get(caveslug__slug = slug) if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated(): return render(request,'nonpublic.html', {'instance': cave}) else: return render(request,'cave_entrances.html', {'cave': cave}) def caveDescription(request, slug): cave = Cave.objects.get(caveslug__slug = slug) if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated(): return render(request,'nonpublic.html', {'instance': cave}) else: return render(request,'cave_uground_description.html', {'cave': cave}) def caveQMs(request, slug): cave = Cave.objects.get(caveslug__slug = slug) if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated(): return render(request,'nonpublic.html', {'instance': cave}) else: return render(request,'cave_qms.html', {'cave': cave}) def caveLogbook(request, slug): cave = Cave.objects.get(caveslug__slug = slug) if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated(): return render(request,'nonpublic.html', {'instance': cave}) else: return render(request,'cave_logbook.html', {'cave': cave}) def caveSlug(request, slug): cave = Cave.objects.get(caveslug__slug = slug) if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated(): return render(request,'nonpublic.html', {'instance': cave, 'cave_editable': slug}) else: return render(request,'cave.html', {'cave': cave, 'cave_editable': slug}) @login_required_if_public def edit_cave(request, slug=None): if slug is not None: cave = Cave.objects.get(caveslug__slug = slug) else: cave = Cave() if request.POST: form = CaveForm(request.POST, instance=cave) ceFormSet = CaveAndEntranceFormSet(request.POST) versionControlForm = VersionControlCommentForm(request.POST) if form.is_valid() and ceFormSet.is_valid() and versionControlForm.is_valid(): cave = form.save(commit = False) if slug is None: for a in form.cleaned_data["area"]: if a.kat_area(): myArea = a.kat_area() if form.cleaned_data["kataster_number"]: myslug = "%s-%s" % (myArea, form.cleaned_data["kataster_number"]) else: myslug = "%s-%s" % (myArea, form.cleaned_data["unofficial_number"]) else: myslug = slug cave.filename = myslug + ".html" cave.save() form.save_m2m() if slug is None: cs = CaveSlug(cave = cave, slug = myslug, primary = True) cs.save() ceinsts = ceFormSet.save(commit=False) for ceinst in ceinsts: ceinst.cave = cave ceinst.save() cave.writeDataFile() return HttpResponseRedirect("/" + cave.url) else: form = CaveForm(instance=cave) ceFormSet = CaveAndEntranceFormSet(queryset=cave.caveandentrance_set.all()) versionControlForm = VersionControlCommentForm() return render(request, 'editcave2.html', {'form': form, 'caveAndEntranceFormSet': ceFormSet, 'versionControlForm': versionControlForm }) @login_required_if_public def editEntrance(request, caveslug, slug=None): cave = Cave.objects.get(caveslug__slug = caveslug) if slug is not None: entrance = Entrance.objects.get(entranceslug__slug = slug) else: entrance = Entrance() if request.POST: form = EntranceForm(request.POST, instance = entrance) versionControlForm = VersionControlCommentForm(request.POST) if slug is None: entletter = EntranceLetterForm(request.POST) else: entletter = None if form.is_valid() and versionControlForm.is_valid() and (slug is not None or entletter.is_valid()): entrance = form.save(commit = False) if slug is None: slugname = cave.slug() + entletter.cleaned_data["entrance_letter"] entrance.cached_primary_slug = slugname entrance.filename = slugname + ".html" entrance.save() if slug is None: es = EntranceSlug(entrance = entrance, slug = slugname, primary = True) es.save() el = entletter.save(commit = False) el.cave = cave el.entrance = entrance el.save() entrance.writeDataFile() return HttpResponseRedirect("/" + cave.url) else: form = EntranceForm(instance = entrance) versionControlForm = VersionControlCommentForm() if slug is None: entletter = EntranceLetterForm(request.POST) else: entletter = None return render(request, 'editentrance.html', {'form': form, 'versionControlForm': versionControlForm, 'entletter': entletter }) def qm(request,cave_id,qm_id,year,grade=None): year=int(year) try: qm=getCave(cave_id).get_QMs().get(number=qm_id,found_by__date__year=year) return render(request,'qm.html',locals()) except QM.DoesNotExist: url=urlparse.urljoin(settings.URL_ROOT, r'/admin/core/qm/add/'+'?'+ r'number=' + qm_id) if grade: url += r'&grade=' + grade return HttpResponseRedirect(url) def ent(request, cave_id, ent_letter): cave = Cave.objects.filter(kataster_number = cave_id)[0] cave_and_ent = CaveAndEntrance.objects.filter(cave = cave).filter(entrance_letter = ent_letter)[0] return render(request,'entrance.html', {'cave': cave, 'entrance': cave_and_ent.entrance, 'letter': cave_and_ent.entrance_letter,}) def entranceSlug(request, slug): entrance = Entrance.objects.get(entranceslug__slug = slug) if entrance.non_public and not request.user.is_authenticated(): return render(request,'nonpublic.html', {'instance': entrance}) else: return render(request,'entranceslug.html', {'entrance': entrance}) def survexblock(request, survexpath): survexpath = re.sub("/", ".", survexpath) print "jjjjjj", survexpath survexblock = models.SurvexBlock.objects.get(survexpath=survexpath) #ftext = survexblock.filecontents() ftext = survexblock.text return render(request,'survexblock.html', {'survexblock':survexblock, 'ftext':ftext, }) def surveyindex(request): surveys=Survey.objects.all() expeditions=Expedition.objects.order_by("-year") return render(request,'survey.html',locals()) def survey(request,year,wallet_number): surveys=Survey.objects.all() expeditions=Expedition.objects.order_by("-year") current_expedition=Expedition.objects.filter(year=year)[0] if wallet_number!='': current_survey=Survey.objects.filter(expedition=current_expedition,wallet_number=wallet_number)[0] notes=current_survey.scannedimage_set.filter(contents='notes') planSketches=current_survey.scannedimage_set.filter(contents='plan') elevationSketches=current_survey.scannedimage_set.filter(contents='elevation') return render(request,'survey.html', locals()) def cave_description(request, cavedescription_name): cave_description = get_object_or_404(CaveDescription, short_name = cavedescription_name) return render(request,'cave_description.html', locals()) def get_entrances(request, caveslug): cave = Cave.objects.get(caveslug__slug = caveslug) return render(request,'options.html', {"items": [(e.entrance.slug(), e.entrance.slug()) for e in cave.entrances()]}) def get_qms(request, caveslug): cave = Cave.objects.get(caveslug__slug = caveslug) return render(request,'options.html', {"items": [(e.entrance.slug(), e.entrance.slug()) for e in cave.entrances()]}) 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): #for key, name in areanames: # print key, Area.objects.get(short_name = key) areas = [] for key, name in areanames: a = Area.objects.get(short_name = key) caves = list(a.cave_set.all()) caves.sort(caveCmp) 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) 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 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 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", "C:\WINNT\Fonts\ARIAL.TTF" ]: if os.path.isfile(FONT): break TEXTSIZE = 16 CIRCLESIZE =8 LINEWIDTH = 2 myFont = ImageFont.truetype(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 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) = 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") except: pass def prospecting_image(request, name): mainImage = Image.open(os.path.join(settings.SURVEY_SCANS, "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 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") #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') plot("laser.0_7", "BNase", "Reference", "Bräuning Nase laser point", name, draw, img) plot("226-96", "BZkn", "Reference", "Bräuning Zinken trig point", name, draw, img) plot("vd1","VD1","Reference", "VD1 survey point", name, draw, img) plot("laser.kt114_96","HSK","Reference", "Hinterer Schwarzmooskogel trig point", name, draw, img) plot("2000","Nipple","Reference", "Nipple (Weiße Warze)", name, draw, img) plot("3000","VSK","Reference", "Vorderer Schwarzmooskogel summit", name, draw, img) plot("topcamp", "TC", "Reference", "Top Camp", name, draw, img) plot("laser.0", "LSR0", "Reference", "Laser Point 0", name, draw, img) plot("laser.0_1", "LSR1", "Reference", "Laser Point 0/1", name, draw, img) plot("laser.0_3", "LSR3", "Reference", "Laser Point 0/3", name, draw, img) plot("laser.0_5", "LSR5", "Reference", "Laser Point 0/5", name, draw, img) plot("225-96", "BAlm", "Reference", "Bräuning Alm trig point", name, draw, img) for entrance in Entrance.objects.all(): station = entrance.best_station() if station: #try: areaName = entrance.caveandentrance_set.all()[0].cave.getArea().short_name plot(station, "%s-%s" % (areaName, str(entrance)[5:]), entrance.needs_surface_work(), str(entrance), name, draw, img) #except: # pass 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) = 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") response = HttpResponse(content_type = "image/png") del draw img.save(response, "PNG") return response STATIONS = {} poslineregex = re.compile("^\(\s*([+-]?\d*\.\d*),\s*([+-]?\d*\.\d*),\s*([+-]?\d*\.\d*)\s*\)\s*([^\s]+)$") def LoadPos(): call([settings.CAVERN, "--output=%s/all.3d" % settings.SURVEX_DATA, "%s/all.svx" % settings.SURVEX_DATA]) call([settings.THREEDTOPOS, '%sall.3d' % settings.SURVEX_DATA], cwd = settings.SURVEX_DATA) posfile = open("%sall.pos" % settings.SURVEX_DATA) posfile.readline()#Drop header for line in posfile.readlines(): r = poslineregex.match(line) if r: x, y, z, name = r.groups() STATIONS[name] = (x, y, z)