[从头学数学] 第172节 直线与方程

剧情提要:
[机器小伟]在[工程师阿伟]的陪同下进入了结丹初期的修炼,
这次要修炼的目标是[直线与方程]。

正剧开始:

星历2016年04月11日 09:30:00, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起研究[直线与方程]。



开始今天的修炼之前,小伟先整理了一下这件法器:

<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>



[从头学数学] 第172节 直线与方程_第1张图片

看来用得上它的地方很多,小伟很满意。


[从头学数学] 第172节 直线与方程_第2张图片



[从头学数学] 第172节 直线与方程_第3张图片

[从头学数学] 第172节 直线与方程_第4张图片


<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>

[从头学数学] 第172节 直线与方程_第5张图片

<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>



[从头学数学] 第172节 直线与方程_第6张图片

<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>


[从头学数学] 第172节 直线与方程_第7张图片

[从头学数学] 第172节 直线与方程_第8张图片


>>> 
[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>


[从头学数学] 第172节 直线与方程_第9张图片

<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>


[从头学数学] 第172节 直线与方程_第10张图片

<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;



[从头学数学] 第172节 直线与方程_第11张图片



>>> 
[-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>

[从头学数学] 第172节 直线与方程_第12张图片

[从头学数学] 第172节 直线与方程_第13张图片

<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>

[从头学数学] 第172节 直线与方程_第14张图片


这个问题的答案是这样的:魔术师撒谎了。

魔术师改进后的地毯不是矩形的。


[从头学数学] 第172节 直线与方程_第15张图片

<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


[从头学数学] 第172节 直线与方程_第16张图片

[从头学数学] 第172节 直线与方程_第17张图片


[从头学数学] 第172节 直线与方程_第18张图片

[从头学数学] 第172节 直线与方程_第19张图片




>>> 
[-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>


[从头学数学] 第172节 直线与方程_第20张图片


[从头学数学] 第172节 直线与方程_第21张图片

[从头学数学] 第172节 直线与方程_第22张图片



[从头学数学] 第172节 直线与方程_第23张图片


[从头学数学] 第172节 直线与方程_第24张图片

<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


[从头学数学] 第172节 直线与方程_第25张图片


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]];


算得对不对呢?

[从头学数学] 第172节 直线与方程_第26张图片


既然[人叫板老师]也觉得是这样的答案,那就说明小伟的工具是可用的。


[从头学数学] 第172节 直线与方程_第27张图片


[从头学数学] 第172节 直线与方程_第28张图片


#点到直线的距离[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;

[从头学数学] 第172节 直线与方程_第29张图片

>>> 
1.6666666666666667

print(disOfP2L(-1,2,3,0,-2));


[从头学数学] 第172节 直线与方程_第30张图片
	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>


[从头学数学] 第172节 直线与方程_第31张图片


这里贴一下小伟用到的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;
	}

}



本节到此结束,欲知后事如何,请看下回分解。

你可能感兴趣的:([从头学数学] 第172节 直线与方程)