«

Android Path和PathMeasure类的使用之获取圆弧上的坐标值

时间:2024-3-2 18:47     作者:韩俊     分类: Android


问题:

已知图中的中心圆点在屏幕上的坐标为(x, y),分别求出点1、2、3、4的坐标值!



解决方法:

可以利用Android的SDK自带类 android.graphics.Path和android.graphics.PathMeasure,

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);
    }


标签: android

热门推荐