前段时间发现了这个效果;
于是开始了我的迭代之旅,感觉很有目的性!
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成递减的趋势
传一张效果图,欢迎大家提供建议,不足之处望大家提出,谢谢!