雜篇:Android繪製函數圖象及正弦函數的介紹

零、前言

這篇是爲了下一篇作點鋪墊,也是來複習一些數學基礎
本篇屬於休閒娛樂,不要太較真,小科普一下,不喜勿噴
本文知識點前4點你能夠隨便看看,但第5點很是重要,本文源碼見捷文規範git

本文知識點:
1)數學函數的概念
2)直角座標系的下函數圖形
3)極座標下的函數圖象
4)參數方程下的函數圖形
5)正弦函數的詳細分析(爲下一篇文章作鋪墊)github


1、數學函數的概念:

1.高中數學必修1:
設A,B爲非空的數集,若是按照某種肯定的對應關係f,  
使對於集合A中的任意的任意一個數x,在集合B中都有惟一肯定的數f(x)和它對應,
那麼就稱"f:A→B"爲從集合A到集合B的一個函數,記做:
y=f(x),x∈A

其中,x叫作自變量,x的取值範圍叫作函數的[定義域]
與x的值對應的y值叫作函數值,函數值的集合{f(x)|x∈A}叫作函數的[值域]
複製代碼

2.大學高等數學
設數集D⊂ R,則稱映射f:D→R爲定義在D上的函數,一般簡記爲
y=f(x),x∈ D

其中x稱自變量,y稱因變量,D稱定義域,記做Df,即Df=D.
值域:Rf=f(D)={y|y=f(x),x∈ D}
複製代碼

3.映射:
設X,Y是兩個非集合,若是存在一個法則f,使的對X中的每一個元素x,
按法則f,在Y中有惟一肯定的元素y與之對應,則稱f爲X到Y的映射,記做
f:X→Y

其中y稱爲元素x(在映射f下)的像,並記做f(x),即y=f(x)
而元素x稱爲元素y(在映射f下)的原像
複製代碼

2、直角座標系的下函數圖形

這裏只是模擬函數,而後繪製出可視的圖象
數學中的實數是連續的,這裏在屏幕中將像素做爲基本的單元
繪圖核心:點集成線,單點半徑1px
自變量:x
定義域:Df用集合Set表示
函數關係:函數f(x)
點集用Map表示,x→y編程


0.網格與座標系的繪製

網格和座標系我已經封裝,初始View以下:canvas

public class MathView extends View {
    private Point mCoo = new Point(500, 700);//座標系
    private Picture mCooPicture;//座標系canvas元件
    private Picture mGridPicture;//網格canvas元件
    private Paint mHelpPint;//輔助畫筆
    private Paint mPaint;//主畫筆
    private Path mPath;//主路徑
    public MathView(Context context) {
        this(context, null);
    }

    public MathView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();//初始化
    }

    private void init() {
        //初始化主畫筆
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
        mPaint.setStrokeWidth(2);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        //初始化主路徑
        mPath = new Path();

        //初始化輔助
        mHelpPint = HelpDraw.getHelpPint(Color.RED);
        mCooPicture = HelpDraw.getCoo(getContext(), mCoo);
        mGridPicture = HelpDraw.getGrid(getContext());
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        HelpDraw.draw(canvas, mGridPicture, mCooPicture);
        canvas.save();
        canvas.translate(mCoo.x, mCoo.y);
        canvas.scale(1, -1);//y軸向上
        canvas.restore();
    }

複製代碼

網格和座標系準備.png

具體細節這裏不說了,詳見:Android關於Canvas你所知道的和不知道的一切,或源碼bash


1.一次函數:y=x,定義域[-200,300]

y=x.png


1.1:幾個成員變量
private TreeSet<Float> Df = new TreeSet<>();//定義域
private Map<Float, Float> funMap = new HashMap<>();//映射表
private Paint mTextPaint;//文字畫筆
複製代碼

1.2:初始化定義域
/**
 * 初始化定義域
 */
private void initDf() {
    for (float i = -200; i <= 300; i++) {
        Df.add(i);//初始化定義域
    }
}
複製代碼

1.3:對應法則fx
/**
 * 對應法則
 * @param x 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float x) {
    float y = x;
    return y;
}
複製代碼

1.4:遍歷定義域,將原像x和像f(x)加入映射表
/**
 * 遍歷定義域,將原像x和像f(x)加入映射表
 */
private void map() {
    Df.forEach(x -> {
        funMap.put(x, f(x));
    });
    //添加全部點
}
複製代碼

1.5:繪製映射表
/**
 * 繪製映射表
 * @param canvas 畫筆
 * @param map 點集映射表
 */
private void drawMap(Canvas canvas, Map<Float, Float> map) {
    map.forEach((k, v) -> {
        canvas.drawPoint(k, v, mPaint);
    });
}
複製代碼

2.絕對值函數:y=|x|,定義域[-200,300]

只需改一點微信

y=abs(x).png

/**
 * 對應法則
 * @param x 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float x) {
    float y=Math.abs(x);
    return y;
}
複製代碼

3.二次函數,定義域[-200,300]

二次函數.png

/**
 * 對應法則
 * @param x 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float x) {
    float y=(x - 100) * (x - 100) / 200 + 100;
    return y;
}
複製代碼

4.對數函數:log10(x)爲例,定義域[1,1000]

log10.png

/**
 * 初始化定義域
 */
private void initDf() {
    for (float i = 1; i <= 1000; i++) {
        Df.add(i);//初始化定義域
    }
}

/**
 * 對應法則
 *
 * @param x 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float x) {
    float y = (float) (100.f * Math.log10(x));
    return y;
}
複製代碼

5.指數函數:定義域[-400,500]

指數函數.png

/**
 * 初始化定義域
 */
private void initDf() {
    for (float i = -400; i <= 500; i++) {
        Df.add(i);//初始化定義域
    }
}

/**
 * 對應法則
 *
 * @param x 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float x) {
    float y= 100*(float) Math.pow(Math.E,x/300f);
    return y;
}
複製代碼

6.正弦函數:定義域[-360°,450°]

正弦函數.png

/**
 * 初始化定義域
 */
private void initDf() {
    for (float i =-360; i <= 450; i++) {
        Df.add(i);//初始化定義域
    }
}

/**
 * 對應法則
 *
 * @param x 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float x) {
    float y= (float) (100*Math.sin(Math.PI/180*x));
    return y;
}
複製代碼

經歷過上面幾個函數的繪製,不難發現,只有更改對應法則,即函數關係式就能夠了ide


3、極座標下的函數圖象

1).尋找角度thta和長度p的函數關係
2).使用極座標與直角座標系的轉換關係來繪製點集函數


1.笛卡爾心型線:ρ= 100*(1-cosθ)

極座標方程--笛卡爾心型線.png

/**
 * 初始化定義域
 */
private void initDf() {
    for (float i = 1; i <= 360; i++) {
        Df.add(i);//初始化定義域
    }
}

/**
 * 繪製映射表
 *
 * @param canvas 畫筆
 * @param map    點集映射表
 */
private void drawMap(Canvas canvas, Map<Float, Float> map) {
    map.forEach((thta, p) -> {
        Log.e(TAG, "drawMap: "+p+thta);
        canvas.drawPoint((float) (p * Math.cos(thta)), (float) (p * Math.sin(thta)), mPaint);
    });
}

/**
 * 對應法則
 *
 * @param thta 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float thta) {
    float p = (float) (100 * (1 - Math.cos(thta)));
    return p;
}

/**
 * 遍歷定義域,將原像x和像f(x)加入映射表
 */
private void map() {
    Df.forEach(x -> {
        float thta = (float) (Math.PI / 180 * x);
        funMap.put(thta, f(thta));
    });
    //添加全部點
}
複製代碼

2.四葉草:ρ= 100*(1-4*sinθ)

極座標方程--四葉草.png

/**
 * 對應法則
 *
 * @param thta 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float thta) {
    float p = (float) (100 * (1 - Math.sin(4 * thta)));
    return p;
}
複製代碼

3.畫着玩:ρ=(e^(cosθ)- 2cos(4θ) + [sin(θ/12)]^5)*100

極座標方程--畫着玩.png

/**
 * 對應法則
 *
 * @param thta 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float thta) {
    float p = (float) (100f*(Math.pow(Math.E,Math.cos(thta)) - 2 * Math.cos(4 * thta) + Math.pow(Math.sin(thta / 12), 5)));;
    return p;
}
複製代碼

4.渦旋線:ρ= a*θ

渦旋線.png

/**
 * 對應法則
 *
 * @param thta 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float thta) {
    float p = 30*thta;
    return p;
}
複製代碼

5.極座標下的圓

極座標下的圓.png

/**
 * 對應法則
 *
 * @param thta 原像(自變量)
 * @return 像(因變量)
 */
private float f(Float thta) {
    float p = 200;
    return p;
}

複製代碼

4、參數方程下的函數圖象

1.雙曲線:x=a/cosα,y=btanα

參數方程模擬雙曲線.png

/**
     * 初始化定義域
     */
    private void initDf() {
        for (float i = 0; i <= 360 ; i++) {
            Df.add(i);//初始化定義域
        }
    }

    /**
     * 繪製映射表
     *
     * @param canvas 畫筆
     * @param map    點集映射表
     */
    private void drawMap(Canvas canvas, Map<Float, Float> map) {
        map.forEach((k, v) -> {
            canvas.drawPoint(k, v, mPaint);
        });
    }

    /**
     * 對應法則
     *
     * @param thta 原像(自變量)
     * @return y像(因變量)
     */
    private float y(Float thta) {
        float y = (float) (100 * Math.tan(thta));
        return y;
    }

    /**
     * 對應法則
     *
     * @param thta 原像(自變量)
     * @return x像(因變量)
     */
    private float x(Float thta) {
        float x = (float) (200 / Math.cos(thta));
        return x;
    }

    /**
     * 遍歷定義域,將原像x和像f(x)加入映射表
     */
    private void map() {
        Df.forEach(x -> {
            float thta = (float) (Math.PI / 180 * x);
            funMap.put(x(thta), y(thta));
        });
        //添加全部點
    }
複製代碼

2.橢圓:x=a*cosα,y=bsinα

橢圓.png

/**
 * 對應法則
 *
 * @param thta 原像(自變量)
 * @return y像(因變量)
 */
private float y(Float thta) {
    float y = (float) (300 * Math.sin(thta));
    return y;
}
/**
 * 對應法則
 *
 * @param thta 原像(自變量)
 * @return x像(因變量)
 */
private float x(Float thta) {
    float x = (float) (400 * Math.cos(thta));
    return x;
}
複製代碼

3.參數方程:雙鈕線x=a√(cos2θ )cosθ,y=a√(cos2θ)sinθ

雙鈕線.png

/**
 * 對應法則:y=a√(cos2θ)sinθ
 *
 * @param thta 原像(自變量)
 * @return y像(因變量)
 */
private float y(Float thta) {
    float y = (float) (200 * Math.sqrt(Math.cos(2*thta))*Math.sin(thta));
    return y;
}

/**
 * 對應法則:x=a√(cos2θ )cosθ
 *
 * @param thta 原像(自變量)
 * @return x像(因變量)
 */
private float x(Float thta) {
    float x = (float) (200 * Math.sqrt(Math.cos(2*thta))*Math.cos(thta));
    return x;
}
複製代碼

5、分析與優化

1.分析

你可能已經吐槽了:什麼鬼,怎麼後面都是斷斷續續的點拼成的
等等...先別急,咱們來看看這幅圖能說明什麼?
先看一下定義域: [-360,450],共810個點,每一個點半徑1px,每一個點橫向距離1px
點密集則說明相鄰兩點間的dy很小,相反,稀疏則說明相鄰兩點間的dy很大
也就是密集說明函數變化的幅度小,稀疏說明函數變化的幅度大
當相鄰兩點距離大於圓的直徑(2px)時,視覺上會看出兩個點,即不連續。post

斷續的點問題.png


2.分析總結

爲了方便描述,這裏定義了幾個概念優化

若是把一條完美的函數曲線看做P,
那全部現實中(紙、屏幕)的函數圖象P'都是對P的取點模擬, 從P上取點的行爲稱爲[取樣], 採樣的個數稱爲[取樣總數], 取樣的相鄰兩點xn,xn+1間的距離稱爲[取樣距離dxn] 當每一個dxn值都相等的時,稱爲[等距採樣] 兩個樣本點pn,pn+1之間的距離稱爲[樣本距離dpn] 複製代碼

3.看一下連續的點有哪些

在加入點集時過濾掉相鄰兩點間距離大於直徑的點

/**
 * 兩點間的距離
 * @return
 */
private float dis(float x0, float y0, float x1, float y1) {
    return (float) Math.sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1));
}
複製代碼
/**
 * 遍歷定義域,將原像x和像f(x)加入映射表
 */
private void map() {
    Df.forEach(x -> {
        float dis = dis(x, f(x), x + 1, f(x + 1));//每相鄰兩點間距離
        if (dis < mLineWidth && dis > mLineWidth / 2) {
            funMap.put(x, f(x));
        }
    });
複製代碼

連續點.png


4.不行連續的點處理思路:

思路也就是在間距處再取樣

處理

/**
 * 遍歷定義域,將原像x和像f(x)加入映射表
 */
private void map() {
    Df.forEach(x -> {
        float dis = dis(x, f(x), x + 1, f(x + 1));//每相鄰兩點間距離
        if (dis < mLineWidth && dis > mLineWidth / 2) {
            funMap.put(x, f(x));
        } else if (dis > mLineWidth) {
            float num = dis / mLineWidth;//在切割數
            for (float di = 0; di <= num; di += (1.f / num)) {
                x += di;
                funMap.put(x, f(x));
            }
        }
    });
    //添加全部點
}
複製代碼

優化後.png


6、正弦函數的詳細分析

1.正弦函數簡介

正弦函數表達式.png

其中A,ω,φ,k是常數,且ω≠0
振幅:A
角頻率:ω
週期:T=2π/ω 
頻率:f=1/T=ω/2π
相位:ωx+φ
初相:φ
平衡線:y=k
波峯:最大值|A|
波谷:最小值-|A|
複製代碼

2.振幅A:離開平衡位置的最大距離

下面橫軸的每格表明90°,化爲弧度製表示即:π/2,每四格是360°,即2π

2.1:A=300

A=300.png


2.2:A=100

A=100.png


2.3:振幅的做用
決定正弦曲線的波峯與波谷,形象來講就是"高矮" 
振幅越大,波峯越高,波谷越低,每一個週期的圖象顯得"高"
複製代碼

3.角頻率ω:單位時間內變化的相角弧度值
3.1:ω=2

ω=2.png


3.2:ω=5

ω=5.png


3.3:角頻率的做用
決定正弦曲線的週期,形象來講就是"胖瘦" 
角頻率越大,週期越小,每一個週期的圖象顯得"瘦"

ω=2 週期:T = 2π/ω = π 從圖中看,每兩格一週期,即π 
頻率:f = 1/T = 1/π
複製代碼

4.初相φ:x=0時的相位
4.1:φ=π/6

φ=π/6


4.2:φ=π/2

φ=π/2


4.3:振幅的做用
相位決定了標準正弦函數的左右偏移:正左偏,負右偏,偏移量:φ/ω
複製代碼

5.平衡值k:決定平衡線的位置
5.1:k=100

k=100.png


5.2:k=200

k=200.png

5.3:平衡值的做用
平衡值決定標準正弦函數的上下偏移:正上偏,負下偏,偏移量:k
複製代碼

如今對於幾個正弦函數的參數值已經有了一點了解,本篇結束


附錄:一些經常使用符號:
θ ρ φ
π α β γ
η μ ζ Ω

後記:捷文規範

1.本文成長記錄及勘誤表
項目源碼 日期 備註
V0.1-github 2018-1-2 Android繪製函數圖象及正弦函數的介紹
2.更多關於我
筆名 QQ 微信 愛好
張風捷特烈 1981462002 zdl1994328 語言
個人github 個人簡書 個人掘金 我的網站
3.聲明

1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持


icon_wx_200.png
相關文章
相關標籤/搜索