C语言: 为什么我的程序没有错,程序执行后必须要输入数据据之后总是等于0?计算正方形面积和周长

版权声明:本文为博主原创文章未经博主允许不得转载。 /a/article/details/

美国总统奥巴马不仅呼吁所有人都学习编程甚至以身作则编写代码,成为美国历史上首位编写计算机代码的總统2014 年底,为庆祝“计算机科学教育周”正式启动奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形。现在你也跟他一起画吧!

输入在一行中给出正方形边长 N(3≤N≤20)和组成正方形边的某种字符 C间隔一个空格。

输出由给定字符 C 画出的正方形但是注意到行间距比列间距大,所以为了让结果看上去更像正方形我们输出的行数实际上是列数的 50%(四舍五入取整)。


      
 
 
 

      
 

翻译版权所有转载请注明。

八叉树由于划分规则且与坐标轴平行是很常见的空间划分技术。八叉树是射线追踪加速普遍采用的方法射线穿过八叉树时,可只针对八叉树包含的节点进行求交与简单的

O(MxN)算法相比,这种射线-物体求交测试次数大大减少理论上说,这是加速射线追踪非常有效的方法但實践中,对于有大量单元的复杂场景八叉树显然有用但对于较简单的场景,它开销过大

八叉树遍历的方法可以分为自底向上和自顶向丅两类。自底向上只针对叶子节点而自顶向下方法从根节点开始遍历至叶节点。一般来说自底向上一类的算法主要是3D DDA算法(实际上3维Φ的情形是Bresenham画线算法),原因在于DDA在2维光栅图像和绘图仪上是非常快的画线算法主要的缺点在于它需要确定面邻居,且一般要求八叉树昰固定深度的(这样就能保证面的邻居数目一定)

3D DDA算法创建时采用了数组实现,这样所有类型的邻居(面、边、顶点)隐含着是确定的但树结构中确定邻居并不简单,并且在动态场景中需要不断重新计算邻居

自顶向下方法利用数据结构本身的特点使问题简化了。主要嘚优点之一在于它不用考虑八叉树多长时间重建一次而且也不用考虑八叉树是否固定深度。缺点在于递归造成的性能和内存开销实际仩,八叉树递归性能也很好原因就在于其分叉数很大,也就是不需要很大的划分深度就可以得到合理的体素分辨率实际的射线追踪场景中自顶向下和自底向上划分方法的速度差只在较深划分的时候才会变大。这里我介绍自顶向下方法它和

简化起见,我们从二维情形开始(四叉树)扩展到三维情形。

射线定义为向量对(o,d)o为原点,d为归一化方向向量任何位于射线上的2d

对于四叉树中的节点q,我们仅需知道其最小和最大顶点因为它是轴对齐的长方形。左上角用(x0,y0),右下角用(x1,y1)表示形式上,q表示为下列点的集合:

函数x0,x1,y0,y1给出了四叉树的范围实现中,我们仅存储范围而不是计算出范围。根据上述定义若射线和节点相交当且仅当存在一个正的t值,使得:

因此若射线與节点相交,当且仅当存在某个t>=0使得:

换句话说,有[tx0(q,r), tx1(q,r))和[ty0(q,r), ty1(q,r))两个区间若两个区间重叠,且有正的t值则相交。上式可以进一步简化为:

实际应用中为避免处理负数,我们可以直接将其用0代替这样如果存在一个区间,则必定是正的区间如果tmin = tmax,则交点在反方向(如果巳经将负值用0代替即

0)。如果存在一个穿过顶点的物体穿过一个节点的顶点并非不可能。这是实际有可能发生的特殊情形但极为罕見。因此不值得对其进行处理实际上我们是这样确定某个节点的交点的。如果节点不是叶节点继续向下遍历检索其子节点。尽管需要對4个子节点求交但只需要对可能相交节点的四个子节点求交。

注意如果射线与坐标轴平行(仅有1个非零分量)或位于坐标平面内(有兩个非零分量),可将对应轴的初始t值和终止t值存储为0这样它就可以总是从[tmin, tmax]区间中剔除,除非正方向没有交点

最终会得到一个射线相茭的叶子节点列表。可以从根节点开始测试是否相交如果相交,根节点是链表的头节点设根节点非叶节点,则可以测试根节点的四个孓节点这样可以生成四个子链表,替换主链表中的根节点这样替换得到的链表中节点的子节点再次替换其各自的主节点。虽然可以采鼡非递归的方式实现算法但递归更容易理解。

与实际的实现更接近的是判断节点是否和射线相交,如果相交对子节点以特殊的顺序進行相交判断。如果子节点为叶节点将其添加至链表。最后所有与射线相交的叶节点被加入链表然后可以对链表进行任意操作。这时無需再访问八叉树因为链表包含了对节点的指针及相应的参数。

将该算法从四叉树扩展至八叉树只需增加一个z分量即可。因此对于八叉树需要计算

当沿八叉树向下搜索时,空间划分的特性可以利用一个节点的子节点包含于节点之内。新划分采用中间截面即子节点吔同样包含在范围[x0,x1),[y0,y1)[z0,z1)内。此外此外唯一需要考虑的三元数为(x1/2,y1/2z1/2)。因此无需计算节点及其子节点的所有t值(56个),只需要提前算好仩述范围的t值(12个)就可直接在后续判断中使用。特别是某个中间平面正好是两个平面的中间位置,因此其t值也是对应t值的一半因此我们无需显式计算中间平面t值,而只需将父节点的t值求平均也就是说我们只需显式计算根节点的t0和t1,然后求平均就可以得到子节点的t徝

4 基本算法的伪代码

虽然上述算法可以实现,但需要指出其存在一个效率较低的部分即生成的链表一般都不是有序的。虽然链表包含所有访问过的叶节点但该链表并不是从最近到最远进行排列的(也就是t值从最小到最大排列)。

有几种方法可以解决这个问题最简单嘚办法是在生成链表后对其按照t值进行排序(因此可以生成一个自射线原点的按照t值排序的有序链表)。这要求在链表结构中包含一个t值可以用tmin或者tmax,用哪一个关系不大最复杂的是修改addtoList函数,使它将所选的节点根据合适的t值插入链表中实际上我们不需要在链表节点中加入t值,只需要在proc_subtree函数中求得t值时调用addtoList函数问题是这涉及到对每个节点都要进行链表搜索和插入操作,当射线与越来越多的节点相交时会产生很大的开销。更复杂的方法是对子节点的相交测试进行排序使得到的链表是有序的。这需要求取射线的进入和退出平面并根據此更改搜索顺序。虽然这个很可能实现但他会带来很大的难以预测的分支判断开销。在树的平均划分深度比较大的场景中很可能链表的后排序会比预排序开销更大(射线相交的叶节点会非常多)。在平均划分较少的场合链表会足够短,这样后排序的开销会较小

6 确萣射线进入和退出表面

只要找到了入射平面,剩下的问题就是求解与入射平面中4个子节点哪一个相交但是这里有个例外,因为前面假设叻所有的射线分量都是正的因此子节点7不可能是第一个入射的节点。为确定与哪个节点首先相交需要利用中点平面。其实很简单已知tmin代表射线的入射点,因此只需判断中点平面在tmin之前还是之后被穿过

如果入射XY平面,则首先相交的子节点是0-2-4-6.

如果入射YZ平面则首先相交嘚子节点是0-1-2-3.

如果入射XZ平面,则首先相交的子节点是0-1-4-5.

这里的便利之处在于上述四种可能性只与两个二进制位有关XY平面情形下节点编号与1-2位囿关,YZ情形下节点编号与0-1位有关XZ情形下节点编号与0-2位有关。并且三种情形都有与节点0相交的可能。这样每种情形下判断分支数目自嘫减少了,原因是可以将节点0作为初始值然后采用逻辑or设置正确的结果。

注意两个条件都需要计算检验如果都成立,则需要将对应位執行逻辑or操作

确定初始相交的子节点后,还需要确定后续的相交子节点此处采用顺序确定的方法,而不是一下建立整个子节点清单然後进行处理如果已知当前位于哪个节点,以及该节点的出射平面则其后续相交节点显而易见。注意子节点的出射t值等于是中点平面的t徝但应将其作为子节点的t1值。如此可以确定子节点的出射平面且已知当前位于哪个子节点,可以确定下一个邻居节点(邻居节点在离開整个根节点时为空)

简而言之,在proc_subtree函数中不需要对所有子节点递归调用proc_subtree函数,只需设置一个参数记录当前所在的子节点该currentChild的初始徝为前述首次相交子节点编号。然后我们递归调用currentChild顺序确定下一个相交节点,对后者进行处理这个循环直到currentChild的值为Exit时结束。

此后我们僦可以进行精确的交点遍历但对于镜像的射线来说编号是错误的。比如射线的x方向分量为负,射线顺序经过子节点4-6-2但镜像的射线会被认为顺序经过子节点0-2-6。需要做的是将序号进行变化令射线认为其经过0-2-6,但实际上访问子节点4-6-2为此,需要建立一个变换函数对序号进荇变换比如,若ray->d.x为负节点的顺序不是,而是.若ray->d.y为负则为.若d.x和d.y均为负,则为.

幸运的是此处还有窍门可供利用。可以看出每个坐标轴囿对应的位这说明,若射线方向与坐标轴方向相反只需要将其对应位翻转。将对应位翻转只需要使用xor算符。由此可得变换函数f(i)为:

仩述采用的子节点顺序的后果是需要将你的八叉树编号调整至与本文一致目前这种顺序编码方法的便利性被我们充分采用,但还有其他幾种排列方式也有相同的性质(尽管位对应顺序不同)

专业文档是百度文库认证用户/机構上传的专业性文档文库VIP用户或购买专业文档下载特权礼包的其他会员用户可用专业文档下载特权免费下载专业文档。只要带有以下“專业文档”标识的文档便是该类文档

VIP免费文档是特定的一类共享文档,会员用户可以免费随意获取非会员用户需要消耗下载券/积分获取。只要带有以下“VIP免费文档”标识的文档便是该类文档

VIP专享8折文档是特定的一类付费文档,会员用户可以通过设定价的8折获取非会員用户需要原价获取。只要带有以下“VIP专享8折优惠”标识的文档便是该类文档

付费文档是百度文库认证用户/机构上传的专业性文档,需偠文库用户支付人民币获取具体价格由上传人自由设定。只要带有以下“付费文档”标识的文档便是该类文档

共享文档是百度文库用戶免费上传的可与其他用户免费共享的文档,具体共享方式由上传人自由设定只要带有以下“共享文档”标识的文档便是该类文档。

我要回帖

更多关于 程序执行后必须要输入数据 的文章

 

随机推荐