參考
【分享】Cocos Creator 向量基礎(chǔ)及其使用
Cocos Creator 向量基礎(chǔ)及其使用
https://www.bilibili.com/video/BV1X7411F744?p=2
一疗认、向量歸一化
向量的歸一化表示得到一個(gè)方向和向量相同的向量菩帝, 但是向量的模(向量的長度)為 1 。歸一化后的向量,也被叫作單位向量二蓝。
二、向量點(diǎn)乘
向量點(diǎn)乘公式:
根據(jù)點(diǎn)乘公式惩猫,我們知道霉颠,向量點(diǎn)乘是一個(gè)數(shù),那么這個(gè)數(shù)在圖形學(xué)上的幾何意義是什么呢事期?
1.計(jì)算兩個(gè)向量之間的夾角
如果將向量a和向量b進(jìn)行歸一化滥壕,那么可以推導(dǎo)出
我們就可以知道兩個(gè)向量之間的夾角(角度)
vec3 a;
vec3 b;
float c = dot(normalize(a), normalize(b));
2.判斷兩個(gè)向量前后(方向)
觀察cosθ的曲線,可知在0到90度兽泣,270到360度時(shí)其值為正绎橘。
以上圖為例,如果向量a為玩家的正方向唠倦。那么虛線上方的點(diǎn)乘值大于0金踪,即為同方向,也可以理解為前方牵敷。
以上圖為例胡岔,如果AB在X軸上,那么點(diǎn)乘可以幫我們知道點(diǎn)C會落在Y軸的左側(cè)還是右側(cè)枷餐。這個(gè)也很好理解靶瘸,之前的例子向量a是沖著y軸正方向,這個(gè)例子變成沖著x軸正方向而已毛肋。
這里順便說一下叉積怨咪,因?yàn)槭莝inθ,此時(shí)根據(jù)sinθ曲線,0到180度是大于0润匙,所以可以幫我們判斷點(diǎn)C位于X軸的上方還是下方诗眨。
利用這個(gè)幾何意義,可以實(shí)現(xiàn):Creator3D:shader8_這種shader怎樣配標(biāo)題 3D內(nèi)發(fā)光
3.計(jì)算向量投影
得到投影后孕讳,還可以在進(jìn)一步分解向量
投影的一個(gè)典型應(yīng)用在對OBB包圍盒進(jìn)行碰撞檢測的時(shí)候匠楚,經(jīng)常會使用 分離軸定理SAT(Separating Axis Theorem) 進(jìn)行檢測
分離軸定理:通過判斷任意兩個(gè)矩形在任意角度下的投影是否均存在重疊,來判斷是否發(fā)生碰撞厂财。若在某一角度光源下芋簿,兩物體的投影存在間隙,則為不碰撞璃饱,否則為發(fā)生碰撞与斤。
計(jì)算投影就可以用到向量點(diǎn)乘了
詳細(xì)可以參考 碰撞檢測的向量實(shí)現(xiàn)
4.計(jì)算投影點(diǎn),點(diǎn)到線段的距離
已知A,B,C三點(diǎn)坐標(biāo),求出C在AB上的投影坐標(biāo)O撩穿。這樣就能求點(diǎn)C到AB的距離CO磷支。
AB點(diǎn)乘AC=|AB||AC|cosθ,很容易求得AC在AB方向 的投影長度|AO|食寡。將向量AB歸一化之后齐唆,再乘以距離|AO|,然后加上A點(diǎn)的坐標(biāo)冻河,即可得到O的坐標(biāo)箍邮。
擴(kuò)展一下,求C相對AB的鏡面坐標(biāo)叨叙,其實(shí)求到O的坐標(biāo)后锭弊,得到向量CO,然后再加上O的坐標(biāo)擂错,即可得到結(jié)果味滞。即2O-C。
三钮呀、向量叉乘
1.力矩與力偶的概念
從實(shí)踐中知道剑鞍,力除了能使物體移動外,還能使物體轉(zhuǎn)動爽醋。例如用扳手?jǐn)Q螺母時(shí)蚁署,加力可使扳手繞螺母中心轉(zhuǎn)動;拉門把手拽門蚂四,可把門打開光戈,也是加力使門產(chǎn)生轉(zhuǎn)動效應(yīng)的實(shí)例。
那么力使物體產(chǎn)生轉(zhuǎn)動效應(yīng)與哪些因素有關(guān)呢?力F使扳手繞螺母中心O轉(zhuǎn)動的效應(yīng)遂赠,不僅與力的大小成正比久妆,而且還與螺母中心到該力作用線的垂直距離d成正比。因此可用兩者的乘積F·d來度量力F對扳手的轉(zhuǎn)動效應(yīng)跷睦。
轉(zhuǎn)動中心O筷弦,稱為矩心,矩心到力作用線的垂直距離d稱為力臂抑诸,矩心和力的作用線所決定的平面稱為力矩作用面烂琴,過矩心與此平面垂直的直線稱為該力矩使物體轉(zhuǎn)動的軸線。
因此哼鬓,我們用力的大小與力臂的乘積F·d再加上正號或負(fù)號來表示力F使物體繞點(diǎn)轉(zhuǎn)動的效應(yīng)如圖所示监右,稱為力F對O點(diǎn)的矩,簡稱力矩异希,用符號Mo(F)或Mo表示。
一般規(guī)定:順著轉(zhuǎn)軸看力矩作用面使物體產(chǎn)生逆時(shí)針方向轉(zhuǎn)動的力矩為正;反之称簿,為負(fù)
2.知乎 力矩到底是一種什么樣的矢量,為什么他的方向這么奇怪?
當(dāng)物體在旋轉(zhuǎn)時(shí)屉凯,旋轉(zhuǎn)的方向一直在變母赵,我們只能描述成是順勢針或者逆時(shí)針,而不能在旋轉(zhuǎn)的平面里找到一個(gè)方向固定的向量來描述旋轉(zhuǎn)的方向授药,所以物理上用垂直于旋轉(zhuǎn)平面的方向來表示旋轉(zhuǎn)方向士嚎。垂直于平面有兩種可能的方向,以此分別表示逆時(shí)針和順時(shí)針悔叽。這么奇葩大概是為了數(shù)據(jù)表達(dá)的簡潔性和準(zhǔn)確性吧
如果力和力臂都是在紙面上莱衩,那么使杠桿逆時(shí)針轉(zhuǎn)動的,力矩的方向垂直于紙面指向外娇澎,如果力矩使杠桿順時(shí)針轉(zhuǎn)動笨蚁,方向是垂直于紙面指向內(nèi)
3.「力矩」是什么?
請注意我的措辭趟庄,力矩是來描述力對物體的轉(zhuǎn)動作用括细,是描述作用的物理量,就是說轉(zhuǎn)的厲不厲害
M=FrsinωF
力越大轉(zhuǎn)的越厲害r離軸越遠(yuǎn)戚啥,轉(zhuǎn)的越厲害奋单。。猫十。辱匿。。補(bǔ)充炫彩。匾七。。江兢。昨忆。。
叉積之后的方向應(yīng)該是垂直F和L的杉允,這怎么理解呢~為了判定轉(zhuǎn)動方向邑贴。如果力矩方向在F,l所處平面上,你會發(fā)現(xiàn)轉(zhuǎn)動一周力矩會指向平面上各個(gè)方向叔磷,沒有辦法選取正方向拢驾。如果垂直于F,l平面,就可以輕松的選定正方向改基,判定順逆繁疤。
4.點(diǎn)積和叉乘的出現(xiàn)背景是什么?
5.回歸本源系列1.3-向量叉乘
將右手四個(gè)手指指向u的方向,朝著v的方向彎曲稠腊。注意躁染,誰在乘號前,四指先經(jīng)過誰架忌。
我們一般使用的是右手參照系吞彤。這種定義方法并不是一定的,比如在Unity中就是采用左手參照系叹放。
判定左右手坐標(biāo)系的這種思考饰恕,也可以參考讓人懵圈的左右手坐標(biāo)系及Unity中的叉積
這張圖axb時(shí),右手逆時(shí)針旋轉(zhuǎn)時(shí)大拇指指向藍(lán)色箭頭(向上)井仰,所以是右手坐標(biāo)系的圖埋嵌。
6.計(jì)算法線向量
向量a和向量b的叉乘得到一個(gè)垂直于這個(gè)平面的向量,這個(gè)向量也叫法向量
7.判斷向量的左右
假設(shè)向量a 糕档,向量 b 都在 xy 的二維平面上莉恼,并假設(shè)a x b = c 。那么
因?yàn)槎S平面上速那,向量 \ a 和向量 b 的 z 肯定為 0俐银,所以
根據(jù)右手螺旋定則, a x b 表示端仰,法向量 c 是繞向量 a b 所在平面旋轉(zhuǎn)得到的捶惜,這里可以定義
- c 的 z 值為正,則表示向量 a 在向量 b 的 右側(cè)
- c 的 z 值為負(fù)荔烧,則表示向量 a 在向量 b 的 左側(cè)
8.判斷點(diǎn)在多邊形內(nèi)部還是外部
以上圖為例吱七,在剛才左右的基礎(chǔ)上,如果
- 向量{AP} 在向量{AB} 的左邊
- 向量{BP} 在向量{BC} 的左邊
- 向量{CP} 在向量{CA} 的左邊
那么鹤竭,點(diǎn)P 在三角線 ABC 內(nèi)踊餐。這樣子通過叉乘就可以知道點(diǎn)是否在三角形內(nèi)/外,這也是光柵化的基礎(chǔ)臀稚,判斷點(diǎn)是否在三角形內(nèi)吝岭。
更進(jìn)一步,我們還可以通過向量叉乘來判斷點(diǎn)是否在多邊形內(nèi)吧寺。比如:Cocos Creator 提供的 cc.Intersection.pointInPolygon 方法窜管,其內(nèi)部原理是通過向量叉乘來判斷點(diǎn)是否在多邊形內(nèi)
SVG 的填充屬性 fill-rule: evenodd(奇偶填充) 和 nonzero(非零填充) ,其內(nèi)部實(shí)現(xiàn) 我猜 應(yīng)該也是可以通過向量叉乘來解決
9.畫多邊形
既然知道了向量叉乘可以判斷點(diǎn)是否在多邊形內(nèi)外稚机,那么我們也可以根據(jù)這個(gè)幾何意義去畫任意多邊形幕帆。以六邊形為例:
/**
* 畫六邊形
* @param center 中心點(diǎn)
* @param side 六邊形邊長
* @param color 六邊形顏色
*/
vec4 drawHex(vec2 center, float side, vec4 color) {
// 將uv往六邊形中心點(diǎn)偏移,實(shí)現(xiàn)偏移后的坐標(biāo)系原點(diǎn)在紋理中心赖条,x 向右 y 向下
// 并轉(zhuǎn)換為我們需要判斷的點(diǎn)
vec2 uv = v_uv0.xy - center;
vec3 p = vec3(uv, 0.0);
// 計(jì)算六邊形的六個(gè)頂點(diǎn)
float c = cos(radians(60.0));
float s = sin(radians(60.0));
vec3 p0 = vec3(side, 0.0, 0.0);
vec3 p1 = vec3(side * c, -side * s, 0.0);
vec3 p2 = vec3(-side * c, -side * s, 0.0);
vec3 p3 = vec3(-side, 0.0, 0.0);
vec3 p4 = vec3(-side * c, side * s, 0.0);
vec3 p5 = vec3(side * c, side * s, 0.0);
// 計(jì)算當(dāng)前點(diǎn)是否在六邊形內(nèi)(通過向量叉乘)
float r0 = step(0.0, cross(p-p0, p1-p0).z);
float r1 = step(0.0, cross(p-p1, p2-p1).z);
float r2 = step(0.0, cross(p-p2, p3-p2).z);
float r3 = step(0.0, cross(p-p3, p4-p3).z);
float r4 = step(0.0, cross(p-p4, p5-p4).z);
float r5 = step(0.0, cross(p-p5, p0-p5).z);
// 如果在內(nèi)部失乾,inside = 1.0常熙,否則 inside = 0.0
float inside = r0 * r1 * r2 * r3 * r4 * r5;
return vec4(color.rgb, color.a * inside);
}
void main() {
// ... 其他代碼
gl_FragColor = drawHex(vec2(0.5, 0.5), 0.5, o);
}
四、cocos 向量轉(zhuǎn)換為夾角signAngle
signAngle(other: Vec2): number
Defined in cocos/core/math/vec2.ts:774
獲取當(dāng)前向量和指定向量之間的有符號角度仗扬。
有符號角度的取值范圍為 (-180, 180]症概,當(dāng)前向量可以通過逆時(shí)針旋轉(zhuǎn)有符號角度與指定向量同向蕾额。
1.Cocos creator中需要掌握哪些數(shù)學(xué)物理知識
在游戲中早芭,有時(shí)候我們需要計(jì)算物體旋轉(zhuǎn)了多少度,比如我們要模擬一個(gè)KTV里面的游戲轉(zhuǎn)盤诅蝶,手指觸摸的時(shí)候退个,要獲取觸摸的點(diǎn)的位置,觸摸點(diǎn)的位置與轉(zhuǎn)盤中心點(diǎn)之間構(gòu)成一個(gè)向量调炬,我們要獲取轉(zhuǎn)動了多少度语盈,就需要有一個(gè)參考向量。
如下圖所示缰泡,假如藍(lán)色的圓就是轉(zhuǎn)盤的邊緣刀荒,我們最開始觸摸A點(diǎn),然后轉(zhuǎn)動到B點(diǎn)棘钞,這時(shí)候轉(zhuǎn)動的角度就是∠AOB缠借,這個(gè)角度在Cocos中如何求呢?
代碼pos就表示B點(diǎn)的坐標(biāo)宜猜,pos和原點(diǎn)(0,0)相減泼返,得到向量OB,也即代碼中的dirVec姨拥,弧AB為radian绅喉,轉(zhuǎn)換為角度degree。
// 向量轉(zhuǎn)換為角度
vectorsToDegree(dirVec) {
// 水平向右的對比向量
let comVec = cc.v2(1, 0);
// 求方向向量與對比向量間的弧度
let radian = dirVec.signAngle(comVec);
// 將弧度轉(zhuǎn)換為角度
let degree = cc.misc.radiansToDegrees(radian);
return degree;
},
調(diào)用示例(具體可以參考我們的《KTV酒令轉(zhuǎn)盤虛擬仿真實(shí)現(xiàn)》):
// 獲取觸摸點(diǎn)與原點(diǎn)連線的射線與X軸正向的角度
getTouchAngle(e){
var screen_pos = e.getLocation(); // 觸摸點(diǎn)世界坐標(biāo)
// 轉(zhuǎn)換為相對于當(dāng)前節(jié)點(diǎn)的錨點(diǎn)的坐標(biāo)
var pos = this.node.convertToNodeSpaceAR(screen_pos);
// 獲取觸摸點(diǎn)距離輪盤中心點(diǎn)的向量
var dirVec = pos.sub(cc.v2(0,0));
// 將向量轉(zhuǎn)換為基于參考方向(v2(0,1))的角度
return this.vectorsToDegree(dirVec);
},
2.CocosCreator計(jì)算夾角
export default class TestAngle extends cc.Component {
@property(cc.Node)
root: cc.Node;
@property(cc.Graphics)
graph: cc.Graphics;
@property(cc.Node)
target: cc.Node;
@property(cc.Label)
angleDes: cc.Label;
start() {
this.node.on(cc.Node.EventType.TOUCH_MOVE,this.onTouchMove,this);
}
onTouchMove(event: cc.Event.EventTouch): void {
let startPos: cc.Vec2 = this.target.convertToWorldSpaceAR(new cc.Vec2(0, 0));
let endPos: cc.Vec2 = event.getLocation();
let dirVec = endPos.sub(startPos);//獲得從startPos指向endPos的方向向量
let comVec = new cc.Vec2(1, 0);//計(jì)算夾角的參考方向叫乌,這里選擇x軸正方向
let radian = dirVec.signAngle(comVec);//獲得帶方向的夾角弧度值(參考方向順時(shí)針為正值柴罐,逆時(shí)針為負(fù)值)
let degree = Math.floor(cc.misc.radiansToDegrees(radian));
console.log("x角度:" + degree)
this.angleDes.node.position = this.root.convertToNodeSpaceAR(endPos);
this.angleDes.string = degree + "°";
let comEnd = new cc.Vec2(startPos.x + 200, startPos.y);
this.drawAngle(startPos, endPos, comEnd);
}
/**
*
* @param startPos 起始點(diǎn)
* @param endPos 終點(diǎn)(對應(yīng)鼠標(biāo)點(diǎn)擊的點(diǎn))
* @param comEnd 參照向量的終點(diǎn)
*/
private drawAngle(startPos: cc.Vec2, endPos: cc.Vec2, comEnd: cc.Vec2) {
this.graph.clear();
this.graph.lineWidth = 1;
this.graph.strokeColor = cc.Color.WHITE;
this.graph.moveTo(startPos.x, startPos.y);
this.graph.lineTo(endPos.x, endPos.y);
this.graph.stroke();
this.graph.strokeColor = cc.Color.GREEN;
this.graph.moveTo(startPos.x, startPos.y);
this.graph.lineTo(comEnd.x, comEnd.y);
this.graph.stroke();
}
}
五、麒麟子Cocos Creator實(shí)用技巧七:方向與角度轉(zhuǎn)換
本DEMO完整地址:https://gitee.com/qilinzi/qlz_ccc_tips 目錄 base/assets/07_rotationtodir
1.讓一個(gè)對象朝著他的方向移動
cc.Node節(jié)點(diǎn)的rotation是一個(gè)角度憨奸,因此革屠,我們?yōu)榱藢?shí)現(xiàn)這個(gè)目標(biāo),首先要根據(jù)rotation求出他的dir方向膀藐,就好辦了屠阻。示例代碼
update(dt){
//由于Math函數(shù)接受的是孤度,所以我們先節(jié)節(jié)點(diǎn)的旋轉(zhuǎn)轉(zhuǎn)化為弧度
var angle = this.node.rotation / 180 * Math.PI;
//合成基于 X正方向的方向向量
var dir = cc.v2(Math.cos(angle),Math.sin(angle));
//單位化向量
dir.normalizeSelf();
//根據(jù)方向向量移動位置
var moveSpeed = 100;
this.node.x += dt * dir.x * moveSpeed;
this.node.y += dt * dir.y * moveSpeed;
}
2.讓一個(gè)對象朝向另一個(gè)對象
通過高中數(shù)學(xué)我們可以知道额各, A到B的向量 = B點(diǎn) - A點(diǎn)国觉。 那我們只需要將目標(biāo)對象的位置 - 自己的位置,即可得到方向向量虾啦。
方向向量轉(zhuǎn)換為角度麻诀,需要認(rèn)清一個(gè)隱含變量痕寓,就是這個(gè)角度的基準(zhǔn)是 X 軸正方向。 使用向量來表示就是 (1,0)蝇闭。
cc.Vec2提供了兩個(gè)函數(shù) cc.Vec2.angle和cc.Vec2.signAngle呻率, 后者相比前者來說,后者產(chǎn)生的角度是有符號的呻引,而前者會永遠(yuǎn)為正礼仗。 我們使用cc.Vec2.signAngle來將方向向量轉(zhuǎn)換為弧度。 具體操作請看代碼逻悠。
function lookAtObj(target){
//計(jì)算出朝向
var dx = target.x - this.node.x;
var dy = target.y - this.node.y;
var dir = cc.v2(dx,dy);
//根據(jù)朝向計(jì)算出夾角弧度
var angle = dir.signAngle(cc.v2(1,0));
//將弧度轉(zhuǎn)換為歐拉角
var degree = angle / Math.PI * 180;
//賦值給節(jié)點(diǎn)
this.node.rotation = degree;
}
六元践、反復(fù)橫跳的瞄準(zhǔn)線! 從向量計(jì)算說起童谒!基于射線檢測的實(shí)現(xiàn)单旁!
已知入射向量(單位向量),法向量(單位向量)饥伊,如何得出反射向量象浑?
我們將反射向量平移至入射向量起點(diǎn),延長法向量與其相交琅豆,這個(gè)延長線的長度愉豺,剛好是 入射向量在法向量上的投影的相反數(shù)的兩倍 。再根據(jù)投影和向量加法可以推出反射向量的計(jì)算公式趋距。
// author : lamyoung
const AIM_LINE_MAX_LENGTH = 1440;
const { ccclass, property } = cc._decorator;
@ccclass
export default class Main extends cc.Component {
@property({ type: cc.Graphics, tooltip: '瞄準(zhǔn)線作圖' })
graphic_line: cc.Graphics = null;
onLoad() {
cc.director.getPhysicsManager().enabled = true;
// cc.director.getPhysicsManager().debugDrawFlags = 1;
this.graphic_line.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
this.graphic_line.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
this.graphic_line.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
this.graphic_line.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
}
private onTouchStart(touch: cc.Event.EventTouch) {
this.graphic_line.clear();
}
private _cur_length: number = 0;
private onTouchMove(touch: cc.Event.EventTouch) {
this.graphic_line.clear();
this._cur_length = 0;
const startLocation = touch.getStartLocation();
const location = touch.getLocation();
// 計(jì)算射線
this.drawRayCast(startLocation, location.subSelf(startLocation).normalizeSelf());
this.graphic_line.stroke();
}
private onTouchEnd(touch: cc.Event.EventTouch) {
this.graphic_line.clear();
}
/**
* @description 計(jì)算射線
* @param startLocation 起始位置 世界坐標(biāo)系
* @param vector_dir 單位方向向量
*/
private drawRayCast(startLocation: cc.Vec2, vector_dir: cc.Vec2) {
// 剩余長度
const left_length = AIM_LINE_MAX_LENGTH - this._cur_length;
if (left_length <= 0) return;
// 計(jì)算線的終點(diǎn)位置
const endLocation = startLocation.add(vector_dir.mul(left_length));
// 射線測試
// 檢測給定的線段穿過哪些碰撞體粒氧,可以獲取到碰撞體在線段穿過碰撞體的那個(gè)點(diǎn)的法線向量和其他一些有用的信息。
const results = cc.director.getPhysicsManager().rayCast(startLocation, endLocation, cc.RayCastType.Closest);
if (results.length > 0) {
const result = results[0];
// 指定射線與穿過的碰撞體在哪一點(diǎn)相交节腐。
const point = result.point;
// 畫入射線段
this.drawAimLine(startLocation, point);
// 計(jì)算長度
const line_length = point.sub(startLocation).mag();
// 計(jì)算已畫長度
this._cur_length += line_length;
// 指定碰撞體在相交點(diǎn)的表面的法線單位向量外盯。
const vector_n = result.normal;
// 入射單位向量
const vector_i = vector_dir;
// 反射單位向量
const vector_r = vector_i.sub(vector_n.mul(2 * vector_i.dot(vector_n)));
// 接著計(jì)算下一段
this.drawRayCast(point, vector_r);
} else {
// 畫剩余線段
this.drawAimLine(startLocation, endLocation);
}
}
/**
* @description 畫瞄準(zhǔn)線
* @param startLocation 起始位置 世界坐標(biāo)系
* @param endLocation 結(jié)束位置 世界坐標(biāo)系
*/
private drawAimLine(startLocation: cc.Vec2, endLocation: cc.Vec2) {
// 轉(zhuǎn)換坐標(biāo)
const graphic_startLocation = this.graphic_line.node.convertToNodeSpaceAR(startLocation);
this.graphic_line.moveTo(graphic_startLocation.x, graphic_startLocation.y);
// 畫小圓圓
// 間隔
const delta = 20;
// 方向
const vector_dir = endLocation.sub(startLocation);
// 數(shù)量
const total_count = Math.round(vector_dir.mag() / delta);
// 每次間隔向量
vector_dir.normalizeSelf().mulSelf(delta);
for (let index = 0; index < total_count; index++) {
graphic_startLocation.addSelf(vector_dir)
this.graphic_line.circle(graphic_startLocation.x, graphic_startLocation.y, 2);
}
}
}
// 歡迎關(guān)注【白玉無冰】公眾號
七、三維向量
在COCOS 3.x版本中翼雀,使用Vec3向量
1.向量長度
let t2 = v3(2, 2, 2).subtract(v3(0, 0, 0));
console.log("len:", t2.length(), "len2:", Vec3.len(t2));
上述代碼打印出來的值是根號12饱苟,即三個(gè)維度的平方和,再開根號
let l = v3Points[1].clone().subtract(v3Points[0]).length();
let l2 = Vec3.len(v3Points[1].subtract(v3Points[0]));
console.log("p0:", v3Points[0], "p1:", v3Points[1], "len:", l, "l2:", l2);
這里展示的是clone方法的用處狼渊,如果不使用clone箱熬,第一次subtract改變了原始向量,導(dǎo)致兩次取長度結(jié)果不一致狈邑。