1.1  扇形变换

将如图1所示的上边长方形的图形变换为下边的扇形图形的变换称为扇形变换。

设长方形图形中任一点P1(X1,Y1)变换为扇形图形上的点P2(X2,Y2),长方形的长为X,扇形圆心坐标为(X0,Y0),扇形半径为L,扇形与X轴的最小夹角为B,扇形弧对应夹角为C,则点P2的坐标计算公式为:

X2=(L+Y1)*COS(θ)+X0

Y2=-(L+Y1)*SIN(θ)+Y0

其中: θ=C*(X-X1)/X1+B

图1  扇形变换

生成一个六瓣花型图案的基本数据,将长方形中的8个六瓣花型作为基本图案,进行指定层数的扇形变换。

编写如下的HTML代码。

<!DOCTYPE html>

<head>

<title>扇形变换</title>

<script type="text/javascript">

function drawBase(id)

{

var canvas=document.getElementById(id);

if (canvas==null)

return false;

var context=canvas.getContext('2d');

context.fillStyle="#EEEEFF";

context.fillRect(0,0,700,100);

context.fillStyle="yellow";

context.strokeStyle="red";

context.lineWidth=2;

context.beginPath();

var dig=Math.PI/64;

var x=new Array();

var y=new Array();

var w=80;

// 生成一个六瓣花型图案的数据

for (var i=0;i<=128;i++)

{

d=w/2*(0.8+Math.sin(18*i*dig)/5)*1.2;

t=d*(0.5+Math.sin(6*i*dig)/2);

x[i]=t*Math.cos(i*dig);

y[i]=t*Math.sin(i*dig);

}

// 在水平一行中绘制8个六瓣花型图案

for (n=1;n<=8;n++)

{

px=(2*n-1)/2*w+30;

for (i=0;i<=128;i++)

{

x1=px+x[i];

y1=w/2-y[i];

if (i==0)

{

context.moveTo(x1,y1);

bx=x1;  by=y1;

}

else

context.lineTo(x1,y1);

}

}

context.lineTo(bx,by);

context.closePath();

context.stroke();

context.fill();

}

function drawSector(id)

{

var canvas=document.getElementById(id);

if (canvas==null)

return false;

var context=canvas.getContext('2d');

context.fillStyle="#EEEEFF";

context.fillRect(0,0,700,500);

context.fillStyle="yellow";

context.strokeStyle="red";

context.lineWidth=2;

context.beginPath();

var dig=Math.PI/64;

w=80;

var x=new Array();

var y=new Array();

// 生成一个六瓣花型图案的数据

for (var i=0;i<=128;i++)

{

d=w/2*(0.8+Math.sin(18*i*dig)/5)*1.2;

t=d*(0.5+Math.sin(6*i*dig)/2);

x[i]=t*Math.cos(i*dig);

y[i]=t*Math.sin(i*dig);

}

var k=eval(document.myForm.levelNum.value);

if (k<1 || k>=6)     {

alert("扇形层数需设定为1~5之一!");

return;

}

// 进行多重扇形变换

l=100;  b=Math.PI/3;  c=Math.PI/3;  x0=350;  y0=500;

for (m=1;m<=k;m++)

for (n=1;n<=8;n++)

for (var i=0;i<=128;i++)

{

px=(2*n-1)/2*w;

py=(2*m-1)/2*w;

x1=px+x[i];

y1=py-y[i];

th=c*(w*8-x1)/(w*8)+b;

x2=(l+y1)*Math.cos(th)+x0;

y2=-(l+y1)*Math.sin(th)+y0;

if (i==0)

{

context.moveTo(x2,y2);

bx=x2;  by=y2;

}

else

context.lineTo(x2,y2);

}

context.lineTo(bx,by);

context.closePath();

context.stroke();

context.fill();

}

</script>

</head>

<body onload="drawBase('myCanvas1');">

基本图案<br/>

<canvas id="myCanvas1" width="700" height="100">您的浏览器不支持canvas!</canvas>

<form name="myForm">

扇形中基本图案层次数<input type=number name="levelNum" value=4 size=3>

<input type=button value="确定" onClick="drawSector('myCanvas2');">

</form><br>

<canvas id="myCanvas2" width="700" height="500">您的浏览器不支持canvas!</canvas>

</body>

</html>

将上述HTML代码保存到一个html文本文件中,再在浏览器中打开包含这段HTML代码的html文件,在“扇形中基本图案层次数”数值框中输入“5”,单击“确定”按钮,可以在浏览器窗口中看到基本六瓣花型图案的5层扇形变换,如图2所示。

图2  扇形变换

1.2  环形变换

将如图3所示的上边长方形带状图形变换为下边的环状图形的变换称为环形变换。环状变换将带状图的左右两端接在一起,因而带状图的上部被拉伸,下部被压缩。

设带状图形中任一点P1(X1,Y1)变换为环状图形上的点P2(X2,Y2),带状长方形的长为X,环状图形的圆心坐标为(PX,PY),L为环形内半径(L的值越小,变换后图案的变形越大),则点P2的坐标计算公式为:

X2=(L+Y1)*COS(θ)+PX

Y2=-(L+Y1)*SIN(θ)+PY

其中: θ=2π*(X-X1)/X

图3  环形变换

按环形变换的方法将如图4所示的基本图案进行环形变换。

图4  用于环形变换的基本图案

编写如下的HTML代码。

<!DOCTYPE html>

<head>

<title>环形变换</title>

<script type="text/javascript">

function draw1(id)

{

var canvas=document.getElementById(id);

if (canvas==null)

return false;

var context=canvas.getContext('2d');

context.fillStyle="#EEEEFF";

context.fillRect(0,0,800,500);

context.fillStyle="yellow";

context.strokeStyle="red";

context.lineWidth=1;

context.beginPath();

var dig=Math.PI/64;

var x=new Array();

var y=new Array();

var w=100;

// 生成一个六瓣花型图案的数据

for (var i=0;i<=128;i++)

{

d=w/2*(0.8+Math.sin(18*i*dig)/5)*1.2;

t=d*(0.5+Math.sin(6*i*dig)/2);

x[i]=t*Math.cos(i*dig);

y[i]=t*Math.sin(i*dig);

}

// 在水平一行中绘制8个六瓣花型图案

for (n=1;n<=8;n++)

{

px=(2*n-1)/2*w;

for (i=0;i<=128;i++)

{

x1=px+x[i];

y1=w/2-y[i];

if (i==0)

{

context.moveTo(x1,y1);

bx=x1;  by=y1;

}

else

context.lineTo(x1,y1);

}

}

context.lineTo(bx,by);

context.closePath();

context.stroke();

context.fill();

}

function draw2(id)

{

var canvas=document.getElementById(id);

if (canvas==null)

return false;

var context=canvas.getContext('2d');

context.fillStyle="#EEEEFF";

context.fillRect(0,0,800,500);

context.fillStyle="yellow";

context.strokeStyle="red";

context.lineWidth=2;

context.beginPath();

var dig=Math.PI/64;

var x=new Array();

var y=new Array();

var w=100;

var l=80;

// 生成一个六瓣花型图案的数据

for (var i=0;i<=128;i++)

{

d=w/2*(0.8+Math.sin(18*i*dig)/5)*1.2;

t=d*(0.5+Math.sin(6*i*dig)/2);

x[i]=t*Math.cos(i*dig);

y[i]=t*Math.sin(i*dig);

}

// 进行一重环形变换

for (n=1;n<=8;n++)

for (var i=0;i<=128;i++)

{

px=(2*n-1)/2*w;

x1=px+x[i];

y1=w/2+y[i];

th=2*Math.PI*(w*8-x1)/(w*8);

x2=(l+y1)*Math.cos(th)+400;

y2=(l+y1)*Math.sin(th)+250;

if (i==0)

{

context.moveTo(x2,y2);

bx=x2;  by=y2;

}

else

context.lineTo(x2,y2);

}

context.lineTo(bx,by);

context.closePath();

context.stroke();

context.fill();

}

function draw3(id,k)

{

var canvas=document.getElementById(id);

if (canvas==null)

return false;

var context=canvas.getContext('2d');

context.fillStyle="#EEEEFF";

context.fillRect(0,0,800,500);

context.fillStyle="yellow";

context.strokeStyle="red";

context.lineWidth=2;

context.beginPath();

var dig=Math.PI/64;

w=200/k;  l=0;

var x=new Array();

var y=new Array();

// 生成一个六瓣花型图案的数据

for (var i=0;i<=128;i++)

{

d=w/2*(0.8+Math.sin(18*i*dig)/5)*1.2;

t=d*(0.5+Math.sin(6*i*dig)/2);

x[i]=t*Math.cos(i*dig);

y[i]=t*Math.sin(i*dig);

}

// 进行多重环形变换

for (m=1;m<=k;m++)

for (n=1;n<=8;n++)

for (var i=0;i<=128;i++)

{

px=(2*n-1)/2*w;

py=(2*m-1)/2*w;

x1=px+x[i];

y1=py-y[i];

th=2*Math.PI*(w*8-x1)/(w*8);

x2=(l+y1)*Math.cos(th)+400;

y2=(l+y1)*Math.sin(th)+250;

if (i==0)

{

context.moveTo(x2,y2);

bx=x2;  by=y2;

}

else

context.lineTo(x2,y2);

}

context.lineTo(bx,by);

context.closePath();

context.stroke();

context.fill();

}

</script>

</head>

<body>

<button onClick="draw1('myCanvas');">基本图案</button>&nbsp;&nbsp;

<button onClick="draw2('myCanvas');">环形变换</button>&nbsp;&nbsp;

<button onClick="draw3('myCanvas',2);">二重环形变换</button>&nbsp;&nbsp;

<button onClick="draw3('myCanvas',3);">三重环形变换</button>

<br/><br/>

<canvas id="myCanvas" width="800" height="500">您的浏览器不支持canvas!</canvas>

</body>

</html>

将上述HTML代码保存到一个html文本文件中,再在浏览器中打开包含这段HTML代码的html文件,可以看到在浏览器窗口中,出现“基本图案”、“环形变换”、“二重环形变换”、“三重环形变换”这四个按钮,单击“基本图案”按钮,绘制出如图4所示的基本图案,单击“环形变换”,绘制出如图5所示的环形变换图案,单击“二重环形变换”,绘制出如图6所示的二重环形变换图案,单击“三重环形变换”,绘制出如图7所示的三重环形变换图案。

图5  环形变换图案

图6 二重环形变换图案

图7 三重环形变换图案

下面我们将上面的例子进行扩充,提供多种基本图案的选择,选择好基本图案后,进行环形变换。编写的HTML文件内容如下。

<!DOCTYPE html>

<head>

<title>可选择图案的环形变换</title>

<script type="text/javascript">

// 定义保存基本图案数据的二维数组

var x=new Array(10);

var y=new Array(10);

for (var i=0;i<10;i++)

{

x[i]=new Array(129);

y[i]=new Array(129);

}

var sele=0;

function initGraph()

{

var dig=Math.PI/64;

var w=100;

// 生成一个六瓣花型图案的数据

for (var i=0;i<=128;i++)

{

d=10*Math.sin(8*(i*dig+Math.PI/16));

x[0][i]=d*Math.cos(i*dig)+30*Math.cos(i*dig)*Math.cos(i*dig)*Math.cos(i*dig);

y[0][i]=d*Math.sin(i*dig)+30*Math.sin(i*dig)*Math.sin(i*dig)*Math.sin(i*dig);

}

// 生成一个六瓣花型图案的数据

for (var i=0;i<=128;i++)

{

d=w/2*(0.8+Math.sin(18*i*dig)/5)*1.2;

t=d*(0.5+Math.sin(6*i*dig)/2);

x[1][i]=t*Math.cos(i*dig);

y[1][i]=t*Math.sin(i*dig);

}

// 生成一个六瓣花型图案的数据

for (var i=0;i<=128;i++)

{

d=35*Math.sqrt(Math.abs(Math.cos(3*i*dig)));

t=d+10*Math.sqrt(Math.abs(Math.cos(9*i*dig)));

x[2][i]=t*Math.cos(i*dig)*1.2;

y[2][i]=t*Math.sin(i*dig);

}

}

initGraph();

function seleShape()

{

sele=document.frm.shape.selectedIndex-1;

drawBase('myCanvas');

}

function drawBase(id)

{

var canvas=document.getElementById(id);

if (canvas==null)

return false;

var context=canvas.getContext('2d');

context.fillStyle="#EEEEFF";

context.fillRect(0,0,800,500);

context.fillStyle="yellow";

context.strokeStyle="red";

context.lineWidth=1;

context.beginPath();

var dig=Math.PI/64;

var w=100;

// 在水平一行中绘制8个基本花型图案

for (n=1;n<=8;n++)

{

px=(2*n-1)/2*w;

for (i=0;i<=128;i++)

{

x1=px+x[sele][i];

y1=w/2-y[sele][i];

if (i==0)

{

context.moveTo(x1,y1);

bx=x1;  by=y1;

}

else

context.lineTo(x1,y1);

}

}

context.lineTo(bx,by);

context.closePath();

context.stroke();

context.fill();

}

function drawRound(id,k)

{

var canvas=document.getElementById(id);

if (canvas==null)

return false;

var context=canvas.getContext('2d');

context.fillStyle="#EEEEFF";

context.fillRect(0,0,800,500);

context.fillStyle="yellow";

context.strokeStyle="red";

context.lineWidth=2;

context.beginPath();

var dig=Math.PI/64;

w=80;  l=10;

// 进行多重环形变换

for (m=1;m<=k;m++)

for (n=1;n<=10;n++)

for (var i=0;i<=128;i++)

{

px=(2*n-1)/2*w;

py=(2*m-1)/2*w;

x1=px+x[sele][i];

y1=py-y[sele][i];

th=2*Math.PI*(w*10-x1)/(w*10);

x2=(l+y1)*Math.cos(th)+400;

y2=(l+y1)*Math.sin(th)+250;

if (i==0)

{

context.moveTo(x2,y2);

bx=x2;  by=y2;

}

else

context.lineTo(x2,y2);

}

context.lineTo(bx,by);

context.closePath();

context.stroke();

context.fill();

}

</script>

</head>

<body>

<form name="frm">基本图案选择:

<select name="shape" onchange="seleShape();">

<option value="图案1">--请选择--</option>

<option value="图案1">图案1</option>

<option value="图案2">图案2</option>

<option value="图案3">图案3</option>

</select>

</form>

<button onClick="drawRound('myCanvas',1);">环形变换</button>&nbsp;&nbsp;

<button onClick="drawRound('myCanvas',2);">二重环形变换</button>&nbsp;&nbsp;

<button onClick="drawRound('myCanvas',3);">三重环形变换</button>

<br/><br/>

<canvas id="myCanvas" width="800" height="500">您的浏览器不支持canvas!</canvas>

</body>

</html>

将上述HTML代码保存到一个html文本文件中,再在浏览器中打开包含这段HTML代码的html文件,可以看到在浏览器窗口中,出现“基本图案选择”下拉列表框,提供三种基本图案的选择,还有“环形变换”、“二重环形变换”、“三重环形变换”这三个命令按钮。选定“基本图案”后,单击某个按钮,绘制出基本图案的相应环形变换图案。整个演示过程录屏后展示如图8所示。

图8  可选择图案的环形变换

JavaScript图形实例:图形的扇形变换和环形变换的更多相关文章

  1. JavaScript图形实例:再谈IFS生成图形

    在“JavaScript图形实例:迭代函数系统生成图形”一文中,我们介绍了采用迭代函数系统(Iterated Function System,IFS)创建分形图案的一些实例.在该文中,仿射变换函数W的 ...

  2. JavaScript图形实例:Canvas API

    1.Canvas概述 Canvas API(画布)用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitmap). 要使用HTML5在浏览器窗口中绘制 ...

  3. JavaScript图形实例:线段构图

    在“JavaScript图形实例:四瓣花型图案”和“JavaScript图形实例:蝴蝶结图案”中,我们绘制图形时,主要采用的方法是先根据给定的曲线参数方程计算出两点坐标,然后将两点用线段连接起来,线段 ...

  4. JavaScript图形实例:随机SierPinski三角形

    在“JavaScript图形实例:SierPinski三角形”中,我们介绍了SierPinski三角形的基本绘制方法,在“JavaScript图形实例:迭代函数系统生成图形”一文中,介绍了采用IFS方 ...

  5. JavaScript动画实例:李萨如曲线

    在“JavaScript图形实例:阿基米德螺线”和“JavaScript图形实例:曲线方程”中,我们学习了利用曲线的方程绘制曲线的方法.如果想看看曲线是怎样绘制出来的,怎么办呢?编写简单的动画,就可以 ...

  6. JavaScript动画实例:递归分形图动态展示

    在“JavaScript图形实例:SierPinski三角形” 和“JavaScript图形实例:Levy曲线及其变形”等文章中我们介绍了通过递归生成分形图形的方法.我们可以将绘制的分形图形每隔一定的 ...

  7. JavaScript动画实例:曲线的绘制

    在“JavaScript图形实例:曲线方程”一文中,我们给出了15个曲线方程绘制图形的实例.这些曲线都是根据其曲线方程,在[0,2π]区间取一系列角度值,根据给定角度值计算对应的各点坐标,然后在计算出 ...

  8. JavaScript小实例:拖拽应用(二)

    经常在网站别人的网站的注册页中看到一个拖拽验证的效果,就是它的验证码刚开始不出来,而是有一个拖拽的条,你必须将这个拖拽条拖到底,验证码才出来,说了感觉跟没说一样,你还是不理解,好吧,我给个图你看看: ...

  9. javascript小实例,拖拽应用(一)

    前面我们将了一下拖拽的基本思想,理论是有了,那实践呢,可以运用到什么地方呢?下面就给大家带来一个用拖拽思想写的一个小实例,供大家参考,大致效果看下图: 就是这样一个简单的一个拖拽条,你可以把它理解为滚 ...

随机推荐

  1. learning java 文件过滤器

    import java.io.File; public class FilenameFilterTest { public static void main(String[] args) { var ...

  2. WAMP 403 Forbidden禁止访问,别的电脑访问不了;

    直接上图: 1:修改httpd.conf; deny from all 改成------ allow from all 重启服务就好了: 2:如果搜不到deny from all 就按照下面的方法来 ...

  3. Luogu P1903 BZOJ 2120 数颜色 带修改的莫队

    https://www.luogu.org/problemnew/show/P1903 之前切过这道题,复习莫队再切一遍,不过我之前写的是主席树和树状数组,也不知道我当时怎么想的…… 这个题卡常我没写 ...

  4. (21)打鸡儿教你Vue.js

    组件化思想: 组件化实现功能模块的复用 高执行效率 开发单页面复杂应用 组件状态管理(vuex) 多组件的混合使用 vue-router 代码规范 vue-router <template> ...

  5. [golang]7种 Go 程序性能分析方法

    视频信息 Seven ways to Profile Go Applicationsby Dave Cheneyat Golang UK Conf. 2016 视频:https://www.youtu ...

  6. 深度Linux /etc/profile 环境变量生效问题

    /etc/profile 环境变量生效问题 设置了环境变量后 ,使用source /etc/profile生效后,每次关闭终端后,都需要重新输入source /etc/profile命令使环境变量生效 ...

  7. 【BZOJ】BZOJ3040 最短路 线段树优化Dijkstra

    题目描述 N个点,M条边的有向图,求点1到点N的最短路(保证存在). 1<=N<=1000000,1<=M<=10000000 输入格式 第一行两个整数N.M,表示点数和边数. ...

  8. GO语言数组,切片,MAP总结

    数组 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型. 数组的长度必须是常量,并且长度是数组类型的一部分.一旦定义,长度不能变.数 ...

  9. redis rehash

    rehash 随着操作的不断执行, 哈希表保存的键值对会逐渐地增多或者减少, 为了让哈希表的负载因子(load factor)维持在一个合理的范围之内, 当哈希表保存的键值对数量太多或者太少时, 程序 ...

  10. ubuntu之路——day10.7 提高模型的表现

    总结一下就是在提升偏差的方面(即贝叶斯最优误差和训练误差的差距) 1.尝试更大更深的网络 2.加入优化算法比如前面提过的momentum.RMSprop.Adam等 3.使用别的神经网络架构比如RNN ...