|
@@ -0,0 +1,601 @@
|
|
|
+
|
|
|
+import * as THREE from "../../libs/three.js/build/three.module.js";
|
|
|
+import searchRings from "./searchRings.js";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+var math = {
|
|
|
+ getBaseLog(x, y) {//返回以 x 为底 y 的对数(即 logx y) . Math.log 返回一个数的自然对数
|
|
|
+ return Math.log(y) / Math.log(x);
|
|
|
+ }
|
|
|
+ ,
|
|
|
+ convertVector : {
|
|
|
+ ZupToYup: function(e){//navvis -> 4dkk
|
|
|
+ return new THREE.Vector3(e.x,e.z,-e.y)
|
|
|
+ },
|
|
|
+ YupToZup: function(e){//4dkk -> navvis
|
|
|
+ return new THREE.Vector3(e.x,-e.z,e.y)
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ },
|
|
|
+ convertQuaternion: {
|
|
|
+ ZupToYup: function(e){//navvis -> 4dkk //不同于convertVisionQuaternion
|
|
|
+ let rotation = new THREE.Euler(-Math.PI/2,0,0)
|
|
|
+ let quaternion = new THREE.Quaternion().setFromEuler(rotation)
|
|
|
+ return e.clone().premultiply(quaternion)
|
|
|
+ //return new THREE.Quaternion(e.x,e.z,-e.y,e.w).multiply((new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(1,0,0), THREE.Math.degToRad(90)))
|
|
|
+ },
|
|
|
+ YupToZup: function(e){//4dkk -> navvis
|
|
|
+ let rotation = new THREE.Euler(Math.PI/2,0,0)
|
|
|
+ let quaternion = new THREE.Quaternion().setFromEuler(rotation)
|
|
|
+ return e.clone().premultiply(quaternion)
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ convertVisionQuaternion: function(e) {
|
|
|
+ return new THREE.Quaternion(e.x,e.z,-e.y,e.w).multiply((new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(0,1,0), THREE.Math.degToRad(90)))
|
|
|
+ },
|
|
|
+ invertVisionQuaternion : function(e) {//反转给算法部
|
|
|
+ var a = e.clone().multiply((new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(0,1,0), THREE.Math.degToRad(-90)))
|
|
|
+ return new THREE.Quaternion(a.x,-a.z,a.y,a.w)
|
|
|
+ },
|
|
|
+ //------------
|
|
|
+
|
|
|
+ getVec2Angle : function(dir1,dir2){
|
|
|
+ return Math.acos( THREE.Math.clamp(this.getVec2Cos(dir1,dir2), -1,1) )
|
|
|
+ },
|
|
|
+ getVec2Cos : function(dir1,dir2){
|
|
|
+ return dir1.dot(dir2) / dir1.length() / dir2.length()
|
|
|
+ },
|
|
|
+ getAngle:function(vec1, vec2, axis){//带方向的角度 vector3
|
|
|
+ var angle = vec1.angleTo(vec2)
|
|
|
+ var axis_ = vec1.clone().cross(vec2);
|
|
|
+ if(axis_[axis] < 0){
|
|
|
+ angle *= -1
|
|
|
+ }
|
|
|
+ return angle
|
|
|
+ },
|
|
|
+
|
|
|
+ closeTo : function(a,b, precision=1e-6){
|
|
|
+ let f = (a,b)=>{
|
|
|
+ return Math.abs(a-b) < precision;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(typeof (a) == 'number'){
|
|
|
+ return f(a, b);
|
|
|
+ }else{
|
|
|
+ let judge = (name)=>{
|
|
|
+ if(a[name] == void 0)return true //有值就判断,没值就不判断
|
|
|
+ else return f(a[name],b[name])
|
|
|
+ }
|
|
|
+ return judge('x') && judge('y') && judge('z') && judge('w')
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ toPrecision: function (e, t) {//xzw change 保留小数
|
|
|
+ var f = function (e, t) {
|
|
|
+ var i = Math.pow(10, t);
|
|
|
+ return Math.round(e * i) / i
|
|
|
+ }
|
|
|
+ if (e instanceof Array) {
|
|
|
+ for (var s = 0; s < e.length; s++) {
|
|
|
+ e[s] = f(e[s], t);
|
|
|
+ }
|
|
|
+ return e;
|
|
|
+ } else if (e instanceof Object) {
|
|
|
+ for (var s in e) {
|
|
|
+ e[s] = f(e[s], t);
|
|
|
+ }
|
|
|
+ return e;
|
|
|
+ } else return f(e, t)
|
|
|
+ },
|
|
|
+ isEmptyQuaternion: function(e) {
|
|
|
+ return 0 === Math.abs(e.x) && 0 === Math.abs(e.y) && 0 === Math.abs(e.z) && 0 === Math.abs(e.w)
|
|
|
+ },
|
|
|
+ projectPositionToCanvas: function(e, t, i) {
|
|
|
+ i = i || new THREE.Vector3,
|
|
|
+ i.copy(e);
|
|
|
+ var r = .5 * $('#player').width()
|
|
|
+ , o = .5 * $('#player').height();
|
|
|
+ return i.project(t),
|
|
|
+ i.x = i.x * r + r,
|
|
|
+ i.y = -(i.y * o) + o,
|
|
|
+ i
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ handelPadResize:false,
|
|
|
+ /* handelPadding : function () { //去除player左边和上面的宽高,因为pc的player左上有其他element 许钟文
|
|
|
+
|
|
|
+ var pads = [];//记录下来避免反复计算
|
|
|
+ var index = [];
|
|
|
+ var resetPad = function(){
|
|
|
+ pads = [];
|
|
|
+ index = [];
|
|
|
+ math.handelPadResize = false; //switchview时resized为true
|
|
|
+ }
|
|
|
+
|
|
|
+ if(config.isEdit && !config.isMobile){
|
|
|
+ window.addEventListener('resize',resetPad);
|
|
|
+ }
|
|
|
+ return function(x, y, domE){
|
|
|
+ if(!config.isEdit || config.isMobile) {
|
|
|
+ return {
|
|
|
+ x: x,
|
|
|
+ y: y
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.handelPadResize)resetPad();
|
|
|
+ domE = domE || $('#player')[0];
|
|
|
+ var pad;
|
|
|
+ var i = index.indexOf(domE);
|
|
|
+ if (i == -1){
|
|
|
+ index.push(domE);
|
|
|
+ pad = {
|
|
|
+ x: this.getOffset("left", domE),
|
|
|
+ y: this.getOffset("top", domE)
|
|
|
+ }
|
|
|
+ pads.push(pad)
|
|
|
+ }
|
|
|
+ else pad = pads[i];
|
|
|
+ return {
|
|
|
+ x: x - pad.x,
|
|
|
+ y: y - pad.y
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }(), */
|
|
|
+
|
|
|
+ getOffset: function (type, element, parent) {//获取元素的边距 许钟文
|
|
|
+ var offset = (type == "left") ? element.offsetLeft : element.offsetTop;
|
|
|
+ if (!parent) parent = $("body")[0];
|
|
|
+ while (element = element.offsetParent) {
|
|
|
+ if (element == parent) break;
|
|
|
+ offset += (type == "left") ? element.offsetLeft : element.offsetTop;
|
|
|
+ }
|
|
|
+ return offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ ,
|
|
|
+ constrainedTurn: function(e) {
|
|
|
+ var t = e % (2 * Math.PI);
|
|
|
+ return t = t > Math.PI ? t -= 2 * Math.PI : t < -Math.PI ? t += 2 * Math.PI : t
|
|
|
+ },
|
|
|
+ getFOVDotThreshold: function(e) {
|
|
|
+ return Math.cos(THREE.Math.degToRad(e / 2))
|
|
|
+ },
|
|
|
+ transform2DForwardVectorByCubeFace: function(e, t, i, n) {
|
|
|
+ switch (e) {
|
|
|
+ case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
|
|
+ i.set(1, t.y, t.x);
|
|
|
+ break;
|
|
|
+ case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
|
|
+ i.set(-1, t.y, -t.x);
|
|
|
+ break;
|
|
|
+ case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
|
|
+ i.set(-t.x, 1, -t.y);
|
|
|
+ break;
|
|
|
+ case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
|
|
+ i.set(-t.x, -1, t.y);
|
|
|
+ break;
|
|
|
+ case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
|
|
+ i.set(-t.x, t.y, 1);
|
|
|
+ break;
|
|
|
+ case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
|
|
+ i.set(t.x, t.y, -1)
|
|
|
+ }
|
|
|
+ n && i.normalize()
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ getFootPoint : function(oldPos, p1, p2, restricInline){ //找oldPos在线段p1, p2上的垂足
|
|
|
+ /* if(isWorld){//输出全局坐标 需要考虑meshGroup.position
|
|
|
+ p1 = p1.clone();
|
|
|
+ p2 = p2.clone();
|
|
|
+ p1.y += mainDesign.meshGroup.position.y;
|
|
|
+ p2.y += mainDesign.meshGroup.position.y;
|
|
|
+ } */
|
|
|
+ if(p1.equals(p2))return p1.clone()
|
|
|
+ var op1 = oldPos.clone().sub(p1);
|
|
|
+ var p1p2 = p1.clone().sub(p2)
|
|
|
+ var p1p2Len = p1p2.length()
|
|
|
+ var leftLen = op1.dot(p1p2) / p1p2Len;
|
|
|
+ var pos = p1.clone().add(p1p2.multiplyScalar( leftLen/p1p2Len ));
|
|
|
+
|
|
|
+ if(restricInline && pos.clone().sub(p1).dot( pos.clone().sub(p2) ) > 0){//foot不在线段上
|
|
|
+ if(pos.distanceTo(p1) < pos.distanceTo(p2)) pos = p1.clone();
|
|
|
+ else pos = p2.clone();
|
|
|
+ }
|
|
|
+
|
|
|
+ return pos;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算多边形的重心
|
|
|
+ * @param {*} points
|
|
|
+ */
|
|
|
+ getCenterOfGravityPoint : function(mPoints){
|
|
|
+ var area = 0.0;//多边形面积
|
|
|
+ var Gx = 0.0, Gy = 0.0;// 重心的x、y
|
|
|
+
|
|
|
+ for (var i = 1; i <= mPoints.length; i++) {
|
|
|
+ var ix = mPoints[i % mPoints.length].x;
|
|
|
+ var iy = mPoints[i % mPoints.length].y;
|
|
|
+ var nx = mPoints[i - 1].x;
|
|
|
+ var ny = mPoints[i - 1].y;
|
|
|
+ var temp = (ix * ny - iy * nx) / 2.0;
|
|
|
+ area += temp;
|
|
|
+ Gx += temp * (ix + nx) / 3.0;
|
|
|
+ Gy += temp * (iy + ny) / 3.0;
|
|
|
+ }
|
|
|
+ Gx = Gx / area;
|
|
|
+ Gy = Gy / area;
|
|
|
+ return { x: Gx, y: Gy };
|
|
|
+ },
|
|
|
+
|
|
|
+ getBound : function(ring){
|
|
|
+ var bound = new THREE.Box2();
|
|
|
+ for(var j=0,len = ring.length; j<len; j++){
|
|
|
+ bound.expandByPoint(ring[j])
|
|
|
+ }
|
|
|
+ return bound;
|
|
|
+ },
|
|
|
+
|
|
|
+ isPointInArea : function(ring, holes, point, ifAtLine){//判断点是否在某个环内, 若传递了holes代表还要不能在内环内
|
|
|
+ var bound = this.getBound(ring);
|
|
|
+ if(point.x < bound.min.x || point.x > bound.max.x || point.y < bound.min.y || point.y > bound.max.y)return false;
|
|
|
+
|
|
|
+
|
|
|
+ var inside = false;
|
|
|
+ var x = point.x,
|
|
|
+ y = point.y;
|
|
|
+
|
|
|
+ for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
|
+ var xi = ring[i].x,
|
|
|
+ yi = ring[i].y;
|
|
|
+ var xj = ring[j].x,
|
|
|
+ yj = ring[j].y;
|
|
|
+
|
|
|
+ if((xi - x)*(yj - y) == (xi - x)*(yi - y) && x>=Math.min(xi,xj) && x<=Math.max(xi,xj)//xzw add
|
|
|
+ && y>=Math.min(yi,yj) && y<=Math.max(yi,yj)
|
|
|
+ ){
|
|
|
+ //return !!ifAtLine;//在线段上,则判断为…… (默认在外)
|
|
|
+ return {atLine:true}
|
|
|
+ }
|
|
|
+
|
|
|
+ if (((yi > y) != (yj > y)) &&
|
|
|
+ (x < (xj - xi) * (y - yi) / (yj - yi) + xi)
|
|
|
+ ) {
|
|
|
+ inside = !inside;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inside && holes){
|
|
|
+ return !holes.some(ring=>this.isPointInArea(ring, null, point, ifAtLine) ) //不能存在于任何一个二级内环内
|
|
|
+ }else{
|
|
|
+ return inside;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ getArea : function (ring) { //求面积 顺时针为正 来自three shape
|
|
|
+ for (var t = ring.length, i = 0, n = t - 1, r = 0; r < t; n = r++)
|
|
|
+ i += ring[n].x * ring[r].y - ring[r].x * ring[n].y;
|
|
|
+ return -.5 * i
|
|
|
+ },
|
|
|
+ isInBetween : function(a, b, c, precision) {
|
|
|
+ // 如果b几乎等于a或c,返回false.为了避免浮点运行时两值几乎相等,但存在相差0.00000...0001的这种情况出现使用下面方式进行避免
|
|
|
+
|
|
|
+ /* if (Math.abs(a - b) < 0.000001 || Math.abs(b - c) < 0.000001) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return (a <= b && b <= c) || (c <= b && b <= a);*/
|
|
|
+
|
|
|
+
|
|
|
+ //更改:如果b和a或c中一个接近 就算在a和c之间
|
|
|
+ return (a <= b && b <= c) || (c <= b && b <= a) || this.closeTo(a,b,precision) || this.closeTo(b,c,precision);
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ ifPointAtLineBound:function(point, linePoints, precision){
|
|
|
+ //待验证 横线和竖线比较特殊
|
|
|
+ return math.isInBetween(linePoints[0].x, point.x, linePoints[1].x, precision) && math.isInBetween(linePoints[0].y, point.y, linePoints[1].y, precision)
|
|
|
+ }
|
|
|
+
|
|
|
+ ,
|
|
|
+
|
|
|
+ isLineIntersect: function (line1, line2, notSegment, precision) {//线段和线段是否有交点. notSegment代表是直线而不是线段
|
|
|
+ var a1 = line1[1].y - line1[0].y;
|
|
|
+ var b1 = line1[0].x - line1[1].x;
|
|
|
+ var c1 = a1 * line1[0].x + b1 * line1[0].y;
|
|
|
+ //转换成一般式: Ax+By = C
|
|
|
+ var a2 = line2[1].y - line2[0].y;
|
|
|
+ var b2 = line2[0].x - line2[1].x;
|
|
|
+ var c2 = a2 * line2[0].x + b2 * line2[0].y;
|
|
|
+ // 计算交点
|
|
|
+ var d = a1 * b2 - a2 * b1;
|
|
|
+
|
|
|
+ // 当d==0时,两线平行
|
|
|
+ if (d == 0) {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ var x = (b2 * c1 - b1 * c2) / d;
|
|
|
+ var y = (a1 * c2 - a2 * c1) / d;
|
|
|
+
|
|
|
+ // 检测交点是否在两条线段上
|
|
|
+ /* if (notSegment || (isInBetween(line1[0].x, x, line1[1].x) || isInBetween(line1[0].y, y, line1[1].y)) &&
|
|
|
+ (isInBetween(line2[0].x, x, line2[1].x) || isInBetween(line2[0].y, y, line2[1].y))) {
|
|
|
+ return {x,y};
|
|
|
+ } */
|
|
|
+ if (notSegment || math.ifPointAtLineBound({x,y}, line1, precision) && math.ifPointAtLineBound({x,y}, line2, precision)){
|
|
|
+ return {x,y};
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ getNormal2d : function(o={} ){//获取二维法向量 方向向内
|
|
|
+ var x,y, x1,y1;
|
|
|
+ //line2d的向量
|
|
|
+ if(o.vec){
|
|
|
+ x1 = o.vec.x; y1 = o.vec.y
|
|
|
+ }else{
|
|
|
+ x1 = o.p1.x - o.p2.x;
|
|
|
+ y1 = o.p1.y - o.p2.y;
|
|
|
+ }
|
|
|
+
|
|
|
+ //假设法向量的x或y固定为1或-1
|
|
|
+ if(y1 != 0){
|
|
|
+ x = 1;
|
|
|
+ y = - (x1 * x) / y1;
|
|
|
+ }else if(x1 != 0){//y如果为0,正常情况x不会是0
|
|
|
+ y = 1;
|
|
|
+ x = - (y1 * y) / x1;
|
|
|
+ }else{
|
|
|
+ console.log("两个点一样");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ //判断方向里或者外:
|
|
|
+ var vNormal = new THREE.Vector3(x, 0, y);
|
|
|
+ var vLine = new THREE.Vector3(x1, 0, y1);
|
|
|
+ var vDir = vNormal.cross(vLine);
|
|
|
+ if(vDir.y>0){
|
|
|
+ x *= -1;
|
|
|
+ y *= -1;
|
|
|
+ }
|
|
|
+ return new THREE.Vector2(x, y).normalize();
|
|
|
+ },
|
|
|
+
|
|
|
+ getQuaBetween2Vector:function(oriVec, newVec, upVec){ //获取从oriVec旋转到newVec可以应用的quaternion
|
|
|
+ var angle = oriVec.angleTo(newVec);
|
|
|
+ var axis = oriVec.clone().cross( newVec).normalize();//两个up之间
|
|
|
+ if(axis.length() == 0){//当夹角为180 或 0 度时,得到的axis为(0,0,0),故使用备用的指定upVec
|
|
|
+ return new THREE.Quaternion().setFromAxisAngle( upVec, angle );
|
|
|
+ }
|
|
|
+ return new THREE.Quaternion().setFromAxisAngle( axis, angle );
|
|
|
+ }
|
|
|
+ /* ,
|
|
|
+ getQuaBetween2Vector2 : function(oriVec, newVec ){//not camera
|
|
|
+ var _ = (new THREE.Matrix4).lookAt( oriVec, new THREE.Vector3, new THREE.Vector3(0,1,0))
|
|
|
+ var aimQua = (new THREE.Quaternion).setFromRotationMatrix(_)
|
|
|
+ var _2 = (new THREE.Matrix4).lookAt( newVec, new THREE.Vector3, new THREE.Vector3(0,1,0))
|
|
|
+ var aimQua2 = (new THREE.Quaternion).setFromRotationMatrix(_2)
|
|
|
+
|
|
|
+ return aimQua2.multiply(aimQua.clone().inverse())
|
|
|
+
|
|
|
+ } */
|
|
|
+
|
|
|
+
|
|
|
+ ,
|
|
|
+
|
|
|
+ getScaleForConstantSize : function(){ //获得规定二维大小的mesh的scale值。可以避免因camera的projection造成的mesh视觉大小改变。 来源:tag.updateDisc
|
|
|
+ var w;
|
|
|
+ var i = new THREE.Vector3, o = new THREE.Vector3, l = new THREE.Vector3, c = new THREE.Vector3, h = new THREE.Vector3
|
|
|
+ return function(op={}){
|
|
|
+ if(op.width2d) w = op.width2d //如果恒定二维宽度
|
|
|
+ else{//否则考虑上距离,加一丢丢近大远小的效果
|
|
|
+ var currentDis, nearBound, farBound
|
|
|
+ if(op.camera.type == "OrthographicCamera"){
|
|
|
+ currentDis = 200 / op.camera.zoom //(op.camera.right - op.camera.left) / op.camera.zoom
|
|
|
+ }else{
|
|
|
+ currentDis = op.position.distanceTo(op.camera.position);
|
|
|
+ }
|
|
|
+ w = op.maxSize - ( op.maxSize - op.minSize) * THREE.Math.smoothstep(currentDis, op.nearBound, op.farBound);
|
|
|
+ //maxSize : mesh要表现的最大像素宽度; nearBound: 最近距离,若比nearBound近,则使用maxSize
|
|
|
+ }
|
|
|
+ i.copy(op.position).project(op.camera), //tag中心在屏幕上的二维坐标
|
|
|
+ o.set(op.resolution.x / 2, op.resolution.y / 2, 1).multiply(i), //转化成px -w/2 到 w/2的范围
|
|
|
+ l.set(w / 2, 0, 0).add(o), //加上tag宽度的一半
|
|
|
+ c.set(2 / op.resolution.x, 2 / op.resolution.y, 1).multiply(l), //再转回 -1 到 1的范围
|
|
|
+ h.copy(c).unproject(op.camera);//再转成三维坐标,求得tag边缘的位置
|
|
|
+ var g = h.distanceTo(op.position)//就能得到tag的三维半径
|
|
|
+ //这里使用的都是resolution2, 好处是手机端不会太小, 坏处是pc更改网页显示百分比时显示的大小会变(或许可以自己算出设备真实的deviceRatio, 因window.screen是不会改变的),但考虑到用户可以自行调节字大小也许是好的
|
|
|
+ return g //可能NAN 当相机和position重叠时
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ ,
|
|
|
+
|
|
|
+ //W , H, left, top分别是rect的宽、高、左、上
|
|
|
+ getCrossPointAtRect : function(p1, aim, W , H, left, top){//求射线p1-aim在rect边界上的交点,其中aim在rect范围内,p1则不一定(交点在aim这边的延长线上)
|
|
|
+
|
|
|
+ var x,y, borderX;
|
|
|
+ var r = (aim.x - p1.x) / (aim.y - p1.y);//根据相似三角形原理先求出这个比值
|
|
|
+ var getX = function(y){
|
|
|
+ return r * (y-p1.y) + p1.x;
|
|
|
+ }
|
|
|
+ var getY = function(x){
|
|
|
+ return 1/r * (x-p1.x) + p1.y;
|
|
|
+ }
|
|
|
+ if(aim.x >= p1.x){
|
|
|
+ borderX = W+left;
|
|
|
+ }else{
|
|
|
+ borderX = left;
|
|
|
+ }
|
|
|
+ x = borderX;
|
|
|
+ y = getY(x);
|
|
|
+ if(y < top || y > top+H){
|
|
|
+ if(y < top){
|
|
|
+ y = top;
|
|
|
+ }else{
|
|
|
+ y = top+H;
|
|
|
+ }
|
|
|
+ x = getX(y)
|
|
|
+ }
|
|
|
+ return new THREE.Vector2(x, y);
|
|
|
+ },
|
|
|
+ getDirFromUV : function(uv){ //获取dir 反向计算 - - 二维转三维比较麻烦
|
|
|
+ var dirB; //所求 单位向量
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ var y = Math.cos(uv.y * Math.PI); //uv中纵向可以直接确定y, 根据上面getUVfromDir的反向计算
|
|
|
+ // 故 uv.y * Math.PI 就是到垂直线(向上)的夹角
|
|
|
+ var angle = 2 * Math.PI * uv.x - Math.PI //x/z代表的是角度
|
|
|
+
|
|
|
+ var axisX, axisZ; //axis为1代表是正,-1是负数
|
|
|
+ if (-Math.PI <= angle && angle < 0) {
|
|
|
+ axisX = -1 //下半圆
|
|
|
+ } else {
|
|
|
+ axisX = 1 //上半圆
|
|
|
+ }
|
|
|
+ if (-Math.PI / 2 <= angle && angle < Math.PI / 2) {
|
|
|
+ axisZ = 1 //右半圆
|
|
|
+ } else {
|
|
|
+ axisZ = -1 //左半圆
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ var XDivideZ = Math.tan(angle);
|
|
|
+ var z = Math.sqrt((1 - y * y) / (1 + XDivideZ * XDivideZ));
|
|
|
+ var x = XDivideZ * z
|
|
|
+
|
|
|
+
|
|
|
+ if (z * axisZ < 0) { //异号
|
|
|
+ z *= -1;
|
|
|
+ x *= -1;
|
|
|
+ if (x * axisX < 0) {
|
|
|
+ // console.log("wrong!!!!!??????????")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ x *= -1 //计算完成后这里不能漏掉 *= -1
|
|
|
+ dirB = this.convertVector.YupToZup(new THREE.Vector3(x, y, z))
|
|
|
+
|
|
|
+ //理想状态下x和z和anotherDir相同
|
|
|
+ return dirB
|
|
|
+
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ getUVfromDir : function(dir) { //获取UV 同shader里的计算
|
|
|
+ var dir = this.convertVector.ZupToYup(dir)
|
|
|
+ dir.x *= -1; //计算前这里不能漏掉 *= -1 见shader
|
|
|
+ var tx = Math.atan2(dir.x, dir.z) / (Math.PI * 2.0) + 0.5; //atan2(y,x) 返回从 X 轴正向逆时针旋转到点 (x,y) 时经过的角度。区间是-PI 到 PI 之间的值
|
|
|
+ var ty = Math.acos(dir.y) / Math.PI;
|
|
|
+ return new THREE.Vector2(tx, ty)
|
|
|
+
|
|
|
+ //理想状态下tx相同
|
|
|
+ },
|
|
|
+
|
|
|
+ getDirByLonLat : function(lon,lat){
|
|
|
+ var dir = new THREE.Vector3
|
|
|
+ var phi = THREE.Math.degToRad(90 - lat);
|
|
|
+ var theta = THREE.Math.degToRad(lon);
|
|
|
+ dir.x = Math.sin(phi) * Math.cos(theta);
|
|
|
+ dir.y = Math.cos(phi);
|
|
|
+ dir.z = Math.sin(phi) * Math.sin(theta);
|
|
|
+ return dir
|
|
|
+ } //0,0 => (1,0,0) 270=>(0,0,-1)
|
|
|
+ ,
|
|
|
+ projectPointAtPlane:function(o={}){//获取一个点在一个面上的投影 {facePoints:[a,b,c], point:}
|
|
|
+ var plane = new THREE.Plane().setFromCoplanarPoints(...o.facePoints)
|
|
|
+ return plane.projectPoint(o.point, new THREE.Vector3() )
|
|
|
+ }
|
|
|
+ ,
|
|
|
+
|
|
|
+ getPolygonsMixedRings:function( polygons, onlyGetOutRing){//{points:[vector2,...],holes:[[],[]]}
|
|
|
+
|
|
|
+
|
|
|
+ let points = []
|
|
|
+ let lines = []
|
|
|
+ let i = 0
|
|
|
+
|
|
|
+ polygons.forEach(e=> points.push(...e.map(a=>new THREE.Vector2().copy(a) )) )
|
|
|
+ polygons.forEach((ps,j)=>{
|
|
|
+ let length = ps.length;
|
|
|
+ let index = 0;
|
|
|
+ while(index<length){
|
|
|
+ lines.push({p1:index+i,p2:(index+1)%length+i});
|
|
|
+ index ++;
|
|
|
+ }
|
|
|
+ i+=length
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ points.forEach((p,j)=>{p.id = j})
|
|
|
+
|
|
|
+ let rings = searchRings({
|
|
|
+ points,
|
|
|
+ lines,
|
|
|
+ onlyGetOutRing
|
|
|
+ })
|
|
|
+ //console.log(rings)
|
|
|
+
|
|
|
+ rings = rings.filter(e=>e.closetParent == void 0)// 子环不加,被外环包含了
|
|
|
+
|
|
|
+ return rings
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ getQuaFromPosAim( position, target ){
|
|
|
+ let matrix = (new THREE.Matrix4).lookAt(position, target, new THREE.Vector3(0,0,1))
|
|
|
+ return (new THREE.Quaternion).setFromRotationMatrix(matrix)
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ getBoundByPoints(points, minSize){
|
|
|
+ var bound = new THREE.Box3
|
|
|
+ points.forEach(point=>{
|
|
|
+ bound.expandByPoint(point)
|
|
|
+ })
|
|
|
+ let center = bound.getCenter(new THREE.Vector3)
|
|
|
+ if(minSize){
|
|
|
+ let minBound = (new THREE.Box3()).setFromCenterAndSize(center, minSize)
|
|
|
+ bound.union(minBound)
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ bounding:bound,
|
|
|
+ size: bound.getSize(new THREE.Vector3),
|
|
|
+ center,
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+Potree.math = math
|
|
|
+
|
|
|
+
|
|
|
+export default math
|