前段時間發現了這個效果;
於是開始了我的迭代之旅,感覺很有目的性!
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成遞減的趨勢
傳一張效果圖,歡迎大家提供建議,不足之處望大家提出,謝謝!