关于绘制圣诞树,关键点在于像素点的对称堆积和基础像素点的排版
实现过程截图:
主方法:
第一阶段:思考 最开始有两种构想,第一种是使用GD库,第二种就是直接输出像素点,直接在页面上展示 然后我就开始是思考如何做 1.首先我想到的一个点就是需要坐标定位,无论是GD库还是像素点的堆积都是需要指定坐标的 2.然后我就自然而然的想到数组(数组需要一个对称数组;一个实体,一个中心点,一个镜像(实体镜像)),然后实现指定实体长度的数组,那个数据最终的数据个数=1(中心点)+ 实体个数 + 镜像个数(就是实体个数) 3.坐标点确定好了,之后就该决定使用GD库还是像素点这两个方案中的当中的一个了,我想做的是油画的效果,所以使用像素点的方案方便调节和查看效果 4.像素点的方案确定好之后,我又在思考后续的问题(1.树是一个锐角三角形,锐角的角度是多少?实际上就是宽高比的问题,2,像素点如何在限定的边界内输出的像素点颜色是随机的,如果太整齐了效果不好),带着这些问题自然进入了下一个阶段
第二阶段:实施 1.选择像素点输出圣诞树,首先需要确定一个点,就是树的顶点,其他所有的坐标点都会以这个点来作为参照物,所以实施的第一步就是要确定顶点,那么我设置了一个顶点 : $top = array(100,600); 注释:100代表 距离顶部100个相对像素单位,600代表距离左边600个相对像素单位,为什么这样设置?因为的的屏幕是宽度大于高度,所以这样设置,如果是移动设备,可以把第一个数据设置成大于第二个数据 2.像素点在输出时X轴的偏移量,最终调试后,0.2的标准比较适合个人审美,所以选择了0.2作为标准,于是就有了 $offsetx = 0.2; 举例:单针对X轴来说,第三个数据作为中心点:array('0'=>array(99.6,600),'1'=>array(99.8,600),'2'=>array(100,600),'3'=>array(100.2,600),'4'=>array(100.4,600)); 3.像素点在输出时Y轴的偏移量,最终调试后,2的标准比较适合个人审美,所以选择了2作为标准,于是就有了 $offsety = 2; 举例:单针对Y轴来说,第三个数据作为中心点:array('0'=>array(100,604),'1'=>array(100,602),'2'=>array(100,600),'3'=>array(100,602),'4'=>array(100,604)); 4.将第2点和第3点合并起来,于是就有了一下数组:array('0'=>array(99.6,604),'1'=>array(99.8,602),'2'=>array(100,600),'3'=>array(100.2,602),'4'=>array(104,604)); 这样的话就得到了高度为3个像素点的锐角三角形 例如:^ :参照:partone + partfive 5.将第四点的数组按规律增加足够大,就能得到一个巨大的锐角三角形,于是设置了参数:$treebody = 120; 那么树桩的高是:120相对像素单位,那么树的高度是:480相对像素单位 = 600-120 6.根据第五点,树干的高度是480相对像素单位,那么左右的树叶是对称的,于是创建二维数组(480层,每一个相对像素单位为一层,那边树干部分最终的数据个数:480(实体个数:左边树叶)+480(镜像个数:右边树叶) + 1(中心点) = 961) 7.根据第六点,树的边界确定了,那么需要画出 形状为:^ 三角形 底部 : 那么需要知道最左边和最右边的树叶(对应数组的横坐标),用两者之差来打印像素点,实现现打印三角形的底边 参照:partfour 8.根据第六点,树的边界确定了,那么需要画出 形状为:^ 三角形 树桩 : 那么需要知道最左边和最右边的树叶(对应数组的横坐标),用两者之差的对称点来打印像素点+树桩高($treebody) 来实现打印树桩 参照:partthree 9.实现树叶的打印,随机颜色(红或者绿,使用rand来实现,取2的模,来实现颜色的随机) 10.实现油画的效果,那就需要在左右边界内.每一层数据的树叶左右连续的排列,实现连续的钝角三角形,颜色也是随机,可以参照第9点(越往下连续的三角形边长需要越长)偏移量:$offsetz 参照:parttwo 11.点缀效果,实现礼物(小铃铛) 参照:partsix
实现原理示意图:
public function tree(){
//初始化像素点容器 $html = ''; //设置顶点坐标,和底部最底下的坐标(X轴位置一样),那么高度是40 $top = array(100,600); /************偏移量设置开始************/ //横向(X轴)偏移量 $offsetx = 0.2; //纵向(Y轴)偏移量 $offsety = 2; //纵向(Z轴,油画效果)偏移量 $offsetz = 2; /************偏移量设置结束************/ //露出来的树干高 $treebody = 120; //设置树叶虽大宽度 //那么树的基本情况就已经出来了,算出边界(以2个单位为一个尺度算出各个点的范围) $heightmark= $top[1]-$treebody; //初始化容器(对称数组) $arrar = array(); for($i=0;$i<$heightmark;$i++){ $arrar[$i]['x']=$top[1]; $arrar[$i]['y']=$top[0]-$i; } //初始化临时容器 $arrardouble =array(); //算出水平点的位置 foreach ($arrar as $key=>$value){ /*************partone start***************/ $arrardouble[$key]['left']['x'] = ($value['x']-($offsetx*$key)?$value['x']-($offsetx*$key):0).'px'; $arrardouble[$key]['left']['y'] = ($value['y']+($offsety*$key)).'px'; $arrardouble[$key]['right']['x'] = ($value['x']+($offsetx*$key)?$value['x']+($offsetx*$key):0).'px'; $arrardouble[$key]['right']['y'] = ($value['y']+($offsety*$key)).'px'; /*************partone end***************/ /*************parttwo start***************/ //取随机数 $xmarx = rand($arrardouble[$key]['left']['x']-$offsetz,$arrardouble[$key]['right']['x']+$offsetz); $ymary = rand($arrardouble[$key]['left']['y']-$offsetz,$arrardouble[$key]['right']['y']+$offsetz); //数据分层(10个单位) if($key%5==0){ $nums= intval($key/5); for ($i=1;$i<$nums;$i++){ $num = rand(0,1); $nummark = rand(0,$i); $nummarks = rand(0,5); if($num%2==0){ $html .= "<span style='color:green;position: fixed;top:".intval($ymary+$nummark)."px;left:".intval($xmarx+$nummark)."px'>*</span>"; $html .= "<span style='color:green;position: fixed;top:".intval($ymary+$nummark)."px;left:".intval($xmarx-$nummark)."px'>*</span>"; }else{ $html .= "<span style='color:red;position: fixed;top:".intval($ymary+$nummark)."px;left:".intval($xmarx+$nummark)."px'>*</span>"; $html .= "<span style='color:red;position: fixed;top:".intval($ymary+$nummark)."px;left:".intval($xmarx-$nummark)."px'>*</span>"; } /*************partsix start***************/ $html .= "<span style='color:yellow;position: fixed;top:" .intval($ymary+$nummarks)."px;left:".intval($xmarx+$nummarks)."px'>*</span>"; /*************partsix end***************/ } } if($key%2==0){ $html .= "<span style='color:green;position: fixed;top:".$ymary."px;left:".$xmarx."px'>*</span>"; }else{ $html .= "<span style='color:red;position: fixed;top:".$ymary."px;left:".$xmarx."px'>*</span>"; } /*************parttwo end***************/ } //获取数据 $result = []; array_map(function ($value) use (&$result) { $result = array_merge($result, array_values($value)); }, $arrardouble); //画出横线和树干 $num = count($result); /*************partthree start***************/ for($i=0;$i<$treebody;$i++){ $html .= "<span style='color:green;position: fixed;top:".intval($result[$num-1]['y']+$i)."px;left:".intval((intval($result[$num-1]['x']-$result[$num-2]['x'])/2)+$result[$num-2]['x'])."px'>.</span>"; $html .= "<span style='color:green;position: fixed;top:".intval($result[$num-1]['y']+$i-1)."px;left:".intval((intval($result[$num-1]['x']-$result[$num-2]['x']-1)/2)+$result[$num-2]['x'])."px'>.</span>"; $html .= "<span style='color:green;position: fixed;top:".intval($result[$num-1]['y']+$i+1)."px;left:".intval((intval($result[$num-1]['x']-$result[$num-2]['x']+1)/2)+$result[$num-2]['x'])."px'>.</span>"; } /*************partthree end***************/ $left = intval(trim($result[$num-2]['x'],'px')); $right = intval(trim($result[$num-1]['x'],'px')); $with = intval($right-$left); /*************partfour start***************/ //底部 //for($i=0;$i<$with;$i++){ // $html .= "<span style='position: fixed;top:".$result[$num-1]['y'].";left:".intval($result[$num-2]['x']+$i)."px'>.</span>"; //} /*************partfour end***************/ /*************partfive start***************/ //左右树叶 //foreach ($result as $key=>$value){ // $html .= "<span style='position: fixed;top:".$value['y'].";left:".$value['x']."'>.</span>"; //} /*************partfive end***************/ var_dump($html);die; }