计算机中很多功能的实现,都是“先通过某种条件,筛选出符合要求的元素,然后对这些元素进行操作”。 |
以下例子来自于吕国英主编的《算法设计与分析》第二版(例20,82页)。
【例20】编程打印有如下规律的n*n方阵。
使左对角线和右对角线上的元素为0,它们上方的元素为0,左边元素为2,下方元素为3,右边元素为4,下图是一个符合条件的五阶矩阵。
0 1 1 1 0
2 0 1 0 4
2 2 0 4 4
2 0 3 0 4
0 3 3 3 0
算法设计:根据数据分布的特点,利用以上关于二维数组的基本常识,只考虑可读性的情况。
算法如下:(原书中为伪代码,此处我直接写成了C++)
#include <iostream>
int main()
{
int i, j, a[100][100], n;
std::cin >> n;
for (i = 1; i <= n; i = i + 1)
{
for (int j = 1; j < n; j++)
{
if(i==j || i+j==n+1) a[i][j]=0;
if(i+j<n+1 && i<j) a[i][j]=1;
if(i+j<n+1 && i>j) a[i][j]=2;
if(i+j>n+1 && i>j) a[i][j]=3;
if(i+j>n+1 && i<j) a[i][j]=4;
}
}
for (i = 1; i <= n; i = i + 1)
{
for (int j = 1; j <= n; j++)
{
std::cout <<a[i][j] <<"\t";
}
std::cout <<"\n";
}
system("pause");
return 0;
}
可以看到,在循环中,根据元素的位置,判断出当前位置所在的元素应该是几,然后赋给合理的值。
在上个例子看过以后过了一两天,学到了使用xlwings来操作excel。在一个教程下面看到了大牛们操作excel输出图案的例子。https://blog.csdn.net/whalefall/article/details/102665002。于是想到自己也试试吧,做了两个练手。
import xlwings as xw
import math
def Cross(n):
book=xw.Book()
sht=book.sheets(1)
H=7.5
W=1.188
for i in range(1,n+1):
for j in range(1,n+1):
rng=sht.range(i,j)
if j==1:
rng.row_height=H
if i==1:
rng.column_width=W
if i==j:
rng.color=(255,0,0)
elif j==n+1-i:
rng.color=(255,0,0)
def Sin(n):
book=xw.Book()
sht=book.sheets(1)
H=7.5
W=1.188
for i in range(1,2*n+2):
for j in range(1,2*n+1):
rng=sht.range(i,j)
if j==1:
rng.row_height=H
if i==1:
rng.column_width=W
if abs(n*math.sin(2*math.pi/(2*n+1) * (j-1))-(n+1-i))<0.7:
rng.color=(255,0,0)
Cross(21)
# Sin(21)
实际上,这个例子和上面那一个课本中的例子非常像,也是遍历各个元素,在符合条件的位置处进行某种特殊操作。(实际上我刚开始想像书中的例子一样,把一个区域按对角线划分成四个块,分别给不同的颜色,不过后来觉得太过麻烦,就先划了叉)。
Fluent是一个仿真软件,如果没有接触过,可以直接跳过这一部分。
在Fluent中,可以通过UDF来实现一些较为复杂的操作。在Fluent的帮助中提供了很多例子,比如根据入口处网格的坐标,设定不同的入口压强。(这里是压强,压强,压强,不是压力!)
UDF语句能做的事情挺多,甚至可以直接修改整个场中的值(假如你是上帝,知道每个网格内物理量的值的话,你可以通过UDF直接给每个网格赋值,这样或许能节约一些节省计算时间)。我现在去做个例子。
做了个正方形,正方形的中心在坐标原点,正方形边长为10。通过以下UDF,对网格温度赋值,使每个网格的温度值等于其到原点的距离。
#include "udf.h"
// 注意,整个场是正方形,中心在原点,每条边长是20(单位就不写了)
DEFINE_ON_DEMAND(test)
{
cell_t c;
real pos[2];
real x,y;
real dis; // 到原点的距离
Domain *d=Get_Domain(1);
Thread *ct=Lookup_Thread(d,8);
begin_c_loop(c,ct)
{
C_CENTROID(pos,c,ct);
x=pos[0];
y=pos[1];
dis=sqrt(x*x+y*y);
C_T(c,ct)=dis;
}
end_c_loop(c,ct)
}
使用上述UDF后查看温度场,得到结果如下。
可以看到,这其实与前面是相同的,又是一个找到合理的点,给点赋值的操作。
很久不搞UDF,刚才做了好半天好半天啊,都有点没有刚开始写东西的时候的感觉了,我得酝酿一下。
今天看了一点很多人推荐的图形学入门资料,Peter Shirley 的《Ray Tracing in One Weekend》。磕磕绊绊地把书上的内容做了一点。现在刚做到第五章。
虽然确实能感觉这书通俗易懂,但是有些地方以我的水平看着还是挺费劲。书上的向量运算倒是不难,但是我总觉得表示光线的那个向量怎么那么别扭。反复看了看,突然有一刻我发现,这怎么跟操作Excel单元格一样!
其实不管多复杂,都是为了最终给每个像素算一组想要的颜色,比如要显示球,就要找到在当前的光线下,屏幕上哪个点应该是可以显示球,再算出来具体颜色值应该是多少。这样一看,我觉得现在接触到的这几章里的内容,与之前几个例子之间最大的不同可能就是复杂程度了。而且感觉,为了将程序通用化,在目前这个阶段看写出来的代码,似乎有些冗长。其实整个程序就是得到每个像素点的颜色,然后再输出到文本文件里,我甚至直接不用看书,按之前说的Python,或者Fluent UDF的思路也,肯定完全是可以的!
光线追踪这部分的代码有点长,我就偷懒不贴了。给个抄书中代码得到的ppm结果图意思一下,是用matlab打开的。
发现了,从宏观上来看我现在接触到的图形学的这点入门知识,总结成一句话就是计算出每个像素中的颜色,并输出。
于是,从战略角度,对图形学没有一点生疏和恐惧,因为我类似的事情早就做过很多次了!
当然从具体实现手段来讲,肯定需要用到非常多的计算,想要掌握还是要付出巨大的努力。
(写的途中搞了一些杂七杂八的事情,感觉没开始时那么兴奋了,可能真的是个显而易见的东西,耽误大佬们的时间了。)