有时候,我们想判断一下第四个点是否在前面三个点构成的三角形范围内,可以参考以下的代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>已经有拉伸出来的正交投影模型,接下来要将中心转向面的选取和模型的平移,旋转,以及读取obj并显示模型</title>
<style>
.tabx{border-collapse:collapse;border-style: solid;border-width: 1px;text-align:center;}
.tdx{border-style: solid;border-width: 1px;}
</style>
</head>
<body>
<a><input type="file" id="selectFiles" onchange="dealSelectFiles()" value="后续计划可以直接加载obj或gltf文件的模型" ></a>
<a><input type="button" id="btne" value="拉伸" ></a>
<a><input type="button" id="btn" value="保存" ></a>
<input type="text" id="txt" style="display:none;"/>
<div id="div" style="border:1px solid #000;"><canvas id="canvas"></canvas></div>
</br>
<script>
var vShaderSource = 'attribute vec2 a_Position;'+
'attribute vec2 a_Screen_Size;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
//视图坐标(0~800,0~600)转换为 OPENGL坐标(-1.0,1.0)之间的值
'vec2 xyposition = (a_Position / a_Screen_Size) * 2.0 - 1.0;'+
'vec4 position=vec4(xyposition,0.0,1.0);'+
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position);'+
'gl_PointSize = 10.0;'+
'vColor = color;'+
'}';
var fShaderSource = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
let canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;//当前的宽度
canvas.height = window.innerHeight;//当前的高度
let gl = canvas.getContext('webgl');
//创建顶点着色器
let vShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vShader,vShaderSource);
gl.compileShader(vShader);
//创建片元着色器
let fShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fShader,fShaderSource);
gl.compileShader(fShader);
//创建一个完整的着色器
let propgram = gl.createProgram();
gl.attachShader(propgram,vShader);
gl.attachShader(propgram,fShader);
gl.linkProgram(propgram);
gl.useProgram(propgram);
let positions =[];//设置一个数据
let vectexs =[];//设置一个数据
let x0=0;
let y0=0;
//设置缓冲区存放玩家点击的点的坐标
let buffer = gl.createBuffer();
//绑定缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
//取到我们需要使用的变量
let a_Position = gl.getAttribLocation(propgram,'a_Position');
gl.enableVertexAttribArray(a_Position);
//每次取两个数据
let size = 2;
//每个数据的类型是32位浮点型
let type = gl.FLOAT;
//不需要归一化数据
let normalize = false;
// 每次迭代运行需要移动数据数 * 每个数据所占内存 到下一个数据开始点。
let stride = 0;
// 从缓冲起始位置开始读取
let offset = 0;
// 将 a_Position 变量获取数据的缓冲区指向当前绑定的 buffer。
gl.vertexAttribPointer(a_Position, size, type, normalize, stride, offset)
//片元色器
let u_Color = gl.getAttribLocation(propgram,'color');
gl.vertexAttrib3f(u_Color,0.0,0.0,1.0);
//顶点着色器
//处理顶点着色器中的变量
let a_Screen_Size = gl.getAttribLocation(propgram,'a_Screen_Size');//取到屏幕的大小
gl.vertexAttrib2f(a_Screen_Size,canvas.width,canvas.height);//设置参数
//获取地址
var _PM = gl.getUniformLocation(propgram, "Pmatrix");
var _VM = gl.getUniformLocation(propgram, "Vmatrix");
var _MM = gl.getUniformLocation(propgram, "Mmatrix");
//正交投影
var p_matrix = orth_projection(-1,1,-1,1,1,100);
//模型举证
var m_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
//视图矩阵
var v_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
//绑定
gl.uniformMatrix4fv(_PM, false, p_matrix);
gl.uniformMatrix4fv(_VM, false, v_matrix);
gl.uniformMatrix4fv(_MM, false, m_matrix);
//背景色
gl.clearColor(1,1,1,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
//捕获按钮事件
var handler=function(e){
var x = e.offsetX;
var y = e.offsetY;
positions .push(x,y);
vectexs.push(x,y)
if(positions.length == 2){
x0=x;
y0=y;
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(positions),gl.STATIC_DRAW);
gl.clearColor(1,1,1,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, positions.length / 2);
}else if(vectexs.length<6)
{
positions .push(x,y);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(positions),gl.STATIC_DRAW);
gl.clearColor(1,1,1,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.LINES, 0, positions.length / 2);
}else if(vectexs.length==6)
{
positions .push(x,y);
positions .push(x0,y0);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(positions),gl.STATIC_DRAW);
gl.clearColor(1,1,1,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.LINES, 0, positions.length / 2);
}else if(vectexs.length==8)
{
//判断第四个点是否在前三个点形成的三角形范围内
//到最长边的垂直线和到其他两个边的垂直线的夹角都大于90度
var PMax,Ver;
var P1=Math.sqrt((vectexs[0]-vectexs[2])*(vectexs[0]-vectexs[2])+(vectexs[1]-vectexs[3])*(vectexs[1]-vectexs[3]));
var P2=Math.sqrt((vectexs[2]-vectexs[4])*(vectexs[2]-vectexs[4])+(vectexs[3]-vectexs[5])*(vectexs[3]-vectexs[5]));
var P3=Math.sqrt((vectexs[4]-vectexs[0])*(vectexs[4]-vectexs[0])+(vectexs[5]-vectexs[1])*(vectexs[5]-vectexs[1]));
if(P1>P2){PMax=P1;Ver="0";}else{PMax=P2;Ver="2";}
if(PMax<P3){PMax=P3;Ver="4";}
var Vec1=new vec2(vectexs[0],vectexs[1]);
var Vec2=new vec2(vectexs[2],vectexs[3]);
var Vec3=new vec2(vectexs[4],vectexs[5]);
var Vec4=new vec2(vectexs[6],vectexs[7]);
//y=ax+b=>Vec1._y=a*Vec1._x+b;Vec2._y=a*Vec2._x+b;
//=> a=(Vec2._y-Vec1._y)/(Vec2._x-Vec1._x);
//=> b=Vec1._y-(Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)*Vec1._x
//相互垂直的两条线的斜率乘积为-1;y=a1x+b1=>
//=> a1=-(Vec2._x-Vec1._x)/(Vec2._y-Vec1._y);
//=> b1=Vec4._y+(Vec2._x-Vec1._x)/(Vec2._y-Vec1._y)*Vec4._x
//两条线的交点的坐标为(y=ax+b;y=a1x+b1 =>(a-a1)*x=b1-b =>x=(b1-b)/(a-a1):
var x12=-(Vec1._y-(Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)*Vec1._x-Vec4._y-(Vec2._x-Vec1._x)/(Vec2._y-Vec1._y)*Vec4._x)/((Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)+(Vec2._x-Vec1._x)/(Vec2._y-Vec1._y));
var y12=(Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)*x12+Vec1._y-(Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)*Vec1._x;
var x23=-(Vec2._y-(Vec3._y-Vec2._y)/(Vec3._x-Vec2._x)*Vec2._x-Vec4._y-(Vec3._x-Vec2._x)/(Vec3._y-Vec2._y)*Vec4._x)/((Vec3._y-Vec2._y)/(Vec3._x-Vec2._x)+(Vec3._x-Vec2._x)/(Vec3._y-Vec2._y));
var y23=(Vec3._y-Vec2._y)/(Vec3._x-Vec2._x)*x23+Vec2._y-(Vec3._y-Vec2._y)/(Vec3._x-Vec2._x)*Vec2._x;
var x31=-(Vec3._y-(Vec1._y-Vec3._y)/(Vec1._x-Vec3._x)*Vec3._x-Vec4._y-(Vec1._x-Vec3._x)/(Vec1._y-Vec3._y)*Vec4._x)/((Vec1._y-Vec3._y)/(Vec1._x-Vec3._x)+(Vec1._x-Vec3._x)/(Vec1._y-Vec3._y));
var y31=(Vec1._y-Vec3._y)/(Vec1._x-Vec3._x)*x31+Vec3._y-(Vec1._y-Vec3._y)/(Vec1._x-Vec3._x)*Vec3._x;
//计算三条垂直线的矢量
var nor1=new vec2(x12-Vec4._x,y12-Vec4._y)
var nor2=new vec2(x23-Vec4._x,y23-Vec4._y)
var nor3=new vec2(x31-Vec4._x,y31-Vec4._y)
//根据点积公式算夹角
var A1=vec2.angleBetween(nor1,nor2)/3.1415926*180;
var A2=vec2.angleBetween(nor2,nor3)/3.1415926*180;
var A3=vec2.angleBetween(nor3,nor1)/3.1415926*180;
//目前的判断基本准确,可能在钝边三角形有时候判断出错,可能是因为第四个点落点问题
if(Ver=="0")
{
console.log("最长的边为第一条边,边长为:"+PMax+";对应的两个角为:"+A1+","+A3);
if(A1>=90&&A3>=90)
{
console.log("第四个点在三角形范围内。");
}else
{
console.log("第四个点 不 在三角形范围内。");
}
}else if(Ver=="2")
{
console.log("最长的边为第二条边,边长为:"+PMax+";对应的两个角为:"+A1+","+A2);
if(A1>=90&&A2>=90)
{
console.log("第四个点在三角形范围内。");
}else
{
console.log("第四个点 不 在三角形范围内。");
}
}else if(Ver=="4")
{
console.log("最长的边为第三条边,边长为:"+PMax+";对应的两个角为:"+A2+","+A3);
if(A2>=90&&A3>=90)
{
console.log("第四个点在三角形范围内。");
}else
{
console.log("第四个点 不 在三角形范围内。");
}
}
}
};
var handlerm=function(e){
var x = e.offsetX;
var y = e.offsetY;
var PMax,Ver;
var P1=Math.sqrt((vectexs[0]-vectexs[2])*(vectexs[0]-vectexs[2])+(vectexs[1]-vectexs[3])*(vectexs[1]-vectexs[3]));
var P2=Math.sqrt((vectexs[2]-vectexs[4])*(vectexs[2]-vectexs[4])+(vectexs[3]-vectexs[5])*(vectexs[3]-vectexs[5]));
var P3=Math.sqrt((vectexs[4]-vectexs[0])*(vectexs[4]-vectexs[0])+(vectexs[5]-vectexs[1])*(vectexs[5]-vectexs[1]));
if(P1>P2){PMax=P1;Ver="0";}else{PMax=P2;Ver="2";}
if(PMax<P3){PMax=P3;Ver="4";}
var Vec1=new vec2(vectexs[0],vectexs[1]);
var Vec2=new vec2(vectexs[2],vectexs[3]);
var Vec3=new vec2(vectexs[4],vectexs[5]);
var Vec4=new vec2(x,y);
var x12=-(Vec1._y-(Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)*Vec1._x-Vec4._y-(Vec2._x-Vec1._x)/(Vec2._y-Vec1._y)*Vec4._x)/((Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)+(Vec2._x-Vec1._x)/(Vec2._y-Vec1._y));
var y12=(Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)*x12+Vec1._y-(Vec2._y-Vec1._y)/(Vec2._x-Vec1._x)*Vec1._x;
var x23=-(Vec2._y-(Vec3._y-Vec2._y)/(Vec3._x-Vec2._x)*Vec2._x-Vec4._y-(Vec3._x-Vec2._x)/(Vec3._y-Vec2._y)*Vec4._x)/((Vec3._y-Vec2._y)/(Vec3._x-Vec2._x)+(Vec3._x-Vec2._x)/(Vec3._y-Vec2._y));
var y23=(Vec3._y-Vec2._y)/(Vec3._x-Vec2._x)*x23+Vec2._y-(Vec3._y-Vec2._y)/(Vec3._x-Vec2._x)*Vec2._x;
var x31=-(Vec3._y-(Vec1._y-Vec3._y)/(Vec1._x-Vec3._x)*Vec3._x-Vec4._y-(Vec1._x-Vec3._x)/(Vec1._y-Vec3._y)*Vec4._x)/((Vec1._y-Vec3._y)/(Vec1._x-Vec3._x)+(Vec1._x-Vec3._x)/(Vec1._y-Vec3._y));
var y31=(Vec1._y-Vec3._y)/(Vec1._x-Vec3._x)*x31+Vec3._y-(Vec1._y-Vec3._y)/(Vec1._x-Vec3._x)*Vec3._x;
//计算三条垂直线的矢量
var nor1=new vec2(x12-Vec4._x,y12-Vec4._y)
var nor2=new vec2(x23-Vec4._x,y23-Vec4._y)
var nor3=new vec2(x31-Vec4._x,y31-Vec4._y)
//根据点积公式算夹角
var A1=vec2.angleBetween(nor1,nor2)/3.1415926*180;
var A2=vec2.angleBetween(nor2,nor3)/3.1415926*180;
var A3=vec2.angleBetween(nor3,nor1)/3.1415926*180;
//目前的判断基本准确,可能在钝边三角形有时候判断出错,可能是因为第四个点落点问题
if(Ver=="0")
{
console.log("最长的边为第一条边,边长为:"+PMax+";对应的两个角为:"+A1+","+A3);
if(A1>=90&&A3>=90)
{
console.log("第四个点在三角形范围内。");
}else
{
console.log("第四个点 不 在三角形范围内。");
}
}else if(Ver=="2")
{
console.log("最长的边为第二条边,边长为:"+PMax+";对应的两个角为:"+A1+","+A2);
if(A1>=90&&A2>=90)
{
console.log("第四个点在三角形范围内。");
}else
{
console.log("第四个点 不 在三角形范围内。");
}
}else if(Ver=="4")
{
console.log("最长的边为第三条边,边长为:"+PMax+";对应的两个角为:"+A2+","+A3);
if(A2>=90&&A3>=90)
{
console.log("第四个点在三角形范围内。");
}else
{
console.log("第四个点 不 在三角形范围内。");
}
}
};
canvas.addEventListener('mouseup',handler,false);
canvas.addEventListener('mousemove',handlerm,false);
document.addEventListener('keydown',e=>{
if(e.key=='c')
{
drawconvex();
}
});
//定义vec2类型
function vec2(x,y){
this._x = x;
this._y = y;
}
vec2.angleBetween = function(v1,v2){
if(!v1.isNormalized()){
v1 = v1.clone().normalize();
}
if(!v2.isNormalized()){
v2 = v2.clone().normalize();
}
return Math.acos(v1.dotProd(v2));
};
vec2.prototype = {
setX : function(x){
this._x = x;
},
getX : function(){
return this._x;
},
setY : function(y){
this._y = y;
},
getY : function(){
return this._y;
},
clone : function(){
return new vec2(this._x,this._y);
},
zero : function(){
this._x = 0;
this._y = 0;
return this;
},
isZero : function(){
return this._x == 0 && this._y == 0;
},
setLength : function(length){
var angle = this.getAngle();
this._x = Math.cos(angle) * length;
this._y = Math.sin(angle) * length;
},
getLength : function(){
return Math.sqrt(this.getLengthSQ());
},
getLengthSQ : function(){
return this._x * this._x + this._y * this._y;
},
setAngle : function(angle){
var length = this.getLength();
this._x = Math.cos(angle) * length;
this._y = Math.sin(angle) * length;
},
getAngle : function(){
return Math.atan2(this._y,this._x);
},
normalize : function(){
var length = this.getLength();
if(length == 0){
this._x = 1;
return this;
}
this._x /= length;
this._y /= length;
return this;
},
isNormalized : function(){
return this.getLength() == 1.0;
},
reverse : function(){
this._x = -this._x;
this._y = -this._y;
return this;
},
dotProd : function(v2){
return this._x * v2.getX() + this._y * v2.getY();
},
crossProd : function(v2){
return this._x * v2.getY() - this._y * v2.getX();
},
getPerp : function(){
return new vec2(-this._y,this._x);
},
sign : function(v2){
return this.getPerp().dotProd(v2) < 0 ? -1 : 1;
},
dist : function(v2){
return Math.sqrt(this.distSQ(v2));
},
distSQ : function(v2){
var dx = v2.getX() - this._x;
dy = v2.getY() - this._y;
return dx * dx + dy * dy;
},
add : function(v2){
return new vec2(this._x + v2.getX(),this._y + this.getY());
},
subtract : function(v2){
return new vec2(this._x - v2.getX(),this._y - v2.getY());
},
multiply : function(n){
return new vec2(this._x * n,this._y * n);
},
divide : function(n){
return new vec2(this._x / n,this._y / n);
},
equals : function(v2){
return this._x == v2.getX() && this._y == v2.getY();
}
};
function dealSelectFiles() {
var file = document.getElementById("selectFiles").files[0];
var name = file.name;//读取选中文件的文件名
var path = document.getElementById("selectFiles").value;//读取选中文件的路径
console.log("文件名:"+name+"大小:"+path);
//获取读取我文件的File对象
//alert(title:'hello',content:'success');
var reader = new FileReader();//这是核心,读取操作就是由它完成.
reader.readAsText(file,'UTF-8');//读取文件的内容,也可以读取文件的URL
reader.onload = function (event) {
//当读取完成后回调这个函数,然后此时文件的内容存储到了result中,直接操作即可
document.getElementById("txt").value =event.target.result;
document.getElementById("txt").style.display="block";
}
}
function drawconvex()
{
console.log(vectexs.length);
}
function ExtrudeShape()
{
positions.push(x0,y0);
var pos=[];
var poss=[]
for(var m=0;m<positions.length/2;m++)
{
pos=[positions[2*m],positions[2*m+1]];
poss.push(pos);
}
if(convex(poss,positions.length)==1)
{
//alert("凸集");
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(positions),gl.STATIC_DRAW);
this.show(gl);
//vertexs里面存储了所有顶点的信息,可以利用来拉伸出立方体
//如P1,P2,P3,P4,P5,P6;先画P1,P2,P3;P1,P3,P4;P1,P4,P5;P1,P5,P6四个三角形
//再画对面P11,P12,P13;P11,P13,P14;P11,P14,P15;P11,P15,P16四个三角形
//再画旁边P1,P2,P11;P12,P2,P11;P2,P3,P12;P13,P3,P12;P3,P4,P13;P14,P4,P13;
//P4,P5,P14;P15,P5,P14;P5,P6,P15;P16,P6,P15;P6,P1,P16;P11,P1,P16;十二个三角形
var vers =[];
var cors=[];
for(var m=0;m<vectexs.length/2;m++)
{
vers.push(vectexs[2*m],vectexs[2*m+1],-100);
cors.push(1/(m+1),0,1);
vers.push(vectexs[2*m],vectexs[2*m+1],100);
cors.push(1/(m+1),1,0);
}
var inds=[];
//准备顶点的顺序
for(var m=1;m<vers.length/6-1;m++)
{
inds.push(0,2*m,2*m+2);
}
var btm=vers.length/3;
for(var m=0;m<vers.length/6;m++)
{
inds.push(2*m % btm,(2*m+1) % btm,(2*m+2)% btm);
inds.push((2*m+1)% btm,(2*m+2)% btm,(2*m+3)% btm);
}
for(var m=1;m<vers.length/6-1;m++)
{
inds.push(1,2*m+1,2*m+3);
}
var _Pmatrix;
var _Vmatrix;
var _Mmatrix;
var index_buffer;
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vers), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cors), gl.STATIC_DRAW);
// Create and store data into index buffer
//attribute变量和uniform变量,一次只能传输一个顶点的信息
//缓冲区对象可以一次性的向着色器传入多个顶点的数据
//步骤一:创建buffer
index_buffer = gl.createBuffer ();
//步骤二:绑定buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
//步骤三:数据写入buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(inds), gl.STATIC_DRAW);
/*=================== SHADERS =================== */
var vertCode = 'attribute vec3 position;'+
'attribute vec3 a_Screen_Size;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'vec3 outposition = (position / a_Screen_Size) * 2.0 - 1.0;'+
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(outposition, 1.0);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderprogram = gl.createProgram();
gl.attachShader(shaderprogram, vertShader);
gl.attachShader(shaderprogram, fragShader);
gl.linkProgram(shaderprogram);
var a_Screen_Size = gl.getAttribLocation(propgram,'a_Screen_Size');//取到屏幕的大小
gl.vertexAttrib3f(a_Screen_Size,canvas.width,canvas.height,100);//设置参数
/*======== Associating attributes to vertex shader =====*/
_Pmatrix = gl.getUniformLocation(shaderprogram, "Pmatrix");
_Vmatrix = gl.getUniformLocation(shaderprogram, "Vmatrix");
_Mmatrix = gl.getUniformLocation(shaderprogram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var _position = gl.getAttribLocation(shaderprogram, "position");
//步骤四:buffer对象分配给一个attribute变量
gl.vertexAttribPointer(_position, 3, gl.FLOAT, false,0,0);
//步骤五:开启attribute变量
gl.enableVertexAttribArray(_position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var _color = gl.getAttribLocation(shaderprogram, "color");
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false,0,0) ;
gl.enableVertexAttribArray(_color);
gl.useProgram(shaderprogram);
//透视矩阵
//40-y方向视角,canvas.width/canvas.height-宽高比,1-Znear,100-Zfar
//var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
//正交投影
var proj_matrix = orth_projection(-1,1,-1,1,1,100);
//模型举证
var mo_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
//视图矩阵
var view_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
view_matrix[14] = view_matrix[14]-6;
/*================= Mouse events ======================*/
var AMORTIZATION = 0.95;
var drag = false;
var old_x, old_y;
var dX = 0, dY = 0;
var THETA = 0,
PHI = 0;
var time_old = 0;
var mouseDown = function(e) {
drag = true;
old_x = e.pageX, old_y = e.pageY;
console.log(e.pageX+"_"+e.pageY);
//要搞清楚每一个三角形在屏幕上的点的坐标
//然后判断点的坐标是否在三角形内
e.preventDefault();
return false;
};
var mouseUp = function(e){
drag = false;
};
var mouseMove = function(e) {
//1.先计算三角形的三条边长
//2.计算出点击点到三条边的法向矢量
//3.如果到最长边的法向矢量和另外2个法向矢量的夹角都大于90度(小于180),点在三角形内部,否则在三角形外面
dX = (e.pageX-old_x)*2*Math.PI/canvas.width,
dY = (e.pageY-old_y)*2*Math.PI/canvas.height;
THETA+= dX;
PHI+=dY;
old_x = e.pageX, old_y = e.pageY;
e.preventDefault();
};
canvas.removeEventListener('mouseup',handler,false);
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mouseup", mouseUp, false);
canvas.addEventListener("mouseout", mouseUp, false);
canvas.addEventListener("mousemove", mouseMove, false);
var animate = function(time) {
var dt = time-time_old;
if (!drag) {
dX *= AMORTIZATION, dY*=AMORTIZATION;
THETA+=dX, PHI+=dY;
}
//set model matrix to I4
mo_matrix[0] = 1, mo_matrix[1] = 0, mo_matrix[2] = 0,
mo_matrix[3] = 0,
mo_matrix[4] = 0, mo_matrix[5] = 1, mo_matrix[6] = 0,
mo_matrix[7] = 0,
mo_matrix[8] = 0, mo_matrix[9] = 0, mo_matrix[10] = 1,
mo_matrix[11] = 0,
mo_matrix[12] = 0, mo_matrix[13] = 0, mo_matrix[14] = 0,
mo_matrix[15] = 1;
rotateY(mo_matrix, THETA);
rotateX(mo_matrix, PHI);
time_old = time;
gl.enable(gl.DEPTH_TEST);
// gl.depthFunc(gl.LEQUAL);
gl.clearColor(1, 1, 1, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(_Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(_Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(_Mmatrix, false, mo_matrix);
//绑定index_buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
//用index_buffer中的顶点画模型
gl.drawElements(gl.TRIANGLES, inds.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
}else if(convex(poss,positions.length)==-1)
{
alert("凹集");
}else if(convex(poss,positions.length)==0)
{
alert("曲线不符合要求,无法计算");
}
}
const buttonext = document.getElementById('btne');
buttonext.onclick = () => {
drawconvex();
}
// 获取按钮
const button = document.getElementById('btn')
// 给按钮添加点击事件
button.onclick = () => {
// 要保存的字符串
var stringData ='您输入的坐标是:';
for(var m=0;m<vectexs.length;m++)
{
if(m % 2==1)
{
stringData=stringData+vectexs[m]+";";
}else
{
stringData=stringData+vectexs[m]+"-";
}
}
// dada 表示要转换的字符串数据,type 表示要转换的数据格式
const blob = new Blob([stringData], {
type: "text/plain;charset=utf-8"
})
// 根据 blob生成 url链接
const objectURL = URL.createObjectURL(blob)
// 创建一个 a 标签Tag
const aTag = document.createElement('a')
// 设置文件的下载地址
aTag.href = objectURL
// 设置保存后的文件名称
aTag.download = "文本文件.txt"
// 给 a 标签添加点击事件
document.body.appendChild(aTag)
let evt = document.createEvent("MouseEvents");
evt.initEvent("click", true, true);
aTag.dispatchEvent(evt);
document.body.removeChild(aTag);
}
/*=========================rotation================*/
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m[1], mv5 = m[5], mv9 = m[9];
m[1] = m[1]*c-m[2]*s;
m[5] = m[5]*c-m[6]*s;
m[9] = m[9]*c-m[10]*s;
m[2] = m[2]*c+mv1*s;
m[6] = m[6]*c+mv5*s;
m[10] = m[10]*c+mv9*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]+s*m[2];
m[4] = c*m[4]+s*m[6];
m[8] = c*m[8]+s*m[10];
m[2] = c*m[2]-s*mv0;
m[6] = c*m[6]-s*mv4;
m[10] = c*m[10]-s*mv8;
}
function orth_projection(Lpos,Rpos,Tpos,Bpos,Znear,Zfar)
{
return [2/(Rpos-Lpos),0,0,0,
0,2/(Tpos-Bpos),0,0,
0,0,1/(Zfar-Znear),0,
-(Rpos+Lpos)/(Rpos-Lpos),-(Tpos+Bpos)/(Tpos-Bpos),-Znear/(Zfar-Znear),1];
}
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
1/ang/a, 0 , 0, 0,
0, 1/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
function abs(x,y)
{
if(x>y)
{
return x-y;
}else
{
return y-x;
}
}
function circle()
{
alert("Hi");
//r*cos(60*m),r*sin(60*m)
}
function convex(p,n){
var j,k,z;
var flag=0;
if(n<3){
return 0;
}
for(var i=0;i<n/2-1;i++)
{
j=(i+1)%(n/2-1);
k=(i+2)%(n/2-1);
z=(p[j][0]-p[i][0])*(p[k][1]-p[j][1]);
z-=(p[j][1]-p[i][1])*(p[k][0]-p[j][0]);
if(z<0)
{
flag|=1;
}else if(z>0)
{
flag|=2;
}
if(flag==3)
{
return -1;
}
}
if(flag!=0)
{
return 1;
}else
{
return 0;
}
}
// this.show(gl);
function show(gl) {
gl.clearColor(1,1,1,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.LINES, 0, positions.length / 2);
}
//随机取到相关的颜色
function randomColor() {
return {
r: Math.random() * 255,
g: Math.random() * 255,
b: Math.random() * 255,
a: 1 * 1
};
}
</script>
</body>
</html>
将以上代码保存到一个html文件里面,在浏览其中打开文件,就可以看到效果了。
备注:代码已升级,鼠标在桌面移动时,会看到鼠标所在的点是否在三角形范围内。