[从头学数学] 第178节 平面向量

剧情提要:
[机器小伟]在[工程师阿伟]的陪同下进入了结丹中期的修炼,
这次要修炼的目标是[平面向量]。

正剧开始:

星历2016年04月15日 10:37:27, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起研究[平面向量]。






'


小伟看到这里,觉得有必要制造一件能够画出向量来的法器,

于是[工程师阿伟]给小伟做了一件:


<span style="font-size:18px;">/**
* @usage   向量图
* @author  mw
* @date    2016年04月15日  星期五  08:34:05 
* @param   向量点阵
* @return
*
*/
this.vectorDraw = function(array, style, scale) {

	style = style ? style : 'black';
	scale = scale ? scale : 1;
	
	var size = array.length;
	var size_1 = array[0].length;
	
	//保证传入点阵中至少有两个点,并且是采用[[x1,y1], [x2,y2]...[xn, yn]]这种格式
	if (size < 2 || size_1 != 2) {
		return;
	}
	
	var x1 = x2 = y1 = y2 = k = thita = 0;
	//箭头两边与中心线的夹角和长度
	var dThita = Math.PI/180*15, dL = 15/scale;
	var x3 = y3 = x4 = y4 = 0;
	
	
	plot.setStrokeStyle(style)
		.beginPath();
	
	for (var i = 0; i < size-1; i++) {
		x1 = array[i][0];
		y1 = array[i][1];
		
		x2 = array[i+1][0];
		y2 = array[i+1][1];
		
		if (x1 == x2 && y1 == y2) continue;
		else if (x1 == x2) {
			thita = Math.PI/2;
			
			if (y1 < y2) {
				thita += Math.PI;
			}
		}
		else {
			if ((y1 == y2 && x1 < x2)) {
				thita = Math.PI+Math.atan((y2-y1)/(x2-x1));
			}
			else if ((y1 == y2 && x1 > x2)){
				thita = Math.atan((y2-y1)/(x2-x1));
			}
			else if (x1 < x2) {
				thita = Math.PI+Math.atan((y2-y1)/(x2-x1));
			}
			else {
				thita = Math.atan((y2-y1)/(x2-x1));
			}
				
		}
		

		x3 = x2 + dL*Math.cos(thita+dThita);
		y3 = y2 + dL*Math.sin(thita+dThita);
		x4 = x2 + dL*Math.cos(thita-dThita);
		y4 = y2 + dL*Math.sin(thita-dThita);

		
		
		plot.moveTo(x1*scale, -y1*scale)
			.lineTo(x2*scale, -y2*scale)
			.moveTo(x2*scale, -y2*scale)
			.lineTo(x3*scale, -y3*scale)
			.moveTo(x2*scale, -y2*scale)
			.lineTo(x4*scale, -y4*scale);
	}
	
	plot.closePath()
		.stroke();
	

	

}
</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,190);          
            
        //坐标轴设定    
        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 array = [[1, 2], [4, 5], [7,2], [-8, -5], [-5, 3], [-8, 3], [-8, 5], [-2, 5], [-2, -1], [7, -3], [3, 1]];


        var size = array.length;
              
        var transform = new Transform();  
        var tmp = [];  
          
        array = transform.scale(transform.translate(array, 0, 0), scaleX/spaceX, scaleY/spaceY);      
		
		
	

		tmp = [].concat(array);        
       vectorDraw(tmp, 'red'); 
	   
	    tmp = [].concat(array);        
        shape.pointDraw(tmp, 'orange', 1, 1);     


		plot.setFillStyle('blue');
		plot.fillText('向量图', -270, -170, 300);
		
		

              
      
    }</span>


还不错是吧,为了把这几个箭头的位置摆正确,阿伟可是出了一身的汗。


但是小伟说,这光有图肯定是不行的,这写个表达式神马的还是很必须的。

要怎样把这个箭头写出来呢?

于是,阿伟又做了一件法器:


<span style="font-size:18px;">/**
* @usage   数学表达式,代数式的书写
* @author  mw
* @date    2016年03月12日  星期六  11:05:12 
* @param
* @return
*
*/
function MathText() {
	//上标标记形式为...^[内容]...
	//分数不进行处理, 根式不进行处理,都转成指数式进行
	//特殊数学符号设想加\[alpha]进行转义,待续
	//可以进行指数上标代数式的书写
	//可扩展下标,待续
	
	
	this.setNormalFont = function() {
		plot.setFont("normal normal normal 24px Times Lt Std");	
	}
	
	this.setScriptFont = function() {
		plot.setFont("italic normal bold 16px Dark Courier ");
	}
	
	this.print = function(text, xPos, yPos) {
		xPos = xPos ? xPos : 0;
		yPos = yPos ? yPos : 0;
		
		plot.save();
		
		
		var s = text ? text : '';
		
		if (s != '') {
			s = s.replace(/\/\//ig, '÷');
			s = s.replace(/>=/ig, '≥');
			s = s.replace(/<=/ig, '≤');
			s = s.replace(/!=/ig, '≠');
			s = s.replace(/pi/ig, 'π');
		}
		
		//字符串长度
		var len = s.length;
		//不同字体大小设置在此
		var r1 = 20;
		//单个字符暂存处
		var c;
		//文本显示位置
		var x = xPos, y = yPos;
		//正常文本暂存
		var s0 = '';
		//字符串打印长度
		var measure; 
		//记录上一个x位置,可记录三层
		var xMem = [x, x, x];
		//记录每一层的左括号位置
		var bracketPos = [x, x, x];
		//记录括号层次
		var bracketsLevel = 0;
		//记录根号层次
		var radicalLevel = 0;
		//记录每一层根号的起始位置和层次数的数组...[[start, end, level], ...]
		var radicalSpan = [];
		
		//设置正常字体
		this.setNormalFont();				
		
		for (var i = 0; i < len; i++) {
			if (s[i] == '_' && s[i+1] == '[') {
				//下标开始
				//下标标记形式为..._[内容]...
				
				if (s0 != '') { //先把正常字符打印出
					if (r1 != 20) { //字体字号大小还在上标状态
						r1 = 20;
						this.setNormalFont();					
					}
					
					measure = plot.measureText(s0);
					plot.fillText(s0, x, y, measure);
					s0 = '';

					x += measure;
				
				}
				
				var subScript = '';
				var j = 0;
				for (j = i+1; s[j]!=']'; j++) {
					if (s[j] != '[') {
						subScript+=s[j];
					}
				}
				
				if (r1 != 10) {//正常字体状态,需要改为上标字体
					r1 = 10;
					this.setScriptFont();
					
				}
			
				measure = plot.measureText(subScript);
				plot.fillText(subScript, x, y+8, measure);
					
				if (j < len-1 && s[j+1] == '^') {
				
				}
				else {
					x += 1.2*measure;
				}
				
				i = j;
			
			}
			else if (s[i] == '^'&&s[i+1] == '[') {
				//上标开始
				//上标标记形式为...^[内容]...
				
				if (s0 != '') { //先把正常字符打印出
					if (r1 != 20) { //字体字号大小还在上标状态
						r1 = 20;
						this.setNormalFont();					
					}
					
					measure = plot.measureText(s0);
					plot.fillText(s0, x, y, measure);
					s0 = '';

					x += measure;
				
				}
					
				var upperScript = '';
				var j = 0;
				for (j = i+1; s[j]!=']'; j++) {
					if (s[j] != '[') {
						upperScript+=s[j];
					}
				}
				
				

					
				
				//二次根式
				if (upperScript == '1/2' || upperScript == '0.5') {		
					var x1, y1;
					
					if (i > 0 && s[i-1] == ')') {
						x1 = bracketPos[bracketsLevel];
					}
					else {
						x1 = xMem[bracketsLevel];
					}
					
					
					/* 存疑代码
					
					if (radicalSpan == []) {
						radicalLevel = 0;
						radicalSpan.push([x1, x, radicalLevel]);
					}
					else {
						var len = radicalSpan.length;
						for (var k = 0; k < len; k++) {
							if (x1 < radicalSpan[k][0]) {
								radicalLevel = radicalSpan[k][2]+1;
								break;
							}
							
							if (k >= len-1) {
								radicalLevel = 0;
							}
						}
						radicalSpan.push([x1, x, radicalLevel]);
					}*/
					
					y1 = y-20-5*radicalLevel;			

					
					plot.save()
						.setLineWidth(1);
					plot.beginPath()
						.moveTo(x1-5, y+5)
						.lineTo(x1-8, y-3)
						.moveTo(x1-5, y+5)
						.lineTo(x1+5, y1)
						.moveTo(x1+5, y1)
						.lineTo(x, y1)
						.closePath()
						.stroke();
					plot.restore();
					
				}
				
				//向量符号
				else if (upperScript == '->') {
					var x1, y1;
					
					if (i > 0 && s[i-1] == ')') {
						x1 = bracketPos[bracketsLevel];
					}
					else {
						x1 = xMem[bracketsLevel];
					}
					
					y1 = y-18-5*radicalLevel;			

					
					plot.save()
						.setLineWidth(1);
					plot.beginPath()
						.moveTo(x1, y1)
						.lineTo(x+2, y1)
						.moveTo(x+2, y1)
						.lineTo(x-5, y1-3)
						.moveTo(x+2, y1)
						.lineTo(x-5, y1+3)
						.closePath()
						.stroke();
					plot.restore();
					
				
				
				
				}
				else {

					if (r1 != 10) {//正常字体状态,需要改为上标字体
						r1 = 10;
						this.setScriptFont();
						
					}
				
					measure = plot.measureText(upperScript);
					plot.fillText(upperScript, x, y-8, measure);
					
					if (j < len-1 && s[j+1] == '_') {
					
					}
					else {
						x += 1.2*measure;
					}
				}
				
				//直接跳跃过上标字符区段
				i = j;
			}
			else {
				c = s[i];
				
				if (c == ')') {
					s0 += c;
					bracketsLevel -= 1;
					
				}
				else if (c == '(') {
					//如果整个括号被开根式,根号在括号左边
					bracketPos[bracketsLevel] = x + plot.measureText(s0);					
					s0 += c;
					
					bracketsLevel+=1;
					//过了括号就是过了一道关,要刷新坐标
					xMem[bracketsLevel] = x + plot.measureText(s0);
					
					
				}
				else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '÷'
					|| c == '=' || c == ' ') {
					
					if (c == '*') {
						if (i > 0 && /[0-9]/.test(s[i-1]) && /[0-9]/.test(s[i+1])) {
							//对于乘号前后都是数字的情况,把乘号改成叉号
							c = ' \u00D7 ';
						}
						else {
							//对于代数式中,乘号改为点号
							c = ' \u00B7 ';
						}
					}
					
					//如果是运算符后的数被开根式,根号在运算符右边
					if (c == '-' || c == '/') {
						s0 += ' '+c+' ';
					}
					else {
						s0 += c;
					}
				
					if (bracketsLevel < 3) {
						xMem[bracketsLevel] = x+plot.measureText(s0);
					}						
				} else if (c == '|') { //隔字符
					if (bracketsLevel < 3) {
						xMem[bracketsLevel] = x+plot.measureText(s0)-3;
					}
				
				}
				else {
					s0 += c;				
				}				
				
			}
		}
		
		if (s0 != '') { //先把正常字符打印出
			if (r1 != 20) { //字体字号大小还在上标状态
				r1 = 20;
				this.setNormalFont();				
			}
			measure = plot.measureText(s0);
			plot.fillText(s0, x, y, measure);
			x += measure;
		}
		
		plot.restore();
	}
	
	//集合符号,集合表达式的书写
	this.printSet = function(text, xpos, ypos) {
		var s = text ? text : '';
		
		if (s != '') {
			s = s.replace(/\[B\]/ig, '\u2208'); //∈
			s = s.replace(/\[NB\]/ig, '\u2209'); //不属于
			s = s.replace(/\[S\]/ig, '\u2286'); //包含于(是子集)
			s = s.replace(/\[SS\]/ig, '\u2287'); //包含
			s = s.replace(/\[ST\]/ig, '\u228A'); //真包含于(是真子集)
			s = s.replace(/\[SST\]/ig, '\u228B'); //真包含
			
			s = s.replace(/\[UU\]/ig, '\u222A'); //并集 ,由于U表示全集,又常为下标,此处错开
			s = s.replace(/\[I\]/ig, '\u2229'); //交集
			s = s.replace(/\[C\]/ig, '\u2201'); //补集
			s = s.replace(/\[INF\]/ig, '\u221E'); //无穷大
			

		}

		return this.print(s, xpos, ypos);
	}

}
</span>

随着[人叫板老师]教的东西越来越多,现在这些函数是越来越胖了。

不过,这样才能做更多的事。


还是来看看效果:


这些可以这样写出来:

<span style="font-size:18px;">	if (1) {
		var mathText = new MathText();
		
		var s = [
			'a+b+c = d',
			'a_[1]+b_[2]+c_[3] = d_[4]',
			'a^[b] + c^[d] = e^[2.5]',
			'sss^[0.5] + ttt^[0.5] = uuu^[2]',
			'a^[->]+b^[->]+c^[->] = d^[->]',
			'OA^[->]^[2] = a^[->]',
			'OA^[->] = CB^[->] = DO^[->]',
			'OB^[->] = DC^[->] = EO^[->]',
			'OC^[->] = AB^[->] = ED^[->] = FO^[->]',
			
			
			
		];
		
		var x =40, y=40;
		var r1 = 40;
			
		var len = s.length;
		for (var i = 0; i < len; i++) {
		
			if (s[i] == '') {
				if (x < 100) {
					x += 300;
					y-=r1*3;
				}
				else {
					x = 20;
					y += r1;
				}
			}
			else {			
				mathText.print(s[i], x, y);
				y+=r1;
			}
		}		
	
	}
	</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,190);          
            
        //坐标轴设定    
        var scaleX = 3*r, scaleY = 3*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 array = [[0, 0], [5, 0], [6, 4]];
			array_1 = [[0, 0], [6,4]];
			array_2 = [[0, 0], [1, 4], [6, 4]];
			
		var points = [];
		for (var i = 0; i < array.length; i++) {
			points.push(array[i]);
		}
		
		for (var i = 0; i < array_1.length; i++) {
			points.push(array_1[i]);
		}
		
		for (var i = 0; i < array_2.length; i++) {
			points.push(array_2[i]);
		}
		
		points = removeDuplicatedPoint(points);


        var size = array.length;
              
        var transform = new Transform();  
        var tmp = [];  
          
        array = transform.scale(transform.translate(array, 0, 0), scaleX/spaceX, scaleY/spaceY);   
		array_1 = transform.scale(transform.translate(array_1, 0, 0), scaleX/spaceX, scaleY/spaceY);  
		array_2 = transform.scale(transform.translate(array_2, 0, 0), scaleX/spaceX, scaleY/spaceY);  
		points = transform.scale(transform.translate(points, 0, 0), scaleX/spaceX, scaleY/spaceY);   
	

		tmp = [].concat(array);        
		vectorDraw(tmp, 'red'); 
				tmp = [].concat(array_1);        
		vectorDraw(tmp, 'green'); 
				tmp = [].concat(array_2);        
		vectorDraw(tmp, 'blue'); 
	   
	    tmp = [].concat(points);        
        shape.pointDraw(tmp, 'orange', 1, 1, 'OACB');   



		plot.setFillStyle('blue');
		plot.fillText('向量图', -270, -170, 300);
		
		

              
      
    }
	
//去除重复点
function removeDuplicatedPoint(pointArray) {
	var array = new Array();
	var size = pointArray.length;
	
	array.push(pointArray[0]);
	var len = 0;
	
	for (var i = 0; i < size; i++) {
		len = array.length;
		
		for (var j = 0; j < len; j++) {
			if (pointArray[i][0] == array[j][0] &&
				pointArray[i][1] == array[j][1]) {
				break;
			}
			
			if (j >= len-1) {
				array.push(pointArray[i]);
			}
		}
	}
	return array;
}</span>










<span style="font-size:18px;">	if (1) {
		var mathText = new MathText();
		
		var s = [
			'a^[->]+b^[->]=(x_[1]|i^[->]+y_[1]|j^[->])+(x_[2]|i^[->]+y_[2]|j^[->])',
			'=(x_[1]+x_[2])|i^[->]+(y_[1]+y_[2])|j^[->]',
			'=> a^[->]+b^[->]=(x_[1]+x_[2], y_[1]+y_[2])',
			'=> a^[->]-b^[->]=(x_[1]-x_[2], y_[1]-y_[2])',
			'λ|a^[->] = (λx_[1], λy_[1])'
			
			
			
		];
		
		var x =40, y=40;
		var r1 = 40;
			
		var len = s.length;
		for (var i = 0; i < len; i++) {
		
			if (s[i] == '') {
				if (x < 100) {
					x += 300;
					y-=r1*3;
				}
				else {
					x = 20;
					y += r1;
				}
			}
			else {			
				mathText.print(s[i], x, y);
				y+=r1;
			}
		}		
	
	}</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,190);          
            
        //坐标轴设定    
        var scaleX = 3*r, scaleY = 3*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 array = [[0, 0], [2, 1], [-3, 4]];
			array_1 = [[0, 0], [-1,5]];
			array_2 = [[0, 0], [-3, 4]];
			
		var points = [];
		for (var i = 0; i < array.length; i++) {
			points.push(array[i]);
		}
		
		
		for (var i = 0; i < array_1.length; i++) {
			points.push(array_1[i]);
		}
		
		for (var i = 0; i < array_2.length; i++) {
			points.push(array_2[i]);
		}
		
		points = removeDuplicatedPoint(points);


        var size = array.length;
              
        var transform = new Transform();  
        var tmp = [];  
          
        array = transform.scale(transform.translate(array, 0, 0), scaleX/spaceX, scaleY/spaceY);   
		
		if (array_1.length > 0) {
			array_1 = transform.scale(transform.translate(array_1, 0, 0), scaleX/spaceX, scaleY/spaceY);  
		}
		if (array_2.length > 0) {
			array_2 = transform.scale(transform.translate(array_2, 0, 0), scaleX/spaceX, scaleY/spaceY);  
		}
		points = transform.scale(transform.translate(points, 0, 0), scaleX/spaceX, scaleY/spaceY);   
	

		tmp = [].concat(array);        
		vectorDraw(tmp, 'red'); 
		if (array_1.length > 0) {
			tmp = [].concat(array_1);        
			vectorDraw(tmp, 'green'); 
		}
		if (array_2.length > 0) {
			tmp = [].concat(array_2);        
			vectorDraw(tmp, 'blue'); 
		}
	   
	    tmp = [].concat(points);        
        shape.pointDraw(tmp, 'orange', 1, 1);   



		plot.setFillStyle('blue');
		plot.fillText('向量图', -270, -170, 300);
		
		

              
      
    }</span>










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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值