1. 程式人生 > >Android Path和PathMeasure類的使用之獲取圓弧上的座標值

Android Path和PathMeasure類的使用之獲取圓弧上的座標值

問題:

已知圖中的中心圓點在螢幕上的座標為(x, y),分別求出點1、2、3、4的座標值!


解決方法:

1)以圓點座標(x,y)為中心畫一個矩形RectF,

2)再通過Path類畫一個90度(180—270)的內切圓弧路徑,

3)然後將該路徑平分成3段,

4)再利用PathMeasure分別測量出各個點的座標值

程式碼如下:

private void calculateItemPositions() {
        // Create an arc that starts from startAngle and ends at endAngle
        // in an area that is as large as 4*radius^2
        //獲取中心圓點的座標值
        Point center = getActionViewCenter();
        //內切弧形路徑
        //以圓點座標(x,y)為中心畫一個矩形RectF
        RectF area = new RectF(center.x - radius, center.y - radius, center.x + radius, center.y + radius);
        Path orbit = new Path();
        //通過Path類畫一個90度(180—270)的內切圓弧路徑
        orbit.addArc(area, startAngle, endAngle - startAngle);

        PathMeasure measure = new PathMeasure(orbit, false);

        // Prevent overlapping when it is a full circle
        //然後將該路徑平分成3段,這裡的size為4
        int divisor;
        if(Math.abs(endAngle - startAngle) >= 360 || subActionItems.size() <= 1) {
            divisor = subActionItems.size();
        }
        else {
            divisor = subActionItems.size() -1;
        }

        // Measure this path, in order to find points that have the same distance between each other
        for(int i=0; i<subActionItems.size(); i++) {
            float[] coords = new float[] {0f, 0f};
            //利用PathMeasure分別測量出各個點的座標值coords
            measure.getPosTan((i) * measure.getLength() / divisor, coords, null);
            // get the x and y values of these points and set them to each of sub action items.
            subActionItems.get(i).x = (int) coords[0] - subActionItems.get(i).width / 2;
            subActionItems.get(i).y = (int) coords[1] - subActionItems.get(i).height / 2;
        }
    }

ps:簡單介紹一下Path類的一些方法的使用和說明

1.addArc(RectF oval, float startAngle, float sweepAngle)

畫扇形(弧線)。第二個引數為0時的位置是矩形右邊1/2高度的點,90為矩形底部1/2寬的位置,如此如此....正數為順時針旋轉,負數是逆時針旋轉。第三個引數是圖形繪製角度,上圖第三個引數為180,如果是-180,那麼圖形倒過來。

2.addCircle(float x, float y, float radius, Path.Direction dir)

畫圓。第一、二引數是圓心座標,第三引數是半徑,第四引數是順時針畫還是逆時針畫(啥玩意?)。

3.addOval(RectF oval, Path.Direction dir)

畫橢圓。

4.addPath(Path src, float dx, float dy)

複製一份Path,包含被複制的src的一切,並向X與Y軸方向移動第二、三引數的距離。

5.addRect(RectF rect, Path.Direction dir)

6.addRect(float left, float top, float right, float bottom, Path.Direction dir)

畫個矩形、四個引數對應與原點的相對距離的是個點。

7.addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)

畫圓角矩形。第二、三個引數為0時就是個矩形,為360時,就是個橢圓。第二個引數指X軸方向的角度,決定了與參考矩形的橫線交點位置,0-360決定交點範圍為 角點與線中點之間的某點。

8.arcTo(RectF oval, float startAngle, float sweepAngle)

等同於arcTo(RectF oval, float startAngle, float sweepAngle, boolean false)。測試發現:從之前的最後一點開始畫線到畫橢圓的開始點,接著畫個橢圓。

9.arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

如果最後一個引數為true,那麼等同於addArc(RectF oval, float startAngle, float sweepAngle)。

10.cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

畫貝塞爾曲線。前四個引數是兩個控制點,最後倆個引數是終止點。起始點通過moveTo(float x, float y)或者setLastPoint(float dx, float dy)方法設定。關於貝塞爾曲線,可以去網上找找資料。某人的部落格,關於此曲線

11.moveTo(float x, float y)

設定下一個圖形的開始點。

12.setLastPoint(float dx, float dy)

設定圖形的最後一個點位置。如果畫的是個封閉圖形,而這個點不在圖形線上,那麼這個點與最後一個圖形連上線完成封閉。如圖,本來畫了個圓角矩形,最後setLastPoint了一下。

13.close()

關閉當前圖形,如果最後一點不是開始的那點,那麼從最後一點畫線到開始點。簡而言之,畫三角型只需要畫倆條線,再調此方法能三角型就完成了。

/**
     * Pins distance to 0 <= distance <= getLength(), and then computes the
     * corresponding position and tangent. Returns false if there is no path,
     * or a zero-length path was specified, in which case position and tangent
     * are unchanged.
     *
     * @param distance The distance along the current contour to sample
     * @param pos If not null, eturns the sampled position (x==[0], y==[1])
     * @param tan If not null, returns the sampled tangent (x==[0], y==[1])
     * @return false if there was no path associated with this measure object
    */
    public boolean getPosTan(float distance, float pos[], float tan[]) {
        if (pos != null && pos.length < 2 ||
            tan != null && tan.length < 2) {
            throw new ArrayIndexOutOfBoundsException();
        }
        return native_getPosTan(native_instance, distance, pos, tan);
    }