android迭代畫樹

前段時間發現了這個效果;


於是開始了我的迭代之旅,感覺很有目的性!

android用自定義view來處理視圖,總體思路就是先畫V,畫線就需要兩個點的座標,所有主要難的就是求每次畫線的點的座標

1.點分爲左點,右點,下面的基點,以及中心線的中點:思路如下,迭代的過程就是先可左側邊的線開始畫,然後返回倒數第一個點畫右側,再判斷次數是否滿足,滿足繼續畫新右側點的左線,不滿足,回到最開始的左線,畫倒數第二個右線的,這樣依次迭代

2.求點的座標,由於每次的夾角是固定的所有每次畫V時都用上次的基點和本次的基點求出中點,再將中點和本次基點代入公式,分別求出V的左點和右點的座標

3.中點座標的求法,由於每次畫的長度是固定的S,所有中點到基點的距離是固定的S*cos(夾角的一半),由於中點,本次基點和上次基點在一條直線上,所以可以求出對應的△x和△y,再對應點在左視圖和右視圖分別求出座標即可

4.最後講一下左點右點的求法,傳入基點和中點,基本思路是根據tan的比值先求出中線與豎直線的夾角,再偏轉V夾角的一半,根據左線或右線與豎直線的夾角就能求出△x和△y,這樣對應的座標就出來了

package com.lg.drawtree;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class LView extends View {
	private double Viewwidge;
	private double Viewhight;
	private Canvas canvas;
	private Paint p;
	private Context context;
	private int X = 15;// 角度
	private int S = 100;// 每次畫線的距離
	private Point P = new Point();// 初點
	private int N = 7;//迭代次數

	public LView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	public LView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public LView(Context context) {
		super(context);
		init(context);
	}

	private void init(Context context) {
		this.context = context;
		p = new Paint();
		p.setStrokeWidth(8);
		p.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,大家一看效果就明白了
		p.setColor(Color.GREEN);// 設置綠色
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		Viewwidge = MeasureSpec.getSize(widthMeasureSpec);
		Viewhight = MeasureSpec.getSize(heightMeasureSpec);
		P = new Point(Viewwidge / 2.0, Viewhight*0.75);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		this.canvas = canvas;
		drawTreeL(P, P, N - 1);
	}

	private void drawTreeL(Point p, Point pp, int n) {
		Point pp0 = pp;// 基點新
		Point p1;// 左點
		Point p2;// 右點
		Point p3 = new Point();// 中點
		Point p0 = p;// 基點原
		// 先求中點,
		if (p0.getX() == pp0.getX() && p0.getY() == pp0.getY()) {
			// 先求出初值的中點;
			p3.setX(p0.getX());
			p3.setY(p0.getY() - S * (Math.cos(Math.toRadians(X))));
		} else {
			if (pp0.getX() <= (Viewwidge / 2.0)) {
				// 左側的中點
				p3.setX(pp0.getX() - (Math.cos(Math.toRadians(X))) * (p0.getX() - pp0.getX()));
				p3.setY(pp0.getY() - (Math.cos(Math.toRadians(X))) * (p0.getY() - pp0.getY()));
			} else {
				// 右側的中點
				p3.setX((Math.cos(Math.toRadians(X))) * (pp0.getX() - p0.getX()) + pp0.getX());
				p3.setY(pp0.getY() - (Math.cos(Math.toRadians(X))) * (p0.getY() - pp0.getY()));

			}
		}
		if (0 == n) {

		} else {
			p1 = lt(p3, pp0);
			Log.e("LG", "左中點" + p3.toString() + ",左新基點" + p1.toString() + ",原基點" + p0.toString());
			drawT(pp0, p1, this.p);
			drawTreeL(pp0, p1, n - 1);//將新的左點作爲下次的基點

			p2 = rt(p3, pp0);
			Log.e("LG", "右中點" + p3.toString() + ",右新基點" + p1.toString() + ",原基點" + p0.toString());
			drawT(pp0, p2, this.p);
			drawTreeL(pp0, p2, n - 1);//將新的右點作爲下次的基點
		}
	}

	/** 
	* @Title: lt 
	* @Description: 求左點的座標
	* @param @param p3 中點
	* @param @param po 本次的基點
	* @param @return    左點 
	* @return Point    返回類型 
	* @throws 
	*/
	private Point lt(Point p3, Point po) {
		double f;
		// 用中點和基點求座標
		Point pn = new Point();
		if (po.getX() <= (Viewwidge / 2.0)) {
			if ((p3.getY() - po.getY()) == 0) {
				f = Math.toRadians(0) + Math.toRadians(X);
			} else {
				f = Math.atan((po.getX() - p3.getX()) / (po.getY() - p3.getY())) + Math.toRadians(X);
			}
			pn.setX(po.getX() - S * (Math.sin(f)));
			pn.setY(po.getY() - S * (Math.cos(f)));
		} else {
			if ((p3.getY() - po.getY()) == 0) {
				f = Math.toRadians(0) - Math.toRadians(X);
			} else {
				f = Math.atan((p3.getX() - po.getX()) / (po.getY() - p3.getY())) - Math.toRadians(X);
			}
			pn.setX(po.getX() + S * (Math.sin(f)));
			pn.setY(po.getY() - S * (Math.cos(f)));
		}
		return pn;
	}

	/** 
	* @Title: rt 
	* @Description: 求右點的座標 
	* @param @param p3 中點
	* @param @param po 本次的基點
	* @param @return    右點
	* @return Point    返回類型 
	* @throws 
	*/
	private Point rt(Point p3, Point po) {
		double f;
		// 用中點和基點求座標
		Point pn = new Point();
		if (po.getX() < (Viewwidge / 2.0)) {
			if ((p3.getY() - po.getY()) == 0) {
				f = Math.toRadians(0) + Math.toRadians(X);
			} else {
				f = Math.atan((po.getX() - p3.getX()) / (po.getY() - p3.getY())) - Math.toRadians(X);
			}
			pn.setX(po.getX() - S * (Math.sin(f)));
			pn.setY(po.getY() - S * (Math.cos(f)));
		} else {
			if ((p3.getY() - po.getY()) == 0) {
				f = Math.toRadians(0) + Math.toRadians(X);
			} else {
				f = Math.atan((p3.getX() - po.getX()) / (po.getY() - p3.getY())) + Math.toRadians(X);
			}
			pn.setX(po.getX() + S * (Math.sin(f)));
			pn.setY(po.getY() - S * (Math.cos(f)));
		}
		return pn;
	}

	private void drawT(Point po, Point pn, Paint p) {
		canvas.drawLine((float) po.getX(), (float) po.getY(), (float) pn.getX(), (float) pn.getY(), p);
	}
}

class Point {
	@Override
	public String toString() {
		return "Point [x=" + x + ", y=" + y + "]";
	}

	/**
	 * @return x
	 */
	public double getX() {
		return x;
	}

	/**
	 * @param x
	 *            要設置的 x
	 */
	public void setX(double x) {
		this.x = x;
	}

	/**
	 * @return y
	 */
	public double getY() {
		return y;
	}

	/**
	 * @param y
	 *            要設置的 y
	 */
	public void setY(double y) {
		this.y = y;
	}

	double x;
	double y;

	Point() {
		this.x = 0;
		this.y = 0;
	}

	Point(Double x, Double y) {
		this.x = x;
		this.y = y;
	}
}

              1,仍存在的問題,當角度超過180度時,對應的角度的三角函數的計算需要改動,(主要是正負的處理)

              2,當迭代次數較大時,畫線的長度應隨N成遞減的趨勢

              傳一張效果圖,歡迎大家提供建議,不足之處望大家提出,謝謝!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章