potree
Version:
WebGL point cloud viewer - WORK IN PROGRESS
418 lines (342 loc) • 11 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>lasmap</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.11.2/css/ol.css" type="text/css">
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.12/proj4.js"></script>
<script src="http://openlayers.org/en/v3.11.2/build/ol.js"></script>
<div id="potree_map" style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%">
<div id="potree_map_content" class="map" style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%"></div>
</div>
<script>
var gExtent = null;
var sourcesLayer = null;
var sourcesLabelLayer = null;
var dragBoxLayer = null;
var sceneProjection = null;
var map = null;
var olCenter = null;
var mapProjectionName = "EPSG:3857";
var mapProjection = proj4.defs(mapProjectionName);
var toMap = null;
var toScene = null;
// from http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
var source = getParameterByName("sources");
<!-- INCLUDE SOURCE -->
var sourceurl = source.substring(0, source.lastIndexOf("/") + 1) + "sources";
function init(){
gExtent = new ol.geom.LineString([[0,0], [0,0]]);
// EXTENT LAYER
var feature = new ol.Feature(gExtent);
var featureVector = new ol.source.Vector({
features: [feature]
});
var visibleBoundsLayer = new ol.layer.Vector({
source: featureVector,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new ol.style.Stroke({
color: '#0000ff',
width: 2
}),
image: new ol.style.Circle({
radius: 3,
fill: new ol.style.Fill({
color: '#0000ff'
})
})
})
});
// SOURCES EXTENT LAYER
sourcesLayer = new ol.layer.Vector({
source: new ol.source.Vector({}),
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(0, 0, 150, 0.1)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 150, 1)',
width: 1
})
})
});
// SOURCES LABEL LAYER
sourcesLabelLayer = new ol.layer.Vector({
source: new ol.source.Vector({
}),
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 0, 0, 0.1)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(255, 0, 0, 1)',
width: 2
})
}),
minResolution: 0.01,
maxResolution: 20
});
var mousePositionControl = new ol.control.MousePosition({
coordinateFormat: ol.coordinate.createStringXY(4),
projection: sceneProjection,
undefinedHTML: ' '
});
var DownloadSelectionControl = function(opt_options) {
var options = opt_options || {};
// TOGGLE TILES
var btToggleTiles = document.createElement('button');
btToggleTiles.innerHTML = 'T';
btToggleTiles.addEventListener('click', function(){
var visible = sourcesLayer.getVisible();
sourcesLayer.setVisible(!visible);
sourcesLabelLayer.setVisible(!visible);
}, false);
btToggleTiles.style.float = "left";
btToggleTiles.title = "show / hide tiles";
// DOWNLOAD SELECTED TILES
var link = document.createElement("a");
link.href = "#";
link.download = "list.txt";
link.style.float = "left";
var button = document.createElement('button');
button.innerHTML = 'D';
link.appendChild(button);
var this_ = this;
var handleDownload = function(e) {
var features = selectedFeatures.getArray();
var url = [location.protocol, '//', location.host, location.pathname].join('');
if(features.length === 0){
alert("No tiles were selected. Select area with ctrl + left mouse button!");
e.preventDefault();
e.stopImmediatePropagation();
return false;
}else if(features.length === 1){
var feature = features[0];
if(feature.source){
var sourceurl = new URL(document.location.href + "/../" + source + '/../source/' + feature.source.name);
link.href = sourceurl.href;
link.download = feature.source.name;
}
}else{
var content = "";
for(var i = 0; i < features.length; i++){
var feature = features[i];
if(feature.source){
var sourceurl = new URL(document.location.href + "/../" + source + '/../source/' + feature.source.name);
content += sourceurl.href + "\n";
}
}
var uri = "data:application/octet-stream;base64,"+btoa(content);
link.href = uri;
link.download = "list_of_files.txt";
}
};
button.addEventListener('click', handleDownload, false);
// assemble container
var element = document.createElement('div');
element.className = 'ol-unselectable ol-control';
element.appendChild(link);
element.appendChild(btToggleTiles);
element.style.bottom = "0.5em";
element.style.left = "0.5em";
element.title = "Download file or list of selected tiles. Select tile with left mouse button or area using ctrl + left mouse.";
ol.control.Control.call(this, {
element: element,
target: options.target
});
};
ol.inherits(DownloadSelectionControl, ol.control.Control);
map = new ol.Map({
controls: ol.control.defaults({
attributionOptions: ({
collapsible: false
})
}).extend([
new DownloadSelectionControl(),
mousePositionControl
]),
layers: [
new ol.layer.Tile({source: new ol.source.OSM()}),
sourcesLayer,
sourcesLabelLayer,
visibleBoundsLayer,
],
target: 'potree_map_content',
view: new ol.View({
center: olCenter,
zoom: 9
})
});
// DRAGBOX / SELECTION
dragBoxLayer = new ol.layer.Vector({
source: new ol.source.Vector({}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 255, 1)',
width: 2
})
})
});
map.addLayer(dragBoxLayer);
var select = new ol.interaction.Select();
map.addInteraction(select);
var selectedFeatures = select.getFeatures();
var dragBox = new ol.interaction.DragBox({
condition: ol.events.condition.platformModifierKeyOnly
});
map.addInteraction(dragBox);
dragBox.on('boxend', function(e) {
// features that intersect the box are added to the collection of
// selected features, and their names are displayed in the "info"
// div
var extent = dragBox.getGeometry().getExtent();
sourcesLayer.getSource().forEachFeatureIntersectingExtent(extent, function(feature) {
selectedFeatures.push(feature);
});
});
// clear selection when drawing a new box and when clicking on the map
dragBox.on('boxstart', function(e) {
selectedFeatures.clear();
});
map.on('click', function() {
selectedFeatures.clear();
});
};
function setSceneProjection(proj){
sceneProjection = proj;
toMap = proj4(sceneProjection, mapProjection);
toScene = proj4(mapProjection, sceneProjection);
};
function load(url){
var createLabelStyle = function(text){
var style = new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: 'rgba(100,50,200,0.5)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(120,30,100,0.8)',
width: 3
})
}),
text: new ol.style.Text({
font: '12px helvetica,sans-serif',
text: text,
fill: new ol.style.Fill({
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 2
})
})
});
return style;
}
$.getJSON(url, function(data){
var sources = data.sources;
setSceneProjection(data.projection);
var extent = {
min: [Infinity, Infinity],
max: [-Infinity, -Infinity]
};
for(var i = 0; i < sources.length; i++){
var source = sources[i];
var name = source.name;
var points = source.points;
var bounds = source.bounds;
extent.min[0] = Math.min(extent.min[0], bounds.min[0]);
extent.min[1] = Math.min(extent.min[1], bounds.min[1]);
extent.max[0] = Math.max(extent.max[0], bounds.max[0]);
extent.max[1] = Math.max(extent.max[1], bounds.max[1]);
var mapBounds = {
min: toMap.forward( [bounds.min[0], bounds.min[1]] ),
max: toMap.forward( [bounds.max[0], bounds.max[1]] )
}
var mapCenter = [
(mapBounds.min[0] + mapBounds.max[0]) / 2,
(mapBounds.min[1] + mapBounds.max[1]) / 2,
];
var p1 = toMap.forward( [bounds.min[0], bounds.min[1]] );
var p2 = toMap.forward( [bounds.max[0], bounds.min[1]] );
var p3 = toMap.forward( [bounds.max[0], bounds.max[1]] );
var p4 = toMap.forward( [bounds.min[0], bounds.max[1]] );
var boxes = [];
//var feature = new ol.Feature({
// 'geometry': new ol.geom.LineString([p1, p2, p3, p4, p1])
//});
var feature = new ol.Feature({
'geometry': new ol.geom.Polygon([[p1, p2, p3, p4, p1]])
});
feature.source = source;
sourcesLayer.getSource().addFeature(feature);
feature = new ol.Feature({
geometry: new ol.geom.Point(mapCenter),
name: name
});
feature.setStyle(createLabelStyle(name));
sourcesLabelLayer.getSource().addFeature(feature);
}
sceneExtent = extent;
var mapExtent = getMapExtent();
var mapCenter = getMapCenter();
var view = map.getView();
view.setCenter(mapCenter);
gExtent.setCoordinates([
mapExtent.bottomLeft,
mapExtent.bottomRight,
mapExtent.topRight,
mapExtent.topLeft,
mapExtent.bottomLeft
]);
view.fit(gExtent, [300, 300], {
constrainResolution: false
});
});
};
function getMapExtent(){
var e = sceneExtent;
var bottomLeft = toMap.forward([e.min[0], e.min[1]]);
var bottomRight = toMap.forward([e.max[0], e.min[1]]);
var topRight = toMap.forward([e.max[0], e.max[1]]);
var topLeft = toMap.forward([e.min[0], e.max[1]]);
var mapExtent = {
bottomLeft: bottomLeft,
bottomRight: bottomRight,
topRight: topRight,
topLeft: topLeft
};
return mapExtent;
};
this.getMapCenter = function(){
var mapExtent = getMapExtent();
var mapCenter = [
(mapExtent.bottomLeft[0] + mapExtent.topRight[0]) / 2,
(mapExtent.bottomLeft[1] + mapExtent.topRight[1]) / 2
];
return mapCenter;
};
function update(){
requestAnimationFrame(update);
};
init();
load(source);
update();
</script>
</body>
</html>