[从头学数学] 第172节 直线与方程
[机器小伟]在[project师阿伟]的陪同下进入了结丹初期的修炼。
这次要修炼的目标是[直线与方程]。
正剧開始:
星历2016年04月11日 09:30:00, 银河系厄尔斯星球中华帝国江南行省。
[project师阿伟]正在和[机器小伟]一起研究[直线与方程]。
開始今天的修炼之前,小伟先整理了一下这件法器:
<span style="font-size:18px;"> if (1) {
var r = 20;
config.setSector(1,1,1,1);
config.graphPaper2D(0, 0, r);
config.axis2D(0, 0, 180);
var transform = new Transform();
var a = 4, b = 3, h = 2;
var edges = 4;
var array = shape.trapezoid(0, 0, 0, a, b, Math.PI/3);
var scale = 2.5*r;
array = transform.flipX(array);
shape.angleDraw(transform.translate(array, -200/scale, 0), 'cyan', scale);
shape.areaDraw(array, 'red', scale);
}</span>
看来用得上它的地方非常多。小伟非常惬意。
<span style="font-size:18px;">def slopeCalc(x1, y1, x2, y2):
if (x1 == x2):
print('k = Inf');
else:
print('k = {0}'.format((y2-y1)/(x2-x1)));</span>>>>
[3, 2] 与 [-4, 1] 两点的斜率是 0.14285714285714285;
[-4, 1] 与 [0, -1] 两点的斜率是 -0.5;
[0, -1] 与 [3, 2] 两点的斜率是 1.0;
<span style="font-size:18px;">def slopeCalc(x1, y1, x2, y2):
if (x1 == x2):
return float('inf');
else:
return (y2-y1)/(x2-x1);
def tmp():
triangle = [[3, 2],[-4, 1], [0, -1]];
size = len(triangle);
for i in range(size):
x1 = triangle[i%3][0];
y1 = triangle[i%3][1];
x2 = triangle[(i+1)%3][0];
y2 = triangle[(i+1)%3][1];
print('[{0}, {1}] 与 [{2}, {3}] 两点的斜率是 {4};'\
.format(x1, y1, x2, y2, slopeCalc(x1,y1,x2,y2)));
</span><span style="font-size:18px;"> if (1) {
var r = 20;
config.setSector(1,1,1,1);
config.graphPaper2D(0, 0, r);
config.axis2D(0, 0, 180);
var transform = new Transform();
var a = 4, b = 3, h = 2;
var edges = 4;
var array = [[3,2],[-4,1],[0,-1]];
var scale = 2.5*r;
shape.areaDraw(transform.translate(array, 0, -150/scale), 'red', scale);
shape.angleDraw([].concat(array), 'orange', scale);
}</span>
<span style="font-size:18px;"> if (1) {
var r = 20;
config.setSector(1,1,1,1);
config.graphPaper2D(0, 0, r);
config.axis2D(0, 0,180, 1.5);
//坐标轴设定
var scaleX = 2*r, scaleY = 2*r;
var spaceX = 2, spaceY = 2;
var xS = -10, xE = 10;
var yS = -10, yE = 10;
config.axisSpacing(xS, xE, spaceX, scaleX, 'X');
config.axisSpacing(yS, yE, spaceY, scaleY, 'Y');
var transform = new Transform();
//存放函数图像上的点
var a = [], b = [], c = [], d = [];
//须要显示的函数说明
var f1 = 'y=x', f2 = 'y=-x', f3 = 'y=2x', f4 = 'y=-3x';
//函数描点
for (var x = xS; x <= xE; x+=1) {
if (x != 0) {
a.push([x, x]);
b.push([x, -x]);
c.push([x, 2*x]);
d.push([x, -3*x]);
}
}
//存放暂时数组
var tmp = [];
//显示变换
if (a.length > 0) {
a = transform.scale(transform.translate(a, 0, 0), scaleX/spaceX, scaleY/spaceY);
//函数1
tmp = [].concat(a);
shape.pointDraw(tmp, 'red');
tmp = [].concat(a);
shape.multiLineDraw(tmp, 'pink');
plot.setFillStyle('red');
plot.fillText(f1, 100, -90, 200);
}
if (b.length > 0) {
b = transform.scale(transform.translate(b, 0, 0), scaleX/spaceX, scaleY/spaceY);
//函数2
tmp = [].concat(b);
shape.pointDraw(tmp, 'blue');
tmp = [].concat(b);
shape.multiLineDraw(tmp, '#22CCFF');
plot.setFillStyle('blue');
plot.fillText(f2, 100, -120, 200);
}
if (c.length > 0) {
c = transform.scale(transform.translate(c, 0, 0), scaleX/spaceX, scaleY/spaceY);
tmp = [].concat(c);
shape.pointDraw(tmp, 'green');
tmp = [].concat(c);
shape.multiLineDraw(tmp, '#CCFF22');
plot.setFillStyle('green');
plot.fillText(f3, 100, -150, 200);
}
if (d.length > 0) {
d = transform.scale(transform.translate(d, 0, 0), scaleX/spaceX, scaleY/spaceY);
tmp = [].concat(d);
shape.pointDraw(tmp, 'orange');
tmp = [].concat(d);
shape.multiLineDraw(tmp, '#CC8800');
plot.setFillStyle('orange');
plot.fillText(f4, 100, -180, 200);
}
}</span>
>>>
[2, 3] 与 [-4, 0] 两点的斜率是 0.5;
[-4, 0] 与 [-3, 1] 两点的斜率是 1.0;
[-3, 1] 与 [2, 3] 两点的斜率是 0.4;
[2, 3] 与 [-4, 0] 两点的斜率是 0.5;
<span style="font-size:18px;">def slopeCalc(x1, y1, x2, y2):
if (x1 == x2):
return float('inf');
else:
return (y2-y1)/(x2-x1);
def tmp():
points = [[2,3],[-4,0],[-3,1],[-1,2]];
size = len(points);
for i in range(size):
x1 = points[i%3][0];
y1 = points[i%3][1];
x2 = points[(i+1)%3][0];
y2 = points[(i+1)%3][1];
print('[{0}, {1}] 与 [{2}, {3}] 两点的斜率是 {4};'\
.format(x1, y1, x2, y2, slopeCalc(x1,y1,x2,y2)));</span>
<span style="font-size:18px;"> if (1) {
var r = 20;
config.setSector(1,1,1,1);
config.graphPaper2D(0, 0, r);
config.axis2D(0, 0, 180);
var transform = new Transform();
var a = 4, b = 3, h = 2;
var edges = 4;
var array = [[2,3],[-4,0],[-3,1],[-1,2]];
var scale = 3*r;
shape.areaDraw(transform.translate(array, 0, -150/scale), 'red', scale);
shape.angleDraw([].concat(array), 'orange', scale, 'AQPB');
}</span>
<span style="font-size:18px;"> if (1) {
var r = 20;
config.setSector(1,1,1,1);
config.graphPaper2D(0, 0, r);
config.axis2D(0, 0, 180);
var transform = new Transform();
var a = 4, b = 3, h = 2;
var edges = 4;
var array = [[0,0],[2,-1],[4,2],[2,3]];
var scale = 3*r;
shape.areaDraw(transform.translate(array, 0, -150/scale), 'red', scale);
shape.angleDraw([].concat(array), 'orange', scale, 'CDAB');
}</span>>>>
[0, 0] 与 [2, -1] 两点的斜率是 -0.5;
[2, -1] 与 [4, 2] 两点的斜率是 1.5;
[4, 2] 与 [0, 0] 两点的斜率是 0.5;
[0, 0] 与 [2, -1] 两点的斜率是 -0.5;
>>>
[-6, 0] 与 [3, 6] 两点的斜率是 0.6666666666666666;
[3, 6] 与 [0, 3] 两点的斜率是 1.0;
[0, 3] 与 [6, -6] 两点的斜率是 -1.5;
[6, -6] 与 [-6, 0] 两点的斜率是 -0.5;
<span style="font-size:18px;">def slopeCalc(x1, y1, x2, y2):
if (x1 == x2):
return float('inf');
else:
return (y2-y1)/(x2-x1);
def tmp():
points = [[-6,0],[3,6],[0,3],[6,-6]];
size = len(points);
for i in range(size):
x1 = points[i%size][0];
y1 = points[i%size][1];
x2 = points[(i+1)%size][0];
y2 = points[(i+1)%size][1];
print('[{0}, {1}] 与 [{2}, {3}] 两点的斜率是 {4};'\
.format(x1, y1, x2, y2, slopeCalc(x1,y1,x2,y2)));
</span>
<span style="font-size:18px;"> if (1) {
var r = 20;
config.setSector(1,1,1,1);
config.graphPaper2D(0, 0, r);
config.axis2D(0, 0, 180);
var transform = new Transform();
var a = 4, b = 3, h = 2;
var edges = 4;
var array = [[5,-1],[1,1],[2,3]];
var scale = 2*r;
shape.areaDraw(transform.translate(array, 0, -50/r), 'red', scale);
shape.angleDraw([].concat(array), 'orange', scale, 'BPAQ');
}
</span>
这个问题的答案是这种:魔术师撒谎了。
魔术师改进后的地毯不是矩形的。
<span style="font-size:18px;"> if (1) {
var r = 20;
config.setSector(1,1,1,1);
config.graphPaper2D(0, 0, r);
config.axis2D(0, 0, 180);
var transform = new Transform();
var a = 4, b = 3, h = 2;
var edges = 4;
var array = [[0,0],[0,-8],[8,0],[5,-8]];
var scale = r;
array = shape.angularSort(array);
array = transform.translate(array, 0, 8);
shape.areaDraw(transform.translate(array, 0, -200/scale), 'red', scale);
shape.angleDraw([].concat(array), 'orange', scale);
var triangle = new Triangle();
var array2 = triangle.know2edges([5, 13], 90);
array2 = transform.translate(array2, -10, 5);
shape.angleDraw([].concat(array2), 'purple', scale);
}</span>多出来0.5个角度。
总面积:
>>> 52*2+65
169
>>>
[-5, 0] 与 [3, -3] 两点的斜率是 -0.375;
[-5, 0] 与 [0, 2] 两点的斜率是 0.4;
[-5, 0] 与 [1.5, -0.5] 两点的斜率是 -0.07692307692307693;
[3, -3] 与 [0, 2] 两点的斜率是 -1.6666666666666667;
[3, -3] 与 [1.5, -0.5] 两点的斜率是 -1.6666666666666667;
[0, 2] 与 [1.5, -0.5] 两点的斜率是 -1.6666666666666667;
<span style="font-size:18px;">def tmp():
points = [[-5,0],[3,-3],[0,2],[1.5,-0.5]];
size = len(points);
for i in range(size):
for j in range(i+1, size):
x1 = points[i%size][0];
y1 = points[i%size][1];
x2 = points[j%size][0];
y2 = points[j%size][1];
print('[{0}, {1}] 与 [{2}, {3}] 两点的斜率是 {4};'\
.format(x1, y1, x2, y2, slopeCalc(x1,y1,x2,y2)));</span>
<span style="font-size:18px;"> if (1) {
//运用行列式解线性方程组
var matrix = new Matrix();
var matrixArray = new Array();
var rowArray = new Array();
var ma, mb;
//二元一次方程组[[A1,B1,C1], [A2,B2,C2]]
//Ax+By+C=0
var a = [[3, 4, -2], [2,1,2]];
//二阶
var rank = 2;
for (var i = 0; i < rank; i++) {
matrixArray.push([a[i][0], a[i][1]]);
}
ma = matrix.deepCopy(matrixArray);
for (var i = 0; i < rank; i++) {
ma[i][0] = -a[i][2];
}
mb = matrix.deepCopy(matrixArray);
for (var i = 0; i < rank; i++) {
mb[i][1] = -a[i][2];
}
var d, da, db;
d = matrix.delta(matrixArray);
da = matrix.delta(ma);
db = matrix.delta(mb);
matrix.print(matrixArray);
document.write('d = ' + d+'<br/>');
matrix.print(ma);
document.write('da = ' + da+'<br/>');
matrix.print(mb);
document.write('db = '+db+'<br/>');
var s = 'x = da/d = '+ (da/d).toFixed(2)+', y = db/d = '+(db/d).toFixed(2);
document.write(s+'<br/>');
}</span>3.00 , 4.00 ,
2.00 , 1.00 ,
d = -5
2.00 , 4.00 ,
-2.00 , 1.00 ,
da = 10
3.00 , 2.00 ,
2.00 , -2.00 ,
db = -10
x = da/d = -2.00, y = db/d = 2.00
1.00 , -1.00 ,
3.00 , 3.00 ,
d = 6
0.00 , -1.00 ,
10.00 , 3.00 ,
da = 10
1.00 , 0.00 ,
3.00 , 10.00 ,
db = 10
x = da/d = 1.67, y = db/d = 1.67
//二元一次方程组[[A1,B1,C1], [A2,B2,C2]] //Ax+By+C=0 var a = [[1,-1,0], [3,3,-10]];
3.00 , -1.00 ,
6.00 , -2.00 ,
d = 0
-4.00 , -1.00 ,
1.00 , -2.00 ,
da = 9
3.00 , -4.00 ,
6.00 , 1.00 ,
db = 27
x = da/d = Infinity, y = db/d = Infinity
说明第(2)小题无交点
<span style="font-size:18px;"> //二元一次方程组[[A1,B1,C1], [A2,B2,C2]] //Ax+By+C=0 var a = [[3,-1,4], [6,-2,-1]];</span>
3.00 , 4.00 ,
6.00 , 8.00 ,
d = 0
5.00 , 4.00 ,
10.00 , 8.00 ,
da = 0
3.00 , 5.00 ,
6.00 , 10.00 ,
db = 0
x = da/d = NaN, y = db/d = NaN
第(3)小题这是有无穷多组解的节奏。
//二元一次方程组[[A1,B1,C1], [A2,B2,C2]] //Ax+By+C=0 var a = [[3,4,-5], [6,8,-10]];
算得对不正确呢?
既然[人叫板老师]也认为是这种答案,那就说明小伟的工具是可用的。
#点到直线的距离[x,y]-->ax+by+c=0
def disOfP2L(x, y, a, b, c):
return abs(a*x+b*y+c)/(a*a+b*b)**0.5;>>>
1.6666666666666667
print(disOfP2L(-1,2,3,0,-2));
if (1) {
var r = 20;
config.setSector(1,1,1,1);
config.graphPaper2D(0, 0, r);
config.axis2D(0, 0, 180);
var transform = new Transform();
var array = [[1,3],[3,1],[-1,0]];
var scale = 2*r;
array = shape.angularSort(array);
shape.areaDraw(transform.translate(array, 0, -100/scale), 'red', scale);
shape.angleDraw([].concat(array), 'orange', scale, 'ACB');
}
>>> 23/159*53**0.5
1.053097656939949
2.00 , -7.00 ,
6.00 , -21.00 ,
d = 0
8.00 , -7.00 ,
1.00 , -21.00 ,
da = -161
2.00 , 8.00 ,
6.00 , 1.00 ,
db = -46
x = da/d = -Infinity, y = db/d = -Infinity
两条直线平行。 距离是:1.053
这两条直线还真是平行。
<span style="font-size:18px;"> if (1) {
//运用行列式解线性方程组
var matrix = new Matrix();
var matrixArray = new Array();
var rowArray = new Array();
var ma, mb;
//二元一次方程组[[A1,B1,C1], [A2,B2,C2]]
//Ax+By+C=0
var a = [[2,-7,-8], [6,-21,-1]];
//二阶
var rank = 2;
for (var i = 0; i < rank; i++) {
matrixArray.push([a[i][0], a[i][1]]);
}
ma = matrix.deepCopy(matrixArray);
for (var i = 0; i < rank; i++) {
ma[i][0] = -a[i][2];
}
mb = matrix.deepCopy(matrixArray);
for (var i = 0; i < rank; i++) {
mb[i][1] = -a[i][2];
}
var d, da, db;
d = matrix.delta(matrixArray);
da = matrix.delta(ma);
db = matrix.delta(mb);
matrix.print(matrixArray);
document.write('d = ' + d+'<br/>');
matrix.print(ma);
document.write('da = ' + da+'<br/>');
matrix.print(mb);
document.write('db = '+db+'<br/>');
var s = 'x = da/d = '+ (da/d).toFixed(2)+', y = db/d = '+(db/d).toFixed(2);
document.write(s+'<br/>');
if (d == 0 && (da != db)) {
var r = 0;
if (a[0][0] != 0) {
r = a[1][0]/a[0][0];
}
else {
r = a[1][1]/a[0][1];
}
var distance = (a[1][2]/r-a[0][2])/Math.sqrt(a[0][0]*a[0][0] + a[0][1]*a[0][1]);
document.write('两条直线平行, 距离是:'+ distance.toFixed(3)+'<br/>');
}
}</span>
这里贴一下小伟用到的Shape类和Matrix类。以防遗漏。
/**
* @usage 经常使用形状类
* @author mw
* @date 2015年11月29日 星期日 10:21:18
* @param
* @return
*
*/
var shape = function Shape() {
//以给定点为中点的矩形
this.strokeRect = function(x, y, w, h) {
w = Math.abs(w);
h = Math.abs(h);
return plot.strokeRect(x-w/2, y-h/2, w, h);
}
//以给定点为中点的矩形
this.fillRect = function(x, y, w, h) {
w = Math.abs(w);
h = Math.abs(h);
return plot.fillRect(x-w/2, y-h/2, w, h);
}
/**
* @usage 绘制点阵列
* @author mw
* @date 2016年02月21日 星期日 15:16:47
* @param
* @return
*
*/
this.pointDraw = function(array, style, scale, showLable, lable) {
//已经考虑到y轴坐标的取反问题。仅仅需传入原始坐标数组就可以
style = style ? style : 'black';
scale = scale ? scale : 1;
lable = lable ? lable : 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
lables = lable.length;
showLable = showLable ?
showLable : 0;
var x = y = index = 0;
//点的大小
var pSize = 3;
plot.save()
.setFillStyle(style);
var a = new Array();
a = array[0];
//y坐标取反是由于canvas中y坐标以向下为正。与笛卡尔坐标系相反
if (a.length != 2) {
//坐标是流水模式。既x1, y1, x2, y2,...
while (array.length > 0) {
x = array.shift()*scale;
y = -array.shift()*scale;
shape.fillCircle(x, y, pSize);
if (showLable) {
plot.fillText(lable[index++%lables], x+5, y+10, 30);
}
}
}
else {
//坐标是有序对模式,即[x1, y1], [x2, y2], ...
while (array.length > 0) {
a = array.shift();
x = a[0]*scale;
y = -a[1]*scale;
shape.fillCircle(x, y, pSize);
if (showLable) {
plot.fillText(lable[index++%lables], x+5, y+10, 30);
}
}
}
plot.restore();
}
//连接成折线
this.multiLineDraw = function(array,style, scale) {
//已经考虑到y轴坐标的取反问题。仅仅需传入原始坐标数组就可以
style = style ? style : 'black';
scale = scale ?
scale : 1;
plot.save()
.setStrokeStyle(style);
var a = new Array();
var x = y = index = 0;
a = array[0];
if (a.length < 2) {
x = array.shift()*scale;
y = -array.shift()*scale;
if (array.length > 2 && array.length % 2 == 0) {
plot.beginPath()
.moveTo(x, y);
while (array.length > 0) {
x = array.shift()*scale;
y = -array.shift()*scale;
plot.lineTo(x, y);
}
plot.moveTo(x, y)
.closePath()
.stroke();
}
}
else if (a.length == 2) {
if (array.length > 2) {
a = array.shift();
x = a[0]*scale;
y = -a[1]*scale;
plot.beginPath()
.moveTo(x, y);
while (array.length > 0) {
a = array.shift();
x = a[0]*scale;
y = -a[1]*scale;
plot.lineTo(x, y);
}
plot.moveTo(x, y)
.closePath()
.stroke();
}
else {
var a = array.shift();
var b = array.shift();
plot.beginPath()
.moveTo(a[0]*scale, -a[1]*scale)
.lineTo(b[0]*scale, -b[1]*scale)
.closePath()
.stroke();
}
}
plot.restore();
}
this.fillDraw = function(array, style, scale) {
//已经考虑到y轴坐标的取反问题。仅仅需传入原始坐标数组就可以
style = style ? style : 'black';
scale = scale ? scale : 1;
plot.save()
.setFillStyle(style);
var a = array[0];
if (a.length != 2) {
if (array.length > 2 && array.length % 2 == 0) {
plot.beginPath()
.moveTo(array.shift()*scale, -array.shift()*scale);
while (array.length > 0) {
plot.lineTo(array.shift()*scale, -array.shift()*scale);
}
plot.closePath()
.fill();
}
}
else {
if (array.length > 2) {
a = array.shift();
plot.beginPath()
.moveTo(a[0]*scale, -a[1]*scale);
while (array.length > 0) {
a = array.shift();
plot.lineTo(a[0]*scale, -a[1]*scale);
}
plot.closePath()
.fill();
}
}
plot.restore();
}
this.strokeDraw = function(array,style, scale) {
//已经考虑到y轴坐标的取反问题,仅仅需传入原始坐标数组就可以
style = style ? style : 'black';
scale = scale ?
scale : 1;
plot.save()
.setStrokeStyle(style);
var a = array[0];
if (a.length != 2) {
if (array.length > 2 && array.length % 2 == 0) {
plot.beginPath()
.moveTo(array.shift()*scale, -array.shift()*scale);
while (array.length > 0) {
plot.lineTo(array.shift()*scale, -array.shift()*scale);
}
plot.closePath()
.stroke();
}
}
else {
if (array.length > 2) {
a = array.shift();
plot.beginPath()
.moveTo(a[0]*scale, -a[1]*scale);
while (array.length > 0) {
a = array.shift();
plot.lineTo(a[0]*scale, -a[1]*scale);
}
plot.closePath()
.stroke();
}
}
plot.restore();
}
this.angleDraw = function(array, style, scale, vertexLabel) {
//vertexLabel是顶点编号顺序字符串 ABC,...
style = style ? style : 'black';
//array是一个存放二维坐标点序列的数组
var a0 = new Array();
var len = array.length;
var len_1 = array[0].length;
for (var i = 0; i < len; i++) {
a0.push(array[i]);
}
scale = scale ? scale : 1;
len = a0.length;
if (scale != 1 && scale > 0) {
for (var i = 0; i < len; i++) {
for (var j = 0; j < 2; j++) {
a0[i][j]*=scale;
}
}
}
//进行环状排序,这样传入的array就能够随意顺序放置坐标点。
var a = this.angularSort(a0);
//分两次绘点和连线
var tmp = [].concat(a);
this.pointDraw(tmp, style);
tmp = [].concat(a);
this.strokeDraw(tmp, style);
var d1, d2, d3, angle;
var x1,y1, x2, y2, x3, y3;
var s;
//坐标点编号
var s0 = vertexLabel ?
vertexLabel : 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
//标记边的长度
var edgeLong = 0;
var measure = 0;
//为每一个点利用余弦定理求角
for (var i = 0; i < len; i++) {
if (i == 0) {
x1 = a[len-1][0];
y1 = a[len-1][1];
x3 = a[i+1][0];
y3 = a[i+1][1];
}
else if (i == len-1) {
x1 = a[i-1][0];
y1 = a[i-1][1];
x3 = a[0][0];
y3 = a[0][1];
}
else {
x1 = a[i-1][0];
y1 = a[i-1][1];
x3 = a[i+1][0];
y3 = a[i+1][1];
}
x2 = a[i][0];
y2 = a[i][1];
d1 = (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
d2 = (x2-x3)*(x2-x3)+(y2-y3)*(y2-y3);
d3 = (x1-x3)*(x1-x3)+(y1-y3)*(y1-y3);
angle = Math.acos((d1+d2-d3)/(2*Math.sqrt(d1*d2)))/Math.PI*180;
s = angle.toFixed(2)+'°';
//document.write(s+'<p>');
//标注角度和顶点编号
plot.setFillStyle('purple');
plot.fillText(s, x2, -y2-5, 100);
plot.setFillStyle(style);
plot.fillText(s0[i], x2, -y2+20, 20);
edgeLong = (Math.sqrt(d1)/scale).toFixed(2);
measure = plot.measureText(edgeLong);
plot.setFillStyle('blue');
plot.fillText(edgeLong, (x1+x2-measure)/2, -(y1+y2)/2+20, measure);
}
}
/**
* @usage 计算并显示凸多边形的面积
* @author mw
* @date 2016年04月11日 星期一 08:46:52
* @param
* @return
*
*/
//计算并显示凸多边形的面积
this.areaDraw = function(array, style, scale) {
style = style ? style : 'black';
scale = scale ? scale : 1;
var size = array.length;
//document.write(areaCalc(array));
//由阵列切割出的三角形
var tri = [];
var xCenter = yCenter = 0;
var S = 0;
var measure = 0;
var sumS = 0;
var text = '';
plot.save()
.setFillStyle('#CC2288');
for (var i = 1; i < size-1; i++) {
tri = [];
tri.push(array[0]);
tri.push(array[i]);
tri.push(array[i+1]);
xCenter = (tri[0][0]+tri[1][0]+tri[2][0])/3*scale;
yCenter = -(tri[0][1]+tri[1][1]+tri[2][1])/3*scale;
S = this.areaCalc(tri);
if (S > 0) {
shape.strokeDraw(tri, style, scale);
text = 'S='+S.toFixed(2);
measure = plot.measureText(text);
plot.fillText(text, xCenter-measure/2, yCenter, measure);
sumS += S;
}
}
plot.fillText('总面积:'+sumS.toFixed(2), -270, -160, 200);
//shape.angleDraw(array, 'blue', scale);
plot.restore();
}
//计算三角形的面积
this.areaCalc = function(array) {
//array中包括组成三角形的三个点的坐标
array = shape.angularSort(array);
var S = 0;
if (array.length >=3) {
var x1 = array[0][0], y1 = array[0][1],
x2 = array[1][0], y2 = array[1][1],
x3 = array[2][0], y3 = array[2][1];
S = 0.5*(x1*y2+x2*y3+x3*y1-x1*y3-x2*y1-x3*y2);
}
return S;
}
/**
* @usage 以顶点递推方式绘制正多边形 #1
* @author mw
* @date 2015年12月01日 星期二 09:42:33
* @param (x, y)图形中心坐标,r 外接圆半径 edge 边数
* @return
*
*/
this.nEdge = function(x, y, r, edge, angle0) {
edge = edge ? edge : 5;
angle0 = angle0 ?
angle0 : 0;
var retArray = new Array();
var perAngle = Math.PI * 2 / edge;
var a = r * Math.sin(perAngle / 2);
var angle = -angle0;
var xOffset = r * Math.sin(perAngle / 2 - angle0);
var yOffset = r * Math.cos(perAngle / 2 - angle0);
var x1 = x-xOffset;
var y1 = y+yOffset;
for (var i=0; i < edge; i++) {
retArray.push([x1, y1]);
x1 = x1 + 2 * a * Math.cos(angle);
y1 = y1 + 2 * a * Math.sin(angle);
angle -= perAngle;
}
return retArray;
}
/**
* @usage 空心星形 #2 #201 #202
* @author mw
* @date 2015年12月01日 星期二 10:06:13
* @param
* @return
*
*/
this.nStar = function(x, y, r, edge, angle0, arg1, arg0) {
edge = edge ?
edge : 5;
angle0 = angle0 ? angle0 : Math.PI/2;
var retArray=new Array();
var perAngle = Math.PI * 2 / edge;
var r0 = arg0 ? arg0 * r : r / (2 * (1 + Math.cos(perAngle)));
var scale = arg1 ? arg1 : 0.5;
var angle = 0.5 * perAngle - angle0 * scale / 0.5;
var xOffset = x;
var yOffset = y;
for (var i =0; i< edge; i++) {
retArray.push([r0 * Math.cos(angle) + xOffset,r0 * Math.sin(angle) + yOffset] );
retArray.push([r * Math.cos(angle - scale * perAngle) + xOffset,
r * Math.sin(angle - scale * perAngle) + yOffset]);
angle -= perAngle;
}
return retArray;
}
/**
* @usage 平行线, 平行四边形, 梯形
* @author mw
* @date 2016年01月24日 星期日 11:14:43
* @param
* @return
*
*/
/*
平行线 Parallel lines
平行四边形 Parallel quadrilateral
梯形 trapezoid
*/
this.paraline = function(x, y, r, rot) {
rot = rot ? -rot : 0;
y = y ? -y : 0;
plot.beginPath()
.moveTo(x, y)
.lineTo(x + r * Math.cos(rot), y + r*Math.sin(rot))
.moveTo(x, y + r/ 10)
.lineTo(x + r * Math.cos(rot), y+r/10 + r*Math.sin(rot))
.closePath()
.stroke();
};
this.paraquad = function(x, y, rot, a, b, angle) {
angle = angle ?
Math.abs(angle) : 0;
rot = rot ? rot : 0;
//參数说明:
//平行四边形的两条边a, b, 以及它们之间的夹角angle
//这个平行四边形的起始点(x, y), 以及整个图形与x轴的夹角rot
var retArray = new Array();
retArray.push([x, -y]);
retArray.push([x + a * Math.cos(rot), -(y + a * Math.sin(rot))]);
retArray.push([x + a * Math.cos(rot)+ b * Math.cos(rot+angle),
-(y + a * Math.sin(rot)+ b * Math.sin(rot+angle))]);
retArray.push([x + b * Math.cos(rot+angle), -(y + b * Math.sin(rot+angle))]);
return retArray;
}
this.trapezoid = function(x, y, rot, a, b, angle) {
angle = angle ? Math.abs(angle) : 0;
rot = rot ? rot : 0;
//參数说明:
//等腰梯形的下底边a。腰b, 以及它们之间的夹角angle
//如果下底 > 上底。那么上底 = (a - b * Math.cos(angle)*2)/2
//这个平行四边形的起始点(x, y), 以及整个图形与x轴的夹角rot
var c = (a - b * Math.cos(angle)*2)/2;
var retArray = new Array();
if (c < 0) {
//说明给的条件不正确
//缺省画上底是下底一半的梯形
}
else {
retArray.push([x, -y]);
retArray.push([x + a * Math.cos(rot), -(y + a * Math.sin(rot))]);
retArray.push([x + b * Math.cos(rot+angle)+2*c * Math.cos(rot),
-(y + b * Math.sin(rot+angle)+2*c*Math.sin(rot))]);
retArray.push([x + b * Math.cos(rot+angle), -(y + b * Math.sin(rot+angle))]);
}
return retArray;
}
/**
* @usage 用于绘制空间几何体的側面边线
* @author mw
* @date 2016年04月10日 星期日 11:35:40
* @param
* @return
*
*/
this.lineDraw = function(array, style, scale) {
//array的格式[ [线段起点(x,y), 线段终点(x, y)], ...], 每条线段有四个元素确定
style = style ? style : 'black';
scale = scale ? scale : 1;
var newArray = new Array();
var size = array.length;
var itemSize = array[0].length;
var item = [];
//缩放步骤
for (var i = 0; i < size; i++) {
item = [];
for (var j = 0; j < itemSize; j++) {
if (j % 2 == 0) { //x坐标
item.push(array[i][j] * scale);
}
else { //y坐标
item.push(- array[i][j] * scale);
}
}
newArray.push(item);
}
//document.write(newArray.join(', '));
plot.save()
.setStrokeStyle(style);
for (var i = 0; i < size; i++) {
plot.beginPath()
.moveTo(newArray[i][0], newArray[i][1])
.lineTo(newArray[i][2], newArray[i][3])
.closePath()
.stroke();
}
plot.restore();
}
/**
* @usage 用于绘制空间几何体的側面填充面域
* @author mw
* @date 2016年04月10日 星期日 11:35:40
* @param
* @return
*
*/
this.faceDraw = function(array, style, scale) {
//array的格式[ [线段起点(x,y), 线段终点(x, y)], ...], 每条线段有四个元素确定
style = style ? style : 'black';
scale = scale ? scale : 1;
var newArray = new Array();
var size = array.length;
var itemSize = array[0].length;
var item = [];
//缩放步骤
for (var i = 0; i < size; i++) {
item = [];
for (var j = 0; j < itemSize; j++) {
if (j % 2 == 0) { //x坐标
item.push(array[i][j] * scale);
}
else { //y坐标
item.push(- array[i][j] * scale);
}
}
newArray.push(item);
}
//document.write(newArray.join(', '));
plot.save()
.setFillStyle(style)
.setStrokeStyle('yellow')
.setLineWidth(4);
var x1 = x2 = y1 = y2 = 0,
x3 = x4 = y3 = y4 = 0;
for (var i = 0; i < size; i++) {
x1 = newArray[i][0];
y1 = newArray[i][1];
x2 = newArray[i][2];
y2 = newArray[i][3];
if (i < size - 1) {
x3 = newArray[i+1][0];
y3 = newArray[i+1][1];
x4 = newArray[i+1][2];
y4 = newArray[i+1][3];
}
else {
x3 = newArray[0][0];
y3 = newArray[0][1];
x4 = newArray[0][2];
y4 = newArray[0][3];
}
plot.beginPath()
.moveTo(x1, y1)
.lineTo(x2, y2)
.lineTo(x4, y4)
.lineTo(x3, y3)
.closePath()
.fill();
}
for (var i = 0; i < size; i++) {
x1 = newArray[i][0];
y1 = newArray[i][1];
x2 = newArray[i][2];
y2 = newArray[i][3];
plot.beginPath()
.moveTo(x1, y1)
.lineTo(x2, y2)
.closePath()
.stroke();
}
plot.restore();
}
/**
* @usage 用于获取椭圆的坐标数组
* @author mw
* @date 2016年04月10日 星期日 11:35:40
* @param
* @return
*
*/
//获取椭圆上点的坐标
this.ellipse = function(a, b) {
//a, b 分别为椭圆的长、短半轴
var retArray = new Array();
var thita = 0;
//椭圆的圆周分成的线段数量,这个值越大越精确
var N = 32;
var deltaThita = Math.PI*2/N;
var x = y = 0;
for (var i = 0; i < N; i++) {
x = a*Math.cos(thita);
y = b*Math.sin(thita);
retArray.push([x, y]);
thita += deltaThita;
}
return retArray;
}
/**
* @usage 用于获取矩形的坐标数组
* @author mw
* @date 2016年04月10日 星期日 11:35:40
* @param
* @return
*
*/
this.rect = function(w, h) {
return [[-w/2, -h/2], [-w/2, h/2], [w/2, h/2], [w/2, -h/2]];
}
/**
* @usage 绘制圆形
* @author mw
* @date 2015年11月27日 星期五 12:11:38
* @param
* @return
*
*/
this.strokeCircle = function(x, y, r) {
plot.beginPath()
.arc(x, y, r, 0, 2*Math.PI, true)
.closePath()
.stroke();
}
this.fillCircle = function(x, y, r) {
plot.beginPath()
.arc(x, y, r, 0, 2*Math.PI, true)
.closePath()
.fill();
}
//绘制椭圆
this.strokeEllipse = function(x, y, a, b, rotate) {
//关键是bezierCurveTo中两个控制点的设置
//0.5和0.6是两个关键系数(在本函数中为试验而得)
var ox = 0.5 * a,
oy = 0.6 * b;
var rot = rotate ? -rotate : 0;
plot.save()
.rotate(rot)
.translate(x, y)
.beginPath()
//从椭圆纵轴下端開始逆时针方向绘制
.moveTo(0, b)
.bezierCurveTo(ox, b, a, oy, a, 0)
.bezierCurveTo(a, -oy, ox, -b, 0, -b)
.bezierCurveTo(-ox, -b, -a, -oy, -a, 0)
.bezierCurveTo(-a, oy, -ox, b, 0, b)
.closePath()
.stroke()
.restore();
}
//绘制椭圆
this.fillEllipse = function(x, y, a, b, rotate) {
//关键是bezierCurveTo中两个控制点的设置
//0.5和0.6是两个关键系数(在本函数中为试验而得)
var ox = 0.5 * a,
oy = 0.6 * b;
var rot = rotate ? -rotate : 0;
plot.save()
.rotate(rot)
.translate(x, y)
.beginPath()
//从椭圆纵轴下端開始逆时针方向绘制
.moveTo(0, b)
.bezierCurveTo(ox, b, a, oy, a, 0)
.bezierCurveTo(a, -oy, ox, -b, 0, -b)
.bezierCurveTo(-ox, -b, -a, -oy, -a, 0)
.bezierCurveTo(-a, oy, -ox, b, 0, b)
.closePath()
.fill()
.restore();
}
/**
* @usage 绘制正方体
* @author mw
* @date 2016年02月01日 星期一 08:40:27
* @param
* @return
*
*/
this.drawCubic = function(x0, y0, z0, r, style, style2, style3) {
plot.save();
x0*=r;
y0*=r;
z0*=r;
z0 = z0 /2;
x0 = x0 - z0*0.707;
y0 = y0 + z0*0.707;
z0 = 0;
plot.translate(x0, y0);
style = style ? style : 'black';
style2 = style2 ?
style2 : style;
style3 = style3 ?
style3 : style;
var transform = new Transform();
//左下角[x0, y0,边长r
shape.fillDraw(shape.nEdge(0, 0,0.707*r, 4, 0), style);
//顶面
shape.fillDraw(transform.flipX(shape.paraquad(-0.5*r, 0.5*r, 0, r, r/2, Math.PI/4)), style2);
shape.strokeDraw(transform.flipX(shape.paraquad(-0.5*r, 0.5*r, 0, r, r/2, Math.PI/4)), 'white');
//右側面
shape.fillDraw(transform.flipX(shape.paraquad(0.5*r, -0.5*r, Math.PI/4, r/2, r, Math.PI/4)), style3);
shape.strokeDraw(transform.flipX(shape.paraquad(0.5*r, -0.5*r, Math.PI/4, r/2, r, Math.PI/4)), 'white');
plot.restore();
}
this.point3D = function(x0, y0, z0) {
//canvas中y轴坐标向下为正。与笛卡尔坐标系相反
//所以此处先取反
//
z0 = z0 /2;
x0 = -(x0 - z0*0.707);
y0 = y0 + z0*0.707;
return [x0, y0];
}
//左视投影,此时x坐标是无所谓的
this.pointLeft = function(x0, y0, z0) {
return [z0, y0];
}
//右视投影
this.pointRight = function(x0, y0, z0) {
return [-z0, y0];
}
//鸟瞰投影
this.pointTop = function(x0, y0, z0) {
return [x0, -z0];
}
//仰视投影
this.pointBottom = function(x0, y0, z0) {
return [x0, z0];
}
//主视投影
this.pointFront = function(x0, y0, z0) {
return [x0, y0];
}
//后视投影
this.pointBack = function(x0, y0, z0) {
return [-x0, y0];
}
this.strokeCubic = function(x0, y0, z0, r, style) {
plot.save();
x0 *= r;
y0 *= r;
z0 *= r;
r *= 0.5;
var array = [[-r, -r], [-r, r], [r, r], [r, -r]];
var top = [];
var left = [];
var front = [];
var x, y, z;
//存放暂时点
var p = [];
for (var i = 0; i < 4; i++) {
x = (x0+array[i][0]);
y = y0+r;
z = (z0+array[i][1]);
p = this.point3D(x, y, z);
top.push([p[0], -p[1]]);
}
for (var i = 0; i < 4; i++) {
x = x0+r;
y = (y0+array[i][0])+2*r;
z = z0+array[i][1];
p = this.point3D(x, y, z);
left.push([p[0], -p[1]]);
}
for (var i = 0; i < 4; i++) {
x = x0+array[i][0];
y = (y0+array[i][1])+2*r;
z = z0+r;
p = this.point3D(x, y, z);
front.push([p[0], -p[1]]);
}
var tmp = [].concat(top);
shape.fillDraw(tmp, style);
tmp=[].concat(top);
shape.strokeDraw(tmp, '#cccccc');
tmp = [].concat(left);
shape.strokeDraw(left, 'black');
tmp = [].concat(front);
shape.strokeDraw(front, 'black');
plot.restore();
}
/**
* @usage 把三维点阵列依照z, y, x优先级由小到大排列
* @author mw
* @date 2016年02月23日 星期二 09:38:27
* @param [[x1, y1, z1], [x2,y2, z2], ...]
* @return 排序后的[[x, y, z]...]
*
*/
this.xyzSort = function(array) {
var arr = new Array();
arr = array;
arr.sort(function(a, b) {
if (a[2] != b[2]) {
return (a[2] - b[2]);
}
else {
if (a[1] != b[1]) {
return (a[1] - b[1]);
}
else {
return (a[0] - b[0]);
}
}
});
//document.write(arr);
return arr;
}
//把给定的坐标点阵列数组[x, y],...依照距离它们的中心点的角度进行排列
//是为了把无序排列的闭合曲线上的点进行有序排列,兴许可再经过连线形成
//可填充的闭合曲线
this.angularSort = function(array) {
var a = new Array();
a = [].concat(array);
var len = a.length, len1 = a[0].length;
//不符合处理条件,不进行处理
if (len <= 0 || len1 != 2) return array;
//求中心点
var xTotal = 0, yTotal = 0, xCenter = 0, yCenter = 0;
for (var i = 0; i < len; i++) {
xTotal += a[i][0];
yTotal += a[i][1];
}
xCenter = xTotal/len;
yCenter = yTotal/len;
//求与中心点夹角并排序
var b = new Array();
var x, y, xdiff, ydiff;
for (var i = 0; i < len; i++) {
x = a[i][0];
y = a[i][1];
xdiff = x-xCenter;
ydiff = y-yCenter;
if (Math.abs(xdiff)<0.0001) {
if (ydiff > 0) {
b.push([x, y, Math.PI/2]);
}
else {
b.push([x, y, Math.PI/2*3]);
}
}
else if ( xdiff >= 0 && ydiff > 0) {//第一象限
b.push([x, y, Math.atan(Math.abs(ydiff/xdiff))]);
}
else if (xdiff < 0 && ydiff >= 0) {//第二象限
b.push([x, y, Math.PI-Math.atan(Math.abs(ydiff/xdiff))]);
}
else if (xdiff <= 0 && ydiff < 0) {//第三象限
b.push([x, y, Math.PI+Math.atan(Math.abs(ydiff/xdiff))]);
}
else {//第四象限
b.push([x, y, Math.PI*2-Math.atan(Math.abs(ydiff/xdiff))]);
}
}
b.sort(function(b1, b2) {
if (Math.abs(b1[2]-b2[2]) < 0.0001) {
//依照与中心点的距离大小排序
var d1 = (b1[0]-xCenter)*(b1[0]-xCenter)+
(b1[1]-yCenter)*(b1[1]-yCenter);
var d2 = (b2[0]-xCenter)*(b2[0]-xCenter)+
(b2[1]-yCenter)*(b2[1]-yCenter);
return -(d1-d2);
}
else {
return (b1[2]-b2[2]);
}
});
var retArray = new Array();
for (var i = 0; i < len; i++) {
//如果两个点在经过中心点的同一直线上。舍弃这个点
//由于它表示点阵列可能不是单一环,或不是闭合曲线
if (i > 0 && Math.abs(b[i][2]-b[i-1][2]) < 0.0001) continue;
retArray.push([b[i][0], b[i][1]]);
}
return retArray;
}
/**
* @usage 三视图
* @author mw
* @date 2016年02月23日 星期二 09:49:23
* @param
* @return
*
*/
this.threeView = function(array, style) {
var cubic = this.xyzSort(array);
plot.save();
plot.setTransform(1, 0, 0, 1, 0, 0)
.translate(300, 200);
//三维图和三视图
var r = 50;
style = style ? style : 'red';
var len = cubic.length;
for (var i = 0; i < len; i++) {
this.drawCubic(cubic[i][0], -cubic[i][1], cubic[i][2], r, style);
}
var height = 400;
r = r/3;
plot.setTransform(1, 0, 0, 1, 0, 0);
plot.fillText('左视图', 20, 20, 100);
plot.fillText('主视图', 20, 20+1*height/3, 100);
plot.fillText('鸟瞰图', 20, 20+2*height/3, 100);
plot.setFillStyle(style)
.setStrokeStyle('white');
//左视图
plot.translate(100, 80);
for (var i = 0; i < len; i++) {
//y, z两坐标,z坐标变为x坐标
this.fillRect(cubic[i][2]*r, -cubic[i][1]*r, r, r);
this.strokeRect(cubic[i][2]*r, -cubic[i][1]*r, r, r);
}
//主视图
plot.translate(0, 130);
for (var i = 0; i < len; i++) {
//x, y两坐标
this.fillRect(cubic[i][0]*r, -cubic[i][1]*r, r, r);
this.strokeRect(cubic[i][0]*r, -cubic[i][1]*r, r, r);
}
//鸟瞰图
plot.translate(0, 100);
for (var i = 0; i < len; i++) {
//x, z两坐标。z坐标变为y坐标
this.fillRect(cubic[i][0]*r, cubic[i][2]*r, r, r);
this.strokeRect(cubic[i][0]*r, cubic[i][2]*r, r, r);
}
plot.restore();
}
//绘制球体
this.sphere = function(pos/*[x, y, z]*/, r, style) {
plot.save();
var x, y;
var p = [].concat(pos);
if (p.length == 2) {
x = p[0];
y = p[1];
}
else if (p.length == 3) {
var p1 = shape.point3D(p[0], -p[1], p[2]);
x = p1[0];
y = p1[1];
}
var r0 = 0.1*r;
var grd = plot.createRadialGradient(x, y, r, x+0.3*r, y-0.3*r, r0);
grd.addColorStop(0, style);
grd.addColorStop(1, 'white');
plot.setFillStyle(grd);
shape.fillCircle(x, y, r);
plot.restore();
}
return {
fillRect:fillRect,
strokeRect:strokeRect,
fillCircle:fillCircle,
strokeCircle:strokeCircle,
strokeEllipse:strokeEllipse,
fillEllipse:fillEllipse,
//绘制点阵列
pointDraw:pointDraw,
multiLineDraw:multiLineDraw,
strokeDraw:strokeDraw,
fillDraw:fillDraw,
//空间几何体相关
lineDraw:lineDraw,
faceDraw:faceDraw,
//多边形角度标注
angleDraw:angleDraw,
//多边形面积标注
areaDraw:areaDraw,
//三角形面积计算(已知三个点坐标)
areaCalc:areaCalc,
//几何形状
rect:rect,
ellipse:ellipse,
nEdge:nEdge,
nStar:nStar,
paraline:paraline,
paraquad:paraquad,
trapezoid:trapezoid,
//绘制立方体
drawCubic:drawCubic,
strokeCubic:strokeCubic,
//绘制球体
sphere:sphere,
//三维点映射
point3D:point3D,
pointLeft:pointLeft,
pointRight:pointRight,
pointTop:pointTop,
pointBottom:pointBottom,
pointFront:pointFront,
pointBack:pointBack,
//三视图
threeView:threeView,
//顶点排序
xyzSort:xyzSort,
angularSort:angularSort
};
}();
/**
* @usage 矩阵类
* @author mw
* @date 2016年03月24日 星期四 14:51:45
* @param
* @return
*
*/
function Matrix() {
this.delta = function(matrix) {
var size = matrix.length;
if (!matrix[0].length) {
return 0;
}
else {
if (matrix[0].length != size) {
return 0;
}
if (size < 1) {
return 0;
}
else if (size == 1) {
return matrix[0][0];
}
else {
var d = 0;
var subMatrix = [];
for (var i = 0; i < size; i++) {
subMatrix = this.subSet(matrix, i, 0);
d += Math.pow(-1, i)*matrix[i][0]*this.delta(subMatrix);
}
return d;
}
}
}
this.subSet = function(matrix, row, col) {
var size = matrix.length;
if (!matrix[0].length) {
return [];
}
else {
if (matrix[0].length != size) {
return [];
}
var newMatrix = new Array();
var rowArray= new Array();
for (var i = 0; i < size; i++) {
if (i == row) {
continue;
}
else {
rowArray = [];
for (var j = 0; j < size; j++) {
if (j == col) {
continue;
}
else {
rowArray.push(matrix[i][j]);
}
}
newMatrix.push(rowArray)
}
}
return newMatrix;
}
}
this.identityMatrix = function(rank) {
var newMatrix = new Array();
var rowArray= new Array();
for (var i = 0; i < rank; i++) {
rowArray = [];
for (var j = 0; j < rank; j++) {
if (j == i) {
rowArray.push(1);
}
else {
rowArray.push(0);
}
}
newMatrix.push(rowArray);
}
return newMatrix;
}
//把从1-n的n个数按顺序放到矩阵中
this.sequenceMatrix = function(rank) {
var newMatrix = new Array();
var rowArray= new Array();
var count = 0;
for (var i = 0; i < rank; i++) {
rowArray = [];
for (var j = 0; j < rank; j++) {
count++;
rowArray.push(count);
}
newMatrix.push(rowArray);
}
return newMatrix;
}
this.print = function(matrix) {
var size = matrix.length;
if (!matrix[0].length) {
return [];
}
else {
var rSize = matrix[0].length;
var s = '';
for (var i = 0; i < size; i++) {
s = '';
for (var j = 0; j < rSize; j++) {
s += matrix[i][j].toFixed(2) + ' , ';
}
document.write(s+'<br/>');
}
}
}
this.deepCopy = function(matrix) {
var size = matrix.length;
if (!matrix[0].length) {
return [];
}
else {
var rSize = matrix[0].length;
var newMatrix = new Array();
var rowArray= new Array();
for (var i = 0; i < size; i++) {
rowArray = [];
for (var j = 0; j < rSize; j++) {
rowArray.push(matrix[i][j]);
}
newMatrix.push(rowArray);
}
return newMatrix;
}
}
}
/**
* @usage 对点阵列数组进行平移。旋转,缩放,对称等变形
* @author mw
* @date 2016年03月20日 星期日 13:24:58
* @param 传入点阵列矩阵
* @return 输出变形后的点阵列矩阵
*
*/
function Transform() {
this.translate = function(array, xOffset, yOffset) {
var len = array.length;
if (len == 0) {
return [];
}
else {
var len1 = array[0].length;
if (len1 != 2) {
//假设不是点阵列[..., [x,y], [x1,y1], ...]的格式。临时不加处理
return array;
}
else {
var retArray = new Array();
var x = 0, y = 0;
for (var i = 0; i < len; i++) {
x = array[i][0] + xOffset;
y = array[i][1] + yOffset;
retArray.push([x, y]);
}
}
}
return retArray;
}
this.scale = function(array, xScale, yScale) {
var len = array.length;
if (len == 0) {
return [];
}
else {
xScale = xScale ? xScale : 1;
yScale = yScale ? yScale : xScale;
var len1 = array[0].length;
if (len1 != 2) {
//假设不是点阵列[..., [x,y], [x1,y1], ...]的格式,临时不加处理
return array;
}
else {
var retArray = new Array();
var x = 0, y = 0;
for (var i = 0; i < len; i++) {
x = array[i][0] * xScale;
y = array[i][1] * yScale;
retArray.push([x, y]);
}
}
}
return retArray;
}
this.rotate = function(array, angle) {
var len = array.length;
if (len == 0) {
return [];
}
else {
var len1 = array[0].length;
if (len1 != 2) {
//假设不是点阵列[..., [x,y], [x1,y1], ...]的格式,临时不加处理
return array;
}
else {
var retArray = new Array();
var x = 0, y = 0;
var sinA, cosA;
for (var i = 0; i < len; i++) {
sinA = Math.sin(angle);
cosA = Math.cos(angle);
x = array[i][0] * cosA - array[i][1]*sinA;
y = array[i][0] * sinA + array[i][1]*cosA;
retArray.push([x, y]);
}
}
}
return retArray;
}
this.flipX = function(array) {
return this.flipImplement(array, 'X');
}
this.flipY = function(array) {
return this.flipImplement(array, 'Y');
}
this.flipXY = function(array) {
return this.flipImplement(array, 'XY');
}
//关于直线y=kx轴对称
this.flip = function(array, slope) {
//slope为斜率k
var mode = slope.toFixed(3);
return this.flipImplement(array, mode);
}
this.flipImplement = function(array, mode) {
var len = array.length;
if (len == 0) {
return [];
}
else {
var len1 = array[0].length;
if (len1 != 2) {
//假设不是点阵列[..., [x,y], [x1,y1], ...]的格式,临时不加处理
return array;
}
else {
var retArray = new Array();
var x = 0, y = 0;
var sinA, cosA;
var m = 0, n = 0;
if (mode == 'X') {
for (var i = 0; i < len; i++) {
//关于X轴对称,
x = array[i][0];
y = -array[i][1];
retArray.push([x, y]);
}
}
else if (mode == 'Y') {
for (var i = 0; i < len; i++) {
//关于Y轴对称,
x = -array[i][0];
y = array[i][1];
retArray.push([x, y]);
}
}
else if (mode == 'XY') {
for (var i = 0; i < len; i++) {
//中心对称
x = -array[i][0];
y = -array[i][1];
retArray.push([x, y]);
}
}
else {
//模式为斜率 y = kx中k的字符串
k = parseFloat(mode);
for (var i = 0; i < len; i++) {
//可扩展
//此处先放大100倍再缩小是由于对于小尺寸
//计算误差太大。而假设尺寸太大,
//标注会占用太多地方。造成文字拥挤。无法读取
m = array[i][0]*10000;
n = array[i][1]*10000;
//x = (m-2*k+2*k*n-m*k*k)/(1+k*k);
x = (1-k*k)*m+2*k*(n-1)/(1+k*k);
//y = (-n+2*k*m+n*k*k)/(1+k*k);
y = (2*k*m-(1-k*k)*n)/(1+k*k);
retArray.push([x/10000, y/10000]);
}
}
}
}
return retArray;
}
}
本节到此结束。欲知后事怎样,请看下回分解。
posted on 2017-07-22 19:50 cynchanpin 阅读(205) 评论(0) 收藏 举报
浙公网安备 33010602011771号