|
@@ -80074,59 +80074,271 @@ void main() {
|
|
|
|
|
|
}
|
|
|
|
|
|
- class Compass{
|
|
|
+ const initDir = new Vector3(0,1,0);//指南针模型的北方向 向屏幕里
|
|
|
|
|
|
- constructor(viewer){
|
|
|
- this.viewer = viewer;
|
|
|
-
|
|
|
- this.visible = false;
|
|
|
- this.dom = this.createElement();
|
|
|
-
|
|
|
- viewer.addEventListener("update", () => {
|
|
|
- const direction = viewer.scene.view.direction.clone();
|
|
|
- direction.z = 0;
|
|
|
- direction.normalize();
|
|
|
-
|
|
|
- const camera = viewer.scene.getActiveCamera();
|
|
|
-
|
|
|
- const p1 = camera.getWorldPosition(new Vector3());
|
|
|
- const p2 = p1.clone().add(direction);
|
|
|
-
|
|
|
- const projection = viewer.getProjection();
|
|
|
- const azimuth = Utils.computeAzimuth(p1, p2, projection);
|
|
|
-
|
|
|
- this.dom.css("transform", `rotateZ(${-azimuth}rad)`);
|
|
|
- });
|
|
|
-
|
|
|
- this.dom.click( () => {
|
|
|
- viewer.setTopView();
|
|
|
- });
|
|
|
+ class Compass extends EventDispatcher{
|
|
|
+
|
|
|
+ constructor(dom){
|
|
|
+ super();
|
|
|
+ this.angle = 0;
|
|
|
+ if(dom){
|
|
|
+ this.dom = $(dom);
|
|
|
+ }
|
|
|
+
|
|
|
+ this.init();
|
|
|
+ this.show = false;
|
|
|
|
|
|
- const renderArea = $(viewer.renderArea);
|
|
|
- renderArea.append(this.dom);
|
|
|
|
|
|
- this.setVisible(this.visible);
|
|
|
- }
|
|
|
|
|
|
- setVisible(visible){
|
|
|
- this.visible = visible;
|
|
|
+ }
|
|
|
+ init(){
|
|
|
+ var width = 100, height = 100;
|
|
|
+ if(!this.dom){
|
|
|
+ this.dom = $('<div id="compass"></div>');
|
|
|
+ $("#potree_render_area").append(this.dom);
|
|
|
+ }
|
|
|
+ this.dom.css({/* display:"none", */ position:"absolute",right:"2%",top: "4%",width:width+"px",height:height+"px", "z-index":100,"pointer-events":"none" });
|
|
|
|
|
|
- const value = visible ? "" : "none";
|
|
|
- this.dom.css("display", value);
|
|
|
- }
|
|
|
+ let child = $("<div class='dirText north'><span>"+/* (config.lang=='zh'? */'北'/* :'N') */+"</span></div><div class='center'></div>");
|
|
|
+ this.dom.append(child);
|
|
|
|
|
|
- isVisible(){
|
|
|
- return this.visible;
|
|
|
- }
|
|
|
+
|
|
|
+ this.dom.find(".dirText").css({textAlign:"center","font-size":"10px","position":"absolute",
|
|
|
+ width: "100%",
|
|
|
+ height: "25px",
|
|
|
+ "line-height": "25px"});
|
|
|
+
|
|
|
+ this.dom.find(".north").css({"color":"#02a0e9","top":"0"});
|
|
|
+ this.dom.find(".south").css({"color":"#ff1414","bottom":"0"});
|
|
|
+ this.dom.find(".center").css({
|
|
|
+ //"background":`url(${config.getStaticResource('img')}/dire.png)`,
|
|
|
+ width: width/2+"px",
|
|
|
+ height: height/2+"px",
|
|
|
+ "background-size": "contain",
|
|
|
+ "background-position": "center",
|
|
|
+ left: "50%",
|
|
|
+ top: "50%",
|
|
|
+ transform: "translate(-50%,-50%)",
|
|
|
+ position: "absolute"
|
|
|
+ });
|
|
|
+ this.dom.find(".dirText").css({
|
|
|
+ "text-align": "center",
|
|
|
+ "font-size": "10px",
|
|
|
+ "color": "rgb(255, 255, 255)",
|
|
|
+ "position": "absolute",
|
|
|
+ "top": "50%",
|
|
|
+ "left": "50%",
|
|
|
+ "width": "45%",
|
|
|
+ "height": "0px",
|
|
|
+ "transform-origin": "left center",
|
|
|
+
|
|
|
+ });
|
|
|
+ this.dom.find(".dirText span").css({
|
|
|
+ display: "block",
|
|
|
+ position: "absolute",
|
|
|
+ right: "5px",
|
|
|
+ top: "0",
|
|
|
+ width: "20px",
|
|
|
+ height: "20px",
|
|
|
+ "line-height": "20px",
|
|
|
+ // "font-size": ".75rem ",
|
|
|
+ "margin-top": "-10px",
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ try {
|
|
|
+ this.renderer = new WebGLRenderer({ antialias: true, alpha:true });//许钟文 添加个抗锯齿,否则添加的线条锯齿严重,
|
|
|
+ this.renderer.autoClear = !0;
|
|
|
+ this.renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1);
|
|
|
+ this.renderer.domElement.setAttribute('name','compass');
|
|
|
+ this.renderer.setClearAlpha(0.0);
|
|
|
+ this.renderer.setSize(width/2, height/2, false, window.devicePixelRatio ? window.devicePixelRatio : 1);
|
|
|
+ //this.emit(SceneRendererEvents.ContextCreated)
|
|
|
+ } catch (e) {
|
|
|
+ viewer.dispatchEvent('webglError', {msg:e});
|
|
|
+ }
|
|
|
+
|
|
|
+ this.dom.find(".center")[0].appendChild(this.renderer.domElement);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ this.camera = new PerspectiveCamera;
|
|
|
+ this.camera.fov = 50;
|
|
|
+ this.camera.updateProjectionMatrix();
|
|
|
+ this.scene = new Scene,
|
|
|
+ this.scene.add(this.camera);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ this.createCompass();
|
|
|
+
|
|
|
+ viewer.addEventListener('camera_changed', e => {
|
|
|
+ if (e.viewport.name == 'MainView' && (e.changeInfo.positionChanged || e.changeInfo.quaternionChanged)) {
|
|
|
+ this.update();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ createCompass(){
|
|
|
+ //ConeBufferGeometry(radius : Float, height : Float, radialSegments : Integer, heightSegments : Integer, openEnded : Boolean, thetaStart : Float, thetaLength : Float)
|
|
|
+ const height = 2;
|
|
|
+ const geometry1 = new ConeBufferGeometry( 0.7, height, 4, true );
|
|
|
+ const geometry2 = new ConeBufferGeometry( 0.7, height, 4, true );
|
|
|
+ const material = new MeshBasicMaterial({
|
|
|
+ vertexColors :true
|
|
|
+ });
|
|
|
+
|
|
|
+ //指南针由两个四棱锥拼成,为了渐变颜色,采用指定vertexColor的方式。
|
|
|
+ var setColor = function(geometry, color1,color2){
|
|
|
+ const colors = [];
|
|
|
+ for ( let i = 0, n = geometry.attributes.position.count; i < n; ++ i ) {
|
|
|
+ colors.push( 1, 1, 1 );
|
|
|
+ }
|
|
|
+ var set = function(index, color){//设置第index个点的颜色
|
|
|
+ colors[index*3+0] = color[0];
|
|
|
+ colors[index*3+1] = color[1];
|
|
|
+ colors[index*3+2] = color[2];
|
|
|
+ };
|
|
|
+ var mid = [(color1[0]+color2[0])/2, (color1[1]+color2[1])/2, (color1[2]+color2[2])/2 ];
|
|
|
+ set(1,color1); set(5,color1);set(6,color1);
|
|
|
+ set(2,mid); set(3,mid);set(7,mid);
|
|
|
+ set(4,color2); set(8,color2);set(9,color2);
|
|
|
+ geometry.addAttribute("color", new BufferAttribute(new Float32Array(colors), 3));
|
|
|
+ };
|
|
|
+ var blue1 = [1/255,238/255,245/255]; //逐渐变深
|
|
|
+ var blue2 = [20/255,146/255,170/255];
|
|
|
+ var blue3 = [40/255,60/255,103/255];
|
|
|
+ setColor(geometry1, blue1,blue2);
|
|
|
+ setColor(geometry2, blue2,blue3);
|
|
|
+
|
|
|
+ /* 朝箭头方向看点构成如下 虽然geometry.attributes.position.count = 19 只有1-9设置的颜色是有效的 另外为什么7决定了上下两边的颜色呢…… 5、9可将其分成上下两个颜色
|
|
|
+ 6
|
|
|
+ /|\
|
|
|
+ / | \
|
|
|
+ 7 /_2|1_\ 5
|
|
|
+ \ 3|4 / 9
|
|
|
+ \ | /
|
|
|
+ \|/
|
|
|
+ 8
|
|
|
+ */
|
|
|
+ const cone = new Mesh( geometry1, material );
|
|
|
+ cone.position.setY(height/2);
|
|
|
+ geometry1.computeVertexNormals();//computeFaceNormals
|
|
|
+ geometry2.computeVertexNormals();
|
|
|
+
|
|
|
+ const cones = new Object3D();
|
|
|
+ cones.add(cone);
|
|
|
+
|
|
|
+ let cone2 = new Mesh( geometry2, material );
|
|
|
+ cone2.rotation.x = Math.PI;
|
|
|
+ cone2.position.setY(-height/2);
|
|
|
+ cones.add(cone2);
|
|
|
+ //cones.rotation.x = Math.PI / 2;//转向initDir的方向
|
|
|
+ //cones.rotation.z = Math.PI / 2;
|
|
|
+ cones.rotation.z = Math.PI ;//转向initDir的方向
|
|
|
+ cones.scale.set(0.7,0.7,0.7);
|
|
|
+ this.scene.add(cones);
|
|
|
+ this.cones = cones;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ setNorth(){ //设置北方向,这决定了指南针自身的朝向。
|
|
|
+ const floors = store.getters['scene/houstFloor'].floors;
|
|
|
+ if(!floors || !floors.length){
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const floor = floors[0];
|
|
|
+ const metadata = app.store.getters['scene/metadata'] || {};
|
|
|
+
|
|
|
+ this.angle = (floor && floor.dire || 0) + MathUtils.radToDeg(parseFloat(metadata.floorPlanAngle || 0)); //基础朝向
|
|
|
+ this.cones.rotation.y = Math.PI / 2 - MathUtils.degToRad(this.angle);
|
|
|
+ //console.log("dir:"+floor.dire+", floorPlanAngle:"+metadata.floorPlanAngle)
|
|
|
+ this.update();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ update(quaternion){
|
|
|
+ //if(!this.show)return;
|
|
|
+ if(!quaternion) quaternion = viewer.mainViewport.camera.quaternion.clone();
|
|
|
+ this.updateCamera(quaternion);
|
|
|
+ this.updateLabel(quaternion);
|
|
|
+ this.render();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ updateLabel(quaternion){//更新北标签
|
|
|
+
|
|
|
+ var dir = viewer.mainViewport.view.direction;
|
|
|
+ var oriDir = initDir.clone(); //指南针最初始时的北方向
|
|
|
+ var extraQua;
|
|
|
+ /* if(objects.player.mode == "transitioning"){//当transitioning时,相机的quaternion不是用control的lookAt算出来,而是直接由一个quaternion过渡到另一个,这样相机将会是歪的,投影面也就不会是原先的水平面。
|
|
|
+ var tempCamera = new THREE.Camera(); //借用camera的lookAt算出如果正视同样的target, quaternion会是什么值。 将它乘以当前相机quaternion,得到的就是相机歪的旋转值。
|
|
|
+ tempCamera.position.copy(this.camera.position);
|
|
|
+ tempCamera.lookAt(tempCamera.position.clone().add(dir))
|
|
|
+ var q = tempCamera.quaternion.inverse()
|
|
|
+ extraQua = q.premultiply(quaternion) //歪掉的额外旋转值
|
|
|
+
|
|
|
+ } */
|
|
|
+
|
|
|
+ //北标签的方向为指南针轮盘方向,也就是要将camera的方向投影到水平面上。 但是如果相机歪了,看到的世界都会歪一定角度,投影面也要歪一定角度。
|
|
|
+ var up = new Vector3(0,0,1); //投影水平面的法线,也是相机的摆正的up方向
|
|
|
+ extraQua && up.applyQuaternion(extraQua);
|
|
|
+ dir.projectOnPlane(up); //将方向投影到水平面上; 如果相机不是正视(extraQua不为0001),就要将水平面也转动
|
|
|
+ oriDir.projectOnPlane(up);//为什么initDir投影了和没有投影angle结果一样
|
|
|
+ var angle = dir.angleTo(oriDir);
|
|
|
+ if(dir.cross(oriDir).y > 0)angle = -angle;
|
|
|
+
|
|
|
+ var deg = this.angle - 90 + MathUtils.radToDeg(angle); //因为css写的样式初始是指向右方,和initDir差了90°,所以减去。
|
|
|
+
|
|
|
+
|
|
|
+ this.dom.find(".dirText").css( "transform","rotate("+deg+"deg)" );
|
|
|
+ this.dom.find(".dirText span").css("transform","rotate("+(-deg)+"deg)");
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- createElement(){
|
|
|
- const style = `style="position: absolute; top: 10px; right: 10px; z-index: 10000; width: 64px;"`;
|
|
|
- const img = $(`<img src="${Potree.resourcePath}/images/compas.svg" ${style} />`);
|
|
|
|
|
|
- return img;
|
|
|
- }
|
|
|
+ updateLabel(quaternion){//更新北标签
|
|
|
+ let deg = MathUtils.radToDeg(viewer.mainViewport.view.yaw) - 90;
|
|
|
+ this.dom.find(".dirText").css( "transform","rotate("+deg+"deg)" );
|
|
|
+ this.dom.find(".dirText span").css("transform","rotate("+(-deg)+"deg)");
|
|
|
+ }
|
|
|
|
|
|
- };
|
|
|
+
|
|
|
+ updateCamera(quaternion){ //更新canvas中的指南针表现,也就是更新相机,和场景中的相机朝向一致。
|
|
|
+ const radius = 5; //相机距离
|
|
|
+
|
|
|
+ this.camera.quaternion.copy(quaternion);
|
|
|
+ var dir = viewer.mainViewport.view.direction; //相机朝向
|
|
|
+ this.camera.position.copy(dir.multiplyScalar(radius).negate()); //相机绕着指南针中心(000)转动
|
|
|
+ }
|
|
|
+ render(){
|
|
|
+ this.renderer.render(this.scene, this.camera);
|
|
|
+ }
|
|
|
+ setDisplay(state){
|
|
|
+ this.show = !!state;
|
|
|
+ if(this.show){
|
|
|
+ this.update();
|
|
|
+ this.dom.fadeIn(100);
|
|
|
+ }else {
|
|
|
+ this.dom.fadeOut(100);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ autoJudgeDisplay(){
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ setDomLeft(){
|
|
|
+ this.dom.css({'right':'none','left':config.isMobile? "1%" : "2%"});
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
class PotreeRenderer {
|
|
|
|
|
@@ -106335,9 +106547,9 @@ ENDSEC
|
|
|
this.ddsLoader = new DDSLoader; //这个没测过
|
|
|
|
|
|
//路径相对于index.html
|
|
|
- this.dracoLoader.setDecoderPath( urlPrefix + 'three.js/loaders/draco/' /* '../libs/three.js/loaders/draco/' */ /* 'static/lib/three.js/loaders/draco/' */); //这两个路径可以自己改。在laser的环境也要放一份这个路径
|
|
|
- this.ktx2Loader.setTranscoderPath(urlPrefix + 'three.js/loaders/ktx/' /* '../libs/three.js/loaders/ktx/' */ /* 'static/lib/three.js/loaders/ktx/' */ ).detectSupport( renderer );
|
|
|
-
|
|
|
+ this.dracoLoader.setDecoderPath( urlPrefix + 'three.js/loaders/draco/' /*or 'https://unpkg.com/three@0.144.0/examples/js/libs/draco/gltf/' 版本可升级 */); //这两个路径可以自己改。在laser的环境也要放一份这个路径
|
|
|
+ this.ktx2Loader.setTranscoderPath(urlPrefix + 'three.js/loaders/ktx/' /*or 'https://unpkg.com/three@0.144.0/examples/js/libs/basis/' 版本可升级 */).detectSupport( renderer );
|
|
|
+
|
|
|
//------------
|
|
|
|
|
|
|
|
@@ -117634,8 +117846,7 @@ ENDSEC
|
|
|
|
|
|
SplitScreen : new SplitScreen(),
|
|
|
|
|
|
- init(){
|
|
|
-
|
|
|
+ init(){
|
|
|
{
|
|
|
let ground = this.ground = new InfiniteGridHelper(1, 10000, new Color('#fff'), 10000, 0.2, 0.3);
|
|
|
viewer.scene.scene.add(ground);
|
|
@@ -117662,11 +117873,7 @@ ENDSEC
|
|
|
{
|
|
|
|
|
|
this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
|
|
|
-
|
|
|
- //dontHideWhenFaceCamera: true,
|
|
|
- /* scaleAxis: ["x", "y"],
|
|
|
- //隐藏了z轴。虽然参数没用上
|
|
|
- NoScaleZ: true //整体缩放时只缩放xy轴。 */
|
|
|
+ dontHideWhenFaceCamera: true,
|
|
|
});
|
|
|
//this.transformControls.space = 'local'//为了在当前方向上平移
|
|
|
this.transformControls.setSize(1.5);
|
|
@@ -117674,6 +117881,7 @@ ENDSEC
|
|
|
|
|
|
//右屏
|
|
|
this.transformControls2 = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
|
|
|
+ dontHideWhenFaceCamera: true,
|
|
|
});
|
|
|
this.transformControls.setSize(1.5);
|
|
|
viewer.scene.scene.add(this.transformControls2);
|
|
@@ -126470,7 +126678,7 @@ ENDSEC
|
|
|
});
|
|
|
this.viewports = [this.mainViewport];
|
|
|
|
|
|
- this.compass = new Compass(this);
|
|
|
+ Potree.settings.showCompass && (this.compass = new Compass(Potree.settings.compassDom));
|
|
|
this.magnifier = new Magnifier(this);
|
|
|
this.reticule = new Reticule(this);
|
|
|
this.scene.scene.add(this.magnifier);
|
|
@@ -131544,7 +131752,6 @@ ENDSEC
|
|
|
exports.ClipTask = ClipTask;
|
|
|
exports.ClipVolume = ClipVolume;
|
|
|
exports.ClippingTool = ClippingTool;
|
|
|
- exports.Compass = Compass;
|
|
|
exports.DeviceOrientationControls = DeviceOrientationControls;
|
|
|
exports.DownloadStatus = DownloadStatus;
|
|
|
exports.EarthControls = EarthControls;
|