canvas 曲线面片1

Canvas曲线面片与贴图
写前面

*姐姐篇已完成 传送 canvas曲线面片2
(别跟我说这东西没用 并不想理你!)
 
 
什么是曲线面片? 如图

上面这个就是相对简单的双线性面片

可通过4个点来控制  左上角 A点  顺时针依次就是 ABCD 

这个东西 其实就是 BA方向 和 DA 方向的线性插值组合 下图

先沿着DA CB 方向插值 再继续对 BA 方向插值

生成三角坐标的代码:

 1 //初始点
 2     var dot_ar = [
 3       new _$.Vec(0, 0)
 4       ,new _$.Vec(w, 0)
 5       ,new _$.Vec(w, h)
 6       ,new _$.Vec(0, h)
 7     ];
 8 
 9     //ABCD外围向量计算
10     var boundVec =()=>{
11       V['BA'] = {
12         pv: dot_ar[0],
13         v: dot_ar[1].sub(dot_ar[0])
14       };
15 
16       V['CB'] = {
17         pv: dot_ar[1],
18         v: dot_ar[2].sub(dot_ar[1])
19       };
20 
21       V['CD'] = {
22         pv: dot_ar[3],
23         v: dot_ar[2].sub(dot_ar[3])
24       };
25 
26       V['DA'] = {
27         pv: dot_ar[0]
28         , v: dot_ar[3].sub(dot_ar[0])
29       };
30     };
31     //获取N个三角网络坐标
32     var getDots =cb=>{
33       
34       let k = +[];
35       //DA CB
36       for (let i = 0; abs(i - 1) > .000001; i += hn) {
37         //++
38         let s_da = V['DA'].v.scale(i + hn).add(V['DA'].pv);
39         let s_cb = V['CB'].v.scale(i + hn).add(V['CB'].pv);
40 
41         
42         let s_da_ = V['DA'].v.scale(i).add(V['DA'].pv);
43         let s_cb_ = V['CB'].v.scale(i).add(V['CB'].pv);
44 
45        
46         let vecx1 = {
47          
48           v: s_cb_.sub(s_da_)
49          
50           , pv: V['DA'].v.scale(i).add(V['DA'].pv)
51         };
52 
53         let vecx2 = {
54           v: s_cb.sub(s_da),
55           pv: V['DA'].v.scale(i + hn).add(V['DA'].pv)
56         };
57 
58         //再BA方向
59         for (let j = 0; abs(j - 1) > .000001; j += wn) {
60           //  s_ba_   s_ba     *vecx1
61           //  s_ba2_  s_ba2   *vecx2
62           let s_ba = vecx1.v.scale(j + wn).add(vecx1.pv);
63           let s_ba2 = vecx2.v.scale(j + wn).add(vecx2.pv);
64 
65           
66           let s_ba_ = vecx1.v.scale(j).add(vecx1.pv);
67           let s_ba2_ = vecx2.v.scale(j).add(vecx2.pv);
68 
69           //两个三角网络
70           cb && cb({
71             0: { dot_ar: { 0: s_ba_, 1: s_ba, 2: s_ba2_ } },
72             1: { dot_ar: { 0: s_ba2, 1: s_ba2_, 2: s_ba } }
73           }, k);
74 
75           k += 2;
76         };
77       };
78     };

 

拿到坐标后就可以生成三角网络对象了 

 1 var createTrangle = ()=>{
 2       boundVec();
 3       //拿到坐标后 生成三角网络对象
 4       getDots((dot,k)=>{
 5         trangle_ar.push(
 6           TrangleMap({
 7             dot_ar: dot[0].dot_ar,
 8             i: k, wireframe: prop.wireframe,
 9             color: _$.color()
10           })
11           ,TrangleMap({
12             dot_ar: dot[1].dot_ar,
13             i: k + 1, wireframe: prop.wireframe,
14             color: _$.color()
15           })
16         );
17       });
18     };

三角对象的代码:

 1 var TrangleMap = prop=>{
 2     // setTransform 中の矩阵
 3     var trans_ar = [
 4      1, 0, 0,
 5      ,1, 0, 0
 6     ];
 7 
 8     var dot_ar = prop.dot_ar;
 9 
10     //拷份初始点
11     var fix_dot = _$.extend([], dot_ar);
12 
13     var color = prop.color || 'black';
14 
15     var draw = Object.create({
16       line(){
17         var ctx = Stg.ctx;
18 
19         ctx.save();
20         ctx.strokeStyle = color;
21         ctx.lineWidth = 2;
22         ctx.beginPath();
23         ctx.moveTo(dot_ar[0].x, dot_ar[0].y);
24         ctx.lineTo(dot_ar[1].x, dot_ar[1].y);
25         ctx.lineTo(dot_ar[2].x, dot_ar[2].y);
26 
27         ctx.closePath();
28 
29         ctx.stroke();
30         ctx.restore();
31       }
32       ,map(){
33         var ctx = Stg.ctx;
34 
35         ctx.save();
36         //clip三角
37         ctx.beginPath();
38         ctx.moveTo(dot_ar[0].x, dot_ar[0].y);
39         ctx.lineTo(dot_ar[1].x, dot_ar[1].y);
40         ctx.lineTo(dot_ar[2].x, dot_ar[2].y);
41         ctx.closePath();
42 
43         ctx.clip();
44 
45         ctx.save();
46 
47         ctx.setTransform.apply(ctx, trans_ar);
48 
49         ctx.beginPath();
50         ctx.drawImage(Pic.map, 0, 0, Pic.width, Pic.height);
51         ctx.closePath();
52         ctx.restore();
53 
54         ctx.restore();
55       }
56     });
57 
58     var _ = Object.create({
59       render(){
60         prop.wireframe && draw.line();
61         draw.map();
62       },
63       transDot(){
64         
65         dot_ar = ar;
66         //X = ax + cy + 1e
67         //Y = bx + dy + 1f
68 
69         var ar = [[fix_dot[0].x, fix_dot[0].y, 1], [fix_dot[1].x, fix_dot[1].y, 1], [fix_dot[2].x, fix_dot[2].y, 1]];
70 
71         //得到 a c e
72         var dtx = _$.Det3(ar, [dot_ar[0].x, dot_ar[1].x, dot_ar[2].x]);
73         //得到 b d f
74         var dty = _$.Det3(ar, [dot_ar[0].y, dot_ar[1].y, dot_ar[2].y]);
75 
76         // a b c d e f
77         trans_ar = [dtx[0], dty[0], dtx[1], dty[1], dtx[2], dty[2]];
78       }
79     });
80 
81     return _;
82   };

到这里确实已经可以形成面片了。。

 

但是 为何有个transDot方法 - -

因为我们还要对面片进行贴图操作 啊~

what? 贴图不是webgl 干的事么 。。 这里canvas2d也可以

一个三角对象就对应一个drawImage  如图:

 

圈的那个三角贴图  是通过原始尺寸clip过的   但是clip又不帮你做拉伸缩放的变换。。

我们还得配合 transform 或者 setTransform api 传递矩阵参数

它内部是这样计算的

X = ax + cy + e 

Y = bx + dy + f

我们要算出abcdef   也就是解个线性方程组

我用矩阵解法(也可用消元法) 我已经封装过了 那个Det3是这样的

 1 Dai.Det3 = function(){
 2       var det = function(a){
 3         return a[0][0]*a[1][1]*a[2][2]
 4           +a[0][1]*a[1][2]*a[2][0]
 5           +a[0][2]*a[1][0]*a[2][1]
 6 
 7           -a[0][2]*a[1][1]*a[2][0]
 8           -a[0][1]*a[1][0]*a[2][2]
 9           -a[0][0]*a[1][2]*a[2][1];
10       };
11       //x x x   //Y
12       //x x x   //Y
13       //x x x   //Y
14       return function(ar,nar){
15         var a,b,c;
16         var D = det(ar);
17 
18         if(D==0) return console.warn('该矩阵不可逆~');
19 
20         var ar1 = _$.extend([],ar);
21         var ar2 = _$.extend([],ar);
22         var ar3 = _$.extend([],ar);
23 
24         ar1[0][0] = nar[0];
25         ar1[1][0] = nar[1];
26         ar1[2][0] = nar[2];
27 
28        
29         ar2[0][1] = nar[0];
30         ar2[1][1] = nar[1];
31         ar2[2][1] = nar[2];
32 
33         ar3[0][2] = nar[0];
34         ar3[1][2] = nar[1];
35         ar3[2][2] = nar[2];
36 
37         var D1 = det(ar1);
38 
39         var D2 = det(ar2);
40 
41         var D3 = det(ar3);
42 
43         return [D1/D,D2/D,D3/D];
44       }
45     }();

好了放出最终DEMO!

DEOM

 

转载于:https://www.cnblogs.com/daidaidai/p/5366204.html

import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection # 生成数据 Round = np.array([0, 1, 2]) # 横轴 Round A1 = np.array([2, 4, 6, 8]) # 纵轴 A1 Z = np.array([ [17.1, 22.3, 23.8, 24.1], [14.5, 19.0,20.4, 20.9], [11.8, 15.1, 16.7, 17.3] ]) # 创建图形 X, Y = np.meshgrid(A1, Round) fig = plt.figure(figsize=(8, 6)) ax = fig.add_subplot(111, projection='3d') # 绘制3D曲面 for i in range(Z.shape[0]): # 绘制每个数据线条,并标注关键点 ax.plot(Y[i], X[i], Z[i], '-o') ax.plot(Y[i], X[i], np.zeros_like(Z[i]), color='gray', alpha=0.5) # 填充每个四边形面 for j in range(len(A1) - 1): verts = [ [Y[i, j], X[i, j], 0], [Y[i, j + 1], X[i, j + 1], 0], [Y[i, j + 1], X[i, j + 1], Z[i, j + 1]], [Y[i, j], X[i, j], Z[i, j]] ] ax.add_collection3d(Poly3DCollection([verts], color=plt.cm.viridis(i / len(Round)), alpha=0.4)) # 在每个关键点上添加注释 for j in range(Z.shape[1]): ax.text(Y[i, j], X[i, j], Z[i, j] + 0.03, f'{Z[i, j]:.2f}', color='black', ha='center') # 绘制每个点之间的连接线 for j in range(Z.shape[1]): ax.plot(Y[:, j], X[:, j], Z[:, j], '--', color='gray') # 设置标签 ax.set_xlabel('Round') ax.set_ylabel('A1') ax.set_zlabel('Cooperation Rate') # 显示图像 plt.show() # 绘制无直线3D瀑布图 import matplotlib.pyplot as plt import matplotlib.ticker as ticker from mpl_toolkits.mplot3d.art3d import Poly3DCollection import numpy as np def line_3d(x, y, z, x_label_indexs): """ 在y轴的每个点,向x轴的方向延伸出一个折线面:展示每个变量的时序变化。 x: x轴,时间维,右边。 y: y轴,变量维,左边。 z: z轴,数值维。二维矩阵,y列x行。每一行是对应变量的一个时间序列。 x_label_indexs: 需要标注的时间点。 """ x_num = len(x) y_num = len(y) if z.shape[0] != y_num or z.shape[1] != x_num: return -1 # 制作坐标格点(z中每个点对应的x、y坐标) X, Y = np.meshgrid(x, y) # 初始化 canvas = plt.figure() # 创建画布 axs = canvas.add_subplot(111, projection='3d') # 添加三维子图 # 若把111改成234,则意思是:创建一个2*3的网格,并在第4个格子中创建一个axes # 绘制折线面
03-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值