【问题标题】:How to make line with rounded (smooth) corners with AndroidPlot如何使用 AndroidPlot 与圆角(光滑)角对齐
【发布时间】:2013-08-03 14:27:41
【问题描述】:

我在绘制图表时遇到了一个小问题。下面的图片是我已经完成的。


图表应代表可用 Wi-Fi 网络的实际信号强度。这是一个简单的XYPlot,这里的数据用SimpleXYSeries 表示(值是动态创建的)。

这是一段小sn-p代码(仅作为示例):

plot = (XYPlot) findViewById(R.id.simplexyPlot);
series1 = new SimpleXYSeries(Arrays.asList(series1Numbers),
SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Link 1");
f1 = new LineAndPointFormatter(color.getColor(), null,
Color.argb(60, color.getRed(), color.getGreen(), color.getBlue()), null);
plot.addSeries(series1, f1);

图片中的例子是dB变化的动态模拟。一切正常,我想,正确,但我想要实现的是与“圆”角对齐(参见图片以了解我的意思)。

我已经尝试自定义 LineFormatter:

f1.getFillPaint().setStrokeJoin(Join.ROUND);
f1.getFillPaint().setStrokeWidth(8);

但这并没有按预期工作。

注意:Wifi Analyzer 应用程序有一个类似的图表,它的图表有我想要的圆角。它看起来像这样:

【问题讨论】:

  • 您可能会发现这篇文章很有帮助,stackoverflow.com/a/7608516/2291915。 getFillPaint() 返回 android 的 Paint 对象,从那里您可以使用 Android 方法来实现您想要的效果。祝你好运。
  • @buczek 谢谢哥们,但它没有像我希望的那样工作。不过谢谢你的意见。
  • 答案已更新为所需图形的屏幕。提前致谢。

标签: android androidplot


【解决方案1】:

您可以使用Path.cubicTo() 方法。它使用三次样条算法绘制一条线,从而产生您想要的平滑效果。

查看similar question here 的答案,其中有人在谈论三次样条曲线。有一个简短的算法显示如何计算Path.cubicTo() 方法的输入参数。您可以使用分隔值来实现所需的平滑度。例如,在下图中,我除以 5 而不是 3。希望这会有所帮助。

我花了一些时间实现了一个SplineLineAndPointFormatter 类,它可以满足您在 androidplot 库中需要的东西。它使用相同的技术。这是 androidplot 示例应用程序的外观。你只需要使用它而不是LineAndPointFormatter

这是代码示例和我编写的类。

f1 = new SplineLineAndPointFormatter(color.getColor(), null, 
      Color.argb(60, color.getRed(), color.getGreen(), color.getBlue()), null);
plot.addSeries(series1, f1);

这里是魔术类。它基于 androidplot 库的 0.6.1 版本。

package com.androidplot.xy;

import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;

import com.androidplot.ui.SeriesRenderer;
import com.androidplot.util.ValPixConverter;

public class SplineLineAndPointFormatter extends LineAndPointFormatter {

    public SplineLineAndPointFormatter() { }

    public SplineLineAndPointFormatter(Integer lineColor, Integer vertexColor, Integer fillColor) {
        super(lineColor, vertexColor, fillColor, null);
    }

    public SplineLineAndPointFormatter(Integer lineColor, Integer vertexColor, Integer fillColor, FillDirection fillDir) {
        super(lineColor, vertexColor, fillColor, null, fillDir);
    }

    @Override
    public Class<? extends SeriesRenderer> getRendererClass() {
        return SplineLineAndPointRenderer.class;
    }

    @Override
    public SeriesRenderer getRendererInstance(XYPlot plot) {
        return new SplineLineAndPointRenderer(plot);
    }

    public static class SplineLineAndPointRenderer extends LineAndPointRenderer<BezierLineAndPointFormatter> {

        static class Point {
            public float x, y, dx, dy;
            public Point(PointF pf) { x = pf.x; y = pf.y; }
        }

        private Point prev, point, next;
        private int pointsCounter;

        public SplineLineAndPointRenderer(XYPlot plot) {
            super(plot);
        }

        @Override
        protected void appendToPath(Path path, final PointF thisPoint, PointF lastPoint) {
            pointsCounter--;

            if (point == null) {
                point = new Point(thisPoint);
                point.dx = ((point.x - prev.x) / 5);
                point.dy = ((point.y - prev.y) / 5);
                return;

            } else if (next == null) {
                next = new Point(thisPoint);
            } else {
                prev = point;
                point = next;
                next = new Point(thisPoint);
            }

            point.dx = ((next.x - prev.x) / 5);
            point.dy = ((next.y - prev.y) / 5);
            path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x - point.dx, point.y - point.dy, point.x, point.y);

            if (pointsCounter == 1) { // last point
                next.dx = ((next.x - point.x) / 5);
                next.dy = ((next.y - point.y) / 5);
                path.cubicTo(point.x + point.dx, point.y + point.dy, next.x - next.dx, next.y - next.dy, next.x, next.y);
            }

        }

        @Override
        protected void drawSeries(Canvas canvas, RectF plotArea, XYSeries series, LineAndPointFormatter formatter) {

            Number y = series.getY(0);
            Number x = series.getX(0);
            if (x == null || y == null) throw new IllegalArgumentException("no null values in xyseries permitted");

            XYPlot p = getPlot();
            PointF thisPoint = ValPixConverter.valToPix(x, y, plotArea,
                    p.getCalculatedMinX(), p.getCalculatedMaxX(), p.getCalculatedMinY(), p.getCalculatedMaxY());

            prev = new Point(thisPoint);
            point = next = null;
            pointsCounter = series.size();

            super.drawSeries(canvas, plotArea, series, formatter);
        }
    }
}

【讨论】:

  • 谢谢,但我需要使用图表而不是 Canvas。
  • 我刚刚通过添加 SplineLineAndPointFormatter 来更新答案,这对 androidplot 库也是如此。您可以将此类添加到您的项目中并按照说明使用。
  • 看起来构造函数中不再允许空值。下面的代码对我有用。 new SplineLineAndPointFormatter(Color.rgb(90, 90, 90), Color.rgb(80, 80, 80), Color.rgb(20, 20, 20), FillDirection.TOP);
  • 我在库的源代码中没有找到这个选项。我会说它不受支持。
  • 你创建了一个Paint,样式为Paint.STROKE,并在其上调用setStrokeWidth()。只需确保使用SplineLineAndPointFormatter.setLinePaint() 进行设置即可。
【解决方案2】:

1- 我猜你只用几个点来绘制信号图。所有图形/图表应用程序都尝试用直线连接点,然后您的图表将显示出来。因此,如果您只使用三个点,您的图表将看起来像一个三角形!如果你想让你的图表弯曲,你必须添加更多的点。然后它像曲线一样出来。

2- 或者你可以找到任何可以绘制sin图形的库,例如GraphView Library。然后尝试绘制这个函数:

所以它看起来像这样:

然后将其翻译成(a,0),这样结果看起来就是你想要的。

3-另外一种方式,你可以在Java中使用内置的Math.sin

例如在 ab 范围内选择 1000 个点,并为每个点计算上述函数的值,最后创建一个 path 并将它们显示在画布中。

您可以使用quadTo (float x1, float y1, float x2, float y2) 为您简化绘图quad curves。文档说:

从最后一点添加二次贝塞尔曲线,接近控制点 (x1,y1),并在 (x2,y2) 处结束。如果没有调用 moveTo() 这个轮廓,第一个点自动设置为(0,0)。

参数

x1 二次曲线上控制点的 x 坐标
y1 二次曲线上控制点的 y 坐标
x2 二次曲线终点的 x 坐标
y2 二次曲线终点的y坐标

最后,我添加了一个简单的类,它扩展了View,并且可以绘制一条看起来像你想要的曲线:

public class SinWave extends View {

    private float first_X = 50;
    private float first_Y = 230;
    private float end_X = 100;
    private float end_Y = 230;
    private float Max = 50;

    public SinWave(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint() {
            {
                setStyle(Paint.Style.STROKE);
                setStrokeCap(Paint.Cap.ROUND);
                setStrokeWidth(0.7f);
                setAntiAlias(true);
                setColor(0xFFFF00FF);
            }
        };
        final Path path = new Path();
        path.moveTo(first_X, first_Y);
        path.quadTo((first_X + end_X)/2, Max, end_X, end_Y);
        canvas.drawPath(path, paint);
    }
}

结果必须如下所示:

您可以向类添加更多方法并对其进行更改以提高性能!

【讨论】:

  • @你能提供一些代码吗?我数学不够好。我不喜欢数学。提前致谢。
  • 嗨,伙计,我在这里。所以它很好,但这是油漆,我需要在一些图形 API 中做到这一点。你能在特别是在 AndroidPlot 中做吗?谢谢(对不起,我现在写,最近几天很忙)。
  • 好的,伙计。我会给你赏金,因为它有效,但不是我想要的。我会继续寻找。
【解决方案3】:

Androidplot 中一直有一个平滑线渲染器:BezierLineAndPointRenderer,它和上面的实现一样使用 Android 内置的 Bezier 绘图例程 cubicTo(...) & quadTo(...) 。问题在于,使用贝塞尔曲线以这种方式绘制平滑线会产生一条假线,它会以不同的量超出实际控制点,如果仔细观察上图,您会发现这种情况。

解决方法是使用Catmull-Rom样条插值,现在Androidplot终于支持了。详情在这里:http://androidplot.com/smooth-curves-and-androidplot/

【讨论】:

    【解决方案4】:

    使用 ChartFactory.getCubeLineChartView 代替 ChartFactory.getLineChartView 使用 chart 引擎

    【讨论】:

      【解决方案5】:

      在一些简单的情况下,这可能会有所帮助:

      mPaint.pathEffect = CornerPathEffect(radius)
      

      甚至结合

      path.lineTo(x,y)
      

      【讨论】:

        【解决方案6】:

        试试这个:

        symbol = new Path();
        paint = new Paint();
        paint.setAntiAlias(true);      
        paint.setStrokeWidth(2);
        paint.setColor(-7829368);  
        paint.setStrokeJoin(Paint.Join.ROUND);    // set the join to round you want
        paint.setStrokeCap(Paint.Cap.ROUND);      // set the paint cap to round too
        paint.setPathEffect(new CornerPathEffect(10) );
        paint.setStyle(Paint.Style.STROKE);       
        
        symbol.moveTo(50.0F, 230.0F);         
        symbol.lineTo(75.0F, 100.0F);
        symbol.lineTo(100.0F, 230.0F);
        

        找到的大部分信息here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-07-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多