From d0e0eee15a0f02a35121bf1758547e01ce22d22a Mon Sep 17 00:00:00 2001
From: expoonserver <devnull@localhost>
Date: Tue, 17 Apr 2018 21:57:02 +0100
Subject: [PATCH] Add CaveView spinny caves view to each troggle cave page

---
 core/views_caves.py |  22 ++-
 templates/cave.html | 436 +++++++++++++++++++++++++++++++++++++++++++-
 urls.py             |   1 +
 3 files changed, 454 insertions(+), 5 deletions(-)

diff --git a/core/views_caves.py b/core/views_caves.py
index 2dcef5e..db3e52d 100644
--- a/core/views_caves.py
+++ b/core/views_caves.py
@@ -17,7 +17,7 @@ import re, urlparse
 from django.shortcuts import get_object_or_404
 import settings
 
-import Image, ImageDraw, ImageFont, string, os, sys
+import Image, ImageDraw, ImageFont, 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."""
@@ -58,12 +58,26 @@ def caveindex(request):
     caves1626.sort(caveCmp)
     return render_with_context(request,'caveindex.html', {'caves1623': caves1623, 'caves1626': caves1626, 'notablecaves':notablecaves, 'cavepage': True})
 
+def cave3d(request, cave_id):
+    cave = getCave(cave_id)
+    survexfilename = '/home/expo/loser/' + cave.survex_file
+    threedfilename = '/home/expo/expowebcache/3d/%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, mimetype='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_with_context(request,'nonpublic.html', {'instance': cave, 'cavepage': True})
+        return render_with_context(request,'nonpublic.html', {'instance': cave, 'cavepage': True, 'cave_id': cave_id})
     else:
-        return render_with_context(request,'cave.html', {'settings': settings, 'cave': cave, 'cavepage': True})
+        return render_with_context(request,'cave.html', {'settings': settings, 'cave': cave, 'cavepage': True, 'cave_id': cave_id})
 
 def caveEntrance(request, slug):
     cave = Cave.objects.get(caveslug__slug = slug)
@@ -202,7 +216,7 @@ def qm(request,cave_id,qm_id,year,grade=None):
         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]
diff --git a/templates/cave.html b/templates/cave.html
index 5bd77f6..a8321a8 100644
--- a/templates/cave.html
+++ b/templates/cave.html
@@ -1,5 +1,438 @@
 {% extends "cavebase.html" %}
 
+{% block extraheaders %}
+{% if cave.survex_file %}
+<style>
+
+
+div.cv-panel {
+	position: absolute;
+	top: 0;
+	left: 0;
+	z-index: 100;
+	background-color: rgba(50,50,50,0.5);
+	color: yellowgreen;
+	border: 1px solid black;
+	border-radius: 5px;
+}
+
+div.cv-compass, div.cv-ahi {
+	position: absolute; 
+	bottom: 95px;
+	right: 5px;
+	margin: 0;
+	padding-top: 2px;
+	/*	border: 1px solid white; */
+	text-align: center;
+	width: 78px;
+	height: 19px;
+	z-index: 50;
+	background-color: rgba(50,50,50,0.5);
+	background-color: black;
+	color: white;
+}
+	
+div.cv-ahi {
+	right: 95px;
+}
+
+div.scale-legend {
+	position: absolute;
+	color: white;
+	background-color: black;
+	bottom: 30px;
+}
+
+div.linear-scale {
+	position: absolute;
+	color: white;
+	background-color: black;
+	right: 30px;
+	width: 40px;
+	padding: 2px 0;
+	text-align: right;
+	border: 1px solid black;
+	font-size: 14px;
+}
+
+div.linear-scale-caption {
+	position: absolute;
+	color: white;
+	background-color: black;
+	right: 5px;
+	width: 65px;
+	padding: 2px 0 5px 0;
+	text-align: left;
+	border: 1px solid black;
+	font-size: 14px;
+}
+
+#min-div {
+	border-bottom: 1px solid white;
+}
+
+#max-div {
+	border-top: 1px solid white;
+}
+
+#angle-legend {
+	position: absolute;
+	width: 80px;
+	right: 5px;
+	bottom: 180px;
+	color: white;
+	background-color: black;
+	font-size: 14px;
+	text-align: center;
+}
+
+#scene {
+	width: 100%;
+	height: 700px;
+	position: relative;
+}
+
+#progress-bar {
+	position: absolute;
+	top: 55%;
+	height: 20px;
+	border: 1px solid white;
+	z-index: 100;
+}
+
+#status-text {
+	position: absolute;
+	top: 50%;
+	height: 20px;
+	padding-left: 4px;
+	background-color: black;
+	color: white;
+	z-index: 100;
+}
+
+#frame div.page ul {
+	list-style-type: none;
+	margin: 8px 0 0 0;
+	padding: 0;
+	width: 200px;
+	height: 100%;
+	cursor: default;
+	font-size: 12px;
+	overflow-y: auto;
+	overflow-x: hidden;
+}
+
+#frame div.page li {
+	position: relative;
+	margin-left: 16px;
+	border-bottom: 1px solid #444444;
+}
+
+#frame div.page li.selected {
+	color: #1ab4e5;
+}
+
+#frame div.page li:hover {
+	color: yellow;
+}
+
+#frame div.page div#ui-path {
+	font-size: 12px;
+	border-top: 1px solid grey;
+	border-bottom: 1px solid grey;
+	margin-top: 8px;
+	padding: 2px 0 2px 12px;
+}
+
+#frame div.page div#ui-path span {
+	color: #1ab4e5;
+}
+
+#frame div.page div.slide {
+	position: absolute;
+	top: 64px;
+	left: 0px;
+	height: auto; 
+	margin-top:0;
+	bottom: 44px;
+	background-color: #222222;
+	transition: transform 0.25s ease-in;
+}
+
+#frame div.slide-out {
+	border-right: 1px grey solid;
+	transform: translateX(-100%);
+}
+
+#frame div.page div.descend-tree {
+	position: absolute;
+	top: 0px;
+	right: 0px;
+	margin: 0;
+	color: #1ab4e5;
+	z-index: 110;
+}
+
+#frame {
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	width: 240px;
+	height: 100%;
+	background-color: transparent;
+	transform: translateX(-200px);
+	transition: transform 0.25s ease-in;
+}
+
+#frame.onscreen {
+	transform: none;
+	transition: transform 0.25s ease-out;
+}
+
+#frame a.download {
+	border: 1px solid green;
+	display: block;
+	width: 180px;
+	box-sizing: border-box;
+	margin-top: 6px;
+	margin-bottom: 4px;
+	margin-left: 8px;
+	border: none;
+	border-bottom: 4px solid #1ab4e5;
+	color: #dddddd;
+	background-color: black;
+	padding-bottom: 4px;
+	box-shadow: 1px 1px 8px 0px #888888;
+	outline: nonlass="cavedisplay"e;
+	text-decoration: none;
+	text-align: center;
+}
+
+#frame a.download:hover {
+	color: white;
+}
+
+#frame a.download:active {
+	color: #dddddd;
+	border-bottom: 4px solid #0c536a;
+	box-shadow: none;
+	box-shadow: inset 1px 1px 8px 0px #888888;
+}
+#frame .tab {
+	position: absolute;
+	right: 0px;lass="cavedisplay"
+	width: 40px;
+	height: 40px;
+	box-sizing: border-box;
+	background-color: #444444;
+	border-left: 1px solid black;
+	background-position: center;
+	border-top: 1px solid black;
+}
+
+#frame #close {
+	position: absolute;
+	right: 40px;
+	bottom: 0px;
+	width: 40px;
+	height: 40px;
+	box-sizing: border-box;
+	z-index: 150;
+	background-image: url(../images/ic_remove.png);
+	background-position: center;
+}
+
+#icon_settings {
+	background-image: url(../images/ic_settings.png);
+}
+
+#icon_terrain {
+	background-image: url(../images/ic_terrain.png);
+}
+
+#icon_explore {
+	background-image: url(../images/ic_explore.png);
+}
+
+#icon_info {
+	background-image: url(../images/ic_info.png);
+}
+
+#icon_route {
+	background-image: url(../images/ic_route.png);
+}
+
+#icon_help {
+	background-image: url(../images/ic_help.png);
+}
+
+#frame div.toptab {
+	background-color: #222222;
+	border-left: none;
+	border-right: 1px solid grey;
+	border-top: 1px solid grey;
+}
+
+#frame div.page {
+	position: absolute;
+	top: 0px;
+	bottom: 40px;
+	left: 0px;
+	width: 200px;
+	height: 100%;
+	color: white;
+	background-color: #222222;
+	padding: 0 4px;
+	box-sizing: border-box;
+	cursor: default;
+	padding-bottom: 40px;
+}
+
+#frame div.page div.header {
+	margin: 16px 0px 8px 0px;
+	font-weight: bold;
+	height: 16px;
+	box-sizing: border-box;
+	padding-left: 2px;
+}
+
+#frame div.page div.control {
+	margin: 2px 0 2px 0;
+	padding-top: 2px;
+}
+
+#frame div.page label {
+	display: block;
+	border-top: 1px solid grey;
+	padding: 2px 0 2px 8px;
+	font-size: 12px;
+}
+
+#frame div.page select {
+	display: block;
+	width: 180px;
+	box-sizing: border-box;
+	padding-top: 2px;
+	margin: 2px 0 4px 8px;
+}
+
+#frame div.page select:empty {
+	background-color: #888888;
+}
+
+#frame div.page button {
+	display: block;
+	width: 180px;
+	box-sizing: border-box;
+	margin-top: 4px;
+	margin-bottom: 4px;
+	margin-left: 8px;
+	border: none;
+	border-bottom: 4px solid #1ab4e5;
+	color: #dddddd;
+	background-color: black;
+	padding-bottom: 4px;
+	box-shadow: 1px 1px 8px 0px #888888;
+	outline: none;
+}
+
+#frame div.page button:hover {
+	color: white;
+}
+
+#frame div.page button:active {
+	color: #dddddd;
+	border-bottom: 4px solid #0c536a;
+	box-shadow: none;
+	box-shadow: inset 1px 1px 8px 0px #888888;
+}
+
+#frame div.page input[type="text"] {
+	display: block;
+	width: 180px;
+	box-sizing: border-box;
+	margin-top: 2px;
+	margin-left: 8px;
+}
+
+#frame div.page input[type="checkbox"] {
+	position: absolute;
+	right: 0px;
+}
+
+#frame div.page input[type="range"] {
+	display: block;
+	width: 180px;
+	margin-left: 8px;
+}
+
+#frame dt, #frame dd {
+	font-size: 12px;
+}
+
+#frame dt {
+	clear: both;
+	float: left;
+	padding-left: 16px;
+}
+
+#frame dd {
+	margin-left: 40px;
+}
+
+#frame p {
+	font-size: 12px;
+	line-height: 18px;
+}
+
+div.station-info {
+	position: absolute;
+	border: 1px solid white;
+	background-color: #222222;
+	color: white;
+	padding: 4px;
+	z-index: 200;
+}
+
+
+.overlay-branding {
+	color: white;
+	margin: 4px;
+	position: absolute;
+	right: 0;
+	top: 0;
+}
+div#scene {
+			width: 100%;
+			height: 90%;		}
+
+</style>
+
+<script type="text/javascript" src="/CaveView/js/CaveView.js" ></script>
+<script type="text/javascript" src="/CaveView/lib/proj4.js" ></script>
+
+
+<script type="text/javascript" >
+
+	function onLoad () {
+
+		// display the user interface - and a blank canvas
+		// the configuration object specifies the location of CaveView, surveys and terrain files
+		CV.UI.init( 'scene', {
+			home: '/javascript/CaveView/',
+			surveyDirectory: '/cave/3d/',
+		terrainDirectory: '/loser/surface/terrain/'
+		} );
+
+		// load a single survey to display
+		CV.UI.loadCave( '{% if cave.kataster_number %}{{ cave.kataster_number }}{% else %}{{ cave.unofficial_number }}{% endif %}.3d' );
+	}
+        window.onload = onLoad;
+</script>
+{% endif %}
+{% endblock %}
+
+
 {% load wiki_markup %}
 {% block content %}
 {% block contentheader %}
@@ -131,7 +564,8 @@
 {% endif %}
 {% if cave.survex_file %}
     <h2>Survex File</h2>
-    {{ cave.survex_file|safe }}
+    {{ cave.survex_file|safe }} <a href="{% if cave.kataster_number %}{% url cave3d cave.kataster_number %}{% else %}{% url cave3d cave.unofficial_number %}{% endif %}">3d file</a>
+    <div id='scene'></div>
 {% endif %}
 {% if cave.notes %}
     <h2>Notes</h2>
diff --git a/urls.py b/urls.py
index 48c9ea4..32084fd 100644
--- a/urls.py
+++ b/urls.py
@@ -56,6 +56,7 @@ actualurlpatterns = patterns('',
     #url(r'^cavedescription/(?P<cavedescription_name>[^/]+)/?$', views_caves.cave_description, name="cavedescription"),
     #url(r'^cavedescription/?$', object_list, {'queryset':CaveDescription.objects.all(),'template_name':'object_list.html'}, name="cavedescriptions"),
     #url(r'^cavehref/(.+)$',     views_caves.cave,       name="cave"),url(r'cave'),
+    url(r'^cave/3d/(?P<cave_id>[^/]+).3d$', views_caves.cave3d, name="cave3d"),
 
 #    url(r'^jgtfile/(.*)$',      view_surveys.jgtfile,       name="jgtfile"),
 #    url(r'^jgtuploadfile$',     view_surveys.jgtuploadfile, name="jgtuploadfile"),